diff --git a/src/run_mod.bat b/src/run_mod.bat index 97caf10..4f4be91 100644 --- a/src/run_mod.bat +++ b/src/run_mod.bat @@ -1 +1 @@ -@"C:\Program Files (x86)\Steam\steamapps\common\source sdk base\hl2.exe" -dev -game "C:\Program Files (x86)\Steam\steamapps\SourceMods\ultragame" -allowdebug %1 %2 %3 %4 %5 %6 %7 %8 %9 +@"C:\Program Files (x86)\Steam\steamapps\common\source sdk base 2007\hl2.exe" -dev -game "C:\Program Files (x86)\Steam\steamapps\SourceMods\ultragame" -allowdebug %1 %2 %3 %4 %5 %6 %7 %8 %9 diff --git a/src/src/cl_dll/c_fire_smoke.cpp b/src/src/cl_dll/c_fire_smoke.cpp deleted file mode 100644 index 76ddeb6..0000000 --- a/src/src/cl_dll/c_fire_smoke.cpp +++ /dev/null @@ -1,1470 +0,0 @@ -//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// -// -// Purpose: -// -// $NoKeywords: $ -//=============================================================================// -#include "cbase.h" -#include "IViewRender.h" -#include "ClientEffectPrecacheSystem.h" -#include "studio.h" -#include "bone_setup.h" -#include "engine/ivmodelinfo.h" -#include "c_fire_smoke.h" -#include "engine/IEngineSound.h" -#include "iefx.h" -#include "dlight.h" -#include "vstdlib/ICommandLine.h" - -// memdbgon must be the last include file in a .cpp file!!! -#include "tier0/memdbgon.h" - -#define PARTICLE_FIRE 0 - -CLIENTEFFECT_REGISTER_BEGIN( SmokeStackMaterials ) - CLIENTEFFECT_MATERIAL( "particle/SmokeStack" ) - CLIENTEFFECT_MATERIAL( "particle/fire" ) - CLIENTEFFECT_MATERIAL( "sprites/flamefromabove" ) - CLIENTEFFECT_MATERIAL( "sprites/flamelet1" ) - CLIENTEFFECT_MATERIAL( "sprites/flamelet2" ) - CLIENTEFFECT_MATERIAL( "sprites/flamelet3" ) - CLIENTEFFECT_MATERIAL( "sprites/flamelet4" ) - CLIENTEFFECT_MATERIAL( "sprites/flamelet5" ) - CLIENTEFFECT_MATERIAL( "sprites/fire1" ) -CLIENTEFFECT_REGISTER_END() - - -//----------------------------------------------------------------------------- -// Purpose: -// Input : *pRecvProp - -// *pStruct - -// *pVarData - -// *pIn - -// objectID - -//----------------------------------------------------------------------------- -void RecvProxy_Scale( const CRecvProxyData *pData, void *pStruct, void *pOut ) -{ - C_FireSmoke *pFireSmoke = (C_FireSmoke *) pStruct; - float scale = pData->m_Value.m_Float; - - //If changed, update our internal information - if ( ( pFireSmoke->m_flScale != scale ) && ( pFireSmoke->m_flScaleEnd != scale ) ) - { - pFireSmoke->m_flScaleStart = pFireSmoke->m_flScaleRegister; - pFireSmoke->m_flScaleEnd = scale; - } - - pFireSmoke->m_flScale = scale; -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : *pRecvProp - -// *pStruct - -// *pVarData - -// *pIn - -// objectID - -//----------------------------------------------------------------------------- -void RecvProxy_ScaleTime( const CRecvProxyData *pData, void *pStruct, void *pOut ) -{ - C_FireSmoke *pFireSmoke = (C_FireSmoke *) pStruct; - float time = pData->m_Value.m_Float; - - //If changed, update our internal information - //if ( pFireSmoke->m_flScaleTime != time ) - { - if ( time == -1.0f ) - { - pFireSmoke->m_flScaleTimeStart = Helper_GetTime()-1.0f; - pFireSmoke->m_flScaleTimeEnd = pFireSmoke->m_flScaleTimeStart; - } - else - { - pFireSmoke->m_flScaleTimeStart = Helper_GetTime(); - pFireSmoke->m_flScaleTimeEnd = Helper_GetTime() + time; - } - } - - pFireSmoke->m_flScaleTime = time; -} - -//Receive datatable -IMPLEMENT_CLIENTCLASS_DT( C_FireSmoke, DT_FireSmoke, CFireSmoke ) - RecvPropFloat( RECVINFO( m_flStartScale )), - RecvPropFloat( RECVINFO( m_flScale ), 0, RecvProxy_Scale ), - RecvPropFloat( RECVINFO( m_flScaleTime ), 0, RecvProxy_ScaleTime ), - RecvPropInt( RECVINFO( m_nFlags ) ), - RecvPropInt( RECVINFO( m_nFlameModelIndex ) ), - RecvPropInt( RECVINFO( m_nFlameFromAboveModelIndex ) ), -END_RECV_TABLE() - -//================================================== -// C_FireSmoke -//================================================== - -C_FireSmoke::C_FireSmoke() -{ - //Server-side - m_flStartScale = 0.0f; - m_flScale = 0.0f; - m_flScaleTime = 0.0f; - m_nFlags = bitsFIRESMOKE_NONE; - m_nFlameModelIndex = 0; - m_nFlameFromAboveModelIndex = 0; - - //Client-side - m_flScaleRegister = 0.0f; - m_flScaleStart = 0.0f; - m_flScaleEnd = 0.0f; - m_flScaleTimeStart = 0.0f; - m_flScaleTimeEnd = 0.0f; - m_bClipTested = false; - - m_flChildFlameSpread = FLAME_CHILD_SPREAD; - - //m_pEmitter = NULL; - - //Clear all child flames - for ( int i = 0; i < NUM_CHILD_FLAMES; i++ ) - { - m_entFlames[i].Clear(); - m_entFlamesFromAbove[i].Clear(); - } - - //m_pEmberEmitter = NULL; - m_pSmokeEmitter = NULL; -} - -C_FireSmoke::~C_FireSmoke() -{ - if ( m_pFireOverlay != NULL ) - { - delete m_pFireOverlay; - m_pFireOverlay = NULL; - } -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void C_FireSmoke::Simulate( void ) -{ - if ( ShouldDraw() == false ) - { - for ( int i = 0; i < NUM_CHILD_FLAMES; i++ ) - { - m_entFlames[i].SetRenderColor( 0, 0, 0, 0 ); - m_entFlames[i].SetBrightness( 0 ); - } - - if ( m_nFlags & bitsFIRESMOKE_VISIBLE_FROM_ABOVE ) - { - for ( int i = 0; i < NUM_CHILD_FLAMES; i++ ) - { - m_entFlamesFromAbove[i].SetRenderColor( 0, 0, 0, 0 ); - m_entFlamesFromAbove[i].SetBrightness( 0 ); - } - } - - m_nFlags &= ~bitsFIRESMOKE_SMOKE; - } - - //Only do this if we're active - if (( m_nFlags & bitsFIRESMOKE_ACTIVE ) == false ) - return; - - Update(); - AddFlames(); -} - -#define FLAME_ALPHA_START 0.9f -#define FLAME_ALPHA_END 1.0f - -#define FLAME_TRANS_START 0.75f - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void C_FireSmoke::AddFlames( void ) -{ -#if PARTICLE_FIRE - - if ( ( gpGlobals->frametime != 0.0f ) && ( m_flScaleRegister > 0.0f ) ) - { - - Vector offset; - float scalar; - - scalar = 32.0f*m_flScaleRegister; - offset[0] = Helper_RandomFloat( -scalar, scalar ); - offset[1] = Helper_RandomFloat( -scalar, scalar ); - offset[2] = 0.0f; - - CSmartPtr pEmitter = CSimpleEmitter::Create( "C_FireSmoke" ); - pEmitter->SetSortOrigin( GetAbsOrigin()+offset ); - - SimpleParticle *sParticle; - - //for ( int i = 0; i < 1; i++ ) - { - scalar = 32.0f*m_flScaleRegister; - offset[0] = Helper_RandomFloat( -scalar, scalar ); - offset[1] = Helper_RandomFloat( -scalar, scalar ); - offset[2] = 12.0f*m_flScaleRegister; - - sParticle = (SimpleParticle *) pEmitter->AddParticle( sizeof(SimpleParticle), pEmitter->GetPMaterial( VarArgs("sprites/flamelet%d", Helper_RandomInt( 1, 5 ) ) ), GetAbsOrigin()+offset ); - - if ( sParticle ) - { - sParticle->m_flLifetime = 0.0f; - sParticle->m_flDieTime = 0.25f; - - sParticle->m_flRoll = Helper_RandomInt( 0, 360 ); - sParticle->m_flRollDelta = Helper_RandomFloat( -4.0f, 4.0f ); - - float alpha = Helper_RandomInt( 128, 255 ); - - sParticle->m_uchColor[0] = alpha; - sParticle->m_uchColor[1] = alpha; - sParticle->m_uchColor[2] = alpha; - sParticle->m_uchStartAlpha = 255; - sParticle->m_uchEndAlpha = 0; - sParticle->m_uchStartSize = 64.0f*m_flScaleRegister; - sParticle->m_uchEndSize = 0; - - float speedScale = ((GetAbsOrigin()+offset)-GetAbsOrigin()).Length2D() / (32.0f*m_flScaleRegister); - sParticle->m_vecVelocity = Vector( Helper_RandomFloat( -32.0f, 32.0f ), Helper_RandomFloat( -32.0f, 32.0f ), Helper_RandomFloat( 32.0f, 128.0f )*speedScale ); - } - } - - pEmitter->Release(); - } - -#endif - -//#if !PARTICLE_FIRE - - float alpha = 1.0f; - - //Update the child flame alpha - for ( int i = 0; i < NUM_CHILD_FLAMES; i++ ) - { - if ( m_entFlames[i].GetScale() > 1e-3f ) - { - m_entFlames[i].SetRenderColor( ( 255.0f * alpha ), ( 255.0f * alpha ), ( 255.0f * alpha ) ); - m_entFlames[i].SetBrightness( 255.0f * alpha ); - - Assert( m_entFlames[i].GetRenderHandle() != INVALID_CLIENT_RENDER_HANDLE ); - m_entFlames[i].AddToLeafSystem(); - } - } - - if ( m_nFlags & bitsFIRESMOKE_VISIBLE_FROM_ABOVE ) - { - for ( int i = 0; i < NUM_CHILD_FLAMES; i++ ) - { - if ( m_entFlamesFromAbove[i].GetScale() > 1e-3f ) - { - m_entFlamesFromAbove[i].SetRenderColor( ( 255.0f * alpha ), ( 255.0f * alpha ), ( 255.0f * alpha ) ); - m_entFlamesFromAbove[i].SetBrightness( 255.0f * alpha ); - - Assert( m_entFlamesFromAbove[i].GetRenderHandle() != INVALID_CLIENT_RENDER_HANDLE ); - m_entFlamesFromAbove[i].AddToLeafSystem(); - } - } - } - -//#endif - -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : bnewentity - -//----------------------------------------------------------------------------- -void C_FireSmoke::OnDataChanged( DataUpdateType_t updateType ) -{ - BaseClass::OnDataChanged( updateType ); - - UpdateEffects(); - - if ( updateType == DATA_UPDATE_CREATED ) - { - Start(); - } -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void C_FireSmoke::UpdateEffects( void ) -{ - /* - if ( m_pEmberEmitter.IsValid() ) - { - m_pEmberEmitter->SetSortOrigin( GetAbsOrigin() ); - } - */ - - if ( m_pSmokeEmitter.IsValid() ) - { - m_pSmokeEmitter->SetSortOrigin( GetAbsOrigin() ); - } - - if ( m_pFireOverlay != NULL ) - { - m_pFireOverlay->m_vPos = GetAbsOrigin(); - } -} - -//----------------------------------------------------------------------------- -// Purpose: -// Output : Returns true on success, false on failure. -//----------------------------------------------------------------------------- -bool C_FireSmoke::ShouldDraw() -{ - if ( GetOwnerEntity() && GetOwnerEntity()->GetRenderColor().a == 0 ) - return false; - - return true; -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void C_FireSmoke::Start( void ) -{ - bool bTools = CommandLine()->CheckParm( "-tools" ) != NULL; - - // Setup the render handles for stuff we want in the client leaf list. - int i; - for ( i = 0; i < NUM_CHILD_FLAMES; i++ ) - { - if ( bTools ) - { - ClientEntityList().AddNonNetworkableEntity( &m_entFlames[i] ); - } - m_entFlames[i].AddToLeafSystem( RENDER_GROUP_TRANSLUCENT_ENTITY ); - } - - if ( m_nFlags & bitsFIRESMOKE_VISIBLE_FROM_ABOVE ) - { - for ( int i = 0; i < NUM_CHILD_FLAMES; i++ ) - { - if ( bTools ) - { - ClientEntityList().AddNonNetworkableEntity( &m_entFlamesFromAbove[i] ); - } - m_entFlamesFromAbove[i].AddToLeafSystem( RENDER_GROUP_TRANSLUCENT_ENTITY ); - } - } - - //Various setup info - m_tParticleSpawn.Init( 2.0f ); - - QAngle offset; - model_t *pModel; - int maxFrames; - - //Setup the child flames - for ( i = 0; i < NUM_CHILD_FLAMES; i++ ) - { - //Setup our offset angles - offset[0] = 0.0f; - offset[1] = Helper_RandomFloat( 0, 360 ); - offset[2] = 0.0f; - - AngleVectors( offset, &m_entFlames[i].m_vecMoveDir ); - m_entFlames[i].m_bFadeFromAbove = ( m_nFlags & bitsFIRESMOKE_VISIBLE_FROM_ABOVE ); - - pModel = (model_t *) modelinfo->GetModel( m_nFlameModelIndex ); - maxFrames = modelinfo->GetModelFrameCount( pModel ); - - //Setup all the information for the client entity - m_entFlames[i].SetModelByIndex( m_nFlameModelIndex ); - m_entFlames[i].SetLocalOrigin( GetLocalOrigin() ); - m_entFlames[i].m_flFrame = Helper_RandomInt( 0.0f, maxFrames - 1 ); - m_entFlames[i].m_flSpriteFramerate = Helper_RandomInt( 15, 30 ); - m_entFlames[i].SetScale( m_flStartScale ); - m_entFlames[i].SetRenderMode( kRenderTransAddFrameBlend ); - m_entFlames[i].m_nRenderFX = kRenderFxNone; - m_entFlames[i].SetRenderColor( 255, 255, 255, 255 ); - m_entFlames[i].SetBrightness( 255 ); - m_entFlames[i].AddEffects( EF_NORECEIVESHADOW | EF_NOSHADOW ); - - m_entFlames[i].index = -1; - - if ( i == 0 ) - { - m_entFlameScales[i] = 1.0f; - } - else - { - //Keep a scale offset - m_entFlameScales[i] = random->RandomFloat( 0.5f, 1.0f ); - } - } - - if ( m_nFlags & bitsFIRESMOKE_VISIBLE_FROM_ABOVE ) - { - for ( int i = 0; i < NUM_CHILD_FLAMES; i++ ) - { - pModel = (model_t *) modelinfo->GetModel( m_nFlameFromAboveModelIndex ); - maxFrames = modelinfo->GetModelFrameCount( pModel ); - - //Setup all the information for the client entity - m_entFlamesFromAbove[i].SetModelByIndex( m_nFlameFromAboveModelIndex ); - m_entFlamesFromAbove[i].SetLocalOrigin( GetLocalOrigin() ); - m_entFlamesFromAbove[i].m_flFrame = Helper_RandomInt( 0.0f, maxFrames - 1 ); - m_entFlamesFromAbove[i].m_flSpriteFramerate = Helper_RandomInt( 15, 30 ); - m_entFlamesFromAbove[i].SetScale( m_flStartScale ); - m_entFlamesFromAbove[i].SetRenderMode( kRenderTransAddFrameBlend ); - m_entFlamesFromAbove[i].m_nRenderFX = kRenderFxNone; - m_entFlamesFromAbove[i].SetRenderColor( 255, 255, 255, 255 ); - m_entFlamesFromAbove[i].SetBrightness( 255 ); - m_entFlamesFromAbove[i].AddEffects( EF_NORECEIVESHADOW | EF_NOSHADOW ); - - m_entFlamesFromAbove[i].index = -1; - - if ( i == 0 ) - { - m_entFlameScales[i] = 1.0f; - } - else - { - //Keep a scale offset - m_entFlameScales[i] = random->RandomFloat( 0.5f, 1.0f ); - } - } - } - - // Start up the smoke - if ( m_nFlags & bitsFIRESMOKE_SMOKE ) - { - //m_pEmberEmitter = CEmberEffect::Create( "C_FireSmoke::m_pEmberEmitter" ); - m_pSmokeEmitter = CLitSmokeEmitter::Create( "C_FireSmoke::m_pSmokeEmitter" ); - m_pSmokeEmitter->Init( "particle/SmokeStack", GetAbsOrigin() ); - } - - //Only make the glow if we've requested it - if ( m_nFlags & bitsFIRESMOKE_GLOW ) - { -#if 0 - //Create the fire overlay - if ( m_pFireOverlay = new CFireOverlay( this ) ) - { - m_pFireOverlay->m_vPos = GetAbsOrigin(); - m_pFireOverlay->m_nSprites = 1; - - m_pFireOverlay->m_vBaseColors[0].Init( 0.4f, 0.2f, 0.05f ); - m_pFireOverlay->Activate(); - } -#endif - } -} - - -//----------------------------------------------------------------------------- -// Purpose: FIXME: what's the right way to do this? -//----------------------------------------------------------------------------- -void C_FireSmoke::StartClientOnly( void ) -{ - Start(); - - ClientEntityList().AddNonNetworkableEntity( this ); - CollisionProp()->CreatePartitionHandle(); - AddEffects( EF_NORECEIVESHADOW | EF_NOSHADOW ); - AddToLeafSystem(); -} - - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void C_FireSmoke::RemoveClientOnly(void) -{ - ClientThinkList()->RemoveThinkable( GetClientHandle() ); - - // Remove from the client entity list. - ClientEntityList().RemoveEntity( GetClientHandle() ); - - partition->Remove( PARTITION_CLIENT_SOLID_EDICTS | PARTITION_CLIENT_RESPONSIVE_EDICTS | PARTITION_CLIENT_NON_STATIC_EDICTS, CollisionProp()->GetPartitionHandle() ); - - RemoveFromLeafSystem(); -} - - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void C_FireSmoke::UpdateAnimation( void ) -{ - int numFrames; - float frametime = Helper_GetFrameTime(); - - for ( int i = 0; i < NUM_CHILD_FLAMES; i++ ) - { - m_entFlames[i].m_flFrame += m_entFlames[i].m_flSpriteFramerate * frametime; - - numFrames = modelinfo->GetModelFrameCount( m_entFlames[i].GetModel() ); - - if ( m_entFlames[i].m_flFrame >= numFrames ) - { - m_entFlames[i].m_flFrame = m_entFlames[i].m_flFrame - (int)(m_entFlames[i].m_flFrame); - } - } - - if ( m_nFlags & bitsFIRESMOKE_VISIBLE_FROM_ABOVE ) - { - for ( int i = 0; i < NUM_CHILD_FLAMES; i++ ) - { - m_entFlamesFromAbove[i].m_flFrame += m_entFlamesFromAbove[i].m_flSpriteFramerate * frametime; - - numFrames = modelinfo->GetModelFrameCount( m_entFlamesFromAbove[i].GetModel() ); - - if ( m_entFlamesFromAbove[i].m_flFrame >= numFrames ) - { - m_entFlamesFromAbove[i].m_flFrame = m_entFlamesFromAbove[i].m_flFrame - (int)(m_entFlamesFromAbove[i].m_flFrame); - } - } - } -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void C_FireSmoke::UpdateFlames( void ) -{ - for ( int i = 0; i < NUM_CHILD_FLAMES; i++ ) - { - float newScale = m_flScaleRegister * m_entFlameScales[i]; - Vector dir; - - dir[2] = 0.0f; - VectorNormalize( dir ); - dir[2] = 0.0f; - - Vector offset = GetAbsOrigin(); - offset[2] += FLAME_SOURCE_HEIGHT * m_entFlames[i].GetScale(); - - //NOTENOTE: Sprite renderer assumes a scale of 0.0 means 1.0 - if ( m_bFadingOut == false ) - { - m_entFlames[i].SetScale( max(0.000001,newScale) ); - } - else - { - m_entFlames[i].SetScale( newScale ); - } - - Assert( !m_entFlames[i].GetMoveParent() ); - if ( i != 0 ) - { - m_entFlames[i].SetLocalOrigin( offset + ( m_entFlames[i].m_vecMoveDir * (m_entFlames[i].GetScale() * m_flChildFlameSpread) ) ); - } - else - { - m_entFlames[i].SetLocalOrigin( offset ); - } - } - - if ( m_nFlags & bitsFIRESMOKE_VISIBLE_FROM_ABOVE ) - { - for ( int i = 0; i < NUM_CHILD_FLAMES; i++ ) - { - float newScale = m_flScaleRegister * m_entFlameScales[i]; - Vector dir; - - dir[2] = 0.0f; - VectorNormalize( dir ); - dir[2] = 0.0f; - - Vector offset = GetAbsOrigin(); - offset[2] += FLAME_FROM_ABOVE_SOURCE_HEIGHT * m_entFlamesFromAbove[i].GetScale(); - - //NOTENOTE: Sprite renderer assumes a scale of 0.0 means 1.0 - if ( m_bFadingOut == false ) - { - m_entFlamesFromAbove[i].SetScale( max(0.000001,newScale) ); - } - else - { - m_entFlamesFromAbove[i].SetScale( newScale ); - } - - Assert( !m_entFlamesFromAbove[i].GetMoveParent() ); - if ( i != 0 ) - { - m_entFlamesFromAbove[i].SetLocalOrigin( offset + ( m_entFlames[i].m_vecMoveDir * (m_entFlamesFromAbove[i].GetScale() * m_flChildFlameSpread) ) ); - } - else - { - m_entFlamesFromAbove[i].SetLocalOrigin( offset ); - } - } - } -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void C_FireSmoke::UpdateScale( void ) -{ - float time = Helper_GetTime(); - - if ( m_flScaleRegister != m_flScaleEnd ) - { - //See if we're done scaling - if ( time > m_flScaleTimeEnd ) - { - m_flScaleRegister = m_flStartScale = m_flScaleEnd; - } - else - { - //Lerp the scale and set it - float timeFraction = 1.0f - ( m_flScaleTimeEnd - time ) / ( m_flScaleTimeEnd - m_flScaleTimeStart ); - float newScale = 0.0f; - - if ( m_bFadingOut == false ) - newScale = m_flScaleStart + ( ( m_flScaleEnd - m_flScaleStart ) * timeFraction ); - else - newScale = m_flScaleStart - ( ( m_flScaleStart - m_flScaleEnd ) * timeFraction ); - - m_flScaleRegister = m_flStartScale = newScale; - } - } -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void C_FireSmoke::Update( void ) -{ - //If we haven't already, find the clip plane for smoke effects - if ( ( m_nFlags & bitsFIRESMOKE_SMOKE ) && ( m_bClipTested == false ) ) - { - FindClipPlane(); - } - - //Update all our parts - UpdateEffects(); - UpdateScale(); - UpdateAnimation(); - UpdateFlames(); - - //See if we should emit smoke - if ( m_nFlags & bitsFIRESMOKE_SMOKE ) - { - float tempDelta = Helper_GetFrameTime(); - - while( m_tParticleSpawn.NextEvent( tempDelta ) ) - { - SpawnSmoke(); - } - } -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void C_FireSmoke::FindClipPlane( void ) -{ - m_bClipTested = true; - m_flClipPerc = 1.0f; - - trace_t tr; - Vector end( 0.0f, 0.0f, SMOKE_RISE_RATE*SMOKE_LIFETIME ); - - UTIL_TraceLine( GetAbsOrigin(), GetAbsOrigin()+end, MASK_SOLID_BRUSHONLY, NULL, COLLISION_GROUP_NONE, &tr ); - - //If the ceiling is too close, reject smoke - if ( tr.fraction < 0.5f ) - { - m_nFlags &= ~bitsFIRESMOKE_SMOKE; - return; - } - - if ( tr.fraction < 1.0f ) - { - m_planeClip.Init( tr.plane.normal, tr.plane.dist ); - m_nFlags |= bitsFIRESMOKE_SMOKE_COLLISION; - m_flClipPerc = tr.fraction * 0.5f; - } -} - -//----------------------------------------------------------------------------- -// Purpose: Spawn smoke (...duh) -//----------------------------------------------------------------------------- - -void C_FireSmoke::SpawnSmoke( void ) -{ - /* - if ( m_pEmberEmitter.IsValid() == false ) - return; - */ - - if ( m_pSmokeEmitter.IsValid() == false ) - return; - - float scalar; - Vector offset; - - scalar = 32.0f*m_flScaleRegister; - offset[0] = Helper_RandomFloat( -scalar, scalar ); - offset[1] = Helper_RandomFloat( -scalar, scalar ); - offset[2] = scalar + ( Helper_RandomFloat( -scalar*0.25f, scalar*0.25f ) ); - - // - // Embers - // - - //FIXME: These aren't visible enough to justify their cost, currently -- jdw - /* - SimpleParticle *sParticle; - sParticle = (SimpleParticle *) m_pEmberEmitter->AddParticle( sizeof(SimpleParticle), m_pEmberEmitter->GetPMaterial( "particle/fire"), GetAbsOrigin()+offset ); - - if( sParticle ) - { - sParticle->m_flLifetime = 0.0f; - sParticle->m_flDieTime = EMBER_LIFETIME; - - sParticle->m_flRoll = 0; - sParticle->m_flRollDelta = 0; - - scalar = Helper_RandomFloat( 0.5f, 2.0f ); - - sParticle->m_uchColor[0] = min( 255, Helper_RandomFloat( 185.0f, 190.0f ) * scalar ); - sParticle->m_uchColor[1] = min( 255, Helper_RandomFloat( 140.0f, 165.0f ) * scalar ); - sParticle->m_uchColor[2] = min( 255, 65.0f * scalar ); - sParticle->m_uchStartAlpha = 255; - sParticle->m_uchEndAlpha = 0; - sParticle->m_uchStartSize = 2; - sParticle->m_uchEndSize = 0; - - sParticle->m_vecVelocity = Vector( Helper_RandomFloat( -16.0f, 16.0f ), Helper_RandomFloat( -16.0f, 16.0f ), Helper_RandomFloat( 92.0f, 128.0f ) ); - } - */ - - // - // Lit smoke - // - - offset[2] += 100.0f; - - m_pSmokeEmitter->SetDirectionalLight( GetAbsOrigin(), Vector( 1.0f, 0.5f, 0.2f ), 2500 ); - - CLitSmokeEmitter::LitSmokeParticle *pParticle; - pParticle = (CLitSmokeEmitter::LitSmokeParticle*) m_pSmokeEmitter->AddParticle( - sizeof(CLitSmokeEmitter::LitSmokeParticle), - m_pSmokeEmitter->GetSmokeMaterial(), - GetAbsOrigin()+offset ); - - if ( pParticle ) - { - float lifeTime = SMOKE_LIFETIME * m_flClipPerc; - - pParticle->m_flLifetime = 0; - pParticle->m_flDieTime = random->RandomFloat( lifeTime * 0.75, lifeTime ); - - pParticle->m_vecVelocity = Vector( random->RandomFloat( -16.0f, 16.0f ), random->RandomFloat( -16.0f, 16.0f ), random->RandomFloat( 2.0f, SMOKE_RISE_RATE ) ); - - int color = random->RandomInt( 8, 64 ); - pParticle->m_uchColor[0] = color; - pParticle->m_uchColor[1] = color; - pParticle->m_uchColor[2] = color; - pParticle->m_uchColor[3] = random->RandomInt( 128, 256 ); - - pParticle->m_uchStartSize = random->RandomFloat( 32.0f, 48.0f ); - pParticle->m_uchEndSize = pParticle->m_uchStartSize * 3.0f; - } -} - - -IMPLEMENT_CLIENTCLASS_DT( C_EntityFlame, DT_EntityFlame, CEntityFlame ) - RecvPropFloat(RECVINFO(m_flSize)), - RecvPropEHandle(RECVINFO(m_hEntAttached)), - RecvPropInt(RECVINFO(m_bUseHitboxes)), - RecvPropTime(RECVINFO(m_flLifetime)), -END_RECV_TABLE() - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -C_EntityFlame::C_EntityFlame( void ) -{ - m_flSize = 4.0f; - m_pEmitter = NULL; - m_flLifetime = 0; - m_bStartedFading = false; - m_bCreatedClientside = false; -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -C_EntityFlame::~C_EntityFlame( void ) -{ - if (m_bAttachedToHitboxes) - { - for (int i = 0; i < NUM_HITBOX_FIRES; i++) - { - delete m_pFireSmoke[i]; - } - } -} - -RenderGroup_t C_EntityFlame::GetRenderGroup() -{ - return RENDER_GROUP_TRANSLUCENT_ENTITY; -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void C_EntityFlame::UpdateOnRemove( void ) -{ - CleanUpRagdollOnRemove(); - BaseClass::UpdateOnRemove(); -} - - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void C_EntityFlame::CleanUpRagdollOnRemove( void ) -{ - if ( !m_hEntAttached ) - return; - - m_hEntAttached->RemoveFlag( FL_ONFIRE ); - m_hEntAttached->SetEffectEntity( NULL ); - m_hEntAttached->StopSound( "General.BurningFlesh" ); - m_hEntAttached->StopSound( "General.BurningObject" ); - - m_hEntAttached = NULL; -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : bnewentity - -//----------------------------------------------------------------------------- -void C_EntityFlame::OnDataChanged( DataUpdateType_t updateType ) -{ - if ( updateType == DATA_UPDATE_CREATED ) - { - C_BaseEntity *pEnt = m_hEntAttached; - if ( !pEnt ) - return; - - if ( m_bUseHitboxes && pEnt->GetBaseAnimating() != NULL ) - { - AttachToHitBoxes(); - } - else - { - m_vecLastPosition = GetRenderOrigin(); - - m_ParticleSpawn.Init( 60 ); //Events per second - - m_pEmitter = CEmberEffect::Create("C_EntityFlame::Create"); - - Assert( m_pEmitter.IsValid() ); - if ( m_pEmitter.IsValid() ) - { - for ( int i = 1; i < NUM_FLAMELETS+1; i++ ) - { - m_MaterialHandle[i-1] = m_pEmitter->GetPMaterial( VarArgs( "sprites/flamelet%d", i ) ); - } - - m_pEmitter->SetSortOrigin( GetAbsOrigin() ); - } - } - } - - BaseClass::OnDataChanged( updateType ); -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void C_EntityFlame::Simulate( void ) -{ - if ( gpGlobals->frametime <= 0.0f ) - return; - -#ifdef HL2_EPISODIC - // Server side flames need to shrink and die - if ( !m_bCreatedClientside && !m_bStartedFading ) - { - float flTTL = (m_flLifetime - gpGlobals->curtime); - if ( flTTL < 2.0 ) - { - for (int i = 0; i < NUM_HITBOX_FIRES; i++) - { - if ( m_pFireSmoke[i] ) - { - m_pFireSmoke[i]->m_flScaleStart = m_pFireSmoke[i]->m_flScaleEnd; - m_pFireSmoke[i]->m_flScaleEnd = 0.00001; - m_pFireSmoke[i]->m_flScaleTimeStart = gpGlobals->curtime; - m_pFireSmoke[i]->m_flScaleTimeEnd = m_flLifetime; - m_pFireSmoke[i]->m_flScaleRegister = -1; - } - } - - m_bStartedFading = true; - } - } - - if ( IsEffectActive(EF_BRIGHTLIGHT) || IsEffectActive(EF_DIMLIGHT) ) - { - dlight_t *dl = effects->CL_AllocDlight ( index ); - dl->origin = GetAbsOrigin(); - dl->origin[2] += 16; - dl->color.r = 254; - dl->color.g = 174; - dl->color.b = 10; - dl->radius = random->RandomFloat(400,431); - dl->die = gpGlobals->curtime + 0.001; - - if ( m_pFireSmoke[0] ) - { - if ( m_pFireSmoke[0]->m_flScaleRegister == -1 ) - { - // We've started shrinking, but UpdateScale() hasn't been - // called since then. We want to use the Start scale instead. - dl->radius *= m_pFireSmoke[0]->m_flScaleStart; - } - else - { - dl->radius *= m_pFireSmoke[0]->m_flScaleRegister; - } - } - } -#endif // HL2_EPISODIC - - if ( m_bAttachedToHitboxes ) - { - UpdateHitBoxFlames(); - } - else if ( !!m_pEmitter ) - { - m_pEmitter->SetSortOrigin( GetAbsOrigin() ); - - SimpleParticle *pParticle; - - Vector offset; - - Vector moveDiff = GetAbsOrigin() - m_vecLastPosition; - float moveLength = VectorNormalize( moveDiff ); - - int numPuffs = moveLength / (m_flSize*0.5f); - - numPuffs = clamp( numPuffs, 1, 8 ); - - Vector offsetColor; - float step = moveLength / numPuffs; - - //Fill in the gaps - for ( int i = 1; i < numPuffs+1; i++ ) - { - offset = m_vecLastPosition + ( moveDiff * step * i ); - - pParticle = (SimpleParticle *) m_pEmitter->AddParticle( sizeof(SimpleParticle), m_MaterialHandle[random->RandomInt( 0, NUM_FLAMELETS-1 )], offset ); - - 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( m_flSize*0.25f, m_flSize*0.5f ); - pParticle->m_uchEndSize = pParticle->m_uchStartSize * 2.0f; - pParticle->m_uchStartAlpha = 255; - pParticle->m_uchEndAlpha = 0; - - pParticle->m_uchColor[0] = pParticle->m_uchColor[1] = pParticle->m_uchColor[2] = 255; - - Vector dir; - - dir.x = random->RandomFloat( -1.0f, 1.0f ); - dir.y = random->RandomFloat( -1.0f, 1.0f ); - dir.z = random->RandomFloat( 0.5f, 1.0f ); - - pParticle->m_vecVelocity = dir * random->RandomInt( 4, 32 ); - pParticle->m_vecVelocity[2] = random->RandomInt( 32, 64 ); - } - } - } - - m_vecLastPosition = GetRenderOrigin(); -} - -void C_EntityFlame::ClientThink( void ) -{ - for (int i = 0; i < NUM_HITBOX_FIRES; i++) - { - if ( m_pFireSmoke[i] != NULL ) - { - if ( m_pFireSmoke[i]->m_bFadingOut == false ) - { - m_pFireSmoke[i]->m_flScaleStart = m_pFireSmoke[i]->m_flScaleEnd; - m_pFireSmoke[i]->m_flScaleEnd = 0.00001; - m_pFireSmoke[i]->m_flScaleTimeStart = Helper_GetTime(); - m_pFireSmoke[i]->m_flScaleTimeEnd = Helper_GetTime() + 2.0; - m_pFireSmoke[i]->m_flScaleRegister = -1; - m_pFireSmoke[i]->m_bFadingOut = true; - } - else - { - if ( m_pFireSmoke[i]->m_flScaleTimeEnd <= Helper_GetTime() ) - { - if ( m_hEntAttached ) - { - CPASAttenuationFilter filter( m_hEntAttached ); - m_hEntAttached->EmitSound( filter, m_hEntAttached->GetSoundSourceIndex(), "General.StopBurning" ); - } - - CleanUpRagdollOnRemove(); - Release(); - return; - } - } - } - } - - SetNextClientThink( gpGlobals->curtime + 0.1f ); -} - - -//----------------------------------------------------------------------------- -// Purpose: Returns the volume of the given box in cubic inches. -//----------------------------------------------------------------------------- -inline float CalcBoxVolume(const Vector &mins, const Vector &maxs) -{ - return (maxs.x - mins.x) * (maxs.y - mins.y) * (maxs.z - mins.z); -} - - -// -// Used for sorting hitboxes by volume. -// -struct HitboxVolume_t -{ - int nIndex; // The index of the hitbox in the model. - float flVolume; // The volume of the hitbox in cubic inches. -}; - - -//----------------------------------------------------------------------------- -// Purpose: Callback function to sort hitboxes by decreasing volume. -// To mix up the sort results a little we pick a random result for -// boxes within 50 cubic inches of another. -//----------------------------------------------------------------------------- -int __cdecl SortHitboxVolumes(HitboxVolume_t *elem1, HitboxVolume_t *elem2) -{ - if (elem1->flVolume > elem2->flVolume + 50) - { - return -1; - } - - if (elem1->flVolume < elem2->flVolume + 50) - { - return 1; - } - - if (elem1->flVolume != elem2->flVolume) - { - return random->RandomInt(-1, 1); - } - - return 0; -} - - -//----------------------------------------------------------------------------- -// Purpose: Attaches fire to the hitboxes of an animating character. The fire -// is distributed based on hitbox volumes -- it attaches to the larger -// hitboxes first. -//----------------------------------------------------------------------------- -void C_EntityFlame::AttachToHitBoxes( void ) -{ - m_pCachedModel = NULL; - - C_BaseCombatCharacter *pAnimating = (C_BaseCombatCharacter *)m_hEntAttached.Get(); - if (!pAnimating || !pAnimating->GetModel()) - { - return; - } - - CStudioHdr *pStudioHdr = pAnimating->GetModelPtr(); - if (!pStudioHdr) - { - return; - } - - mstudiohitboxset_t *set = pStudioHdr->pHitboxSet( pAnimating->m_nHitboxSet ); - if ( !set ) - { - return; - } - - if ( !set->numhitboxes ) - { - return; - } - - m_pCachedModel = pAnimating->GetModel(); - - CBoneCache *pCache = pAnimating->GetBoneCache( pStudioHdr ); - matrix3x4_t *hitboxbones[MAXSTUDIOBONES]; - pCache->ReadCachedBonePointers( hitboxbones, pStudioHdr->numbones() ); - - // - // Sort the hitboxes by volume. - // - HitboxVolume_t hitboxvolume[MAXSTUDIOBONES]; - for ( int i = 0; i < set->numhitboxes; i++ ) - { - mstudiobbox_t *pBox = set->pHitbox(i); - hitboxvolume[i].nIndex = i; - hitboxvolume[i].flVolume = CalcBoxVolume(pBox->bbmin, pBox->bbmax); - } - qsort(hitboxvolume, set->numhitboxes, sizeof(hitboxvolume[0]), (int (__cdecl *)(const void *, const void *))SortHitboxVolumes); - - // - // Attach fire to the hitboxes. - // - for ( int i = 0; i < NUM_HITBOX_FIRES; i++ ) - { - int hitboxindex; - // - // Pick the 5 biggest hitboxes, or random ones if there are less than 5 hitboxes, - // then pick random ones after that. - // - if (( i < 5 ) && ( i < set->numhitboxes )) - { - hitboxindex = i; - } - else - { - hitboxindex = random->RandomInt( 0, set->numhitboxes - 1 ); - } - - mstudiobbox_t *pBox = set->pHitbox( hitboxvolume[hitboxindex].nIndex ); - - Assert( hitboxbones[pBox->bone] ); - - m_nHitbox[i] = hitboxvolume[hitboxindex].nIndex; - m_pFireSmoke[i] = new C_FireSmoke; - - // - // Calculate a position within the hitbox to place the fire. - // - m_vecFireOrigin[i] = Vector(random->RandomFloat(pBox->bbmin.x, pBox->bbmax.x), random->RandomFloat(pBox->bbmin.y, pBox->bbmax.y), random->RandomFloat(pBox->bbmin.z, pBox->bbmax.z)); - Vector vecAbsOrigin; - VectorTransform( m_vecFireOrigin[i], *hitboxbones[pBox->bone], vecAbsOrigin); - m_pFireSmoke[i]->SetLocalOrigin( vecAbsOrigin ); - - - // - // The first fire emits smoke, the rest do not. - // - m_pFireSmoke[i]->m_nFlags = bitsFIRESMOKE_ACTIVE; - - m_pFireSmoke[i]->m_nFlameModelIndex = modelinfo->GetModelIndex("sprites/fire1.vmt"); - m_pFireSmoke[i]->m_nFlameFromAboveModelIndex = modelinfo->GetModelIndex("sprites/flamefromabove.vmt"); - m_pFireSmoke[i]->m_flScale = 0; - m_pFireSmoke[i]->m_flStartScale = 0; - m_pFireSmoke[i]->m_flScaleTime = 1.5; - m_pFireSmoke[i]->m_flScaleRegister = 0.1; - m_pFireSmoke[i]->m_flChildFlameSpread = 20.0; - m_pFireSmoke[i]->m_flScaleStart = 0; - m_pFireSmoke[i]->SetOwnerEntity( this ); - - // Do a simple That Looks About Right clamp on the volumes - // so that we don't get flames too large or too tiny. - float flVolume = hitboxvolume[hitboxindex].flVolume; - - Assert( IsFinite(flVolume) ); - -#define FLAME_HITBOX_MIN_VOLUME 1000.0f -#define FLAME_HITBOX_MAX_VOLUME 4000.0f - - if( flVolume < FLAME_HITBOX_MIN_VOLUME ) - { - flVolume = FLAME_HITBOX_MIN_VOLUME; - } - else if( flVolume > FLAME_HITBOX_MAX_VOLUME ) - { - flVolume = FLAME_HITBOX_MAX_VOLUME; - } - - m_pFireSmoke[i]->m_flScaleEnd = 0.00012f * flVolume; - m_pFireSmoke[i]->m_flScaleTimeStart = Helper_GetTime(); - m_pFireSmoke[i]->m_flScaleTimeEnd = Helper_GetTime() + 2.0; - - m_pFireSmoke[i]->StartClientOnly(); - } - - m_bAttachedToHitboxes = true; -} - - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void C_EntityFlame::DeleteHitBoxFlames(void) -{ - for ( int i = 0; i < NUM_HITBOX_FIRES; i++ ) - { - m_pFireSmoke[i]->RemoveClientOnly(); - delete m_pFireSmoke[i]; - } -} - - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void C_EntityFlame::UpdateHitBoxFlames( void ) -{ - C_BaseCombatCharacter *pAnimating = (C_BaseCombatCharacter *)m_hEntAttached.Get(); - if (!pAnimating) - { - return; - } - - if (pAnimating->GetModel() != m_pCachedModel) - { - if (m_pCachedModel != NULL) - { - // The model changed, we must reattach the flames. - DeleteHitBoxFlames(); - AttachToHitBoxes(); - } - - if (m_pCachedModel == NULL) - { - // We tried to reattach and failed. - return; - } - } - - studiohdr_t *pStudioHdr = modelinfo->GetStudiomodel( pAnimating->GetModel() ); - if (!pStudioHdr) - { - return; - } - - mstudiohitboxset_t *set = pStudioHdr->pHitboxSet( pAnimating->m_nHitboxSet ); - if ( !set ) - { - return; - } - - if ( !set->numhitboxes ) - { - return; - } - - pAnimating->SetupBones( NULL, -1, BONE_USED_BY_ANYTHING, gpGlobals->curtime ); - - for ( int i = 0; i < NUM_HITBOX_FIRES; i++ ) - { - Vector vecAbsOrigin; - mstudiobbox_t *pBox = set->pHitbox(m_nHitbox[i]); - - VectorTransform(m_vecFireOrigin[i], pAnimating->GetBoneForWrite( pBox->bone ), vecAbsOrigin); - - m_pFireSmoke[i]->SetLocalOrigin(vecAbsOrigin); - } -} - - -//CLIENTEFFECT_REGISTER_BEGIN( PrecacheEffectStriderKill ) -//CLIENTEFFECT_MATERIAL( "effects/spark" ) -//CLIENTEFFECT_REGISTER_END() -// -// -//class CStriderKillEffect : public CParticleEffect -//{ -//public: -// -// CStriderKillEffect( const char *pDebugName ) : CParticleEffect( pDebugName ) {} -// -// static CStriderKillEffect *Create( const char *pDebugName ) -// { -// return new CStriderKillEffect( pDebugName ); -// } -// -// void Update( float fTimeDelta ) -// { -// C_BaseCombatCharacter *pAnimating = (C_BaseCombatCharacter *)m_hEntAttached.Get(); -// if (!pAnimating) -// { -// return; -// } -// -// if (pAnimating->model != m_pCachedModel) -// { -// if (m_pCachedModel != NULL) -// { -// // The model changed, we must reattach the sparks. -// DeleteHitBoxFlames(); -// AttachToHitBoxes(); -// } -// -// if (m_pCachedModel == NULL) -// { -// // We tried to reattach and failed. -// return; -// } -// } -// -// studiohdr_t *pStudioHdr = modelrender->GetStudiomodel( pAnimating->model ); -// if (!pStudioHdr) -// { -// return; -// } -// -// mstudiohitboxset_t *set = pStudioHdr->pHitboxSet( pAnimating->m_nHitboxSet ); -// if ( !set ) -// { -// return; -// } -// -// if ( !set->numhitboxes ) -// { -// return; -// } -// -// int boneMask = BONE_USED_BY_HITBOX | BONE_USED_BY_ATTACHMENT; -// studiocache_t *pcache = Studio_GetBoneCache( pStudioHdr, pAnimating->GetSequence(), pAnimating->m_flAnimTime, pAnimating->GetAbsAngles(), pAnimating->GetAbsOrigin(), boneMask ); -// if ( !pcache ) -// { -// matrix3x4_t bonetoworld[MAXSTUDIOBONES]; -// -// pAnimating->SetupBones( bonetoworld, MAXSTUDIOBONES, boneMask, gpGlobals->curtime ); -// pcache = Studio_SetBoneCache( pStudioHdr, pAnimating->GetSequence(), pAnimating->m_flAnimTime, pAnimating->GetAbsAngles(), pAnimating->GetAbsOrigin(), boneMask, bonetoworld ); -// } -// -// matrix3x4_t *hitboxbones[MAXSTUDIOBONES]; -// Studio_LinkHitboxCache( hitboxbones, pcache, pStudioHdr, set ); -// -// //for ( int i = 0; i < NUM_HITBOX_SPARKS; i++ ) -// //{ -// //Vector vecAbsOrigin; -// mstudiobbox_t *pBox = set->pHitbox(m_nHitbox[i]); -// //VectorTransform(m_vecFireOrigin[i], *hitboxbones[pBox->bone], vecAbsOrigin); -// //m_pFireSmoke[i]->SetLocalOrigin(vecAbsOrigin); -// //} -// } -// -// bool SimulateAndRender( Particle *pInParticle, ParticleDraw *pDraw, float &sortKey) -// { -// SimpleParticle *pParticle = (SimpleParticle *) pInParticle; -// float timeDelta = pDraw->GetTimeDelta(); -// -// Vector tPos; -// TransformParticle( ParticleMgr()->GetModelView(), pParticle->m_Pos, tPos ); -// sortKey = (int) tPos.z; -// -// RenderParticle_ColorSizeAngle( -// pDraw, -// tPos, -// UpdateColor( pParticle, timeDelta ), -// UpdateAlpha( pParticle, timeDelta ) * GetAlphaDistanceFade( tPos, m_flNearClipMin, m_flNearClipMax ), -// UpdateScale( pParticle, timeDelta ), -// UpdateRoll( pParticle, timeDelta ) ); -// -// //Should this particle die? -// pParticle->m_flLifetime += timeDelta; -// -// if ( pParticle->m_flLifetime >= pParticle->m_flDieTime ) -// return false; -// -// return true; -// } -// -// -//private: -// -// EHANDLE m_hEntAttached; -// -// CStriderKillEffect( const CStriderKillEffect & ); -//}; -// -// -//----------------------------------------------------------------------------- -// Purpose: -// Input : origin - -// normal - -// scale - -//----------------------------------------------------------------------------- -//void FX_StriderKill( CBaseAnimating *pAnimating ) -//{ -// if ( cl_show_bloodspray.GetBool() == false ) -// return; -// -// debugoverlay->AddLineOverlay( origin, origin + normal * 72, 255, 255, 255, true, 10 ); -// -// Vector offset; -// float spread = 0.2f; -// -// Vector color = Vector( 0.25f, 0.0f, 0.0f ); -// float colorRamp; -// -// int i; -// -// Vector vForward, vRight, vUp; -// Vector offDir; -// -// CSmartPtr pSimple = CStriderKillEffect::Create( "striderkill" ); -// if ( !pSimple ) -// return; -// -// pSimple->SetSortOrigin( pAnimating->GetAbsOrigin() ); -// -// PMaterialHandle hMaterial = ParticleMgr()->GetPMaterial( "effects/spark" ); -// -// SimpleParticle *pParticle; -// -// for ( i = 0; i < NUM_HITBOX_SPARKS; i++ ) -// { -// offset = origin; -// offset[0] += random->RandomFloat( -2.0f, 2.0f ) * scale; -// offset[1] += random->RandomFloat( -2.0f, 2.0f ) * scale; -// -// pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), hMaterial, offset ); -// -// if ( pParticle != NULL ) -// { -// pParticle->m_flLifetime = 0.0f; -// pParticle->m_flDieTime = 0.75f; -// -// spread = 1.0f; -// pParticle->m_vecVelocity.Random( -spread, spread ); -// pParticle->m_vecVelocity += normal; -// VectorNormalize( pParticle->m_vecVelocity ); -// -// pParticle->m_flGravity = 0; -// -// 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( scale * 0.5, scale * 2 ); -// pParticle->m_uchEndSize = pParticle->m_uchStartSize * 2; -// -// pParticle->m_uchStartAlpha = random->RandomInt( 128, 255 ); -// pParticle->m_uchEndAlpha = 0; -// -// pParticle->m_flRoll = random->RandomInt( 0, 360 ); -// pParticle->m_flRollDelta = random->RandomFloat( -4.0f, 4.0f ); -// } -// } -//} diff --git a/src/src/cl_dll/c_prop_vehicle.cpp b/src/src/cl_dll/c_prop_vehicle.cpp deleted file mode 100644 index 4f3d8f1..0000000 --- a/src/src/cl_dll/c_prop_vehicle.cpp +++ /dev/null @@ -1,728 +0,0 @@ -//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// -// -// Purpose: -// -// $NoKeywords: $ -//=============================================================================// - - -#include "cbase.h" -#include "c_prop_vehicle.h" -#include "hud.h" -#include -#include -#include "view.h" -#include "engine/IVDebugOverlay.h" -#include "movevars_shared.h" -#include "iviewrender.h" - -// memdbgon must be the last include file in a .cpp file!!! -#include "tier0/memdbgon.h" - -int ScreenTransform( const Vector& point, Vector& screen ); - - -extern ConVar default_fov; - - -BEGIN_SIMPLE_DATADESC( ViewSmoothingData_t ) - DEFINE_FIELD( vecAnglesSaved, FIELD_VECTOR ), - DEFINE_FIELD( vecOriginSaved, FIELD_POSITION_VECTOR ), - DEFINE_FIELD( vecAngleDiffSaved, FIELD_VECTOR ), - DEFINE_FIELD( vecAngleDiffMin, FIELD_VECTOR ), - DEFINE_FIELD( bRunningEnterExit, FIELD_BOOLEAN ), - DEFINE_FIELD( bWasRunningAnim, FIELD_BOOLEAN ), - DEFINE_FIELD( flAnimTimeElapsed, FIELD_FLOAT ), - DEFINE_FIELD( flEnterExitDuration, FIELD_FLOAT ), - - // These are filled out in the vehicle's constructor: - //CBaseAnimating *pVehicle; - //bool bClampEyeAngles; - //float flPitchCurveZero; - //float flPitchCurveLinear; - //float flRollCurveZero; - //float flRollCurveLinear; - //ViewLockData_t pitchLockData; - //ViewLockData_t rollLockData; - //bool bDampenEyePosition; -END_DATADESC() - - -IMPLEMENT_CLIENTCLASS_DT(C_PropVehicleDriveable, DT_PropVehicleDriveable, CPropVehicleDriveable) - RecvPropEHandle( RECVINFO(m_hPlayer) ), - RecvPropInt( RECVINFO( m_nSpeed ) ), - RecvPropInt( RECVINFO( m_nRPM ) ), - RecvPropFloat( RECVINFO( m_flThrottle ) ), - RecvPropInt( RECVINFO( m_nBoostTimeLeft ) ), - RecvPropInt( RECVINFO( m_nHasBoost ) ), - RecvPropInt( RECVINFO( m_nScannerDisabledWeapons ) ), - RecvPropInt( RECVINFO( m_nScannerDisabledVehicle ) ), - RecvPropInt( RECVINFO( m_bEnterAnimOn ) ), - RecvPropInt( RECVINFO( m_bExitAnimOn ) ), - RecvPropInt( RECVINFO( m_bUnableToFire ) ), - RecvPropVector( RECVINFO( m_vecEyeExitEndpoint ) ), - RecvPropBool( RECVINFO( m_bHasGun ) ), - RecvPropVector( RECVINFO( m_vecGunCrosshair ) ), -END_RECV_TABLE() - - -BEGIN_DATADESC( C_PropVehicleDriveable ) - DEFINE_EMBEDDED( m_ViewSmoothingData ), -END_DATADESC() - - -#define ROLL_CURVE_ZERO 20 // roll less than this is clamped to zero -#define ROLL_CURVE_LINEAR 90 // 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 - -ConVar r_VehicleViewClamp( "r_VehicleViewClamp", "1", FCVAR_CHEAT ); - - -// remaps an angular variable to a 3 band function: -// 0 <= t < start : f(t) = 0 -// start <= t <= end : f(t) = end * spline(( t-start) / (end-start) ) // s curve between clamped and linear -// end < t : f(t) = t -float RemapAngleRange( float startInterval, float endInterval, float value, RemapAngleRange_CurvePart_t *peCurvePart ) -{ - // Fixup the roll - value = AngleNormalize( value ); - float absAngle = fabs(value); - - // beneath cutoff? - if ( absAngle < startInterval ) - { - if ( peCurvePart ) - { - *peCurvePart = RemapAngleRange_CurvePart_Zero; - } - value = 0; - } - // in spline range? - else if ( absAngle <= endInterval ) - { - float newAngle = SimpleSpline( (absAngle - startInterval) / (endInterval-startInterval) ) * endInterval; - - // grab the sign from the initial value - if ( value < 0 ) - { - newAngle *= -1; - } - - if ( peCurvePart ) - { - *peCurvePart = RemapAngleRange_CurvePart_Spline; - } - value = newAngle; - } - // else leave it alone, in linear range - else if ( peCurvePart ) - { - *peCurvePart = RemapAngleRange_CurvePart_Linear; - } - - return value; -} - -//----------------------------------------------------------------------------- -// Purpose: Constructor -//----------------------------------------------------------------------------- -C_PropVehicleDriveable::C_PropVehicleDriveable() : - m_iv_vecGunCrosshair( "C_PropVehicleDriveable::m_iv_vecGunCrosshair" ) - -{ - m_hPrevPlayer = NULL; - - memset( &m_ViewSmoothingData, 0, sizeof( m_ViewSmoothingData ) ); - - m_ViewSmoothingData.pVehicle = this; - m_ViewSmoothingData.bClampEyeAngles = true; - m_ViewSmoothingData.bDampenEyePosition = 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_flFOV = 0.0f; - - AddVar( &m_vecGunCrosshair, &m_iv_vecGunCrosshair, LATCH_SIMULATION_VAR ); -} - -//----------------------------------------------------------------------------- -// Purpose: De-constructor -//----------------------------------------------------------------------------- -C_PropVehicleDriveable::~C_PropVehicleDriveable() -{ -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -C_BaseCombatCharacter *C_PropVehicleDriveable::GetPassenger( int nRole ) -{ - if ( nRole == VEHICLE_ROLE_DRIVER ) - return m_hPlayer.Get(); - - return NULL; -} - -//----------------------------------------------------------------------------- -// Returns the role of the passenger -//----------------------------------------------------------------------------- -int C_PropVehicleDriveable::GetPassengerRole( C_BaseCombatCharacter *pPassenger ) -{ - if ( m_hPlayer.Get() == pPassenger ) - return VEHICLE_ROLE_DRIVER; - - return VEHICLE_ROLE_NONE; -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : updateType - -//----------------------------------------------------------------------------- -void C_PropVehicleDriveable::OnPreDataChanged( DataUpdateType_t updateType ) -{ - BaseClass::OnPreDataChanged( updateType ); - - m_hPrevPlayer = m_hPlayer; -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void C_PropVehicleDriveable::OnDataChanged( DataUpdateType_t updateType ) -{ - BaseClass::OnDataChanged( updateType ); - - if ( m_hPlayer && !m_hPrevPlayer ) - { - OnEnteredVehicle( m_hPlayer ); - SetNextClientThink( CLIENT_THINK_ALWAYS ); - } - else 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; - SetNextClientThink( CLIENT_THINK_NEVER ); - } -} - -//----------------------------------------------------------------------------- -// Should this object cast render-to-texture shadows? -//----------------------------------------------------------------------------- -ShadowType_t C_PropVehicleDriveable::ShadowCastType() -{ - CStudioHdr *pStudioHdr = GetModelPtr(); - if ( !pStudioHdr ) - return SHADOWS_NONE; - - if ( IsEffectActive(EF_NODRAW | EF_NOSHADOW) ) - return SHADOWS_NONE; - - // Always use render-to-texture. We'll always the dirty bits in our think function - return SHADOWS_RENDER_TO_TEXTURE; -} - - -//----------------------------------------------------------------------------- -// Mark the shadow as dirty while the vehicle is being driven -//----------------------------------------------------------------------------- -void C_PropVehicleDriveable::ClientThink( void ) -{ - // The vehicle is always dirty owing to pose parameters while it's being driven. - g_pClientShadowMgr->MarkRenderToTextureShadowDirty( GetShadowHandle() ); -} - - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void C_PropVehicleDriveable::DampenEyePosition( Vector &vecVehicleEyePos, QAngle &vecVehicleEyeAngles ) -{ -} - -//----------------------------------------------------------------------------- -// Purpose: Modify the player view/camera while in a vehicle -//----------------------------------------------------------------------------- -void C_PropVehicleDriveable::GetVehicleViewPosition( int nRole, Vector *pAbsOrigin, QAngle *pAbsAngles ) -{ - VehicleViewSmoothing( m_hPlayer, pAbsOrigin, pAbsAngles, m_bEnterAnimOn, m_bExitAnimOn, &m_vecEyeExitEndpoint, &m_ViewSmoothingData, &m_flFOV ); -} - - -//----------------------------------------------------------------------------- -// Futzes with the clip planes -//----------------------------------------------------------------------------- -void C_PropVehicleDriveable::GetVehicleClipPlanes( float &flZNear, float &flZFar ) const -{ - // FIXME: Need something a better long-term, this fixes the buggy. - flZNear = 6; -} - - -//----------------------------------------------------------------------------- -// Renders hud elements -//----------------------------------------------------------------------------- - -//----------------------------------------------------------------------------- -// Simply used to return intensity value based upon current timer passed in -//----------------------------------------------------------------------------- -int GetFlashColorIntensity( int LowIntensity, int HighIntensity, bool Dimming, int Increment, int Timer ) -{ - if ( Dimming ) - return ( HighIntensity - Timer * Increment ); - else - return ( LowIntensity + Timer * Increment ); -} - -#define TRIANGULATED_CROSSHAIR 1 - -void C_PropVehicleDriveable::DrawHudElements( ) -{ - CHudTexture *pIcon; - int iIconX, iIconY; - - if (m_bHasGun) - { - // draw crosshairs for vehicle gun - pIcon = gHUD.GetIcon( "gunhair" ); - - if ( pIcon != NULL ) - { - float x, y; - Vector screen; - - x = ScreenWidth()/2; - y = ScreenHeight()/2; - - #if TRIANGULATED_CROSSHAIR - ScreenTransform( m_vecGunCrosshair, screen ); - x += 0.5 * screen[0] * ScreenWidth() + 0.5; - y -= 0.5 * screen[1] * ScreenHeight() + 0.5; - #endif - - x -= pIcon->Width() / 2; - y -= pIcon->Height() / 2; - - Color clr = ( m_bUnableToFire ) ? gHUD.m_clrCaution : gHUD.m_clrNormal; - pIcon->DrawSelf( x, y, clr ); - } - - if ( m_nScannerDisabledWeapons ) - { - // Draw icons for scanners "weps disabled" - pIcon = gHUD.GetIcon( "dmg_bio" ); - if ( pIcon ) - { - iIconY = 467 - pIcon->Height() / 2; - iIconX = 385; - if ( !m_bScannerWepIcon ) - { - pIcon->DrawSelf( XRES(iIconX), YRES(iIconY), Color( 0, 0, 255, 255 ) ); - m_bScannerWepIcon = true; - m_iScannerWepFlashTimer = 0; - m_bScannerWepDim = true; - } - else - { - pIcon->DrawSelf( XRES(iIconX), YRES(iIconY), Color( 0, 0, GetFlashColorIntensity(55, 255, m_bScannerWepDim, 10, m_iScannerWepFlashTimer), 255 ) ); - m_iScannerWepFlashTimer++; - m_iScannerWepFlashTimer %= 20; - if(!m_iScannerWepFlashTimer) - m_bScannerWepDim ^= 1; - } - } - } - } - - if ( m_nScannerDisabledVehicle ) - { - // Draw icons for scanners "vehicle disabled" - pIcon = gHUD.GetIcon( "dmg_bio" ); - if ( pIcon ) - { - iIconY = 467 - pIcon->Height() / 2; - iIconX = 410; - if ( !m_bScannerVehicleIcon ) - { - pIcon->DrawSelf( XRES(iIconX), YRES(iIconY), Color( 0, 0, 255, 255 ) ); - m_bScannerVehicleIcon = true; - m_iScannerVehicleFlashTimer = 0; - m_bScannerVehicleDim = true; - } - else - { - pIcon->DrawSelf( XRES(iIconX), YRES(iIconY), Color( 0, 0, GetFlashColorIntensity(55, 255, m_bScannerVehicleDim, 10, m_iScannerVehicleFlashTimer), 255 ) ); - m_iScannerVehicleFlashTimer++; - m_iScannerVehicleFlashTimer %= 20; - if(!m_iScannerVehicleFlashTimer) - m_bScannerVehicleDim ^= 1; - } - } - } -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void C_PropVehicleDriveable::RestrictView( float *pYawBounds, float *pPitchBounds, - float *pRollBounds, QAngle &vecViewAngles ) -{ - int eyeAttachmentIndex = LookupAttachment( "vehicle_driver_eyes" ); - Vector vehicleEyeOrigin; - QAngle vehicleEyeAngles; - GetAttachmentLocal( eyeAttachmentIndex, vehicleEyeOrigin, vehicleEyeAngles ); - - // Limit the yaw. - if ( pYawBounds ) - { - float flAngleDiff = AngleDiff( vecViewAngles.y, vehicleEyeAngles.y ); - flAngleDiff = clamp( flAngleDiff, pYawBounds[0], pYawBounds[1] ); - vecViewAngles.y = vehicleEyeAngles.y + flAngleDiff; - } - - // Limit the pitch. - if ( pPitchBounds ) - { - float flAngleDiff = AngleDiff( vecViewAngles.x, vehicleEyeAngles.x ); - flAngleDiff = clamp( flAngleDiff, pPitchBounds[0], pPitchBounds[1] ); - vecViewAngles.x = vehicleEyeAngles.x + flAngleDiff; - } - - // Limit the roll. - if ( pRollBounds ) - { - float flAngleDiff = AngleDiff( vecViewAngles.z, vehicleEyeAngles.z ); - flAngleDiff = clamp( flAngleDiff, pRollBounds[0], pRollBounds[1] ); - vecViewAngles.z = vehicleEyeAngles.z + flAngleDiff; - } -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void C_PropVehicleDriveable::UpdateViewAngles( C_BasePlayer *pLocalPlayer, CUserCmd *pCmd ) -{ - if ( r_VehicleViewClamp.GetInt() ) - { - float pitchBounds[2] = { -85.0f, 25.0f }; - RestrictView( NULL, pitchBounds, NULL, pCmd->viewangles ); - } -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void C_PropVehicleDriveable::OnEnteredVehicle( C_BaseCombatCharacter *pPassenger ) -{ -} - -//============================================================================================= -// VEHICLE VIEW SMOOTHING. See iclientvehicle.h for details. -//============================================================================================= - -//----------------------------------------------------------------------------- -// Purpose: For a given degree of freedom, blends between the raw and clamped -// view depending on this vehicle's preferences. When vehicles wreck -// catastrophically, it's often better to lock the view for a little -// while until things settle down than to keep trying to clamp/flatten -// the view artificially because we can never really catch up with -// the chaotic flipping. -//----------------------------------------------------------------------------- -float ApplyViewLocking( float flAngleRaw, float flAngleClamped, ViewLockData_t &lockData, RemapAngleRange_CurvePart_t eCurvePart ) -{ - // If we're set up to never lock this degree of freedom, return the clamped value. - if ( lockData.flLockInterval == 0 ) - return flAngleClamped; - - float flAngleOut = flAngleClamped; - - // Lock the view if we're in the linear part of the curve, and keep it locked - // until some duration after we return to the flat (zero) part of the curve. - if ( ( eCurvePart == RemapAngleRange_CurvePart_Linear ) || - ( lockData.bLocked && ( eCurvePart == RemapAngleRange_CurvePart_Spline ) ) ) - { - //Msg( "LOCKED\n" ); - lockData.bLocked = true; - lockData.flUnlockTime = gpGlobals->curtime + lockData.flLockInterval; - flAngleOut = flAngleRaw; - } - else - { - if ( ( lockData.bLocked ) && ( gpGlobals->curtime > lockData.flUnlockTime ) ) - { - lockData.bLocked = false; - if ( lockData.flUnlockBlendInterval > 0 ) - { - lockData.flUnlockTime = gpGlobals->curtime; - } - else - { - lockData.flUnlockTime = 0; - } - } - - if ( !lockData.bLocked ) - { - if ( lockData.flUnlockTime != 0 ) - { - // Blend out from the locked raw view (no remapping) to a remapped view. - float flBlend = RemapValClamped( gpGlobals->curtime - lockData.flUnlockTime, 0, lockData.flUnlockBlendInterval, 0, 1 ); - //Msg( "BLEND %f\n", flBlend ); - - flAngleOut = Lerp( flBlend, flAngleRaw, flAngleClamped ); - if ( flBlend >= 1.0f ) - { - lockData.flUnlockTime = 0; - } - } - else - { - // Not blending out from a locked view to a remapped view. - //Msg( "CLAMPED\n" ); - flAngleOut = flAngleClamped; - } - } - else - { - //Msg( "STILL LOCKED\n" ); - flAngleOut = flAngleRaw; - } - } - - return flAngleOut; -} - - -//----------------------------------------------------------------------------- -// Purpose: -// Input : pData - -// vehicleEyeAngles - -//----------------------------------------------------------------------------- -void RemapViewAngles( ViewSmoothingData_t *pData, QAngle &vehicleEyeAngles ) -{ - QAngle vecEyeAnglesRemapped; - - // Clamp pitch. - RemapAngleRange_CurvePart_t ePitchCurvePart; - vecEyeAnglesRemapped.x = RemapAngleRange( pData->flPitchCurveZero, pData->flPitchCurveLinear, vehicleEyeAngles.x, &ePitchCurvePart ); - - vehicleEyeAngles.z = vecEyeAnglesRemapped.z = AngleNormalize( vehicleEyeAngles.z ); - - // Blend out the roll dampening as our pitch approaches 90 degrees, to avoid gimbal lock problems. - float flBlendRoll = 1.0; - if ( fabs( vehicleEyeAngles.x ) > 60 ) - { - flBlendRoll = RemapValClamped( fabs( vecEyeAnglesRemapped.x ), 60, 80, 1, 0); - } - - RemapAngleRange_CurvePart_t eRollCurvePart; - float flRollDamped = RemapAngleRange( pData->flRollCurveZero, pData->flRollCurveLinear, vecEyeAnglesRemapped.z, &eRollCurvePart ); - vecEyeAnglesRemapped.z = Lerp( flBlendRoll, vecEyeAnglesRemapped.z, flRollDamped ); - - //Msg("PITCH "); - vehicleEyeAngles.x = ApplyViewLocking( vehicleEyeAngles.x, vecEyeAnglesRemapped.x, pData->pitchLockData, ePitchCurvePart ); - - //Msg("ROLL "); - vehicleEyeAngles.z = ApplyViewLocking( vehicleEyeAngles.z, vecEyeAnglesRemapped.z, pData->rollLockData, eRollCurvePart ); -} - - -//----------------------------------------------------------------------------- -// Purpose: -// Input : *pAbsOrigin - -// *pAbsAngles - -// bEnterAnimOn - -// bExitAnimOn - -// *vecEyeExitEndpoint - -// *pData - -//----------------------------------------------------------------------------- -void VehicleViewSmoothing( CBasePlayer *pPlayer, Vector *pAbsOrigin, QAngle *pAbsAngles, bool bEnterAnimOn, bool bExitAnimOn, Vector *vecEyeExitEndpoint, ViewSmoothingData_t *pData, - float *pFOV ) -{ - int eyeAttachmentIndex = pData->pVehicle->LookupAttachment( "vehicle_driver_eyes" ); - matrix3x4_t vehicleEyePosToWorld; - Vector vehicleEyeOrigin; - QAngle vehicleEyeAngles; - pData->pVehicle->GetAttachment( eyeAttachmentIndex, vehicleEyeOrigin, vehicleEyeAngles ); - AngleMatrix( vehicleEyeAngles, vehicleEyePosToWorld ); - - // Dampen the eye positional change as we drive around. - *pAbsAngles = pPlayer->EyeAngles(); - if ( r_VehicleViewDampen.GetInt() && pData->bDampenEyePosition ) - { - C_PropVehicleDriveable *pDriveable = assert_cast(pData->pVehicle); - pDriveable->DampenEyePosition( vehicleEyeOrigin, vehicleEyeAngles ); - } - - // Started running an entry or exit anim? - bool bRunningAnim = ( bEnterAnimOn || bExitAnimOn ); - if ( bRunningAnim && !pData->bWasRunningAnim ) - { - pData->bRunningEnterExit = true; - pData->flAnimTimeElapsed = 0.01; - pData->flEnterExitDuration = pData->pVehicle->SequenceDuration( pData->pVehicle->GetSequence() ); - - pData->vecAnglesSaved = PrevMainViewAngles(); - pData->vecOriginSaved = PrevMainViewOrigin(); - - // Save our initial angular error, which we will blend out over the length of the animation. - pData->vecAngleDiffSaved.x = AngleDiff( vehicleEyeAngles.x, pData->vecAnglesSaved.x ); - pData->vecAngleDiffSaved.y = AngleDiff( vehicleEyeAngles.y, pData->vecAnglesSaved.y ); - pData->vecAngleDiffSaved.z = AngleDiff( vehicleEyeAngles.z, pData->vecAnglesSaved.z ); - - pData->vecAngleDiffMin = pData->vecAngleDiffSaved; - } - - pData->bWasRunningAnim = bRunningAnim; - - float frac = 0; - float flFracFOV = 0; - - // If we're in an enter/exit animation, blend the player's eye angles to the attachment's - if ( bRunningAnim || pData->bRunningEnterExit ) - { - *pAbsAngles = vehicleEyeAngles; - - // Forward integrate to determine the elapsed time in this entry/exit anim. - frac = pData->flAnimTimeElapsed / pData->flEnterExitDuration; - frac = clamp( frac, 0.0f, 1.0f ); - - flFracFOV = pData->flAnimTimeElapsed / ( pData->flEnterExitDuration * 0.85f ); - flFracFOV = clamp( flFracFOV, 0.0f, 1.0f ); - - //Msg("Frac: %f\n", frac ); - - if ( frac < 1.0 ) - { - // Blend to the desired vehicle eye origin - //Vector vecToView = (vehicleEyeOrigin - PrevMainViewOrigin()); - //vehicleEyeOrigin = PrevMainViewOrigin() + (vecToView * SimpleSpline(frac)); - //debugoverlay->AddBoxOverlay( vehicleEyeOrigin, -Vector(1,1,1), Vector(1,1,1), vec3_angle, 0,255,255, 64, 10 ); - } - else - { - pData->bRunningEnterExit = false; - - // Enter animation has finished, align view with the eye attachment point - // so they can start mouselooking around. - if ( !bExitAnimOn ) - { - Vector localEyeOrigin; - QAngle localEyeAngles; - - pData->pVehicle->GetAttachmentLocal( eyeAttachmentIndex, localEyeOrigin, localEyeAngles ); - engine->SetViewAngles( localEyeAngles ); - } - } - - pData->flAnimTimeElapsed += gpGlobals->frametime; - } - - // Compute the relative rotation between the unperturbed eye attachment + the eye angles - matrix3x4_t cameraToWorld; - AngleMatrix( *pAbsAngles, cameraToWorld ); - - matrix3x4_t worldToEyePos; - MatrixInvert( vehicleEyePosToWorld, worldToEyePos ); - - matrix3x4_t vehicleCameraToEyePos; - ConcatTransforms( worldToEyePos, cameraToWorld, vehicleCameraToEyePos ); - - // Damp out some of the vehicle motion (neck/head would do this) - if ( pData->bClampEyeAngles ) - { - RemapViewAngles( pData, vehicleEyeAngles ); - } - - AngleMatrix( vehicleEyeAngles, vehicleEyeOrigin, vehicleEyePosToWorld ); - - // Now treat the relative eye angles as being relative to this new, perturbed view position... - matrix3x4_t newCameraToWorld; - ConcatTransforms( vehicleEyePosToWorld, vehicleCameraToEyePos, newCameraToWorld ); - - // output new view abs angles - MatrixAngles( newCameraToWorld, *pAbsAngles ); - - // UNDONE: *pOrigin would already be correct in single player if the HandleView() on the server ran after vphysics - MatrixGetColumn( newCameraToWorld, 3, *pAbsOrigin ); - - // If we're playing an extry or exit animation... - if ( bRunningAnim || pData->bRunningEnterExit ) - { - float flSplineFrac = clamp( SimpleSpline( frac ), 0, 1 ); - - // Blend out the error between the player's initial eye angles and the animation's initial - // eye angles over the duration of the animation. - QAngle vecAngleDiffBlend = ( ( 1 - flSplineFrac ) * pData->vecAngleDiffSaved ); - - // If our current error is less than the error amount that we're blending - // out, use that. This lets the angles converge as quickly as possible. - QAngle vecAngleDiffCur; - vecAngleDiffCur.x = AngleDiff( vehicleEyeAngles.x, pData->vecAnglesSaved.x ); - vecAngleDiffCur.y = AngleDiff( vehicleEyeAngles.y, pData->vecAnglesSaved.y ); - vecAngleDiffCur.z = AngleDiff( vehicleEyeAngles.z, pData->vecAnglesSaved.z ); - - // In either case, never increase the error, so track the minimum error and clamp to that. - for (int i = 0; i < 3; i++) - { - if ( fabs(vecAngleDiffCur[i] ) < fabs( pData->vecAngleDiffMin[i] ) ) - { - pData->vecAngleDiffMin[i] = vecAngleDiffCur[i]; - } - - if ( fabs(vecAngleDiffBlend[i] ) < fabs( pData->vecAngleDiffMin[i] ) ) - { - pData->vecAngleDiffMin[i] = vecAngleDiffBlend[i]; - } - } - - // Add the error to the animation's eye angles. - *pAbsAngles -= pData->vecAngleDiffMin; - - // Use this as the basis for the next error calculation. - pData->vecAnglesSaved = *pAbsAngles; - - //if ( gpGlobals->frametime ) - //{ - // Msg("Angle : %.2f %.2f %.2f\n", target.x, target.y, target.z ); - //} - //Msg("Prev: %.2f %.2f %.2f\n", pData->vecAnglesSaved.x, pData->vecAnglesSaved.y, pData->vecAnglesSaved.z ); - - Vector vecAbsOrigin = *pAbsOrigin; - - // If we're exiting, our desired position is the server-sent exit position - if ( bExitAnimOn ) - { - //debugoverlay->AddBoxOverlay( vecEyeExitEndpoint, -Vector(1,1,1), Vector(1,1,1), vec3_angle, 255,255,255, 64, 10 ); - - // Blend to the exit position - *pAbsOrigin = Lerp( flSplineFrac, vecAbsOrigin, *vecEyeExitEndpoint ); - if ( ( pData->flFOV != 0.0f ) && pFOV ) - { - *pFOV = Lerp( flFracFOV, pData->flFOV, default_fov.GetFloat() ); - } - } - else - { - // Blend from our starting position to the desired origin - *pAbsOrigin = Lerp( flSplineFrac, pData->vecOriginSaved, vecAbsOrigin ); - if ( ( pData->flFOV != 0.0f ) && pFOV ) - { - *pFOV = Lerp( flFracFOV, default_fov.GetFloat(), pData->flFOV ); - } - } - } - else if ( pFOV ) - { - // Not running an entry/exit anim. Just use the vehicle's FOV. - *pFOV = pData->flFOV; - } -} diff --git a/src/src/cl_dll/c_sceneentity.cpp b/src/src/cl_dll/c_sceneentity.cpp deleted file mode 100644 index e4a9f84..0000000 --- a/src/src/cl_dll/c_sceneentity.cpp +++ /dev/null @@ -1,559 +0,0 @@ -//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// -// -// Purpose: -// -// $NoKeywords: $ -//=============================================================================// -#include "cbase.h" -#include "networkstringtable_clientdll.h" -#include "dt_utlvector_recv.h" -#include "choreoevent.h" -#include "choreoactor.h" -#include "choreochannel.h" -#include "choreoscene.h" -#include "filesystem.h" -#include "ichoreoeventcallback.h" -#include "scenefilecache/ISceneFileCache.h" - -// memdbgon must be the last include file in a .cpp file!!! -#include "tier0/memdbgon.h" - -class C_SceneEntity : public C_BaseEntity, public IChoreoEventCallback -{ - friend class CChoreoEventCallback; - -public: - DECLARE_CLASS( C_SceneEntity, C_BaseEntity ); - DECLARE_CLIENTCLASS(); - - C_SceneEntity( void ); - ~C_SceneEntity( void ); - - // From IChoreoEventCallback - virtual void StartEvent( float currenttime, CChoreoScene *scene, CChoreoEvent *event ); - virtual void EndEvent( float currenttime, CChoreoScene *scene, CChoreoEvent *event ); - virtual void ProcessEvent( float currenttime, CChoreoScene *scene, CChoreoEvent *event ); - virtual bool CheckEvent( float currenttime, CChoreoScene *scene, CChoreoEvent *event ); - - - virtual void PostDataUpdate( DataUpdateType_t updateType ); - virtual void PreDataUpdate( DataUpdateType_t updateType ); - - virtual void ClientThink(); - - void OnResetClientTime(); - -private: - - - // Scene load/unload - CChoreoScene *LoadScene( const char *filename ); - void LoadSceneFromFile( const char *filename ); - void UnloadScene( void ); - - C_BaseFlex *FindNamedActor( CChoreoActor *pChoreoActor ); - - virtual void DispatchStartFlexAnimation( CChoreoScene *scene, C_BaseFlex *actor, CChoreoEvent *event ); - virtual void DispatchEndFlexAnimation( CChoreoScene *scene, C_BaseFlex *actor, CChoreoEvent *event ); - virtual void DispatchStartExpression( CChoreoScene *scene, C_BaseFlex *actor, CChoreoEvent *event ); - virtual void DispatchEndExpression( CChoreoScene *scene, C_BaseFlex *actor, CChoreoEvent *event ); - - char const *GetSceneFileName(); - - void DoThink( float frametime ); - - void ClearSceneEvents( CChoreoScene *scene, bool canceled ); - -private: - - void CheckQueuedEvents(); - void WipeQueuedEvents(); - void QueueStartEvent( float starttime, CChoreoScene *scene, CChoreoEvent *event ); - - bool m_bIsPlayingBack; - bool m_bPaused; - float m_flCurrentTime; - float m_flForceClientTime; - int m_nSceneStringIndex; - - CUtlVector< CHandle< C_BaseFlex > > m_hActorList; - -private: - bool m_bWasPlaying; - - CChoreoScene *m_pScene; - - struct QueuedEvents_t - { - float starttime; - CChoreoScene *scene; - CChoreoEvent *event; - }; - - CUtlVector< QueuedEvents_t > m_QueuedEvents; -}; - -//----------------------------------------------------------------------------- -// Purpose: Decodes animtime and notes when it changes -// Input : *pStruct - ( C_BaseEntity * ) used to flag animtime is changine -// *pVarData - -// *pIn - -// objectID - -//----------------------------------------------------------------------------- -void RecvProxy_ForcedClientTime( const CRecvProxyData *pData, void *pStruct, void *pOut ) -{ - C_SceneEntity *pScene = reinterpret_cast< C_SceneEntity * >( pStruct ); - *(float *)pOut = pData->m_Value.m_Float; - pScene->OnResetClientTime(); -} - -#if defined( CSceneEntity ) -#undef CSceneEntity -#endif - -IMPLEMENT_CLIENTCLASS_DT(C_SceneEntity, DT_SceneEntity, CSceneEntity) - RecvPropInt(RECVINFO(m_nSceneStringIndex)), - RecvPropBool(RECVINFO(m_bIsPlayingBack)), - RecvPropBool(RECVINFO(m_bPaused)), - RecvPropFloat(RECVINFO(m_flForceClientTime), 0, RecvProxy_ForcedClientTime ), - RecvPropUtlVector( - RECVINFO_UTLVECTOR( m_hActorList ), - MAX_ACTORS_IN_SCENE, - RecvPropEHandle(NULL, 0, 0)), -END_RECV_TABLE() - -C_SceneEntity::C_SceneEntity( void ) -{ - m_pScene = NULL; -} - -C_SceneEntity::~C_SceneEntity( void ) -{ - UnloadScene(); -} - -void C_SceneEntity::OnResetClientTime() -{ - m_flCurrentTime = m_flForceClientTime; -} - -char const *C_SceneEntity::GetSceneFileName() -{ - return g_pStringTableClientSideChoreoScenes->GetString( m_nSceneStringIndex ); -} - -void C_SceneEntity::PostDataUpdate( DataUpdateType_t updateType ) -{ - BaseClass::PostDataUpdate( updateType ); - - char const *str = GetSceneFileName(); - - if ( updateType == DATA_UPDATE_CREATED ) - { - Assert( str && str[ 0 ] ); - if ( str && str[ 0 ] ) - { - LoadSceneFromFile( str ); - - // Kill everything except flex events - Assert( m_pScene ); - if ( m_pScene ) - { - int types[ 2 ]; - types[ 0 ] = CChoreoEvent::FLEXANIMATION; - types[ 1 ] = CChoreoEvent::EXPRESSION; - m_pScene->RemoveEventsExceptTypes( types, 2 ); - } - - SetNextClientThink( CLIENT_THINK_ALWAYS ); - } - } - - // Playback state changed... - if ( m_bWasPlaying != m_bIsPlayingBack ) - { - for(int i = 0; i < m_hActorList.Count() ; ++i ) - { - C_BaseFlex *actor = m_hActorList[ i ].Get(); - if ( !actor ) - continue; - - Assert( m_pScene ); - - if ( m_pScene ) - { - ClearSceneEvents( m_pScene, false ); - - if ( m_bIsPlayingBack ) - { - m_pScene->ResetSimulation(); - actor->StartChoreoScene( m_pScene ); - } - else - { - m_pScene->ResetSimulation(); - actor->RemoveChoreoScene( m_pScene ); - } - } - } - } -} - -void C_SceneEntity::PreDataUpdate( DataUpdateType_t updateType ) -{ - BaseClass::PreDataUpdate( updateType ); - - m_bWasPlaying = m_bIsPlayingBack; -} - -//----------------------------------------------------------------------------- -// Purpose: Called every frame that an event is active (Start/EndEvent as also -// called) -// Input : *event - -// Output : Returns true on success, false on failure. -//----------------------------------------------------------------------------- -void C_SceneEntity::ProcessEvent( float currenttime, CChoreoScene *scene, CChoreoEvent *event ) -{ - return; -} - - - -//----------------------------------------------------------------------------- -// Purpose: Called for events that are part of a pause condition -// Input : *event - -// Output : Returns true on event completed, false on non-completion. -//----------------------------------------------------------------------------- -bool C_SceneEntity::CheckEvent( float currenttime, CChoreoScene *scene, CChoreoEvent *event ) -{ - return true; -} - -C_BaseFlex *C_SceneEntity::FindNamedActor( CChoreoActor *pChoreoActor ) -{ - if ( !m_pScene ) - return NULL; - - int idx = m_pScene->FindActorIndex( pChoreoActor ); - if ( idx < 0 || idx >= m_hActorList.Count() ) - return NULL; - - return m_hActorList[ idx ].Get(); -} - -//----------------------------------------------------------------------------- -// Purpose: All events are leading edge triggered -// Input : currenttime - -// *event - -//----------------------------------------------------------------------------- -void C_SceneEntity::StartEvent( float currenttime, CChoreoScene *scene, CChoreoEvent *event ) -{ - Assert( event ); - - if ( !Q_stricmp( event->GetName(), "NULL" ) ) - { - Scene_Printf( "%s : %8.2f: ignored %s\n", GetSceneFileName(), currenttime, event->GetDescription() ); - return; - } - - - C_BaseFlex *pActor = NULL; - CChoreoActor *actor = event->GetActor(); - if ( actor ) - { - pActor = FindNamedActor( actor ); - if ( NULL == pActor ) - { - // This can occur if we haven't been networked an actor yet... we need to queue it so that we can - // fire off the start event as soon as we have the actor resident on the client. - QueueStartEvent( currenttime, scene, event ); - return; - } - } - - Scene_Printf( "%s : %8.2f: start %s\n", GetSceneFileName(), currenttime, event->GetDescription() ); - - switch ( event->GetType() ) - { - case CChoreoEvent::FLEXANIMATION: - { - if ( pActor ) - { - DispatchStartFlexAnimation( scene, pActor, event ); - } - } - break; - case CChoreoEvent::EXPRESSION: - { - if ( pActor ) - { - DispatchStartExpression( scene, pActor, event ); - } - } - break; - default: - break; - } -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : currenttime - -// *event - -//----------------------------------------------------------------------------- -void C_SceneEntity::EndEvent( float currenttime, CChoreoScene *scene, CChoreoEvent *event ) -{ - Assert( event ); - - if ( !Q_stricmp( event->GetName(), "NULL" ) ) - { - return; - } - - C_BaseFlex *pActor = NULL; - CChoreoActor *actor = event->GetActor(); - if ( actor ) - { - pActor = FindNamedActor( actor ); - } - - Scene_Printf( "%s : %8.2f: finish %s\n", GetSceneFileName(), currenttime, event->GetDescription() ); - - switch ( event->GetType() ) - { - case CChoreoEvent::FLEXANIMATION: - { - if ( pActor ) - { - DispatchEndFlexAnimation( scene, pActor, event ); - } - } - break; - case CChoreoEvent::EXPRESSION: - { - if ( pActor ) - { - DispatchEndExpression( scene, pActor, event ); - } - } - break; - default: - break; - } -} - -CChoreoScene *C_SceneEntity::LoadScene( const char *filename ) -{ - char loadfile[ 512 ]; - Q_strncpy( loadfile, filename, sizeof( loadfile ) ); - Q_SetExtension( loadfile, ".vcd", sizeof( loadfile ) ); - Q_FixSlashes( loadfile ); - - char *buffer = NULL; - size_t bufsize = scenefilecache->GetSceneBufferSize( loadfile ); - if ( bufsize <= 0 ) - return NULL; - - buffer = new char[ bufsize ]; - if ( !scenefilecache->GetSceneData( filename, (byte *)buffer, bufsize ) ) - { - delete[] buffer; - return NULL; - } - - g_TokenProcessor.SetBuffer( buffer ); - CChoreoScene *scene = ChoreoLoadScene( loadfile, this, &g_TokenProcessor, Scene_Printf ); - - delete[] buffer; - return scene; -} - -extern "C" void _stdcall Sleep( unsigned long dwMilliseconds ); - -//----------------------------------------------------------------------------- -// Purpose: -// Input : *filename - -//----------------------------------------------------------------------------- -void C_SceneEntity::LoadSceneFromFile( const char *filename ) -{ - UnloadScene(); - - int sleepCount = 0; - while ( scenefilecache->IsStillAsyncLoading( filename ) ) - { - ::Sleep( 10 ); - ++sleepCount; - - if ( sleepCount > 10 ) - { - Assert( 0 ); - break; - } - } - m_pScene = LoadScene( filename ); -} - -void C_SceneEntity::ClearSceneEvents( CChoreoScene *scene, bool canceled ) -{ - if ( !m_pScene ) - return; - - Scene_Printf( "%s : %8.2f: clearing events\n", GetSceneFileName(), m_flCurrentTime ); - - int i; - for ( i = 0 ; i < m_pScene->GetNumActors(); i++ ) - { - C_BaseFlex *pActor = FindNamedActor( m_pScene->GetActor( i ) ); - if ( !pActor ) - continue; - - // Clear any existing expressions - pActor->ClearSceneEvents( scene, canceled ); - } - - WipeQueuedEvents(); -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void C_SceneEntity::UnloadScene( void ) -{ - WipeQueuedEvents(); - - if ( m_pScene ) - { - ClearSceneEvents( m_pScene, false ); - for ( int i = 0 ; i < m_pScene->GetNumActors(); i++ ) - { - C_BaseFlex *pTestActor = FindNamedActor( m_pScene->GetActor( i ) ); - - if ( !pTestActor ) - continue; - - pTestActor->RemoveChoreoScene( m_pScene ); - } - } - delete m_pScene; - m_pScene = NULL; -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : *actor - -// *event - -//----------------------------------------------------------------------------- -void C_SceneEntity::DispatchStartFlexAnimation( CChoreoScene *scene, C_BaseFlex *actor, CChoreoEvent *event ) -{ - actor->AddSceneEvent( scene, event ); -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : *actor - -// *event - -//----------------------------------------------------------------------------- -void C_SceneEntity::DispatchEndFlexAnimation( CChoreoScene *scene, C_BaseFlex *actor, CChoreoEvent *event ) -{ - actor->RemoveSceneEvent( scene, event, false ); -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : *actor - -// *event - -//----------------------------------------------------------------------------- -void C_SceneEntity::DispatchStartExpression( CChoreoScene *scene, C_BaseFlex *actor, CChoreoEvent *event ) -{ - actor->AddSceneEvent( scene, event ); -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : *actor - -// *event - -//----------------------------------------------------------------------------- -void C_SceneEntity::DispatchEndExpression( CChoreoScene *scene, C_BaseFlex *actor, CChoreoEvent *event ) -{ - actor->RemoveSceneEvent( scene, event, false ); -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void C_SceneEntity::DoThink( float frametime ) -{ - if ( !m_pScene ) - return; - - if ( !m_bIsPlayingBack ) - { - WipeQueuedEvents(); - return; - } - - CheckQueuedEvents(); - - if ( m_bPaused ) - { - return; - } - - // Msg( "CL: %d, %f for %s\n", gpGlobals->tickcount, m_flCurrentTime, m_pScene->GetFilename() ); - - // Tell scene to go - m_pScene->Think( m_flCurrentTime ); - // Drive simulation time for scene - m_flCurrentTime += gpGlobals->frametime; -} - -void C_SceneEntity::ClientThink() -{ - DoThink( gpGlobals->frametime ); -} - -void C_SceneEntity::CheckQueuedEvents() -{ -// Check for duplicates - CUtlVector< QueuedEvents_t > events; - events = m_QueuedEvents; - m_QueuedEvents.RemoveAll(); - - int c = events.Count(); - for ( int i = 0; i < c; ++i ) - { - const QueuedEvents_t& check = events[ i ]; - - // Retry starting this event - StartEvent( check.starttime, check.scene, check.event ); - } -} - -void C_SceneEntity::WipeQueuedEvents() -{ - m_QueuedEvents.Purge(); -} - -void C_SceneEntity::QueueStartEvent( float starttime, CChoreoScene *scene, CChoreoEvent *event ) -{ - // Check for duplicates - int c = m_QueuedEvents.Count(); - for ( int i = 0; i < c; ++i ) - { - const QueuedEvents_t& check = m_QueuedEvents[ i ]; - if ( check.scene == scene && - check.event == event ) - return; - } - - QueuedEvents_t qe; - qe.scene = scene; - qe.event = event; - qe.starttime = starttime; - m_QueuedEvents.AddToTail( qe ); -} - -CON_COMMAND( scenefilecache_status, "Print current scene file cache status." ) -{ - scenefilecache->OutputStatus(); -} \ No newline at end of file diff --git a/src/src/cl_dll/cdll_convar.h b/src/src/cl_dll/cdll_convar.h deleted file mode 100644 index 3c6ae55..0000000 --- a/src/src/cl_dll/cdll_convar.h +++ /dev/null @@ -1,46 +0,0 @@ -//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// -// -// Purpose: -// -// $Workfile: $ -// $Date: $ -// -//----------------------------------------------------------------------------- -// $Log: $ -// -// $NoKeywords: $ -//=============================================================================// - -#ifndef CDLL_CONVAR_H -#define CDLL_CONVAR_H -#pragma once - - -// This file implements IConVarAccessor to allow access to console variables. - - - -#include "convar.h" -#include "cdll_util.h" -#include "icvar.h" - -class CDLL_ConVarAccessor : public IConCommandBaseAccessor -{ -public: - virtual bool RegisterConCommandBase( ConCommandBase *pCommand ) - { - // Mark for easy removal - pCommand->AddFlags( FCVAR_CLIENTDLL ); - - // Unlink from client .dll only list - pCommand->SetNext( 0 ); - - // Link to engine's list instead - cvar->RegisterConCommandBase( pCommand ); - return true; - } -}; - - - -#endif // CDLL_CONVAR_H diff --git a/src/src/cl_dll/client_scratch-2003.vcproj b/src/src/cl_dll/client_scratch-2003.vcproj deleted file mode 100644 index 1ea423f..0000000 --- a/src/src/cl_dll/client_scratch-2003.vcproj +++ /dev/null @@ -1,3662 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/src/cl_dll/client_scratch-2005.vcproj b/src/src/cl_dll/client_scratch-2005.vcproj deleted file mode 100644 index de42aad..0000000 --- a/src/src/cl_dll/client_scratch-2005.vcproj +++ /dev/null @@ -1,4915 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/src/cl_dll/entityoriginmaterialproxy.cpp b/src/src/cl_dll/entityoriginmaterialproxy.cpp deleted file mode 100644 index f13adec..0000000 --- a/src/src/cl_dll/entityoriginmaterialproxy.cpp +++ /dev/null @@ -1,49 +0,0 @@ -//========= Copyright © 1996-2006, Valve Corporation, All rights reserved. ============// -// -// Purpose: A base class for all material proxies in the client dll -// -// $NoKeywords: $ -//=============================================================================// - -#include "cbase.h" -// identifier was truncated to '255' characters in the debug information -//#pragma warning(disable: 4786) - -#include "ProxyEntity.h" -#include "materialsystem/IMaterialVar.h" - -class CEntityOriginMaterialProxy : public CEntityMaterialProxy -{ -public: - CEntityOriginMaterialProxy() - { - m_pMaterial = NULL; - m_pOriginVar = NULL; - } - virtual ~CEntityOriginMaterialProxy() - { - } - virtual bool Init( IMaterial *pMaterial, KeyValues *pKeyValues ) - { - m_pMaterial = pMaterial; - bool found; - m_pOriginVar = m_pMaterial->FindVar( "$entityorigin", &found ); - if( !found ) - { - m_pOriginVar = NULL; - return false; - } - return true; - } - virtual void OnBind( C_BaseEntity *pC_BaseEntity ) - { - const Vector &origin = pC_BaseEntity->GetAbsOrigin(); - m_pOriginVar->SetVecValue( origin.x, origin.y, origin.z ); - } - -protected: - IMaterial *m_pMaterial; - IMaterialVar *m_pOriginVar; -}; - -EXPOSE_INTERFACE( CEntityOriginMaterialProxy, IMaterialProxy, "EntityOrigin" IMATERIAL_PROXY_INTERFACE_VERSION ); diff --git a/src/src/cl_dll/episodic/episodic_screenspaceeffects.cpp b/src/src/cl_dll/episodic/episodic_screenspaceeffects.cpp deleted file mode 100644 index 4b6a649..0000000 --- a/src/src/cl_dll/episodic/episodic_screenspaceeffects.cpp +++ /dev/null @@ -1,305 +0,0 @@ -// -// Episodic screen-space effects -// - -#include "cbase.h" -#include "screenspaceeffects.h" -#include "rendertexture.h" -#include "materialsystem/imaterialsystemhardwareconfig.h" -#include "materialsystem/imaterialsystem.h" -#include "materialsystem/imaterialvar.h" -#include "cdll_client_int.h" -#include "materialsystem/itexture.h" -#include "keyvalues.h" -#include "ClientEffectPrecacheSystem.h" - -#include "episodic_screenspaceeffects.h" - -CLIENTEFFECT_REGISTER_BEGIN( PrecacheEffectEpScreenspace ) -CLIENTEFFECT_MATERIAL( "effects/stun" ) -CLIENTEFFECT_MATERIAL( "effects/introblur" ) -CLIENTEFFECT_REGISTER_END() - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CStunEffect::Init( void ) -{ - m_pStunTexture = NULL; - m_flDuration = 0.0f; - m_flFinishTime = 0.0f; - m_bUpdated = false; -} - -//------------------------------------------------------------------------------ -// Purpose: Pick up changes in our parameters -//------------------------------------------------------------------------------ -void CStunEffect::SetParameters( KeyValues *params ) -{ - if( params->FindKey( "duration" ) ) - { - m_flDuration = params->GetFloat( "duration" ); - m_flFinishTime = gpGlobals->curtime + m_flDuration; - m_bUpdated = true; - } -} - -//----------------------------------------------------------------------------- -// Purpose: Render the effect -//----------------------------------------------------------------------------- -void CStunEffect::Render( int x, int y, int w, int h ) -{ - // Make sure we're ready to play this effect - if ( m_flFinishTime < gpGlobals->curtime ) - return; - - IMaterial *pMaterial = materials->FindMaterial( "effects/stun", TEXTURE_GROUP_CLIENT_EFFECTS, true ); - if ( pMaterial == NULL ) - return; - - bool bResetBaseFrame = m_bUpdated; - - // Set ourselves to the proper rendermode - materials->MatrixMode( MATERIAL_VIEW ); - materials->PushMatrix(); - materials->LoadIdentity(); - materials->MatrixMode( MATERIAL_PROJECTION ); - materials->PushMatrix(); - materials->LoadIdentity(); - - // Get our current view - if ( m_pStunTexture == NULL ) - { - m_pStunTexture = GetPowerOfTwoFrameBufferTexture(); - } - - // Draw the texture if we're using it - if ( m_pStunTexture != NULL ) - { - bool foundVar; - IMaterialVar* pBaseTextureVar = pMaterial->FindVar( "$basetexture", &foundVar, false ); - - if ( bResetBaseFrame ) - { - // Save off this pass - Rect_t srcRect; - srcRect.x = x; - srcRect.y = y; - srcRect.width = w; - srcRect.height = h; - pBaseTextureVar->SetTextureValue( m_pStunTexture ); - - materials->CopyRenderTargetToTextureEx( m_pStunTexture, 0, &srcRect, NULL ); - materials->SetFrameBufferCopyTexture( m_pStunTexture ); - m_bUpdated = false; - } - - byte overlaycolor[4] = { 255, 255, 255, 0 }; - - float flEffectPerc = ( m_flFinishTime - gpGlobals->curtime ) / m_flDuration; - overlaycolor[3] = (byte) (150.0f * flEffectPerc); - - render->ViewDrawFade( overlaycolor, pMaterial ); - - float viewOffs = ( flEffectPerc * 32.0f ) * cos( gpGlobals->curtime * 10.0f * cos( gpGlobals->curtime * 2.0f ) ); - float vX = x + viewOffs; - float vY = y; - - // just do one pass for dxlevel < 80. - if (g_pMaterialSystemHardwareConfig->GetDXSupportLevel() >= 80) - { - materials->DrawScreenSpaceRectangle( pMaterial, vX, vY, w, h, - 0, 0, m_pStunTexture->GetActualWidth()-1, m_pStunTexture->GetActualHeight()-1, - m_pStunTexture->GetActualWidth(), m_pStunTexture->GetActualHeight() ); - - render->ViewDrawFade( overlaycolor, pMaterial ); - - materials->DrawScreenSpaceRectangle( pMaterial, x, y, w, h, - 0, 0, m_pStunTexture->GetActualWidth()-1, m_pStunTexture->GetActualHeight()-1, - m_pStunTexture->GetActualWidth(), m_pStunTexture->GetActualHeight() ); - } - - // Save off this pass - Rect_t srcRect; - srcRect.x = x; - srcRect.y = y; - srcRect.width = w; - srcRect.height = h; - pBaseTextureVar->SetTextureValue( m_pStunTexture ); - - materials->CopyRenderTargetToTextureEx( m_pStunTexture, 0, &srcRect, NULL ); - } - - // Restore our state - materials->MatrixMode( MATERIAL_VIEW ); - materials->PopMatrix(); - materials->MatrixMode( MATERIAL_PROJECTION ); - materials->PopMatrix(); -} - -// ================================================================================================================ -// -// Ep 1. Intro blur -// -// ================================================================================================================ - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CEP1IntroEffect::Init( void ) -{ - m_pStunTexture = NULL; - m_flDuration = 0.0f; - m_flFinishTime = 0.0f; - m_bUpdateView = true; - m_bFadeOut = false; -} - -//------------------------------------------------------------------------------ -// Purpose: Pick up changes in our parameters -//------------------------------------------------------------------------------ -void CEP1IntroEffect::SetParameters( KeyValues *params ) -{ - if( params->FindKey( "duration" ) ) - { - m_flDuration = params->GetFloat( "duration" ); - m_flFinishTime = gpGlobals->curtime + m_flDuration; - } - - if( params->FindKey( "fadeout" ) ) - { - m_bFadeOut = ( params->GetInt( "fadeout" ) == 1 ); - } -} - -//----------------------------------------------------------------------------- -// Purpose: Get the alpha value depending on various factors and time -//----------------------------------------------------------------------------- -inline unsigned char CEP1IntroEffect::GetFadeAlpha( void ) -{ - // Find our percentage between fully "on" and "off" in the pulse range - float flEffectPerc = ( m_flDuration == 0.0f ) ? 0.0f : ( m_flFinishTime - gpGlobals->curtime ) / m_flDuration; - flEffectPerc = clamp( flEffectPerc, 0.0f, 1.0f ); - - if ( m_bFadeOut ) - { - // HDR requires us to be more subtle, or we get uber-brightening - if ( g_pMaterialSystemHardwareConfig->GetHDRType() != HDR_TYPE_NONE ) - return (unsigned char) clamp( 50.0f * flEffectPerc, 0.0f, 50.0f ); - - // Non-HDR - return (unsigned char) clamp( 64.0f * flEffectPerc, 0.0f, 64.0f ); - } - else - { - // HDR requires us to be more subtle, or we get uber-brightening - if ( g_pMaterialSystemHardwareConfig->GetHDRType() != HDR_TYPE_NONE ) - return (unsigned char) clamp( 64.0f * flEffectPerc, 50.0f, 64.0f ); - - // Non-HDR - return (unsigned char) clamp( 128.0f * flEffectPerc, 64.0f, 128.0f ); - } -} - -//----------------------------------------------------------------------------- -// Purpose: Render the effect -//----------------------------------------------------------------------------- -void CEP1IntroEffect::Render( int x, int y, int w, int h ) -{ - if ( ( m_flFinishTime == 0 ) || ( IsEnabled() == false ) ) - return; - - IMaterial *pMaterial = materials->FindMaterial( "effects/introblur", TEXTURE_GROUP_CLIENT_EFFECTS, true ); - if ( pMaterial == NULL ) - return; - - // Set ourselves to the proper rendermode - materials->MatrixMode( MATERIAL_VIEW ); - materials->PushMatrix(); - materials->LoadIdentity(); - materials->MatrixMode( MATERIAL_PROJECTION ); - materials->PushMatrix(); - materials->LoadIdentity(); - - // Get our current view - if ( m_pStunTexture == NULL ) - { - m_pStunTexture = GetWaterRefractionTexture(); - } - - // Draw the texture if we're using it - if ( m_pStunTexture != NULL ) - { - bool foundVar; - IMaterialVar* pBaseTextureVar = pMaterial->FindVar( "$basetexture", &foundVar, false ); - - if ( m_bUpdateView ) - { - // Save off this pass - Rect_t srcRect; - srcRect.x = x; - srcRect.y = y; - srcRect.width = w; - srcRect.height = h; - pBaseTextureVar->SetTextureValue( m_pStunTexture ); - - materials->CopyRenderTargetToTextureEx( m_pStunTexture, 0, &srcRect, NULL ); - materials->SetFrameBufferCopyTexture( m_pStunTexture ); - m_bUpdateView = false; - } - - byte overlaycolor[4] = { 255, 255, 255, 0 }; - - // Get our fade value depending on our fade duration - overlaycolor[3] = GetFadeAlpha(); - - // Disable overself if we're done fading out - if ( m_bFadeOut && overlaycolor[3] == 0 ) - { - // Takes effect next frame (we don't want to hose our matrix stacks here) - g_pScreenSpaceEffects->DisableScreenSpaceEffect( "episodic_intro" ); - m_bUpdateView = true; - } - - // Calculate some wavey noise to jitter the view by - float vX = 2.0f * -fabs( cosf( gpGlobals->curtime ) * cosf( gpGlobals->curtime * 6.0 ) ); - float vY = 2.0f * cosf( gpGlobals->curtime ) * cosf( gpGlobals->curtime * 5.0 ); - - // Scale percentage - float flScalePerc = 0.02f + ( 0.01f * cosf( gpGlobals->curtime * 2.0f ) * cosf( gpGlobals->curtime * 0.5f ) ); - - // Scaled offsets for the UVs (as texels) - float flUOffset = ( m_pStunTexture->GetActualWidth() - 1 ) * flScalePerc * 0.5f; - float flVOffset = ( m_pStunTexture->GetActualHeight() - 1 ) * flScalePerc * 0.5f; - - // New UVs with scaling offsets - float flU1 = flUOffset; - float flU2 = ( m_pStunTexture->GetActualWidth() - 1 ) - flUOffset; - float flV1 = flVOffset; - float flV2 = ( m_pStunTexture->GetActualHeight() - 1 ) - flVOffset; - - // Draw the "zoomed" overlay - materials->DrawScreenSpaceRectangle( pMaterial, vX, vY, w, h, - flU1, flV1, - flU2, flV2, - m_pStunTexture->GetActualWidth(), m_pStunTexture->GetActualHeight() ); - - render->ViewDrawFade( overlaycolor, pMaterial ); - - // Save off this pass - Rect_t srcRect; - srcRect.x = x; - srcRect.y = y; - srcRect.width = w; - srcRect.height = h; - pBaseTextureVar->SetTextureValue( m_pStunTexture ); - - materials->CopyRenderTargetToTextureEx( m_pStunTexture, 0, &srcRect, NULL ); - } - - // Restore our state - materials->MatrixMode( MATERIAL_VIEW ); - materials->PopMatrix(); - materials->MatrixMode( MATERIAL_PROJECTION ); - materials->PopMatrix(); -} diff --git a/src/src/cl_dll/episodic/episodic_screenspaceeffects.h b/src/src/cl_dll/episodic/episodic_screenspaceeffects.h deleted file mode 100644 index 3f4a3bd..0000000 --- a/src/src/cl_dll/episodic/episodic_screenspaceeffects.h +++ /dev/null @@ -1,78 +0,0 @@ -//====== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======= -// -// Purpose: -// -//============================================================================= - -#ifndef EPISODIC_SCREENSPACEEFFECTS_H -#define EPISODIC_SCREENSPACEEFFECTS_H -#ifdef _WIN32 -#pragma once -#endif - -#include "screenspaceeffects.h" - -class CStunEffect : public IScreenSpaceEffect -{ -public: - CStunEffect( void ) : - m_pStunTexture( NULL ), - m_flDuration( 0.0f ), - m_flFinishTime( 0.0f ), - m_bUpdated( false ) {} - - virtual void Init( void ); - virtual void Shutdown( void ) {} - virtual void SetParameters( KeyValues *params ); - virtual void Enable( bool bEnable ) {}; - virtual bool IsEnabled( ) { return true; } - - virtual void Render( int x, int y, int w, int h ); - -private: - ITexture *m_pStunTexture; - float m_flDuration; - float m_flFinishTime; - bool m_bUpdated; -}; - -ADD_SCREENSPACE_EFFECT( CStunEffect, episodic_stun ); - -// -// EP1 Intro Blur -// - -class CEP1IntroEffect : public IScreenSpaceEffect -{ -public: - CEP1IntroEffect( void ) : - m_pStunTexture( NULL ), - m_flDuration( 0.0f ), - m_flFinishTime( 0.0f ), - m_bUpdateView( true ), - m_bEnabled( false ), - m_bFadeOut( false ) {} - - virtual void Init( void ); - virtual void Shutdown( void ) {} - virtual void SetParameters( KeyValues *params ); - virtual void Enable( bool bEnable ) { m_bEnabled = bEnable; } - virtual bool IsEnabled( ) { return m_bEnabled; } - - virtual void Render( int x, int y, int w, int h ); - -private: - - inline unsigned char GetFadeAlpha( void ); - - ITexture *m_pStunTexture; - float m_flDuration; - float m_flFinishTime; - bool m_bUpdateView; - bool m_bEnabled; - bool m_bFadeOut; -}; - -ADD_SCREENSPACE_EFFECT( CEP1IntroEffect, episodic_intro ); - -#endif // EPISODIC_SCREENSPACEEFFECTS_H diff --git a/src/src/cl_dll/fx_fleck.cpp b/src/src/cl_dll/fx_fleck.cpp deleted file mode 100644 index 94f04cd..0000000 --- a/src/src/cl_dll/fx_fleck.cpp +++ /dev/null @@ -1,111 +0,0 @@ -//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// -// -// Purpose: -// -// $Workfile: $ -// $NoKeywords: $ -//=============================================================================// -#include "cbase.h" -#include "FX_Fleck.h" - -// memdbgon must be the last include file in a .cpp file!!! -#include "tier0/memdbgon.h" - -// -// CFleckParticles -// - - -CSmartPtr CFleckParticles::Create( const char *pDebugName, const Vector &vCenter ) -{ - CFleckParticles *pRet = new CFleckParticles( pDebugName ); - if ( pRet ) - { - // Set its bbox once so it doesn't update 500 times as the flecks fly outwards. - Vector vDims( 5, 5, 5 ); - pRet->GetBinding().SetBBox( vCenter - vDims, vCenter + vDims ); - } - return pRet; -} - - -//----------------------------------------------------------------------------- -// Purpose: Test for surrounding collision surfaces for quick collision testing for the particle system -// Input : &origin - starting position -// *dir - direction of movement (if NULL, will do a point emission test in four directions) -// angularSpread - looseness of the spread -// minSpeed - minimum speed -// maxSpeed - maximum speed -// gravity - particle gravity for the sytem -// dampen - dampening amount on collisions -// flags - extra information -//----------------------------------------------------------------------------- -void CFleckParticles::Setup( const Vector &origin, const Vector *direction, float angularSpread, float minSpeed, float maxSpeed, float gravity, float dampen, int flags ) -{ - //See if we've specified a direction - m_ParticleCollision.Setup( origin, direction, angularSpread, minSpeed, maxSpeed, gravity, dampen ); -} - - -void CFleckParticles::RenderParticles( CParticleRenderIterator *pIterator ) -{ - const FleckParticle *pParticle = (const FleckParticle*)pIterator->GetFirst(); - while ( pParticle ) - { - Vector tPos; - TransformParticle( ParticleMgr()->GetModelView(), pParticle->m_Pos, tPos ); - float sortKey = (int) tPos.z; - - Vector color; - color[0] = pParticle->m_uchColor[0] / 255.0f; - color[1] = pParticle->m_uchColor[1] / 255.0f; - color[2] = pParticle->m_uchColor[2] / 255.0f; - //Render it - RenderParticle_ColorSizeAngle( - pIterator->GetParticleDraw(), - tPos, - color, - 1.0f - (pParticle->m_flLifetime / pParticle->m_flDieTime), - pParticle->m_uchSize, - pParticle->m_flRoll ); - - pParticle = (const FleckParticle*)pIterator->GetNext( sortKey ); - } -} - - -void CFleckParticles::SimulateParticles( CParticleSimulateIterator *pIterator ) -{ - FleckParticle *pParticle = (FleckParticle*)pIterator->GetFirst(); - while ( pParticle ) - { - const float timeDelta = pIterator->GetTimeDelta(); - - //Should this particle die? - pParticle->m_flLifetime += timeDelta; - - if ( pParticle->m_flLifetime >= pParticle->m_flDieTime ) - { - pIterator->RemoveParticle( pParticle ); - } - else - { - pParticle->m_flRoll += pParticle->m_flRollDelta * timeDelta; - - //Simulate the movement with collision - trace_t trace; - m_ParticleCollision.MoveParticle( pParticle->m_Pos, pParticle->m_vecVelocity, &pParticle->m_flRollDelta, timeDelta, &trace ); - - // If we're in solid, then stop moving - if ( trace.allsolid ) - { - pParticle->m_vecVelocity = vec3_origin; - pParticle->m_flRollDelta = 0.0f; - } - } - - pParticle = (FleckParticle*)pIterator->GetNext(); - } -} - - diff --git a/src/src/cl_dll/hl2_hud/hud_flashlight.cpp b/src/src/cl_dll/hl2_hud/hud_flashlight.cpp deleted file mode 100644 index 9cbd72e..0000000 --- a/src/src/cl_dll/hl2_hud/hud_flashlight.cpp +++ /dev/null @@ -1,117 +0,0 @@ -//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// -// -// Purpose: -// -//=============================================================================// - -#include "hudelement.h" -#include "hud_numericdisplay.h" -#include -#include "cbase.h" -#include "hud.h" -#include "hud_suitpower.h" -#include "hud_macros.h" -#include "iclientmode.h" -#include -#include - -// 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 Init( void ); - - void SetFlashlightState( bool flashlightOn ); - -protected: - virtual void Paint(); - -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", "20", "proportional_float" ); - - bool m_bFlashlightOn; -}; - -using namespace vgui; - -//!! flashlight disabled for now, indicator moved into hud_suitpower -//!! if that is successful this file can be just removed -// DECLARE_HUDELEMENT( CHudFlashlight, HudFlashlight ); - -//----------------------------------------------------------------------------- -// Purpose: Constructor -//----------------------------------------------------------------------------- -CHudFlashlight::CHudFlashlight( const char *pElementName ) : CHudElement( pElementName ), BaseClass( NULL, "HudFlashlight" ) -{ - vgui::Panel *pParent = g_pClientMode->GetViewport(); - SetParent( pParent ); - m_bFlashlightOn = true; - - SetHiddenBits( HIDEHUD_HEALTH | HIDEHUD_PLAYERDEAD | HIDEHUD_NEEDSUIT ); -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CHudFlashlight::Init() -{ -} - -//----------------------------------------------------------------------------- -// Purpose: data accessor -//----------------------------------------------------------------------------- -void CHudFlashlight::SetFlashlightState( bool flashlightOn ) -{ - if ( m_bFlashlightOn == flashlightOn ) - return; - - if ( flashlightOn ) - { - // flashlight on - g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("SuitFlashlightOn"); - } - else - { - // flashlight off - g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("SuitFlashlightOff"); - } - - m_bFlashlightOn = flashlightOn; -} - -//----------------------------------------------------------------------------- -// Purpose: draws the flashlight icon -//----------------------------------------------------------------------------- -void CHudFlashlight::Paint() -{ - C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); - if ( !pPlayer ) - return; - - SetFlashlightState( pPlayer->IsEffectActive( EF_DIMLIGHT ) ); - - // draw our name - wchar_t *text = L"FLASHLIGHT: ON"; - if (!m_bFlashlightOn) - { - text = L"FLASHLIGHT: OFF"; - } - - surface()->DrawSetTextFont(m_hTextFont); - surface()->DrawSetTextColor(m_TextColor); - surface()->DrawSetTextPos(text_xpos, text_ypos); - surface()->DrawUnicodeString( text ); -} - - diff --git a/src/src/cl_dll/hl2mp/hl2mp_hud_chat.cpp b/src/src/cl_dll/hl2mp/hl2mp_hud_chat.cpp deleted file mode 100644 index 9f03ef2..0000000 --- a/src/src/cl_dll/hl2mp/hl2mp_hud_chat.cpp +++ /dev/null @@ -1,459 +0,0 @@ -//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// -// -// Purpose: -// -//=============================================================================// - -#include "cbase.h" -#include "hl2mp_hud_chat.h" -#include "hud_macros.h" -#include "text_message.h" -#include "vguicenterprint.h" -#include "vgui/ILocalize.h" -#include "c_team.h" -#include "c_playerresource.h" -#include "c_hl2mp_player.h" -#include "hl2mp_gamerules.h" - -ConVar cl_showtextmsg( "cl_showtextmsg", "1", 0, "Enable/disable text messages printing on the screen." ); - -float g_ColorBlue[3] = { 153, 204, 255 }; -float g_ColorRed[3] = { 255, 63.75, 63.75 }; -float g_ColorGreen[3] = { 153, 255, 153 }; -float g_ColorYellow[3] = { 255, 178.5, 0.0 }; -float g_ColorGrey[3] = { 204, 204, 204 }; - -float *GetClientColor( int clientIndex ) -{ - if ( clientIndex == 0 ) // console msg - { - return g_ColorYellow; - } - else if( g_PR ) - { - switch ( g_PR->GetTeam( clientIndex ) ) - { - case TEAM_COMBINE : return g_ColorBlue; - case TEAM_REBELS : return g_ColorRed; - default : return g_ColorYellow; - } - } - - return g_ColorYellow; -} - -// converts all '\r' characters to '\n', so that the engine can deal with the properly -// returns a pointer to str -static char* ConvertCRtoNL( char *str ) -{ - for ( char *ch = str; *ch != 0; ch++ ) - if ( *ch == '\r' ) - *ch = '\n'; - return str; -} - -// converts all '\r' characters to '\n', so that the engine can deal with the properly -// returns a pointer to str -static wchar_t* ConvertCRtoNL( wchar_t *str ) -{ - for ( wchar_t *ch = str; *ch != 0; ch++ ) - if ( *ch == L'\r' ) - *ch = L'\n'; - return str; -} - -static void StripEndNewlineFromString( char *str ) -{ - int s = strlen( str ) - 1; - if ( s >= 0 ) - { - if ( str[s] == '\n' || str[s] == '\r' ) - str[s] = 0; - } -} - -static void StripEndNewlineFromString( wchar_t *str ) -{ - int s = wcslen( str ) - 1; - if ( s >= 0 ) - { - if ( str[s] == L'\n' || str[s] == L'\r' ) - str[s] = 0; - } -} - -DECLARE_HUDELEMENT( CHudChat ); - -DECLARE_HUD_MESSAGE( CHudChat, SayText ); -DECLARE_HUD_MESSAGE( CHudChat, TextMsg ); - - -//===================== -//CHudChatLine -//===================== - -void CHudChatLine::ApplySchemeSettings(vgui::IScheme *pScheme) -{ - BaseClass::ApplySchemeSettings( pScheme ); - - m_hFont = pScheme->GetFont( "ChatFont" ); - SetBorder( NULL ); - SetBgColor( Color( 0, 0, 0, 0 ) ); - SetFgColor( Color( 0, 0, 0, 0 ) ); - - SetFont( m_hFont ); -} - -void CHudChatLine::PerformFadeout( void ) -{ - // Flash + Extra bright when new - float curtime = gpGlobals->curtime; - - int lr = m_clrText[0]; - int lg = m_clrText[1]; - int lb = m_clrText[2]; - - //CSPort chat only fades out, no blinking. - if ( curtime <= m_flExpireTime && curtime > m_flExpireTime - CHATLINE_FADE_TIME ) - { - float frac = ( m_flExpireTime - curtime ) / CHATLINE_FADE_TIME; - - int alpha = frac * 255; - alpha = clamp( alpha, 0, 255 ); - - wchar_t wbuf[4096]; - - GetText(0, wbuf, sizeof(wbuf)); - - SetText( "" ); - - if ( m_iNameLength > 0 ) - { - wchar_t wText[4096]; - // draw the first x characters in the player color - wcsncpy( wText, wbuf, min( m_iNameLength + 1, MAX_PLAYER_NAME_LENGTH+32) ); - wText[ min( m_iNameLength, MAX_PLAYER_NAME_LENGTH+31) ] = 0; - - m_clrNameColor[3] = alpha; - - InsertColorChange( m_clrNameColor ); - InsertString( wText ); - - wcsncpy( wText, wbuf + ( m_iNameLength ), wcslen( wbuf + m_iNameLength ) ); - wText[ wcslen( wbuf + m_iNameLength ) ] = '\0'; - InsertColorChange( Color( g_ColorYellow[0], g_ColorYellow[1], g_ColorYellow[2], alpha ) ); - InsertString( wText ); - InvalidateLayout( true ); - } - else - { - InsertColorChange( Color( lr, lg, lb, alpha ) ); - InsertString( wbuf ); - } - } - - OnThink(); -} - - - -//===================== -//CHudChatInputLine -//===================== - -void CHudChatInputLine::ApplySchemeSettings(vgui::IScheme *pScheme) -{ - BaseClass::ApplySchemeSettings(pScheme); - - vgui::HFont hFont = pScheme->GetFont( "ChatFont" ); - - m_pPrompt->SetFont( hFont ); - m_pInput->SetFont( hFont ); - - m_pInput->SetFgColor( pScheme->GetColor( "Chat.TypingText", pScheme->GetColor( "Panel.FgColor", Color( 255, 255, 255, 255 ) ) ) ); - m_pInput->SetBgColor( Color( 255, 255, 255, 0 ) ); -} - - - -//===================== -//CHudChat -//===================== - -CHudChat::CHudChat( const char *pElementName ) : BaseClass( pElementName ) -{ - -} - -void CHudChat::CreateChatInputLine( void ) -{ - m_pChatInput = new CHudChatInputLine( this, "ChatInputLine" ); - m_pChatInput->SetVisible( false ); -} - -void CHudChat::CreateChatLines( void ) -{ - for ( int i = 0; i < CHAT_INTERFACE_LINES; i++ ) - { - char sz[ 32 ]; - Q_snprintf( sz, sizeof( sz ), "ChatLine%02i", i ); - m_ChatLines[ i ] = new CHudChatLine( this, sz ); - m_ChatLines[ i ]->SetVisible( false ); - } -} - -void CHudChat::ApplySchemeSettings( vgui::IScheme *pScheme ) -{ - BaseClass::ApplySchemeSettings( pScheme ); - - SetBgColor( Color( 0, 0, 0, 0 ) ); - SetFgColor( Color( 0, 0, 0, 0 ) ); -} - - -void CHudChat::Init( void ) -{ - BaseClass::Init(); - -// HOOK_HUD_MESSAGE( CHudChat, RadioText ); - HOOK_HUD_MESSAGE( CHudChat, SayText ); - HOOK_HUD_MESSAGE( CHudChat, TextMsg ); -} - -//----------------------------------------------------------------------------- -// Purpose: Overrides base reset to not cancel chat at round restart -//----------------------------------------------------------------------------- -void CHudChat::Reset( void ) -{ -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : *pszName - -// iSize - -// *pbuf - -//----------------------------------------------------------------------------- -void CHudChat::MsgFunc_SayText( bf_read &msg ) -{ - char szString[256]; - - int client = msg.ReadByte(); - msg.ReadString( szString, sizeof(szString) ); - bool bWantsToChat = msg.ReadByte(); - - // flash speaking player dot -// if ( client > 0 ) -// Radar_FlashPlayer( client ); - - if ( bWantsToChat ) - { - // print raw chat text - ChatPrintf( client, "%s", szString ); - } - else - { - // try to lookup translated string - Printf( "%s", hudtextmessage->LookupString( szString ) ); - } - - Msg( "%s", szString ); -} - - -// Message handler for text messages -// displays a string, looking them up from the titles.txt file, which can be localised -// parameters: -// byte: message direction ( HUD_PRINTCONSOLE, HUD_PRINTNOTIFY, HUD_PRINTCENTER, HUD_PRINTTALK ) -// string: message -// optional parameters: -// string: message parameter 1 -// string: message parameter 2 -// string: message parameter 3 -// string: message parameter 4 -// any string that starts with the character '#' is a message name, and is used to look up the real message in titles.txt -// the next (optional) one to four strings are parameters for that string (which can also be message names if they begin with '#') -void CHudChat::MsgFunc_TextMsg( bf_read &msg ) -{ - char szString[2048]; - int msg_dest = msg.ReadByte(); - - wchar_t szBuf[5][128]; - wchar_t outputBuf[256]; - - for ( int i=0; i<5; ++i ) - { - msg.ReadString( szString, sizeof(szString) ); - char *tmpStr = hudtextmessage->LookupString( szString, &msg_dest ); - const wchar_t *pBuf = vgui::localize()->Find( tmpStr ); - if ( pBuf ) - { - // Copy pBuf into szBuf[i]. - int nMaxChars = sizeof( szBuf[i] ) / sizeof( wchar_t ); - wcsncpy( szBuf[i], pBuf, nMaxChars ); - szBuf[i][nMaxChars-1] = 0; - } - else - { - if ( i ) - { - StripEndNewlineFromString( tmpStr ); // these strings are meant for subsitution into the main strings, so cull the automatic end newlines - } - vgui::localize()->ConvertANSIToUnicode( tmpStr, szBuf[i], sizeof(szBuf[i]) ); - } - } - - if ( !cl_showtextmsg.GetInt() ) - return; - - int len; - switch ( msg_dest ) - { - case HUD_PRINTCENTER: - vgui::localize()->ConstructString( outputBuf, sizeof(outputBuf), szBuf[0], 4, szBuf[1], szBuf[2], szBuf[3], szBuf[4] ); - internalCenterPrint->Print( ConvertCRtoNL( outputBuf ) ); - break; - - case HUD_PRINTNOTIFY: - szString[0] = 1; // mark this message to go into the notify buffer - vgui::localize()->ConstructString( outputBuf, sizeof(outputBuf), szBuf[0], 4, szBuf[1], szBuf[2], szBuf[3], szBuf[4] ); - vgui::localize()->ConvertUnicodeToANSI( outputBuf, szString+1, sizeof(szString)-1 ); - len = strlen( szString ); - if ( len && szString[len-1] != '\n' && szString[len-1] != '\r' ) - { - Q_strncat( szString, "\n", sizeof(szString), 1 ); - } - Msg( "%s", ConvertCRtoNL( szString ) ); - break; - - case HUD_PRINTTALK: - vgui::localize()->ConstructString( outputBuf, sizeof(outputBuf), szBuf[0], 4, szBuf[1], szBuf[2], szBuf[3], szBuf[4] ); - vgui::localize()->ConvertUnicodeToANSI( outputBuf, szString, sizeof(szString) ); - len = strlen( szString ); - if ( len && szString[len-1] != '\n' && szString[len-1] != '\r' ) - { - Q_strncat( szString, "\n", sizeof(szString), 1 ); - } - Printf( "%s", ConvertCRtoNL( szString ) ); - break; - - case HUD_PRINTCONSOLE: - vgui::localize()->ConstructString( outputBuf, sizeof(outputBuf), szBuf[0], 4, szBuf[1], szBuf[2], szBuf[3], szBuf[4] ); - vgui::localize()->ConvertUnicodeToANSI( outputBuf, szString, sizeof(szString) ); - len = strlen( szString ); - if ( len && szString[len-1] != '\n' && szString[len-1] != '\r' ) - { - Q_strncat( szString, "\n", sizeof(szString), 1 ); - } - Msg( "%s", ConvertCRtoNL( szString ) ); - break; - } -} - - -//----------------------------------------------------------------------------- -// Purpose: -// Input : *fmt - -// ... - -//----------------------------------------------------------------------------- -void CHudChat::ChatPrintf( int iPlayerIndex, const char *fmt, ... ) -{ - va_list marker; - char msg[4096]; - - va_start(marker, fmt); - Q_vsnprintf(msg, sizeof( msg), fmt, marker); - va_end(marker); - - // Strip any trailing '\n' - if ( strlen( msg ) > 0 && msg[ strlen( msg )-1 ] == '\n' ) - { - msg[ strlen( msg ) - 1 ] = 0; - } - - // Strip leading \n characters ( or notify/color signifiers ) - char *pmsg = msg; - while ( *pmsg && ( *pmsg == '\n' || *pmsg == 1 || *pmsg == 2 ) ) - { - pmsg++; - } - - if ( !*pmsg ) - return; - - CHudChatLine *line = (CHudChatLine *)FindUnusedChatLine(); - if ( !line ) - { - ExpireOldest(); - line = (CHudChatLine *)FindUnusedChatLine(); - } - - if ( !line ) - { - return; - } - - line->SetText( "" ); - - int iNameLength = 0; - - player_info_t sPlayerInfo; - if ( iPlayerIndex == 0 ) - { - Q_memset( &sPlayerInfo, 0, sizeof(player_info_t) ); - Q_strncpy( sPlayerInfo.name, "Console", sizeof(sPlayerInfo.name) ); - } - else - { - engine->GetPlayerInfo( iPlayerIndex, &sPlayerInfo ); - } - - const char *pName = sPlayerInfo.name; - - if ( pName ) - { - const char *nameInString = strstr( pmsg, pName ); - - if ( nameInString ) - { - iNameLength = strlen( pName ) + (nameInString - pmsg); - } - } - else - line->InsertColorChange( Color( g_ColorYellow[0], g_ColorYellow[1], g_ColorYellow[2], 255 ) ); - - char *buf = static_cast( _alloca( strlen( pmsg ) + 1 ) ); - wchar_t *wbuf = static_cast( _alloca( (strlen( pmsg ) + 1 ) * sizeof(wchar_t) ) ); - if ( buf ) - { - float *flColor = GetClientColor( iPlayerIndex ); - - line->SetExpireTime(); - - // draw the first x characters in the player color - Q_strncpy( buf, pmsg, min( iNameLength + 1, MAX_PLAYER_NAME_LENGTH+32) ); - buf[ min( iNameLength, MAX_PLAYER_NAME_LENGTH+31) ] = 0; - line->InsertColorChange( Color( flColor[0], flColor[1], flColor[2], 255 ) ); - line->InsertString( buf ); - Q_strncpy( buf, pmsg + iNameLength, strlen( pmsg )); - buf[ strlen( pmsg + iNameLength ) ] = '\0'; - line->InsertColorChange( Color( g_ColorYellow[0], g_ColorYellow[1], g_ColorYellow[2], 255 ) ); - vgui::localize()->ConvertANSIToUnicode( buf, wbuf, strlen(pmsg)*sizeof(wchar_t)); - line->InsertString( wbuf ); - line->SetVisible( true ); - line->SetNameLength( iNameLength ); - line->SetNameColor( Color( flColor[0], flColor[1], flColor[2], 255 ) ); - } - - CLocalPlayerFilter filter; - C_BaseEntity::EmitSound( filter, -1 /*SOUND_FROM_LOCAL_PLAYER*/, "HudChat.Message" ); -} - -int CHudChat::GetChatInputOffset( void ) -{ - if ( m_pChatInput->IsVisible() ) - { - return m_iFontHeight; - } - else - return 0; -} diff --git a/src/src/cl_dll/hl2mp/ui/hl2mpclientscoreboard.cpp b/src/src/cl_dll/hl2mp/ui/hl2mpclientscoreboard.cpp deleted file mode 100644 index c3f261d..0000000 --- a/src/src/cl_dll/hl2mp/ui/hl2mpclientscoreboard.cpp +++ /dev/null @@ -1,646 +0,0 @@ -//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// -// -// Purpose: -// -// $NoKeywords: $ -//=============================================================================// - -#include "cbase.h" -#include "hud.h" -#include "hl2mpClientScoreBoard.h" -#include "c_team.h" -#include "c_playerresource.h" -#include "c_hl2mp_player.h" -#include "hl2mp_gamerules.h" - -#include - -#include -#include -#include -#include -#include - -#include "voice_status.h" - -using namespace vgui; - -#define TEAM_MAXCOUNT 5 - -// id's of sections used in the scoreboard -enum EScoreboardSections -{ - SCORESECTION_COMBINE = 1, - SCORESECTION_REBELS = 2, - SCORESECTION_FREEFORALL = 3, - SCORESECTION_SPECTATOR = 4 -}; - -const int NumSegments = 7; -static int coord[NumSegments+1] = { - 0, - 1, - 2, - 3, - 4, - 6, - 9, - 10 -}; - -//----------------------------------------------------------------------------- -// Purpose: Konstructor -//----------------------------------------------------------------------------- -CHL2MPClientScoreBoardDialog::CHL2MPClientScoreBoardDialog(IViewPort *pViewPort):CClientScoreBoardDialog(pViewPort) -{ -} - -//----------------------------------------------------------------------------- -// Purpose: Destructor -//----------------------------------------------------------------------------- -CHL2MPClientScoreBoardDialog::~CHL2MPClientScoreBoardDialog() -{ -} - -//----------------------------------------------------------------------------- -// Purpose: Paint background for rounded corners -//----------------------------------------------------------------------------- -void CHL2MPClientScoreBoardDialog::PaintBackground() -{ - m_pPlayerList->SetBgColor( Color(0, 0, 0, 0) ); - m_pPlayerList->SetBorder(NULL); - - int x1, x2, y1, y2; - surface()->DrawSetColor(m_bgColor); - surface()->DrawSetTextColor(m_bgColor); - - int wide, tall; - GetSize( wide, tall ); - - int i; - - // top-left corner -------------------------------------------------------- - int xDir = 1; - int yDir = -1; - int xIndex = 0; - int yIndex = NumSegments - 1; - int xMult = 1; - int yMult = 1; - int x = 0; - int y = 0; - for ( i=0; iDrawFilledRect( x1, y1, x2, y2 ); - - xIndex += xDir; - yIndex += yDir; - } - - // top-right corner ------------------------------------------------------- - xDir = 1; - yDir = -1; - xIndex = 0; - yIndex = NumSegments - 1; - x = wide; - y = 0; - xMult = -1; - yMult = 1; - for ( i=0; iDrawFilledRect( x1, y1, x2, y2 ); - xIndex += xDir; - yIndex += yDir; - } - - // bottom-right corner ---------------------------------------------------- - xDir = 1; - yDir = -1; - xIndex = 0; - yIndex = NumSegments - 1; - x = wide; - y = tall; - xMult = -1; - yMult = -1; - for ( i=0; iDrawFilledRect( x1, y1, x2, y2 ); - xIndex += xDir; - yIndex += yDir; - } - - // bottom-left corner ----------------------------------------------------- - xDir = 1; - yDir = -1; - xIndex = 0; - yIndex = NumSegments - 1; - x = 0; - y = tall; - xMult = 1; - yMult = -1; - for ( i=0; iDrawFilledRect( x1, y1, x2, y2 ); - xIndex += xDir; - yIndex += yDir; - } - - // paint between top left and bottom left --------------------------------- - x1 = 0; - x2 = coord[NumSegments]; - y1 = coord[NumSegments]; - y2 = tall - coord[NumSegments]; - surface()->DrawFilledRect( x1, y1, x2, y2 ); - - // paint between left and right ------------------------------------------- - x1 = coord[NumSegments]; - x2 = wide - coord[NumSegments]; - y1 = 0; - y2 = tall; - surface()->DrawFilledRect( x1, y1, x2, y2 ); - - // paint between top right and bottom right ------------------------------- - x1 = wide - coord[NumSegments]; - x2 = wide; - y1 = coord[NumSegments]; - y2 = tall - coord[NumSegments]; - surface()->DrawFilledRect( x1, y1, x2, y2 ); -} - -//----------------------------------------------------------------------------- -// Purpose: Paint border for rounded corners -//----------------------------------------------------------------------------- -void CHL2MPClientScoreBoardDialog::PaintBorder() -{ - int x1, x2, y1, y2; - surface()->DrawSetColor(m_borderColor); - surface()->DrawSetTextColor(m_borderColor); - - int wide, tall; - GetSize( wide, tall ); - - int i; - - // top-left corner -------------------------------------------------------- - int xDir = 1; - int yDir = -1; - int xIndex = 0; - int yIndex = NumSegments - 1; - int xMult = 1; - int yMult = 1; - int x = 0; - int y = 0; - for ( i=0; iDrawFilledRect( x1, y1, x2, y2 ); - - xIndex += xDir; - yIndex += yDir; - } - - // top-right corner ------------------------------------------------------- - xDir = 1; - yDir = -1; - xIndex = 0; - yIndex = NumSegments - 1; - x = wide; - y = 0; - xMult = -1; - yMult = 1; - for ( i=0; iDrawFilledRect( x1, y1, x2, y2 ); - xIndex += xDir; - yIndex += yDir; - } - - // bottom-right corner ---------------------------------------------------- - xDir = 1; - yDir = -1; - xIndex = 0; - yIndex = NumSegments - 1; - x = wide; - y = tall; - xMult = -1; - yMult = -1; - for ( i=0; iDrawFilledRect( x1, y1, x2, y2 ); - xIndex += xDir; - yIndex += yDir; - } - - // bottom-left corner ----------------------------------------------------- - xDir = 1; - yDir = -1; - xIndex = 0; - yIndex = NumSegments - 1; - x = 0; - y = tall; - xMult = 1; - yMult = -1; - for ( i=0; iDrawFilledRect( x1, y1, x2, y2 ); - xIndex += xDir; - yIndex += yDir; - } - - // top -------------------------------------------------------------------- - x1 = coord[NumSegments]; - x2 = wide - coord[NumSegments]; - y1 = 0; - y2 = 1; - surface()->DrawFilledRect( x1, y1, x2, y2 ); - - // bottom ----------------------------------------------------------------- - x1 = coord[NumSegments]; - x2 = wide - coord[NumSegments]; - y1 = tall - 1; - y2 = tall; - surface()->DrawFilledRect( x1, y1, x2, y2 ); - - // left ------------------------------------------------------------------- - x1 = 0; - x2 = 1; - y1 = coord[NumSegments]; - y2 = tall - coord[NumSegments]; - surface()->DrawFilledRect( x1, y1, x2, y2 ); - - // right ------------------------------------------------------------------ - x1 = wide - 1; - x2 = wide; - y1 = coord[NumSegments]; - y2 = tall - coord[NumSegments]; - surface()->DrawFilledRect( x1, y1, x2, y2 ); -} - -//----------------------------------------------------------------------------- -// Purpose: Apply scheme settings -//----------------------------------------------------------------------------- -void CHL2MPClientScoreBoardDialog::ApplySchemeSettings( vgui::IScheme *pScheme ) -{ - BaseClass::ApplySchemeSettings( pScheme ); - - m_bgColor = GetSchemeColor("SectionedListPanel.BgColor", GetBgColor(), pScheme); - m_borderColor = pScheme->GetColor( "FgColor", Color( 0, 0, 0, 0 ) ); - - SetBgColor( Color(0, 0, 0, 0) ); - SetBorder( pScheme->GetBorder( "BaseBorder" ) ); -} - - -//----------------------------------------------------------------------------- -// Purpose: sets up base sections -//----------------------------------------------------------------------------- -void CHL2MPClientScoreBoardDialog::InitScoreboardSections() -{ - m_pPlayerList->SetBgColor( Color(0, 0, 0, 0) ); - m_pPlayerList->SetBorder(NULL); - - // fill out the structure of the scoreboard - AddHeader(); - - if ( HL2MPRules()->IsTeamplay() ) - { - // add the team sections - AddSection( TYPE_TEAM, TEAM_COMBINE ); - AddSection( TYPE_TEAM, TEAM_REBELS ); - } - else - { - AddSection( TYPE_TEAM, TEAM_UNASSIGNED ); - } - AddSection( TYPE_TEAM, TEAM_SPECTATOR ); -} - -//----------------------------------------------------------------------------- -// Purpose: resets the scoreboard team info -//----------------------------------------------------------------------------- -void CHL2MPClientScoreBoardDialog::UpdateTeamInfo() -{ - if ( g_PR == NULL ) - return; - - int iNumPlayersInGame = 0; - - for ( int j = 1; j <= gpGlobals->maxClients; j++ ) - { - if ( g_PR->IsConnected( j ) ) - { - iNumPlayersInGame++; - } - } - - // update the team sections in the scoreboard - for ( int i = TEAM_SPECTATOR; i < TEAM_MAXCOUNT; i++ ) - { - wchar_t *teamName = NULL; - int sectionID = 0; - C_Team *team = GetGlobalTeam(i); - - if ( team ) - { - sectionID = GetSectionFromTeamNumber( i ); - - // update team name - wchar_t name[64]; - wchar_t string1[1024]; - wchar_t wNumPlayers[6]; - - if ( HL2MPRules()->IsTeamplay() == false ) - { - _snwprintf(wNumPlayers, 6, L"%i", iNumPlayersInGame ); - _snwprintf( name, sizeof(name), L"%s", localize()->Find("#ScoreBoard_Deathmatch") ); - - teamName = name; - - if ( iNumPlayersInGame == 1) - { - localize()->ConstructString( string1, sizeof(string1), localize()->Find("#ScoreBoard_Player"), 2, teamName, wNumPlayers ); - } - else - { - localize()->ConstructString( string1, sizeof(string1), localize()->Find("#ScoreBoard_Players"), 2, teamName, wNumPlayers ); - } - } - else - { - _snwprintf(wNumPlayers, 6, L"%i", team->Get_Number_Players()); - - if (!teamName && team) - { - localize()->ConvertANSIToUnicode(team->Get_Name(), name, sizeof(name)); - teamName = name; - } - - if (team->Get_Number_Players() == 1) - { - localize()->ConstructString( string1, sizeof(string1), localize()->Find("#ScoreBoard_Player"), 2, teamName, wNumPlayers ); - } - else - { - localize()->ConstructString( string1, sizeof(string1), localize()->Find("#ScoreBoard_Players"), 2, teamName, wNumPlayers ); - } - - // update stats - wchar_t val[6]; - swprintf(val, L"%d", team->Get_Score()); - m_pPlayerList->ModifyColumn(sectionID, "frags", val); - if (team->Get_Ping() < 1) - { - m_pPlayerList->ModifyColumn(sectionID, "ping", L""); - } - else - { - swprintf(val, L"%d", team->Get_Ping()); - m_pPlayerList->ModifyColumn(sectionID, "ping", val); - } - - } - - m_pPlayerList->ModifyColumn(sectionID, "name", string1); - } - } -} - -//----------------------------------------------------------------------------- -// Purpose: adds the top header of the scoreboars -//----------------------------------------------------------------------------- -void CHL2MPClientScoreBoardDialog::AddHeader() -{ - // add the top header - m_pPlayerList->AddSection(0, ""); - m_pPlayerList->SetSectionAlwaysVisible(0); - m_pPlayerList->AddColumnToSection(0, "name", "", 0, scheme()->GetProportionalScaledValueEx( GetScheme(), CSTRIKE_NAME_WIDTH ) ); - m_pPlayerList->AddColumnToSection(0, "class", "", 0, scheme()->GetProportionalScaledValueEx( GetScheme(), CSTRIKE_CLASS_WIDTH ) ); - m_pPlayerList->AddColumnToSection(0, "frags", "#PlayerScore", 0 | SectionedListPanel::COLUMN_RIGHT, scheme()->GetProportionalScaledValueEx( GetScheme(), CSTRIKE_SCORE_WIDTH ) ); - m_pPlayerList->AddColumnToSection(0, "deaths", "#PlayerDeath", 0 | SectionedListPanel::COLUMN_RIGHT, scheme()->GetProportionalScaledValueEx( GetScheme(), CSTRIKE_DEATH_WIDTH ) ); - m_pPlayerList->AddColumnToSection(0, "ping", "#PlayerPing", 0 | SectionedListPanel::COLUMN_RIGHT, scheme()->GetProportionalScaledValueEx( GetScheme(), CSTRIKE_PING_WIDTH ) ); -// m_pPlayerList->AddColumnToSection(0, "voice", "#PlayerVoice", SectionedListPanel::COLUMN_IMAGE | SectionedListPanel::HEADER_TEXT| SectionedListPanel::COLUMN_CENTER, scheme()->GetProportionalScaledValueEx( GetScheme(), CSTRIKE_VOICE_WIDTH ) ); -// m_pPlayerList->AddColumnToSection(0, "tracker", "#PlayerTracker", SectionedListPanel::COLUMN_IMAGE | SectionedListPanel::HEADER_TEXT, scheme()->GetProportionalScaledValueEx( GetScheme(), CSTRIKE_FRIENDS_WIDTH ) ); -} - -//----------------------------------------------------------------------------- -// Purpose: Adds a new section to the scoreboard (i.e the team header) -//----------------------------------------------------------------------------- -void CHL2MPClientScoreBoardDialog::AddSection(int teamType, int teamNumber) -{ - int sectionID = GetSectionFromTeamNumber( teamNumber ); - if ( teamType == TYPE_TEAM ) - { - m_pPlayerList->AddSection(sectionID, "", StaticPlayerSortFunc); - - // setup the columns - m_pPlayerList->AddColumnToSection(sectionID, "name", "", 0, scheme()->GetProportionalScaledValueEx( GetScheme(), CSTRIKE_NAME_WIDTH ) ); - m_pPlayerList->AddColumnToSection(sectionID, "class", "" , 0, scheme()->GetProportionalScaledValueEx( GetScheme(), CSTRIKE_CLASS_WIDTH ) ); - m_pPlayerList->AddColumnToSection(sectionID, "frags", "", SectionedListPanel::COLUMN_RIGHT, scheme()->GetProportionalScaledValueEx( GetScheme(), CSTRIKE_SCORE_WIDTH ) ); - m_pPlayerList->AddColumnToSection(sectionID, "deaths", "", SectionedListPanel::COLUMN_RIGHT, scheme()->GetProportionalScaledValueEx( GetScheme(), CSTRIKE_DEATH_WIDTH ) ); - m_pPlayerList->AddColumnToSection(sectionID, "ping", "", SectionedListPanel::COLUMN_RIGHT, scheme()->GetProportionalScaledValueEx( GetScheme(), CSTRIKE_PING_WIDTH ) ); - - // set the section to have the team color - if ( teamNumber ) - { - if ( GameResources() ) - m_pPlayerList->SetSectionFgColor(sectionID, GameResources()->GetTeamColor(teamNumber)); - } - - m_pPlayerList->SetSectionAlwaysVisible(sectionID); - } - else if ( teamType == TYPE_SPECTATORS ) - { - m_pPlayerList->AddSection(sectionID, ""); - m_pPlayerList->AddColumnToSection(sectionID, "name", "#Spectators", 0, scheme()->GetProportionalScaledValueEx( GetScheme(), CSTRIKE_NAME_WIDTH )); - m_pPlayerList->AddColumnToSection(sectionID, "class", "" , 0, scheme()->GetProportionalScaledValueEx( GetScheme(), 100 ) ); - } -} - -int CHL2MPClientScoreBoardDialog::GetSectionFromTeamNumber( int teamNumber ) -{ - switch ( teamNumber ) - { - case TEAM_COMBINE: - return SCORESECTION_COMBINE; - case TEAM_REBELS: - return SCORESECTION_REBELS; - case TEAM_SPECTATOR: - return SCORESECTION_SPECTATOR; - default: - return SCORESECTION_FREEFORALL; - } - return SCORESECTION_FREEFORALL; -} - -//----------------------------------------------------------------------------- -// Purpose: Adds a new row to the scoreboard, from the playerinfo structure -//----------------------------------------------------------------------------- -bool CHL2MPClientScoreBoardDialog::GetPlayerScoreInfo(int playerIndex, KeyValues *kv) -{ - kv->SetInt("playerIndex", playerIndex); - kv->SetInt("team", g_PR->GetTeam( playerIndex ) ); - kv->SetString("name", g_PR->GetPlayerName(playerIndex) ); - kv->SetInt("deaths", g_PR->GetDeaths( playerIndex )); - kv->SetInt("frags", g_PR->GetPlayerScore( playerIndex )); - kv->SetString("class", ""); - - if (g_PR->GetPing( playerIndex ) < 1) - { - if ( g_PR->IsFakePlayer( playerIndex ) ) - { - kv->SetString("ping", "BOT"); - } - else - { - kv->SetString("ping", ""); - } - } - else - { - kv->SetInt("ping", g_PR->GetPing( playerIndex )); - } - - return true; -} - -enum { - MAX_PLAYERS_PER_TEAM = 16, - MAX_SCOREBOARD_PLAYERS = 32 -}; -struct PlayerScoreInfo -{ - int index; - int frags; - int deaths; - bool important; - bool alive; -}; - -int PlayerScoreInfoSort( const PlayerScoreInfo *p1, const PlayerScoreInfo *p2 ) -{ - // check local - if ( p1->important ) - return -1; - if ( p2->important ) - return 1; - - // check alive - if ( p1->alive && !p2->alive ) - return -1; - if ( p2->alive && !p1->alive ) - return 1; - - // check frags - if ( p1->frags > p2->frags ) - return -1; - if ( p2->frags > p1->frags ) - return 1; - - // check deaths - if ( p1->deaths < p2->deaths ) - return -1; - if ( p2->deaths < p1->deaths ) - return 1; - - // check index - if ( p1->index < p2->index ) - return -1; - - return 1; -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CHL2MPClientScoreBoardDialog::UpdatePlayerInfo() -{ - m_iSectionId = 0; // 0'th row is a header - int selectedRow = -1; - int i; - - CBasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); - - if ( !pPlayer || !g_PR ) - return; - - // walk all the players and make sure they're in the scoreboard - for ( i = 1; i <= gpGlobals->maxClients; i++ ) - { - bool shouldShow = g_PR->IsConnected( i ); - if ( shouldShow ) - { - // add the player to the list - KeyValues *playerData = new KeyValues("data"); - GetPlayerScoreInfo( i, playerData ); - int itemID = FindItemIDForPlayerIndex( i ); - int sectionID = GetSectionFromTeamNumber( g_PR->GetTeam( i ) ); - - if (itemID == -1) - { - // add a new row - itemID = m_pPlayerList->AddItem( sectionID, playerData ); - } - else - { - // modify the current row - m_pPlayerList->ModifyItem( itemID, sectionID, playerData ); - } - - if ( i == pPlayer->entindex() ) - { - selectedRow = itemID; // this is the local player, hilight this row - } - - // set the row color based on the players team - m_pPlayerList->SetItemFgColor( itemID, g_PR->GetTeamColor( g_PR->GetTeam( i ) ) ); - - playerData->deleteThis(); - } - else - { - // remove the player - int itemID = FindItemIDForPlayerIndex( i ); - if (itemID != -1) - { - m_pPlayerList->RemoveItem(itemID); - } - } - } - - if ( selectedRow != -1 ) - { - m_pPlayerList->SetSelectedItem(selectedRow); - } - - -} diff --git a/src/src/cl_dll/hud_basechat.cpp b/src/src/cl_dll/hud_basechat.cpp deleted file mode 100644 index e32927e..0000000 --- a/src/src/cl_dll/hud_basechat.cpp +++ /dev/null @@ -1,966 +0,0 @@ -//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// -// -// Purpose: -// -// $NoKeywords: $ -//=============================================================================// - -#include "cbase.h" -#include "hud_basechat.h" - -#include -#include -#include "iclientmode.h" -#include "hud_macros.h" -#include "engine/IEngineSound.h" -#include "text_message.h" -#include -#include "vguicenterprint.h" -#include "vgui/keycode.h" -#include -#include "ienginevgui.h" - -// memdbgon must be the last include file in a .cpp file!!! -#include "tier0/memdbgon.h" - -#define CHAT_WIDTH_PERCENTAGE 0.6f - -#ifndef _XBOX -ConVar hud_saytext_time( "hud_saytext_time", "12", 0 ); - -//----------------------------------------------------------------------------- -// Purpose: -// Input : *parent - -// *panelName - -//----------------------------------------------------------------------------- -CBaseHudChatLine::CBaseHudChatLine( vgui::Panel *parent, const char *panelName ) : - vgui::RichText( parent, panelName ) -{ - m_hFont = m_hFontMarlett = 0; - m_flExpireTime = 0.0f; - m_flStartTime = 0.0f; - m_iNameLength = 0; - - SetPaintBackgroundEnabled( true ); - - SetVerticalScrollbar( false ); -} - - -void CBaseHudChatLine::ApplySchemeSettings(vgui::IScheme *pScheme) -{ - BaseClass::ApplySchemeSettings(pScheme); - - m_hFont = pScheme->GetFont( "Default" ); - -#ifdef HL1_CLIENT_DLL - SetBgColor( Color( 0, 0, 0, 0 ) ); - SetFgColor( Color( 0, 0, 0, 0 ) ); - - SetBorder( NULL ); -#else - SetBgColor( Color( 0, 0, 0, 100 ) ); -#endif - - - m_hFontMarlett = pScheme->GetFont( "Marlett" ); - - m_clrText = pScheme->GetColor( "FgColor", GetFgColor() ); - SetFont( m_hFont ); -} - - -void CBaseHudChatLine::PerformFadeout( void ) -{ - // Flash + Extra bright when new - float curtime = gpGlobals->curtime; - - int lr = m_clrText[0]; - int lg = m_clrText[1]; - int lb = m_clrText[2]; - - if ( curtime >= m_flStartTime && curtime < m_flStartTime + CHATLINE_FLASH_TIME ) - { - float frac1 = ( curtime - m_flStartTime ) / CHATLINE_FLASH_TIME; - float frac = frac1; - - frac *= CHATLINE_NUM_FLASHES; - frac *= 2 * M_PI; - - frac = cos( frac ); - - frac = clamp( frac, 0.0f, 1.0f ); - - frac *= (1.0f-frac1); - - int r = lr, g = lg, b = lb; - - r = r + ( 255 - r ) * frac; - g = g + ( 255 - g ) * frac; - b = b + ( 255 - b ) * frac; - - // Draw a right facing triangle in red, faded out over time - int alpha = 63 + 192 * (1.0f - frac1 ); - alpha = clamp( alpha, 0, 255 ); - - wchar_t wbuf[4096]; - GetText(0, wbuf, sizeof(wbuf)); - - SetText( "" ); - - InsertColorChange( Color( r, g, b, 255 ) ); - InsertString( wbuf ); - } - else if ( curtime <= m_flExpireTime && curtime > m_flExpireTime - CHATLINE_FADE_TIME ) - { - float frac = ( m_flExpireTime - curtime ) / CHATLINE_FADE_TIME; - - int alpha = frac * 255; - alpha = clamp( alpha, 0, 255 ); - - wchar_t wbuf[4096]; - GetText(0, wbuf, sizeof(wbuf)); - - SetText( "" ); - - InsertColorChange( Color( lr * frac, lg * frac, lb * frac, alpha ) ); - InsertString( wbuf ); - } - else - { - wchar_t wbuf[4096]; - GetText(0, wbuf, sizeof(wbuf)); - - SetText( "" ); - - InsertColorChange( Color( lr, lg, lb, 255 ) ); - InsertString( wbuf ); - } - - OnThink(); -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : time - -//----------------------------------------------------------------------------- -void CBaseHudChatLine::SetExpireTime( void ) -{ - m_flStartTime = gpGlobals->curtime; - m_flExpireTime = m_flStartTime + hud_saytext_time.GetFloat(); - m_nCount = CBaseHudChat::m_nLineCounter++; -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -int CBaseHudChatLine::GetCount( void ) -{ - return m_nCount; -} - -//----------------------------------------------------------------------------- -// Purpose: -// Output : Returns true on success, false on failure. -//----------------------------------------------------------------------------- -bool CBaseHudChatLine::IsReadyToExpire( void ) -{ - // Engine disconnected, expire right away - if ( !engine->IsInGame() && !engine->IsConnected() ) - return true; - - if ( gpGlobals->curtime >= m_flExpireTime ) - return true; - return false; -} - -//----------------------------------------------------------------------------- -// Purpose: -// Output : float -//----------------------------------------------------------------------------- -float CBaseHudChatLine::GetStartTime( void ) -{ - return m_flStartTime; -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CBaseHudChatLine::Expire( void ) -{ - SetVisible( false ); - - // Spit out label text now -// char text[ 256 ]; -// GetText( text, 256 ); - -// Msg( "%s\n", text ); -} -#endif _XBOX - -//----------------------------------------------------------------------------- -// Purpose: The prompt and text entry area for chat messages -//----------------------------------------------------------------------------- -#ifndef _XBOX -CBaseHudChatInputLine::CBaseHudChatInputLine( CBaseHudChat *parent, char const *panelName ) : - vgui::Panel( parent, panelName ) -{ - SetMouseInputEnabled( false ); - - m_pPrompt = new vgui::Label( this, "ChatInputPrompt", L"Enter text:" ); - - m_pInput = new CBaseHudChatEntry( this, "ChatInput", parent ); - m_pInput->SetMaximumCharCount( 127 ); -} - -void CBaseHudChatInputLine::ApplySchemeSettings(vgui::IScheme *pScheme) -{ - BaseClass::ApplySchemeSettings(pScheme); - - // FIXME: Outline - vgui::HFont hFont = pScheme->GetFont( "Trebuchet18" ); - - m_pPrompt->SetFont( hFont ); - m_pInput->SetFont( hFont ); - - SetPaintBackgroundEnabled( false ); - m_pPrompt->SetPaintBackgroundEnabled( false ); - m_pPrompt->SetContentAlignment( vgui::Label::a_west ); - m_pPrompt->SetTextInset( 2, 0 ); - -#ifdef HL1_CLIENT_DLL - m_pInput->SetBgColor( Color( 255, 255, 255, 0 ) ); -#else - m_pInput->SetFgColor( GetFgColor() ); - m_pInput->SetBgColor( GetBgColor() ); -#endif - -} - -void CBaseHudChatInputLine::SetPrompt( const wchar_t *prompt ) -{ - Assert( m_pPrompt ); - m_pPrompt->SetText( prompt ); - InvalidateLayout(); -} - -void CBaseHudChatInputLine::ClearEntry( void ) -{ - Assert( m_pInput ); - SetEntry( L"" ); -} - -void CBaseHudChatInputLine::SetEntry( const wchar_t *entry ) -{ - Assert( m_pInput ); - Assert( entry ); - - m_pInput->SetText( entry ); -} - -void CBaseHudChatInputLine::GetMessageText( wchar_t *buffer, int buffersizebytes ) -{ - m_pInput->GetText( buffer, buffersizebytes); -} - -void CBaseHudChatInputLine::PerformLayout() -{ - BaseClass::PerformLayout(); - - int wide, tall; - GetSize( wide, tall ); - - int w,h; - m_pPrompt->GetContentSize( w, h); - m_pPrompt->SetBounds( 0, 0, w, tall ); - - m_pInput->SetBounds( w + 2, 0, wide - w - 2 , tall ); -} - -vgui::Panel *CBaseHudChatInputLine::GetInputPanel( void ) -{ - return m_pInput; -} -#endif //_XBOX - -int CBaseHudChat::m_nLineCounter = 1; -//----------------------------------------------------------------------------- -// Purpose: Text chat input/output hud element -//----------------------------------------------------------------------------- -CBaseHudChat::CBaseHudChat( const char *pElementName ) -: CHudElement( pElementName ), BaseClass( NULL, "HudChat" ) -{ - vgui::Panel *pParent = g_pClientMode->GetViewport(); - SetParent( pParent ); - - vgui::HScheme scheme = vgui::scheme()->LoadSchemeFromFileEx( enginevgui->GetPanel( PANEL_CLIENTDLL ), "resource/ClientScheme.res", "ClientScheme"); - SetScheme(scheme); - - m_nMessageMode = 0; - - CBaseHudChatLine *line = m_ChatLines[ 0 ]; - - if ( line ) - { - vgui::HFont font = line->GetFont(); - m_iFontHeight = vgui::surface()->GetFontTall( font ) + 2; - - // Put input area at bottom - int w, h; - GetSize( w, h ); - m_pChatInput->SetBounds( 1, h - m_iFontHeight - 1, w-2, m_iFontHeight ); - } - - if ( IsPC() ) - { - vgui::ivgui()->AddTickSignal( GetVPanel() ); - } - - // (We don't actually want input until they bring up the chat line). - MakePopup(); - SetZPos( -30 ); - - SetHiddenBits( HIDEHUD_CHAT ); -} - -CBaseHudChat::~CBaseHudChat() -{ - if ( IsXbox() ) - return; - - gameeventmanager->RemoveListener( this ); -} - -void CBaseHudChat::CreateChatInputLine( void ) -{ -#ifndef _XBOX - m_pChatInput = new CBaseHudChatInputLine( this, "ChatInputLine" ); - m_pChatInput->SetVisible( false ); -#endif -} - -void CBaseHudChat::CreateChatLines( void ) -{ -#ifndef _XBOX - for ( int i = 0; i < CHAT_INTERFACE_LINES; i++ ) - { - char sz[ 32 ]; - Q_snprintf( sz, sizeof( sz ), "ChatLine%02i", i ); - m_ChatLines[ i ] = new CBaseHudChatLine( this, sz ); - m_ChatLines[ i ]->SetVisible( false ); - } -#endif -} - -void CBaseHudChat::ApplySchemeSettings( vgui::IScheme *pScheme ) -{ - BaseClass::ApplySchemeSettings( pScheme ); - - SetPaintBackgroundEnabled( false ); - SetKeyBoardInputEnabled( false ); - SetMouseInputEnabled( false ); - m_nVisibleHeight = 0; - - // Put input area at bottom - if ( m_pChatInput ) - { - int w, h; - GetSize( w, h ); - m_pChatInput->SetBounds( 1, h - m_iFontHeight - 1, w-2, m_iFontHeight ); - } - -#ifdef HL1_CLIENT_DLL - SetBgColor( Color( 0, 0, 0, 0 ) ); - SetFgColor( Color( 0, 0, 0, 0 ) ); -#else - SetBgColor( Color( 0, 0, 0, 100 ) ); -#endif - -} - -void CBaseHudChat::Reset( void ) -{ -#ifndef HL1_CLIENT_DLL - m_nVisibleHeight = 0; - Clear(); -#endif -} - -#ifdef _XBOX -bool CBaseHudChat::ShouldDraw() -{ - // never think, never draw - return false; -} -#endif - -void CBaseHudChat::Paint( void ) -{ -#ifndef _XBOX - if ( m_nVisibleHeight == 0 ) - return; - - int w, h; - GetSize( w, h ); - - vgui::surface()->DrawSetColor( GetBgColor() ); - vgui::surface()->DrawFilledRect( 0, h - m_nVisibleHeight, w, h ); - - vgui::surface()->DrawSetColor( GetFgColor() ); - vgui::surface()->DrawOutlinedRect( 0, h - m_nVisibleHeight, w, h ); -#endif -} - -void CBaseHudChat::Init( void ) -{ - if ( IsXbox() ) - return; - - CreateChatInputLine(); - CreateChatLines(); - - gameeventmanager->AddListener( this, "hltv_chat", false ); -} - -#ifndef _XBOX -static int __cdecl SortLines( void const *line1, void const *line2 ) -{ - CBaseHudChatLine *l1 = *( CBaseHudChatLine ** )line1; - CBaseHudChatLine *l2 = *( CBaseHudChatLine ** )line2; - - // Invisible at bottom - if ( l1->IsVisible() && !l2->IsVisible() ) - return -1; - else if ( !l1->IsVisible() && l2->IsVisible() ) - return 1; - - // Oldest start time at top - if ( l1->GetStartTime() < l2->GetStartTime() ) - return -1; - else if ( l1->GetStartTime() > l2->GetStartTime() ) - return 1; - - // Otherwise, compare counter - if ( l1->GetCount() < l2->GetCount() ) - return -1; - else if ( l1->GetCount() > l2->GetCount() ) - return 1; - - return 0; -} -#endif - -//----------------------------------------------------------------------------- -// Purpose: Allow inheriting classes to change this spacing behavior -//----------------------------------------------------------------------------- -int CBaseHudChat::GetChatInputOffset( void ) -{ - return m_iFontHeight; -} - -//----------------------------------------------------------------------------- -// Purpose: Do respositioning here to avoid latency due to repositioning of vgui -// voice manager icon panel -//----------------------------------------------------------------------------- -void CBaseHudChat::OnTick( void ) -{ -#ifndef _XBOX - int i; - for ( i = 0; i < CHAT_INTERFACE_LINES; i++ ) - { - CBaseHudChatLine *line = m_ChatLines[ i ]; - if ( !line ) - continue; - - if ( !line->IsVisible() ) - continue; - - if ( !line->IsReadyToExpire() ) - continue; - - line->Expire(); - } - - int w, h; - - GetSize( w, h ); - - CBaseHudChatLine *line = m_ChatLines[ 0 ]; - - if ( line ) - { - vgui::HFont font = line->GetFont(); - - if ( font ) - { - m_iFontHeight = vgui::surface()->GetFontTall( font ) + 2; - - // Put input area at bottom - int w, h; - GetSize( w, h ); - m_pChatInput->SetBounds( 1, h - m_iFontHeight - 1, w-2, m_iFontHeight ); - } - } - - // Sort chat lines - qsort( m_ChatLines, CHAT_INTERFACE_LINES, sizeof( CBaseHudChatLine * ), SortLines ); - - // Step backward from bottom - int currentY = h - m_iFontHeight - 1; - int startY = currentY; - int ystep = m_iFontHeight; - - currentY -= GetChatInputOffset(); - - // Walk backward - for ( i = CHAT_INTERFACE_LINES - 1; i >= 0 ; i-- ) - { - CBaseHudChatLine *line = m_ChatLines[ i ]; - if ( !line ) - continue; - - if ( !line->IsVisible() ) - { - line->SetSize( w, m_iFontHeight ); - continue; - } - - line->PerformFadeout(); - line->SetSize( w, m_iFontHeight * line->GetNumLines() ); - line->SetPos( 0, ( currentY+m_iFontHeight) - m_iFontHeight * line->GetNumLines() ); - - currentY -= ystep * line->GetNumLines(); - } - - if ( currentY != startY ) - { - m_nVisibleHeight = startY - currentY + 2; - } - else - { - m_nVisibleHeight = 0; - } - - vgui::surface()->MovePopupToBack( GetVPanel() ); -#endif -} - -// Release build is crashing on long strings...sigh -#pragma optimize( "", off ) - -//----------------------------------------------------------------------------- -// Purpose: -// Input : width - -// *text - -// textlen - -// Output : int -//----------------------------------------------------------------------------- -int CBaseHudChat::ComputeBreakChar( int width, const char *text, int textlen ) -{ -#ifndef _XBOX - CBaseHudChatLine *line = m_ChatLines[ 0 ]; - vgui::HFont font = line->GetFont(); - - int currentlen = 0; - int lastbreak = textlen; - for (int i = 0; i < textlen ; i++) - { - char ch = text[i]; - - if ( ch <= 32 ) - { - lastbreak = i; - } - - wchar_t wch[2]; - - vgui::localize()->ConvertANSIToUnicode( &ch, wch, sizeof( wch ) ); - - int a,b,c; - - vgui::surface()->GetCharABCwide(font, wch[0], a, b, c); - currentlen += a + b + c; - - if ( currentlen >= width ) - { - // If we haven't found a whitespace char to break on before getting - // to the end, but it's still too long, break on the character just before - // this one - if ( lastbreak == textlen ) - { - lastbreak = max( 0, i - 1 ); - } - break; - } - } - - if ( currentlen >= width ) - { - return lastbreak; - } - return textlen; -#else - return 0; -#endif -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : *fmt - -// ... - -//----------------------------------------------------------------------------- -void CBaseHudChat::Printf( const char *fmt, ... ) -{ -#ifndef _XBOX - // No chat text in single player - if ( gpGlobals->maxClients == 1 ) - { - return; - } - - va_list marker; - char msg[4096]; - - const char *pTranslatedFmt = hudtextmessage->LookupString(fmt); - - va_start(marker, fmt); - Q_vsnprintf( msg, sizeof( msg ), pTranslatedFmt, marker ); - va_end(marker); - - // Strip any trailing '\n' - if ( strlen( msg ) > 0 && msg[ strlen( msg )-1 ] == '\n' ) - { - msg[ strlen( msg ) - 1 ] = 0; - } - - // Strip leading \n characters ( or notify/color signifiers ) - char *pmsg = msg; - while ( *pmsg && ( *pmsg == '\n' || *pmsg == 1 || *pmsg == 2 ) ) - { - pmsg++; - } - - if ( !*pmsg ) - return; - - // Search for return characters - char *pos = strstr( pmsg, "\n" ); - if ( pos ) - { - char msgcopy[ 8192 ]; - Q_strncpy( msgcopy, pmsg, sizeof( msgcopy ) ); - - int offset = pos - pmsg; - - // Terminate first part - msgcopy[ offset ] = 0; - - // Print first part -#if defined( CSTRIKE_DLL ) || defined( DOD_DLL ) // reltodo - Printf( "%s", msgcopy ); - - // Print remainder - Printf( "%s", &msgcopy[ offset ] + 1 ); -#else - Printf( msgcopy ); - - // Print remainder - Printf( &msgcopy[ offset ] + 1 ); -#endif - return; - } - - CBaseHudChatLine *firstline = m_ChatLines[ 0 ]; - - int len = strlen( pmsg ); - - // Check for string too long and split into multiple lines - // - int breakpos = ComputeBreakChar( firstline->GetWide() - 10, pmsg, len ); - if ( breakpos > 0 && breakpos < len ) - { - char msgcopy[ 8192 ]; - Q_strncpy( msgcopy, pmsg, sizeof( msgcopy ) ); - - int offset = breakpos; - - char savechar; - - savechar = msgcopy[ offset ]; - - // Terminate first part - msgcopy[ offset ] = 0; - - // Print first part -#if defined( CSTRIKE_DLL ) || defined( DOD_DLL ) // reltodo - Printf( "%s", msgcopy ); -#else - Printf( msgcopy ); -#endif - - // Was breakpos a printable char? - if ( savechar > 32 ) - { - msgcopy[ offset ] = savechar; - - // Print remainder -#if defined( CSTRIKE_DLL ) || defined( DOD_DLL ) // reltodo - Printf( "%s", &msgcopy[ offset ] ); -#else - Printf( &msgcopy[ offset ] ); -#endif - } - else - { -#if defined( CSTRIKE_DLL ) || defined( DOD_DLL ) // reltodo - Printf( "%s", &msgcopy[ offset ] + 1 ); -#else - Printf( &msgcopy[ offset ] + 1 ); -#endif - } - return; - } - - CBaseHudChatLine *line = FindUnusedChatLine(); - if ( !line ) - { - ExpireOldest(); - line = FindUnusedChatLine(); - } - - if ( !line ) - { - return; - } - - line->SetText( "" ); - line->InsertColorChange( line->GetTextColor() ); - line->SetExpireTime(); - line->InsertString( pmsg ); - line->SetVisible( true ); - line->SetNameLength( 0 ); - - CLocalPlayerFilter filter; - C_BaseEntity::EmitSound( filter, SOUND_FROM_LOCAL_PLAYER, "HudChat.Message" ); -#endif -} - -#pragma optimize( "", on ) - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CBaseHudChat::StartMessageMode( int iMessageModeType ) -{ -#ifndef _XBOX - m_nMessageMode = iMessageModeType; - - m_pChatInput->ClearEntry(); - - if ( m_nMessageMode == MM_SAY ) - { - m_pChatInput->SetPrompt( L"Say :" ); - } - else - { - m_pChatInput->SetPrompt( L"Say (TEAM) :" ); - } - - vgui::SETUP_PANEL( this ); - SetKeyBoardInputEnabled( true ); - m_pChatInput->SetVisible( true ); - vgui::surface()->CalculateMouseVisible(); - m_pChatInput->RequestFocus(); -#endif -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CBaseHudChat::StopMessageMode( void ) -{ -#ifndef _XBOX - SetKeyBoardInputEnabled( false ); - m_pChatInput->SetVisible( false ); -#endif -} - -//----------------------------------------------------------------------------- -// Purpose: -// Output : CBaseHudChatLine -//----------------------------------------------------------------------------- -CBaseHudChatLine *CBaseHudChat::FindUnusedChatLine( void ) -{ -#ifndef _XBOX - for ( int i = 0; i < CHAT_INTERFACE_LINES; i++ ) - { - CBaseHudChatLine *line = m_ChatLines[ i ]; - if ( !line ) - continue; - - if ( line->IsVisible() ) - continue; - - return line; - } - return NULL; -#else - return NULL; -#endif -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CBaseHudChat::ExpireOldest( void ) -{ -#ifndef _XBOX - float oldestTime = 100000000.0f; - CBaseHudChatLine *oldest = NULL; - - for ( int i = 0; i < CHAT_INTERFACE_LINES; i++ ) - { - CBaseHudChatLine *line = m_ChatLines[ i ]; - if ( !line ) - continue; - - if ( !line->IsVisible() ) - continue; - - if ( !oldest ) - { - oldest = line; - oldestTime = line->GetStartTime(); - continue; - } - - if ( line->GetStartTime() < oldestTime ) - { - oldest = line; - oldestTime = line->GetStartTime(); - } - } - - if ( !oldest ) - { - oldest = m_ChatLines[ 0 ]; - } - - oldest->Expire(); -#endif -} - -void CBaseHudChat::Send( void ) -{ -#ifndef _XBOX - wchar_t szTextbuf[128]; - - m_pChatInput->GetMessageText( szTextbuf, sizeof( szTextbuf ) ); - - char ansi[128]; - vgui::localize()->ConvertUnicodeToANSI( szTextbuf, ansi, sizeof( ansi ) ); - - int len = Q_strlen(ansi); - - /* -This is a very long string that I am going to attempt to paste into the cs hud chat entry and we will see if it gets cropped or not. - */ - - // remove the \n - if ( len > 0 && - ansi[ len - 1 ] == '\n' ) - { - ansi[ len - 1 ] = '\0'; - } - - if( len > 0 ) - { - char szbuf[144]; // more than 128 - Q_snprintf( szbuf, sizeof(szbuf), "%s \"%s\"", m_nMessageMode == MM_SAY ? "say" : "say_team", ansi ); - - engine->ClientCmd(szbuf); - } - - m_pChatInput->ClearEntry(); -#endif -} - -//----------------------------------------------------------------------------- -// Purpose: -// Output : vgui::Panel -//----------------------------------------------------------------------------- -vgui::Panel *CBaseHudChat::GetInputPanel( void ) -{ -#ifndef _XBOX - return m_pChatInput->GetInputPanel(); -#else - return NULL; -#endif -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CBaseHudChat::Clear( void ) -{ -#ifndef _XBOX - // Kill input prompt - StopMessageMode(); - - // Expire all messages - for ( int i = 0; i < CHAT_INTERFACE_LINES; i++ ) - { - CBaseHudChatLine *line = m_ChatLines[ i ]; - if ( !line ) - continue; - - if ( !line->IsVisible() ) - continue; - - line->Expire(); - } -#endif -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : *newmap - -//----------------------------------------------------------------------------- -void CBaseHudChat::LevelInit( const char *newmap ) -{ - Clear(); -} - -void CBaseHudChat::LevelShutdown( void ) -{ - Clear(); -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : *fmt - -// ... - -//----------------------------------------------------------------------------- -void CBaseHudChat::ChatPrintf( int iPlayerIndex, const char *fmt, ... ) -{ -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CBaseHudChat::FireGameEvent( IGameEvent *event ) -{ -#ifndef _XBOX - const char *eventname = event->GetName(); - - if ( Q_strcmp( "hltv_chat", eventname ) == 0 ) - { - C_BasePlayer *player = C_BasePlayer::GetLocalPlayer(); - - if ( !player ) - return; - - ChatPrintf( player->entindex(), "(SourceTV) %s", event->GetString( "text" ) ); - } -#endif -} \ No newline at end of file diff --git a/src/src/cl_dll/hud_hintdisplay.cpp b/src/src/cl_dll/hud_hintdisplay.cpp deleted file mode 100644 index 067e3e5..0000000 --- a/src/src/cl_dll/hud_hintdisplay.cpp +++ /dev/null @@ -1,384 +0,0 @@ -//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// -// -// Purpose: -// -//=============================================================================// - -#include "cbase.h" -#include "hud.h" -#include "hudelement.h" -#include "hud_macros.h" -#include "iclientmode.h" -#include "vgui_controls/AnimationController.h" -#include "vgui_controls/Label.h" -#include "vgui/ILocalize.h" -#include "vgui/ISurface.h" - -// memdbgon must be the last include file in a .cpp file!!! -#include "tier0/memdbgon.h" - -//----------------------------------------------------------------------------- -// Purpose: Displays current ammunition level -//----------------------------------------------------------------------------- -class CHudHintDisplay : public vgui::Panel, public CHudElement -{ - DECLARE_CLASS_SIMPLE( CHudHintDisplay, vgui::Panel ); - -public: - CHudHintDisplay( const char *pElementName ); - void Init(); - void Reset(); - void MsgFunc_HintText( bf_read &msg ); - bool ShouldDraw(); - - bool SetHintText( const char *text ); - -protected: - virtual void ApplySchemeSettings( vgui::IScheme *pScheme ); - virtual void OnThink(); - -private: - CUtlVector m_Labels; - vgui::HFont m_hSmallFont, m_hLargeFont; - char m_szHintText[128]; - int m_iBaseY; - - CPanelAnimationVarAliasType( float, m_iTextX, "text_xpos", "8", "proportional_float" ); - CPanelAnimationVarAliasType( float, m_iTextY, "text_ypos", "8", "proportional_float" ); - CPanelAnimationVarAliasType( float, m_iTextGapX, "text_xgap", "8", "proportional_float" ); - CPanelAnimationVarAliasType( float, m_iTextGapY, "text_ygap", "8", "proportional_float" ); - CPanelAnimationVarAliasType( float, m_iYOffset, "YOffset", "0", "proportional_float" ); -}; - -DECLARE_HUDELEMENT( CHudHintDisplay ); -DECLARE_HUD_MESSAGE( CHudHintDisplay, HintText ); - -//----------------------------------------------------------------------------- -// Purpose: Constructor -//----------------------------------------------------------------------------- -CHudHintDisplay::CHudHintDisplay( const char *pElementName ) : BaseClass(NULL, "HudHintDisplay"), CHudElement( pElementName ) -{ - vgui::Panel *pParent = g_pClientMode->GetViewport(); - SetParent( pParent ); - SetVisible( false ); - m_szHintText[0] = 0; - SetAlpha( 0 ); -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CHudHintDisplay::Init() -{ - HOOK_HUD_MESSAGE( CHudHintDisplay, HintText ); -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CHudHintDisplay::Reset() -{ - SetHintText( NULL ); - SetAlpha( 0 ); -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CHudHintDisplay::ApplySchemeSettings( vgui::IScheme *pScheme ) -{ - m_hSmallFont = pScheme->GetFont( "HudHintTextSmall", true ); - m_hLargeFont = pScheme->GetFont( "HudHintTextLarge", true ); - - BaseClass::ApplySchemeSettings( pScheme ); -} - -//----------------------------------------------------------------------------- -// 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 CHudHintDisplay::ShouldDraw( void ) -{ - return ( ( GetAlpha() > 0 ) && CHudElement::ShouldDraw() ); -} - -//----------------------------------------------------------------------------- -// Purpose: Updates the label color each frame -//----------------------------------------------------------------------------- -void CHudHintDisplay::OnThink() -{ - for (int i = 0; i < m_Labels.Count(); i++) - { - if ( IsXbox() && 0 != ( i & 1 ) ) - { - // Don't change the fg color for buttons (even numbered labels) - m_Labels[i]->SetAlpha( GetFgColor().a() ); - } - else - { - m_Labels[i]->SetFgColor(GetFgColor()); - } - } - - int ox, oy; - GetPos(ox, oy); - SetPos( ox, m_iBaseY + m_iYOffset ); -} - -//----------------------------------------------------------------------------- -// Purpose: Sets the hint text, replacing variables as necessary -//----------------------------------------------------------------------------- -bool CHudHintDisplay::SetHintText( const char *text ) -{ - // clear the existing text - for (int i = 0; i < m_Labels.Count(); i++) - { - m_Labels[i]->MarkForDeletion(); - } - m_Labels.RemoveAll(); - - if ( !text ) - { - m_szHintText[0] = 0; - return false; - } - - strcpy( m_szHintText, text ); - - // look up the text string - wchar_t *ws = vgui::localize()->Find( text ); - if ( !ws || wcslen(ws) <= 0) - return false; - - // parse out the text into a label set - while ( *ws ) - { - wchar_t token[64]; - bool isVar = false; - - // check for variables - if ( *ws == '%' ) - { - isVar = true; - ++ws; - } - - // parse out the string - wchar_t *end = wcschr( ws, '%' ); - if ( end ) - { - wcsncpy( token, ws, end - ws ); - token[end - ws] = 0; - } - else - { - wcscpy( token, ws ); - } - ws += wcslen( token ); - if ( isVar ) - { - // move over the end of the variable - ++ws; - } - - // put it in a label - vgui::Label *label = vgui::SETUP_PANEL(new vgui::Label(this, NULL, token)); - - bool bIsBitmap = false; - - // modify the label if necessary - if ( isVar ) - { - label->SetFont( m_hLargeFont ); - - // lookup key names - char binding[64]; - vgui::localize()->ConvertUnicodeToANSI( token, binding, sizeof(binding) ); - - const char *key = engine->Key_LookupBinding( *binding == '+' ? binding + 1 : binding ); - if ( !key ) - { - key = "< not bound >"; - } - - //!! change some key names into better names - char friendlyName[64]; - Q_snprintf( friendlyName, sizeof(friendlyName), "#%s", key ); - Q_strupr( friendlyName ); - - // set the variable text - key may need to be localized (button images for example) - wchar_t *locName = vgui::localize()->Find( friendlyName ); - if ( !locName || wcslen(locName) <= 0) - { - label->SetText( friendlyName + 1 ); - } - else - { - // Assuming localized vars must be using a bitmap image. *May* not be the case, but since - // keyboard bindings have never been locaized in the past, they probably won't in the future either. - bIsBitmap = true; - label->SetText( locName ); - } - } - else - { - label->SetFont( m_hSmallFont ); - } - - label->SetPaintBackgroundEnabled( false ); - label->SetPaintBorderEnabled( false ); - label->SizeToContents(); - label->SetContentAlignment( vgui::Label::a_west ); - if ( bIsBitmap && isVar ) - { - // Don't change the color of the button art - label->SetFgColor( Color(255,255,255,255) ); - } - else - { - label->SetFgColor( GetFgColor() ); - } - m_Labels.AddToTail( vgui::SETUP_PANEL(label) ); - } - - // find the bounds we need to show - int widest1 = 0, widest2 = 0; - for (int i = 0; i < m_Labels.Count(); i++) - { - vgui::Label *label = m_Labels[i]; - - if (i & 1) - { - // help text - if (label->GetWide() > widest2) - { - widest2 = label->GetWide(); - } - } - else - { - // variable - if (label->GetWide() > widest1) - { - widest1 = label->GetWide(); - } - } - } - - int tallest1 = 0, tallest2 = 0; - for (int i = 0; i < m_Labels.Count(); i++) - { - vgui::Label *label = m_Labels[i]; - - if (i & 1) - { - // help text - if (label->GetTall() > tallest2) - { - tallest2 = label->GetTall(); - } - } - else - { - // variable - if (label->GetTall() > tallest1) - { - tallest1 = label->GetTall(); - } - } - } - int tallest = max( tallest1, tallest2 ); - - // position the labels - int col1_x = m_iTextX; - int col2_x = m_iTextX + widest1 + m_iTextGapX; - int col_y = m_iTextY; - - // Difference between the variable and the help text - int col_y_extra = ( (tallest1 - tallest2) / 2 ); - if ( col_y_extra < 0 ) - { - // text is taller than the variable (multi-line text). - // Push the variable's y down by subtracting the negative value. - col_y -= col_y_extra; - } - - for (int i = 0; i < m_Labels.Count(); i++) - { - vgui::Label *label = m_Labels[i]; - - if (i & 1) - { - label->SetPos( col2_x, col_y + col_y_extra ); - - col_y += tallest; - col_y += m_iTextGapY; - } - else - { - // variable - label->SetPos( col1_x, col_y ); - } - } - - // move ourselves relative to our start position - int newWide = col2_x + widest2 + m_iTextX; - int newTall = col_y; - int ox, oy; - GetPos(ox, oy); - - if (IsRightAligned()) - { - int oldWide = GetWide(); - int diff = newWide - oldWide; - ox -= diff; - } - - if (IsBottomAligned()) - { - int oldTall = GetTall(); - int diff = newTall - oldTall; - oy -= diff; - } - - // set the size of the hint panel to fit - SetPos( ox, oy ); - SetSize( newWide, newTall ); - - m_iBaseY = oy; - - return true; -} - -//----------------------------------------------------------------------------- -// Purpose: Activates the hint display -//----------------------------------------------------------------------------- -void CHudHintDisplay::MsgFunc_HintText( bf_read &msg ) -{ - // how many strings do we receive ? - int count = msg.ReadByte(); - - // here we expect only one string - if ( count != 1 ) - { - DevMsg("CHudHintDisplay::MsgFunc_HintText: string count != 1.\n"); - return; - } - - // read the string - char szString[2048]; - msg.ReadString( szString, sizeof(szString) ); - - // make it visible - if ( SetHintText( szString ) ) - { - SetVisible( true ); - g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "HintMessageShow" ); - } - else - { - // it's being cleared, hide the panel - g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "HintMessageHide" ); - } -} diff --git a/src/src/cl_dll/in_camera.cpp b/src/src/cl_dll/in_camera.cpp deleted file mode 100644 index 0f43cc3..0000000 --- a/src/src/cl_dll/in_camera.cpp +++ /dev/null @@ -1,720 +0,0 @@ -//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// -// -// Purpose: -// -// $NoKeywords: $ -//=============================================================================// - - -#include "cbase.h" -#include "hud.h" -#include "kbutton.h" -#include "input.h" - -// memdbgon must be the last include file in a .cpp file!!! -#include "tier0/memdbgon.h" - -//-------------------------------------------------- Constants - -#define CAM_DIST_DELTA 1.0 -#define CAM_ANGLE_DELTA 2.5 -#define CAM_ANGLE_SPEED 2.5 -#define CAM_MIN_DIST 30.0 -#define CAM_ANGLE_MOVE .5 -#define MAX_ANGLE_DIFF 10.0 -#define PITCH_MAX 90.0 -#define PITCH_MIN 0 -#define YAW_MAX 135.0 -#define YAW_MIN -135.0 - -//-------------------------------------------------- Global Variables - -static ConVar cam_command( "cam_command", "0", FCVAR_CHEAT ); // tells camera to go to thirdperson -static ConVar cam_snapto( "cam_snapto", "0", FCVAR_ARCHIVE ); // snap to thirdperson view -static ConVar cam_idealyaw( "cam_idealyaw", "90", FCVAR_ARCHIVE ); // thirdperson yaw -static ConVar cam_idealpitch( "cam_idealpitch", "0", FCVAR_ARCHIVE ); // thirperson pitch -static ConVar cam_idealdist( "cam_idealdist", "64", FCVAR_ARCHIVE ); // thirdperson distance - -static ConVar c_maxpitch( "c_maxpitch", "90", FCVAR_ARCHIVE ); -static ConVar c_minpitch( "c_minpitch", "0", FCVAR_ARCHIVE ); -static ConVar c_maxyaw( "c_maxyaw", "135", FCVAR_ARCHIVE ); -static ConVar c_minyaw( "c_minyaw", "-135", FCVAR_ARCHIVE ); -static ConVar c_maxdistance( "c_maxdistance", "200", FCVAR_ARCHIVE ); -static ConVar c_mindistance( "c_mindistance", "30", FCVAR_ARCHIVE ); -static ConVar c_orthowidth( "c_orthowidth", "100", FCVAR_ARCHIVE ); -static ConVar c_orthoheight( "c_orthoheight", "100", FCVAR_ARCHIVE ); - -static kbutton_t cam_pitchup, cam_pitchdown, cam_yawleft, cam_yawright; -static kbutton_t cam_in, cam_out, cam_move; - -extern const ConVar *sv_cheats; - -// API Wrappers - -/* -============================== -CAM_ToThirdPerson - -============================== -*/ -void CAM_ToThirdPerson(void) -{ - input->CAM_ToThirdPerson(); -} - -/* -============================== -CAM_ToFirstPerson - -============================== -*/ -void CAM_ToFirstPerson(void) -{ - input->CAM_ToFirstPerson(); -} - -/* -============================== -CAM_ToOrthographic - -============================== -*/ -void CAM_ToOrthographic(void) -{ - input->CAM_ToOrthographic(); -} - -/* -============================== -CAM_StartMouseMove - -============================== -*/ -void CAM_StartMouseMove( void ) -{ - input->CAM_StartMouseMove(); -} - -/* -============================== -CAM_EndMouseMove - -============================== -*/ -void CAM_EndMouseMove( void ) -{ - input->CAM_EndMouseMove(); -} - -/* -============================== -CAM_StartDistance - -============================== -*/ -void CAM_StartDistance( void ) -{ - input->CAM_StartDistance(); -} - -/* -============================== -CAM_EndDistance - -============================== -*/ -void CAM_EndDistance( void ) -{ - input->CAM_EndDistance(); -} - -/* -============================== -CAM_ToggleSnapto - -============================== -*/ -void CAM_ToggleSnapto( void ) -{ - cam_snapto.SetValue( !cam_snapto.GetInt() ); -} - - -/* -============================== -MoveToward - -============================== -*/ -float MoveToward( float cur, float goal, float maxspeed ) -{ - if( cur != goal ) - { - if( abs( cur - goal ) > 180.0 ) - { - if( cur < goal ) - cur += 360.0; - else - cur -= 360.0; - } - - if( cur < goal ) - { - if( cur < goal - 1.0 ) - cur += ( goal - cur ) / 4.0; - else - cur = goal; - } - else - { - if( cur > goal + 1.0 ) - cur -= ( cur - goal ) / 4.0; - else - cur = goal; - } - } - - - // bring cur back into range - if( cur < 0 ) - cur += 360.0; - else if( cur >= 360 ) - cur -= 360; - - return cur; -} - -/* -============================== -CAM_Think - -============================== -*/ -void CInput::CAM_Think( void ) -{ - Vector origin; - Vector ext, pnt, camForward, camRight, camUp; - float dist; - Vector camAngles; - float flSensitivity; - QAngle viewangles; - - switch( cam_command.GetInt() ) - { - case CAM_COMMAND_TOTHIRDPERSON: - CAM_ToThirdPerson(); - break; - - case CAM_COMMAND_TOFIRSTPERSON: - CAM_ToFirstPerson(); - break; - - case CAM_COMMAND_NONE: - default: - break; - } - - if( !m_fCameraInThirdPerson ) - return; - - if ( !sv_cheats ) - { - sv_cheats = cvar->FindVar( "sv_cheats" ); - } - - // If cheats have been disabled, pull us back out of third-person view. - if ( sv_cheats && !sv_cheats->GetBool() ) - { - CAM_ToFirstPerson(); - return; - } - - camAngles[ PITCH ] = cam_idealpitch.GetFloat(); - camAngles[ YAW ] = cam_idealyaw.GetFloat(); - dist = cam_idealdist.GetFloat(); - // - //movement of the camera with the mouse - // - if (m_fCameraMovingWithMouse) - { - int cpx, cpy; -#ifndef _XBOX - //get windows cursor position - GetMousePos (cpx, cpy); -#else - //xboxfixme - cpx = cpy = 0; -#endif - - m_nCameraX = cpx; - m_nCameraY = cpy; - - //check for X delta values and adjust accordingly - //eventually adjust YAW based on amount of movement - //don't do any movement of the cam using YAW/PITCH if we are zooming in/out the camera - if (!m_fCameraDistanceMove) - { - int x, y; - GetWindowCenter( x, y ); - - //keep the camera within certain limits around the player (ie avoid certain bad viewing angles) - if (m_nCameraX>x) - { - //if ((camAngles[YAW]>=225.0)||(camAngles[YAW]<135.0)) - if (camAngles[YAW]c_maxyaw.GetFloat()) - { - - camAngles[YAW]=c_maxyaw.GetFloat(); - } - } - else if (m_nCameraX225.0)) - if (camAngles[YAW]>c_minyaw.GetFloat()) - { - camAngles[ YAW ] -= (CAM_ANGLE_MOVE)* ((x-m_nCameraX)/2); - - } - if (camAngles[YAW] y) - { - if(camAngles[PITCH]c_maxpitch.GetFloat()) - { - camAngles[PITCH]=c_maxpitch.GetFloat(); - } - } - else if (m_nCameraYc_minpitch.GetFloat()) - { - camAngles[PITCH] -= (CAM_ANGLE_MOVE)*((y-m_nCameraY)/2); - } - if (camAngles[PITCH]KeyState( &cam_pitchup ) ) - camAngles[ PITCH ] += CAM_ANGLE_DELTA; - else if( input->KeyState( &cam_pitchdown ) ) - camAngles[ PITCH ] -= CAM_ANGLE_DELTA; - - if( input->KeyState( &cam_yawleft ) ) - camAngles[ YAW ] -= CAM_ANGLE_DELTA; - else if( input->KeyState( &cam_yawright ) ) - camAngles[ YAW ] += CAM_ANGLE_DELTA; - - if( input->KeyState( &cam_in ) ) - { - dist -= CAM_DIST_DELTA; - if( dist < CAM_MIN_DIST ) - { - // If we go back into first person, reset the angle - camAngles[ PITCH ] = 0; - camAngles[ YAW ] = 0; - dist = CAM_MIN_DIST; - } - - } - else if( input->KeyState( &cam_out ) ) - dist += CAM_DIST_DELTA; - - if (m_fCameraDistanceMove) - { - int x, y; - GetWindowCenter( x, y ); - - if (m_nCameraY>y) - { - if(distc_maxdistance.GetFloat()) - { - dist=c_maxdistance.GetFloat(); - } - } - else if (m_nCameraYc_mindistance.GetFloat()) - { - dist -= (CAM_DIST_DELTA)*((y-m_nCameraY)/2); - } - if (distGetViewAngles( viewangles ); - - if( cam_snapto.GetInt() ) - { - camAngles[ YAW ] = cam_idealyaw.GetFloat() + viewangles[ YAW ]; - camAngles[ PITCH ] = cam_idealpitch.GetFloat() + viewangles[ PITCH ]; - camAngles[ 2 ] = cam_idealdist.GetFloat(); - } - else - { - if( camAngles[ YAW ] - viewangles[ YAW ] != cam_idealyaw.GetFloat() ) - camAngles[ YAW ] = MoveToward( camAngles[ YAW ], cam_idealyaw.GetFloat() + viewangles[ YAW ], CAM_ANGLE_SPEED ); - - if( camAngles[ PITCH ] - viewangles[ PITCH ] != cam_idealpitch.GetFloat() ) - camAngles[ PITCH ] = MoveToward( camAngles[ PITCH ], cam_idealpitch.GetFloat() + viewangles[ PITCH ], CAM_ANGLE_SPEED ); - - if( abs( camAngles[ 2 ] - cam_idealdist.GetFloat() ) < 2.0 ) - camAngles[ 2 ] = cam_idealdist.GetFloat(); - else - camAngles[ 2 ] += ( cam_idealdist.GetFloat() - camAngles[ 2 ] ) / 4.0; - } - - m_vecCameraOffset[ 0 ] = camAngles[ 0 ]; - m_vecCameraOffset[ 1 ] = camAngles[ 1 ]; - m_vecCameraOffset[ 2 ] = dist; -} - -void CAM_PitchUpDown(void) { KeyDown( &cam_pitchup ); } -void CAM_PitchUpUp(void) { KeyUp( &cam_pitchup ); } -void CAM_PitchDownDown(void) { KeyDown( &cam_pitchdown ); } -void CAM_PitchDownUp(void) { KeyUp( &cam_pitchdown ); } -void CAM_YawLeftDown(void) { KeyDown( &cam_yawleft ); } -void CAM_YawLeftUp(void) { KeyUp( &cam_yawleft ); } -void CAM_YawRightDown(void) { KeyDown( &cam_yawright ); } -void CAM_YawRightUp(void) { KeyUp( &cam_yawright ); } -void CAM_InDown(void) { KeyDown( &cam_in ); } -void CAM_InUp(void) { KeyUp( &cam_in ); } -void CAM_OutDown(void) { KeyDown( &cam_out ); } -void CAM_OutUp(void) { KeyUp( &cam_out ); } - -/* -============================== -CAM_ToThirdPerson - -============================== -*/ -void CInput::CAM_ToThirdPerson(void) -{ - QAngle viewangles; - -#if !defined( CSTRIKE_DLL ) -#if !defined( _DEBUG ) - -// Do allow third person in TF for now -#if defined ( TF_CLIENT_DLL ) - // This is empty intentionally! -#else - if ( gpGlobals->maxClients > 1 ) - { - // no thirdperson in multiplayer. - return; - } -#endif - -#endif -#endif - - engine->GetViewAngles( viewangles ); - - if( !m_fCameraInThirdPerson ) - { - m_fCameraInThirdPerson = true; - - m_vecCameraOffset[ YAW ] = viewangles[ YAW ]; - m_vecCameraOffset[ PITCH ] = viewangles[ PITCH ]; - m_vecCameraOffset[ 2 ] = CAM_MIN_DIST; - } - - cam_command.SetValue( 0 ); -} - -/* -============================== -CAM_ToFirstPerson - -============================== -*/ -void CInput::CAM_ToFirstPerson(void) -{ - m_fCameraInThirdPerson = false; - cam_command.SetValue( 0 ); -} - -/* -============================== -CAM_ToFirstPerson - -============================== -*/ -bool CInput::CAM_IsOrthographic(void) const -{ - return m_CameraIsOrthographic; -} - - -/* -============================== -CAM_ToFirstPerson - -============================== -*/ -void CInput::CAM_OrthographicSize(float& w, float& h) const -{ - w = c_orthowidth.GetFloat(); h = c_orthoheight.GetFloat(); -} - - -/* -============================== -CAM_ToFirstPerson - -============================== -*/ -void CInput::CAM_ToOrthographic(void) -{ - m_fCameraInThirdPerson = false; - m_CameraIsOrthographic = true; - cam_command.SetValue( 0 ); -} - -/* -============================== -CAM_StartMouseMove - -============================== -*/ -void CInput::CAM_StartMouseMove(void) -{ - float flSensitivity; - - //only move the cam with mouse if we are in third person. - if ( m_fCameraInThirdPerson ) - { - //set appropriate flags and initialize the old mouse position - //variables for mouse camera movement - if (!m_fCameraMovingWithMouse) - { - int cpx, cpy; - - m_fCameraMovingWithMouse=true; - m_fCameraInterceptingMouse=true; -#ifndef _XBOX - GetMousePos(cpx, cpy); -#else - // xboxfixme - cpx = cpy = 0; -#endif - m_nCameraX = cpx; - m_nCameraY = cpy; - - if ( ( flSensitivity = gHUD.GetSensitivity() ) != 0 ) - { - m_nCameraOldX=m_nCameraX*flSensitivity; - m_nCameraOldY=m_nCameraY*flSensitivity; - } - else - { - m_nCameraOldX=m_nCameraX; - m_nCameraOldY=m_nCameraY; - } - } - } - //we are not in 3rd person view..therefore do not allow camera movement - else - { - m_fCameraMovingWithMouse=false; - m_fCameraInterceptingMouse=false; - } -} - -/* -============================== -CAM_EndMouseMove - -the key has been released for camera movement -tell the engine that mouse camera movement is off -============================== -*/ -void CInput::CAM_EndMouseMove(void) -{ - m_fCameraMovingWithMouse=false; - m_fCameraInterceptingMouse=false; -} - -/* -============================== -CAM_StartDistance - -routines to start the process of moving the cam in or out -using the mouse -============================== -*/ -void CInput::CAM_StartDistance(void) -{ - //only move the cam with mouse if we are in third person. - if ( m_fCameraInThirdPerson ) - { - //set appropriate flags and initialize the old mouse position - //variables for mouse camera movement - if (!m_fCameraDistanceMove) - { - int cpx, cpy; - - m_fCameraDistanceMove=true; - m_fCameraMovingWithMouse=true; - m_fCameraInterceptingMouse=true; -#ifndef _XBOX - GetMousePos(cpx, cpy); -#else - // xboxfixme - cpx = cpy = 0; -#endif - - m_nCameraX = cpx; - m_nCameraY = cpy; - - m_nCameraOldX=m_nCameraX*gHUD.GetSensitivity(); - m_nCameraOldY=m_nCameraY*gHUD.GetSensitivity(); - } - } - //we are not in 3rd person view..therefore do not allow camera movement - else - { - m_fCameraDistanceMove=false; - m_fCameraMovingWithMouse=false; - m_fCameraInterceptingMouse=false; - } -} - -/* -============================== -CAM_EndDistance - -the key has been released for camera movement -tell the engine that mouse camera movement is off -============================== -*/ -void CInput::CAM_EndDistance(void) -{ - m_fCameraDistanceMove=false; - m_fCameraMovingWithMouse=false; - m_fCameraInterceptingMouse=false; -} - -/* -============================== -CAM_IsThirdPerson - -============================== -*/ -int CInput::CAM_IsThirdPerson( void ) -{ - return m_fCameraInThirdPerson; -} - -/* -============================== -CAM_GetCameraOffset - -============================== -*/ -void CInput::CAM_GetCameraOffset( Vector& ofs ) -{ - VectorCopy( m_vecCameraOffset, ofs ); -} - -/* -============================== -CAM_InterceptingMouse - -============================== -*/ -int CInput::CAM_InterceptingMouse( void ) -{ - return m_fCameraInterceptingMouse; -} - -static ConCommand startpitchup( "+campitchup", CAM_PitchUpDown ); -static ConCommand endpitcup( "-campitchup", CAM_PitchUpUp ); -static ConCommand startpitchdown( "+campitchdown", CAM_PitchDownDown ); -static ConCommand endpitchdown( "-campitchdown", CAM_PitchDownUp ); -static ConCommand startcamyawleft( "+camyawleft", CAM_YawLeftDown ); -static ConCommand endcamyawleft( "-camyawleft", CAM_YawLeftUp ); -static ConCommand startcamyawright( "+camyawright", CAM_YawRightDown ); -static ConCommand endcamyawright( "-camyawright", CAM_YawRightUp ); -static ConCommand startcamin( "+camin", CAM_InDown ); -static ConCommand endcamin( "-camin", CAM_InUp ); -static ConCommand startcamout( "+camout", CAM_OutDown ); -static ConCommand camout( "-camout", CAM_OutUp ); -static ConCommand thirdperson( "thirdperson", ::CAM_ToThirdPerson, "Switch to thirdperson camera.", FCVAR_CHEAT ); -static ConCommand firstperson( "firstperson", ::CAM_ToFirstPerson, "Switch to firstperson camera." ); -static ConCommand camortho( "camortho", ::CAM_ToOrthographic, "Switch to orthographic camera.", FCVAR_CHEAT ); -static ConCommand startcammousemove( "+cammousemove",::CAM_StartMouseMove); -static ConCommand endcammousemove( "-cammousemove",::CAM_EndMouseMove); -static ConCommand startcamdistance( "+camdistance", ::CAM_StartDistance ); -static ConCommand endcamdistance( "-camdistance", ::CAM_EndDistance ); -static ConCommand snapto( "snapto", CAM_ToggleSnapto ); -/* -============================== -Init_Camera - -============================== -*/ -void CInput::Init_Camera( void ) -{ - m_CameraIsOrthographic = false; -} \ No newline at end of file diff --git a/src/src/cl_dll/sdk/c_sdk_player.cpp b/src/src/cl_dll/sdk/c_sdk_player.cpp deleted file mode 100644 index 2af4a90..0000000 --- a/src/src/cl_dll/sdk/c_sdk_player.cpp +++ /dev/null @@ -1,404 +0,0 @@ -//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// -// -// Purpose: -// -//=============================================================================// - -#include "cbase.h" -#include "c_sdk_player.h" -#include "weapon_sdkbase.h" -#include "c_basetempentity.h" - -#if defined( CSDKPlayer ) - #undef CSDKPlayer -#endif - - - - -// -------------------------------------------------------------------------------- // -// Player animation event. Sent to the client when a player fires, jumps, reloads, etc.. -// -------------------------------------------------------------------------------- // - -class C_TEPlayerAnimEvent : public C_BaseTempEntity -{ -public: - DECLARE_CLASS( C_TEPlayerAnimEvent, C_BaseTempEntity ); - DECLARE_CLIENTCLASS(); - - virtual void PostDataUpdate( DataUpdateType_t updateType ) - { - // Create the effect. - C_SDKPlayer *pPlayer = dynamic_cast< C_SDKPlayer* >( m_hPlayer.Get() ); - if ( pPlayer && !pPlayer->IsDormant() ) - { - pPlayer->DoAnimationEvent( (PlayerAnimEvent_t)m_iEvent.Get() ); - } - } - -public: - CNetworkHandle( CBasePlayer, m_hPlayer ); - CNetworkVar( int, m_iEvent ); -}; - -IMPLEMENT_CLIENTCLASS_EVENT( C_TEPlayerAnimEvent, DT_TEPlayerAnimEvent, CTEPlayerAnimEvent ); - -BEGIN_RECV_TABLE_NOBASE( C_TEPlayerAnimEvent, DT_TEPlayerAnimEvent ) - RecvPropEHandle( RECVINFO( m_hPlayer ) ), - RecvPropInt( RECVINFO( m_iEvent ) ) -END_RECV_TABLE() - -BEGIN_RECV_TABLE_NOBASE( C_SDKPlayer, DT_SDKLocalPlayerExclusive ) - RecvPropInt( RECVINFO( m_iShotsFired ) ), -END_RECV_TABLE() - - -IMPLEMENT_CLIENTCLASS_DT( C_SDKPlayer, DT_SDKPlayer, CSDKPlayer ) - RecvPropDataTable( "sdklocaldata", 0, 0, &REFERENCE_RECV_TABLE(DT_SDKLocalPlayerExclusive) ), - RecvPropFloat( RECVINFO( m_angEyeAngles[0] ) ), - RecvPropFloat( RECVINFO( m_angEyeAngles[1] ) ), - RecvPropInt( RECVINFO( m_iThrowGrenadeCounter ) ), - RecvPropEHandle( RECVINFO( m_hRagdoll ) ), -END_RECV_TABLE() - -BEGIN_PREDICTION_DATA( C_SDKPlayer ) - DEFINE_PRED_FIELD( m_flCycle, FIELD_FLOAT, FTYPEDESC_OVERRIDE | FTYPEDESC_PRIVATE | FTYPEDESC_NOERRORCHECK ), - DEFINE_PRED_FIELD( m_iShotsFired, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ), -END_PREDICTION_DATA() - -class C_SDKRagdoll : public C_BaseAnimatingOverlay -{ -public: - DECLARE_CLASS( C_SDKRagdoll, C_BaseAnimatingOverlay ); - DECLARE_CLIENTCLASS(); - - C_SDKRagdoll(); - ~C_SDKRagdoll(); - - virtual void OnDataChanged( DataUpdateType_t type ); - - int GetPlayerEntIndex() const; - IRagdoll* GetIRagdoll() const; - - void ImpactTrace( trace_t *pTrace, int iDamageType, char *pCustomImpactName ); - -private: - - C_SDKRagdoll( const C_SDKRagdoll & ) {} - - void Interp_Copy( C_BaseAnimatingOverlay *pSourceEntity ); - - void CreateRagdoll(); - - -private: - - EHANDLE m_hPlayer; - CNetworkVector( m_vecRagdollVelocity ); - CNetworkVector( m_vecRagdollOrigin ); -}; - - -IMPLEMENT_CLIENTCLASS_DT_NOBASE( C_SDKRagdoll, DT_SDKRagdoll, CSDKRagdoll ) - RecvPropVector( RECVINFO(m_vecRagdollOrigin) ), - RecvPropEHandle( RECVINFO( m_hPlayer ) ), - RecvPropInt( RECVINFO( m_nModelIndex ) ), - RecvPropInt( RECVINFO(m_nForceBone) ), - RecvPropVector( RECVINFO(m_vecForce) ), - RecvPropVector( RECVINFO( m_vecRagdollVelocity ) ) -END_RECV_TABLE() - - -C_SDKRagdoll::C_SDKRagdoll() -{ -} - -C_SDKRagdoll::~C_SDKRagdoll() -{ - PhysCleanupFrictionSounds( this ); -} - -void C_SDKRagdoll::Interp_Copy( C_BaseAnimatingOverlay *pSourceEntity ) -{ - if ( !pSourceEntity ) - return; - - VarMapping_t *pSrc = pSourceEntity->GetVarMapping(); - VarMapping_t *pDest = GetVarMapping(); - - // Find all the VarMapEntry_t's that represent the same variable. - for ( int i = 0; i < pDest->m_Entries.Count(); i++ ) - { - VarMapEntry_t *pDestEntry = &pDest->m_Entries[i]; - for ( int j=0; j < pSrc->m_Entries.Count(); j++ ) - { - VarMapEntry_t *pSrcEntry = &pSrc->m_Entries[j]; - if ( !Q_strcmp( pSrcEntry->watcher->GetDebugName(), - pDestEntry->watcher->GetDebugName() ) ) - { - pDestEntry->watcher->Copy( pSrcEntry->watcher ); - break; - } - } - } -} - -void C_SDKRagdoll::ImpactTrace( trace_t *pTrace, int iDamageType, char *pCustomImpactName ) -{ - IPhysicsObject *pPhysicsObject = VPhysicsGetObject(); - - if( !pPhysicsObject ) - return; - - Vector dir = pTrace->endpos - pTrace->startpos; - - if ( iDamageType == DMG_BLAST ) - { - dir *= 4000; // adjust impact strenght - - // apply force at object mass center - pPhysicsObject->ApplyForceCenter( dir ); - } - else - { - Vector hitpos; - - VectorMA( pTrace->startpos, pTrace->fraction, dir, hitpos ); - VectorNormalize( dir ); - - dir *= 4000; // adjust impact strenght - - // apply force where we hit it - pPhysicsObject->ApplyForceOffset( dir, hitpos ); - } - - m_pRagdoll->ResetRagdollSleepAfterTime(); -} - - -void C_SDKRagdoll::CreateRagdoll() -{ - // First, initialize all our data. If we have the player's entity on our client, - // then we can make ourselves start out exactly where the player is. - C_SDKPlayer *pPlayer = dynamic_cast< C_SDKPlayer* >( m_hPlayer.Get() ); - - if ( pPlayer && !pPlayer->IsDormant() ) - { - // move my current model instance to the ragdoll's so decals are preserved. - pPlayer->SnatchModelInstance( this ); - - VarMapping_t *varMap = GetVarMapping(); - - // Copy all the interpolated vars from the player entity. - // The entity uses the interpolated history to get bone velocity. - bool bRemotePlayer = (pPlayer != C_BasePlayer::GetLocalPlayer()); - if ( bRemotePlayer ) - { - Interp_Copy( pPlayer ); - - SetAbsAngles( pPlayer->GetRenderAngles() ); - GetRotationInterpolator().Reset(); - - m_flAnimTime = pPlayer->m_flAnimTime; - SetSequence( pPlayer->GetSequence() ); - m_flPlaybackRate = pPlayer->GetPlaybackRate(); - } - else - { - // This is the local player, so set them in a default - // pose and slam their velocity, angles and origin - SetAbsOrigin( m_vecRagdollOrigin ); - - SetAbsAngles( pPlayer->GetRenderAngles() ); - - SetAbsVelocity( m_vecRagdollVelocity ); - - int iSeq = LookupSequence( "walk_lower" ); - if ( iSeq == -1 ) - { - Assert( false ); // missing walk_lower? - iSeq = 0; - } - - SetSequence( iSeq ); // walk_lower, basic pose - SetCycle( 0.0 ); - - Interp_Reset( varMap ); - } - } - else - { - // overwrite network origin so later interpolation will - // use this position - SetNetworkOrigin( m_vecRagdollOrigin ); - - SetAbsOrigin( m_vecRagdollOrigin ); - SetAbsVelocity( m_vecRagdollVelocity ); - - Interp_Reset( GetVarMapping() ); - - } - - SetModelIndex( m_nModelIndex ); - - // Turn it into a ragdoll. - // Make us a ragdoll.. - m_nRenderFX = kRenderFxRagdoll; - - BecomeRagdollOnClient( false ); - -} - - -void C_SDKRagdoll::OnDataChanged( DataUpdateType_t type ) -{ - BaseClass::OnDataChanged( type ); - - if ( type == DATA_UPDATE_CREATED ) - { - CreateRagdoll(); - - IPhysicsObject *pPhysicsObject = VPhysicsGetObject(); - - if( pPhysicsObject ) - { - AngularImpulse aVelocity(0,0,0); - - Vector vecExaggeratedVelocity = 3 * m_vecRagdollVelocity; - - pPhysicsObject->AddVelocity( &vecExaggeratedVelocity, &aVelocity ); - } - } -} - -IRagdoll* C_SDKRagdoll::GetIRagdoll() const -{ - return m_pRagdoll; -} - -C_BaseAnimating * C_SDKPlayer::BecomeRagdollOnClient( bool bCopyEntity ) -{ - // Let the C_CSRagdoll entity do this. - // m_builtRagdoll = true; - return NULL; -} - - -IRagdoll* C_SDKPlayer::GetRepresentativeRagdoll() const -{ - if ( m_hRagdoll.Get() ) - { - C_SDKRagdoll *pRagdoll = (C_SDKRagdoll*)m_hRagdoll.Get(); - - return pRagdoll->GetIRagdoll(); - } - else - { - return NULL; - } -} - - - -C_SDKPlayer::C_SDKPlayer() : - m_iv_angEyeAngles( "C_SDKPlayer::m_iv_angEyeAngles" ) -{ - m_PlayerAnimState = CreatePlayerAnimState( this, this, LEGANIM_9WAY, true ); - - m_angEyeAngles.Init(); - AddVar( &m_angEyeAngles, &m_iv_angEyeAngles, LATCH_SIMULATION_VAR ); -} - - -C_SDKPlayer::~C_SDKPlayer() -{ - m_PlayerAnimState->Release(); -} - - -C_SDKPlayer* C_SDKPlayer::GetLocalSDKPlayer() -{ - return ToSDKPlayer( C_BasePlayer::GetLocalPlayer() ); -} - - -const QAngle& C_SDKPlayer::GetRenderAngles() -{ - if ( IsRagdoll() ) - { - return vec3_angle; - } - else - { - return m_PlayerAnimState->GetRenderAngles(); - } -} - - -void C_SDKPlayer::UpdateClientSideAnimation() -{ - // Update the animation data. It does the local check here so this works when using - // a third-person camera (and we don't have valid player angles). - if ( this == C_SDKPlayer::GetLocalSDKPlayer() ) - m_PlayerAnimState->Update( EyeAngles()[YAW], m_angEyeAngles[PITCH] ); - else - m_PlayerAnimState->Update( m_angEyeAngles[YAW], m_angEyeAngles[PITCH] ); - - BaseClass::UpdateClientSideAnimation(); -} - - -void C_SDKPlayer::PostDataUpdate( DataUpdateType_t updateType ) -{ - // C_BaseEntity assumes we're networking the entity's angles, so pretend that it - // networked the same value we already have. - SetNetworkAngles( GetLocalAngles() ); - - BaseClass::PostDataUpdate( updateType ); -} - -void C_SDKPlayer::OnDataChanged( DataUpdateType_t type ) -{ - BaseClass::OnDataChanged( type ); - - if ( type == DATA_UPDATE_CREATED ) - { - SetNextClientThink( CLIENT_THINK_ALWAYS ); - } - - UpdateVisibility(); -} - - -void C_SDKPlayer::DoAnimationEvent( PlayerAnimEvent_t event ) -{ - if ( event == PLAYERANIMEVENT_THROW_GRENADE ) - { - // Let the server handle this event. It will update m_iThrowGrenadeCounter and the client will - // pick up the event in CCSPlayerAnimState. - } - else - { - m_PlayerAnimState->DoAnimationEvent( event ); - } -} - -bool C_SDKPlayer::ShouldDraw( void ) -{ - // If we're dead, our ragdoll will be drawn for us instead. - if ( !IsAlive() ) - return false; - - if( GetTeamNumber() == TEAM_SPECTATOR ) - return false; - - if( IsLocalPlayer() && IsRagdoll() ) - return true; - - return BaseClass::ShouldDraw(); -} - -CWeaponSDKBase* C_SDKPlayer::GetActiveSDKWeapon() const -{ - return dynamic_cast< CWeaponSDKBase* >( GetActiveWeapon() ); -} \ No newline at end of file diff --git a/src/src/cl_dll/sdk/c_sdk_player.h b/src/src/cl_dll/sdk/c_sdk_player.h deleted file mode 100644 index eced9c0..0000000 --- a/src/src/cl_dll/sdk/c_sdk_player.h +++ /dev/null @@ -1,87 +0,0 @@ -//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// -// -// Purpose: -// -//=============================================================================// - -#ifndef C_SDK_PLAYER_H -#define C_SDK_PLAYER_H -#ifdef _WIN32 -#pragma once -#endif - - -#include "sdk_playeranimstate.h" -#include "c_baseplayer.h" -#include "sdk_shareddefs.h" -#include "baseparticleentity.h" - - -class C_SDKPlayer : public C_BasePlayer, public ISDKPlayerAnimStateHelpers -{ -public: - DECLARE_CLASS( C_SDKPlayer, C_BasePlayer ); - DECLARE_CLIENTCLASS(); - DECLARE_PREDICTABLE(); - DECLARE_INTERPOLATION(); - - C_SDKPlayer(); - ~C_SDKPlayer(); - - static C_SDKPlayer* GetLocalSDKPlayer(); - - virtual const QAngle& GetRenderAngles(); - virtual void UpdateClientSideAnimation(); - virtual void PostDataUpdate( DataUpdateType_t updateType ); - virtual void OnDataChanged( DataUpdateType_t updateType ); - - -// Called by shared code. -public: - - // ISDKPlayerAnimState overrides. - virtual CWeaponSDKBase* SDKAnim_GetActiveWeapon(); - virtual bool SDKAnim_CanMove(); - - void DoAnimationEvent( PlayerAnimEvent_t event ); - bool ShouldDraw(); - - ISDKPlayerAnimState *m_PlayerAnimState; - - QAngle m_angEyeAngles; - CInterpolatedVar< QAngle > m_iv_angEyeAngles; - - CNetworkVar( int, m_iThrowGrenadeCounter ); // used to trigger grenade throw animations. - CNetworkVar( int, m_iShotsFired ); // number of shots fired recently - - EHANDLE m_hRagdoll; - - CWeaponSDKBase *GetActiveSDKWeapon() const; - - C_BaseAnimating *BecomeRagdollOnClient( bool bCopyEntity); - IRagdoll* C_SDKPlayer::GetRepresentativeRagdoll() const; - - void FireBullet( - Vector vecSrc, - const QAngle &shootAngles, - float vecSpread, - int iDamage, - int iBulletType, - CBaseEntity *pevAttacker, - bool bDoEffects, - float x, - float y ); - -private: - C_SDKPlayer( const C_SDKPlayer & ); -}; - - -inline C_SDKPlayer* ToSDKPlayer( CBaseEntity *pPlayer ) -{ - Assert( dynamic_cast< C_SDKPlayer* >( pPlayer ) != NULL ); - return static_cast< C_SDKPlayer* >( pPlayer ); -} - - -#endif // C_SDK_PLAYER_H diff --git a/src/src/cl_dll/sdk/c_sdk_team.cpp b/src/src/cl_dll/sdk/c_sdk_team.cpp deleted file mode 100644 index 62d3b31..0000000 --- a/src/src/cl_dll/sdk/c_sdk_team.cpp +++ /dev/null @@ -1,33 +0,0 @@ -//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// -// -// Purpose: Client side C_SDKTeam class -// -// $NoKeywords: $ -//=============================================================================// -#include "cbase.h" -#include "engine/IEngineSound.h" -#include "hud.h" -#include "recvproxy.h" -#include "c_sdk_team.h" - -// memdbgon must be the last include file in a .cpp file!!! -#include "tier0/memdbgon.h" - - -IMPLEMENT_CLIENTCLASS_DT(C_SDKTeam, DT_SDKTeam, CSDKTeam) -END_RECV_TABLE() - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -C_SDKTeam::C_SDKTeam() -{ -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -C_SDKTeam::~C_SDKTeam() -{ -} - diff --git a/src/src/cl_dll/sdk/c_sdk_team.h b/src/src/cl_dll/sdk/c_sdk_team.h deleted file mode 100644 index df25e99..0000000 --- a/src/src/cl_dll/sdk/c_sdk_team.h +++ /dev/null @@ -1,36 +0,0 @@ -//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// -// -// Purpose: Client side CTFTeam class -// -// $NoKeywords: $ -//=============================================================================// - -#ifndef C_SDK_TEAM_H -#define C_SDK_TEAM_H -#ifdef _WIN32 -#pragma once -#endif - -#include "c_team.h" -#include "shareddefs.h" - -class C_BaseEntity; -class C_BaseObject; -class CBaseTechnology; - -//----------------------------------------------------------------------------- -// Purpose: TF's Team manager -//----------------------------------------------------------------------------- -class C_SDKTeam : public C_Team -{ - DECLARE_CLASS( C_SDKTeam, C_Team ); - DECLARE_CLIENTCLASS(); - -public: - - C_SDKTeam(); - virtual ~C_SDKTeam(); -}; - - -#endif // C_SDK_TEAM_H diff --git a/src/src/cl_dll/sdk/sdk_fx_impacts.cpp b/src/src/cl_dll/sdk/sdk_fx_impacts.cpp deleted file mode 100644 index 6f74d9e..0000000 --- a/src/src/cl_dll/sdk/sdk_fx_impacts.cpp +++ /dev/null @@ -1,44 +0,0 @@ -//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// -// -// Purpose: Game-specific impact effect hooks -// -//=============================================================================// -#include "cbase.h" -#include "fx_impact.h" -#include "engine/IEngineSound.h" - - - -//----------------------------------------------------------------------------- -// Purpose: Handle weapon impacts -//----------------------------------------------------------------------------- -void ImpactCallback( 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, 1.0 ); - - //Play a ricochet sound some of the time - if( random->RandomInt(1,10) <= 3 && (iDamageType == DMG_BULLET) ) - { - CLocalPlayerFilter filter; - C_BaseEntity::EmitSound( filter, SOUND_FROM_WORLD, "Bounce.Shrapnel", &vecOrigin ); - } - } - - PlayImpactSound( pEntity, tr, vecOrigin, nSurfaceProp ); -} - -DECLARE_CLIENT_EFFECT( "Impact", ImpactCallback ); diff --git a/src/src/cl_dll/sdk/sdk_hud_chat.cpp b/src/src/cl_dll/sdk/sdk_hud_chat.cpp deleted file mode 100644 index 6a1015b..0000000 --- a/src/src/cl_dll/sdk/sdk_hud_chat.cpp +++ /dev/null @@ -1,462 +0,0 @@ -//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// -// -// Purpose: -// -//=============================================================================// - -#include "cbase.h" -#include "sdk_hud_chat.h" -//#include "c_sdk_player.h" -//#include "c_sdk_playerresource.h" -#include "hud_macros.h" -#include "text_message.h" -#include "vguicenterprint.h" -#include "vgui/ILocalize.h" - -ConVar cl_showtextmsg( "cl_showtextmsg", "1", 0, "Enable/disable text messages printing on the screen." ); - -float g_ColorGreen[3] = { 153, 255, 153 }; -float g_ColorYellow[3] = { 255, 178.5, 0.0 }; - -float *GetClientColor( int clientIndex ) -{ - if ( clientIndex == 0 ) // console msg - { - return g_ColorGreen; - } - else - { - return g_ColorYellow; - } -} - -// converts all '\r' characters to '\n', so that the engine can deal with the properly -// returns a pointer to str -static char* ConvertCRtoNL( char *str ) -{ - for ( char *ch = str; *ch != 0; ch++ ) - if ( *ch == '\r' ) - *ch = '\n'; - return str; -} - -// converts all '\r' characters to '\n', so that the engine can deal with the properly -// returns a pointer to str -static wchar_t* ConvertCRtoNL( wchar_t *str ) -{ - for ( wchar_t *ch = str; *ch != 0; ch++ ) - if ( *ch == L'\r' ) - *ch = L'\n'; - return str; -} - -static void StripEndNewlineFromString( char *str ) -{ - int s = strlen( str ) - 1; - if ( s >= 0 ) - { - if ( str[s] == '\n' || str[s] == '\r' ) - str[s] = 0; - } -} - -static void StripEndNewlineFromString( wchar_t *str ) -{ - int s = wcslen( str ) - 1; - if ( s >= 0 ) - { - if ( str[s] == L'\n' || str[s] == L'\r' ) - str[s] = 0; - } -} - -DECLARE_HUDELEMENT( CHudChat ); - -DECLARE_HUD_MESSAGE( CHudChat, SayText ); -DECLARE_HUD_MESSAGE( CHudChat, TextMsg ); - - -//===================== -//CHudChatLine -//===================== - -void CHudChatLine::ApplySchemeSettings(vgui::IScheme *pScheme) -{ - BaseClass::ApplySchemeSettings( pScheme ); - - m_hFont = pScheme->GetFont( "ChatFont" ); - SetBorder( NULL ); - SetBgColor( Color( 0, 0, 0, 0 ) ); - SetFgColor( Color( 0, 0, 0, 0 ) ); - - SetFont( m_hFont ); -} - -void CHudChatLine::PerformFadeout( void ) -{ - // Flash + Extra bright when new - float curtime = gpGlobals->curtime; - - int lr = m_clrText[0]; - int lg = m_clrText[1]; - int lb = m_clrText[2]; - - //CSPort chat only fades out, no blinking. - if ( curtime <= m_flExpireTime && curtime > m_flExpireTime - CHATLINE_FADE_TIME ) - { - float frac = ( m_flExpireTime - curtime ) / CHATLINE_FADE_TIME; - - int alpha = frac * 255; - alpha = clamp( alpha, 0, 255 ); - - wchar_t wbuf[4096]; - - GetText(0, wbuf, sizeof(wbuf)); - - SetText( "" ); - - if ( m_iNameLength > 0 ) - { - wchar_t wText[4096]; - // draw the first x characters in the player color - wcsncpy( wText, wbuf, min( m_iNameLength + 1, MAX_PLAYER_NAME_LENGTH+32) ); - wText[ min( m_iNameLength, MAX_PLAYER_NAME_LENGTH+31) ] = 0; - - m_clrNameColor[3] = alpha; - - InsertColorChange( m_clrNameColor ); - InsertString( wText ); - - wcsncpy( wText, wbuf + ( m_iNameLength ), wcslen( wbuf + m_iNameLength ) ); - wText[ wcslen( wbuf + m_iNameLength ) ] = '\0'; - InsertColorChange( Color( g_ColorYellow[0], g_ColorYellow[1], g_ColorYellow[2], alpha ) ); - InsertString( wText ); - InvalidateLayout( true ); - } - else - { - InsertColorChange( Color( lr, lg, lb, alpha ) ); - InsertString( wbuf ); - } - } - - OnThink(); -} - - - -//===================== -//CHudChatInputLine -//===================== - -void CHudChatInputLine::ApplySchemeSettings(vgui::IScheme *pScheme) -{ - BaseClass::ApplySchemeSettings(pScheme); - - vgui::HFont hFont = pScheme->GetFont( "ChatFont" ); - - m_pPrompt->SetFont( hFont ); - m_pInput->SetFont( hFont ); - - m_pInput->SetFgColor( pScheme->GetColor( "Chat.TypingText", pScheme->GetColor( "Panel.FgColor", Color( 255, 255, 255, 255 ) ) ) ); -} - - - -//===================== -//CHudChat -//===================== - -CHudChat::CHudChat( const char *pElementName ) : BaseClass( pElementName ) -{ - -} - -void CHudChat::CreateChatInputLine( void ) -{ - m_pChatInput = new CHudChatInputLine( this, "ChatInputLine" ); - m_pChatInput->SetVisible( false ); -} - -void CHudChat::CreateChatLines( void ) -{ - for ( int i = 0; i < CHAT_INTERFACE_LINES; i++ ) - { - char sz[ 32 ]; - Q_snprintf( sz, sizeof( sz ), "ChatLine%02i", i ); - m_ChatLines[ i ] = new CHudChatLine( this, sz ); - m_ChatLines[ i ]->SetVisible( false ); - } -} - -void CHudChat::ApplySchemeSettings( vgui::IScheme *pScheme ) -{ - BaseClass::ApplySchemeSettings( pScheme ); - - SetBgColor( Color( 0, 0, 0, 0 ) ); - SetFgColor( Color( 0, 0, 0, 0 ) ); -} - - -void CHudChat::Init( void ) -{ - BaseClass::Init(); - - HOOK_HUD_MESSAGE( CHudChat, SayText ); - HOOK_HUD_MESSAGE( CHudChat, TextMsg ); -} - -//----------------------------------------------------------------------------- -// Purpose: Overrides base reset to not cancel chat at round restart -//----------------------------------------------------------------------------- -void CHudChat::Reset( void ) -{ -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : *pszName - -// iSize - -// *pbuf - -//----------------------------------------------------------------------------- -void CHudChat::MsgFunc_SayText( bf_read &msg ) -{ - char szString[256]; - - int client = msg.ReadByte(); - msg.ReadString( szString, sizeof(szString) ); - bool bWantsToChat = msg.ReadByte(); - - if ( bWantsToChat ) - { - // print raw chat text - ChatPrintf( client, "%s", szString ); - } - else - { - // try to lookup translated string - Printf( "%s", hudtextmessage->LookupString( szString ) ); - } - - Msg( "%s", szString ); -} - -wchar_t* ReadLocalizedRadioCommandString( bf_read &msg, wchar_t *pOut, int outSize, bool bStripNewline ) -{ - char szString[2048]; - msg.ReadString( szString, sizeof(szString) ); - - const wchar_t *pBuf = vgui::localize()->Find( szString ); - if ( pBuf ) - { - wcsncpy( pOut, pBuf, outSize/sizeof(wchar_t) ); - pOut[outSize/sizeof(wchar_t)-1] = 0; - } - else - { - vgui::localize()->ConvertANSIToUnicode( szString, pOut, outSize ); - } - - if ( bStripNewline ) - StripEndNewlineFromString( pOut ); - - return pOut; -} - -// Message handler for text messages -// displays a string, looking them up from the titles.txt file, which can be localised -// parameters: -// byte: message direction ( HUD_PRINTCONSOLE, HUD_PRINTNOTIFY, HUD_PRINTCENTER, HUD_PRINTTALK ) -// string: message -// optional parameters: -// string: message parameter 1 -// string: message parameter 2 -// string: message parameter 3 -// string: message parameter 4 -// any string that starts with the character '#' is a message name, and is used to look up the real message in titles.txt -// the next (optional) one to four strings are parameters for that string (which can also be message names if they begin with '#') -void CHudChat::MsgFunc_TextMsg( bf_read &msg ) -{ - char szString[2048]; - int msg_dest = msg.ReadByte(); - - wchar_t szBuf[5][128]; - wchar_t outputBuf[256]; - - for ( int i=0; i<5; ++i ) - { - msg.ReadString( szString, sizeof(szString) ); - char *tmpStr = hudtextmessage->LookupString( szString, &msg_dest ); - const wchar_t *pBuf = vgui::localize()->Find( tmpStr ); - if ( pBuf ) - { - // Copy pBuf into szBuf[i]. - int nMaxChars = sizeof( szBuf[i] ) / sizeof( wchar_t ); - wcsncpy( szBuf[i], pBuf, nMaxChars ); - szBuf[i][nMaxChars-1] = 0; - } - else - { - if ( i ) - { - StripEndNewlineFromString( tmpStr ); // these strings are meant for subsitution into the main strings, so cull the automatic end newlines - } - vgui::localize()->ConvertANSIToUnicode( tmpStr, szBuf[i], sizeof(szBuf[i]) ); - } - } - - if ( !cl_showtextmsg.GetInt() ) - return; - - int len; - switch ( msg_dest ) - { - case HUD_PRINTCENTER: - vgui::localize()->ConstructString( outputBuf, sizeof(outputBuf), szBuf[0], 4, szBuf[1], szBuf[2], szBuf[3], szBuf[4] ); - internalCenterPrint->Print( ConvertCRtoNL( outputBuf ) ); - break; - - case HUD_PRINTNOTIFY: - szString[0] = 1; // mark this message to go into the notify buffer - vgui::localize()->ConstructString( outputBuf, sizeof(outputBuf), szBuf[0], 4, szBuf[1], szBuf[2], szBuf[3], szBuf[4] ); - vgui::localize()->ConvertUnicodeToANSI( outputBuf, szString+1, sizeof(szString)-1 ); - len = strlen( szString ); - if ( len && szString[len-1] != '\n' && szString[len-1] != '\r' ) - { - Q_strncat( szString, "\n", sizeof(szString), 1 ); - } - Msg( "%s", ConvertCRtoNL( szString ) ); - break; - - case HUD_PRINTTALK: - vgui::localize()->ConstructString( outputBuf, sizeof(outputBuf), szBuf[0], 4, szBuf[1], szBuf[2], szBuf[3], szBuf[4] ); - vgui::localize()->ConvertUnicodeToANSI( outputBuf, szString, sizeof(szString) ); - len = strlen( szString ); - if ( len && szString[len-1] != '\n' && szString[len-1] != '\r' ) - { - Q_strncat( szString, "\n", sizeof(szString), 1 ); - } - Printf( "%s", ConvertCRtoNL( szString ) ); - break; - - case HUD_PRINTCONSOLE: - vgui::localize()->ConstructString( outputBuf, sizeof(outputBuf), szBuf[0], 4, szBuf[1], szBuf[2], szBuf[3], szBuf[4] ); - vgui::localize()->ConvertUnicodeToANSI( outputBuf, szString, sizeof(szString) ); - len = strlen( szString ); - if ( len && szString[len-1] != '\n' && szString[len-1] != '\r' ) - { - Q_strncat( szString, "\n", sizeof(szString), 1 ); - } - Msg( "%s", ConvertCRtoNL( szString ) ); - break; - } -} - - -//----------------------------------------------------------------------------- -// Purpose: -// Input : *fmt - -// ... - -//----------------------------------------------------------------------------- -void CHudChat::ChatPrintf( int iPlayerIndex, const char *fmt, ... ) -{ - va_list marker; - char msg[4096]; - - va_start(marker, fmt); - Q_vsnprintf(msg, sizeof( msg), fmt, marker); - va_end(marker); - - // Strip any trailing '\n' - if ( strlen( msg ) > 0 && msg[ strlen( msg )-1 ] == '\n' ) - { - msg[ strlen( msg ) - 1 ] = 0; - } - - // Strip leading \n characters ( or notify/color signifiers ) - char *pmsg = msg; - while ( *pmsg && ( *pmsg == '\n' || *pmsg == 1 || *pmsg == 2 ) ) - { - pmsg++; - } - - if ( !*pmsg ) - return; - - CHudChatLine *line = (CHudChatLine *)FindUnusedChatLine(); - if ( !line ) - { - ExpireOldest(); - line = (CHudChatLine *)FindUnusedChatLine(); - } - - if ( !line ) - { - return; - } - - line->SetText( "" ); - - int iNameLength = 0; - - player_info_t sPlayerInfo; - if ( iPlayerIndex == 0 ) - { - Q_memset( &sPlayerInfo, 0, sizeof(player_info_t) ); - Q_strncpy( sPlayerInfo.name, "Console", sizeof(sPlayerInfo.name) ); - } - else - { - engine->GetPlayerInfo( iPlayerIndex, &sPlayerInfo ); - } - - const char *pName = sPlayerInfo.name; - - if ( pName ) - { - const char *nameInString = strstr( pmsg, pName ); - - if ( nameInString ) - { - iNameLength = strlen( pName ) + (nameInString - pmsg); - } - } - else - line->InsertColorChange( Color( g_ColorYellow[0], g_ColorYellow[1], g_ColorYellow[2], 255 ) ); - - char *buf = static_cast( _alloca( strlen( pmsg ) + 1 ) ); - wchar_t *wbuf = static_cast( _alloca( (strlen( pmsg ) + 1 ) * sizeof(wchar_t) ) ); - if ( buf ) - { - float *flColor = GetClientColor( iPlayerIndex ); - - line->SetExpireTime(); - - // draw the first x characters in the player color - Q_strncpy( buf, pmsg, min( iNameLength + 1, MAX_PLAYER_NAME_LENGTH+32) ); - buf[ min( iNameLength, MAX_PLAYER_NAME_LENGTH+31) ] = 0; - line->InsertColorChange( Color( flColor[0], flColor[1], flColor[2], 255 ) ); - line->InsertString( buf ); - Q_strncpy( buf, pmsg + iNameLength, strlen( pmsg )); - buf[ strlen( pmsg + iNameLength ) ] = '\0'; - line->InsertColorChange( Color( g_ColorYellow[0], g_ColorYellow[1], g_ColorYellow[2], 255 ) ); - vgui::localize()->ConvertANSIToUnicode( buf, wbuf, strlen(pmsg)*sizeof(wchar_t)); - line->InsertString( wbuf ); - line->SetVisible( true ); - line->SetNameLength( iNameLength ); - line->SetNameColor( Color( flColor[0], flColor[1], flColor[2], 255 ) ); - } - - CLocalPlayerFilter filter; - C_BaseEntity::EmitSound( filter, -1 /*SOUND_FROM_LOCAL_PLAYER*/, "HudChat.Message" ); -} - -int CHudChat::GetChatInputOffset( void ) -{ - if ( m_pChatInput->IsVisible() ) - { - return m_iFontHeight; - } - else - return 0; -} diff --git a/src/src/cl_dll/sdk/vgui/sdkviewport.cpp b/src/src/cl_dll/sdk/vgui/sdkviewport.cpp deleted file mode 100644 index 177454a..0000000 --- a/src/src/cl_dll/sdk/vgui/sdkviewport.cpp +++ /dev/null @@ -1,85 +0,0 @@ -//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// -// -// Purpose: Client DLL VGUI2 Viewport -// -// $Workfile: $ -// $Date: $ -// -//----------------------------------------------------------------------------- -// $Log: $ -// -// $NoKeywords: $ -//=============================================================================// - -#include "cbase.h" - -#pragma warning( disable : 4800 ) // disable forcing int to bool performance warning - -// VGUI panel includes -#include -#include -#include -#include -#include -#include -#include -#include - -// client dll/engine defines -#include "hud.h" -#include - -// viewport definitions -#include -#include "SDKViewport.h" - -#include "vguicenterprint.h" -#include "text_message.h" - - -void SDKViewport::ApplySchemeSettings( vgui::IScheme *pScheme ) -{ - BaseClass::ApplySchemeSettings( pScheme ); - - gHUD.InitColors( pScheme ); - - SetPaintBackgroundEnabled( false ); -} - - -IViewPortPanel* SDKViewport::CreatePanelByName(const char *szPanelName) -{ - IViewPortPanel* newpanel = NULL; - -// Up here, strcmp against each type of panel we know how to create. -// else if ( Q_strcmp(PANEL_OVERVIEW, szPanelName) == 0 ) -// { -// newpanel = new CCSMapOverview( this ); -// } - - // create a generic base panel, don't add twice - newpanel = BaseClass::CreatePanelByName( szPanelName ); - - return newpanel; -} - -void SDKViewport::CreateDefaultPanels( void ) -{ - BaseClass::CreateDefaultPanels(); -} - -int SDKViewport::GetDeathMessageStartHeight( void ) -{ - int x = YRES(2); - - IViewPortPanel *spectator = gViewPortInterface->FindPanelByName( PANEL_SPECGUI ); - - //TODO: Link to actual height of spectator bar - if ( spectator && spectator->IsVisible() ) - { - x += YRES(52); - } - - return x; -} - diff --git a/src/src/cl_dll/tempent.h b/src/src/cl_dll/tempent.h deleted file mode 100644 index 9deb7f6..0000000 --- a/src/src/cl_dll/tempent.h +++ /dev/null @@ -1,127 +0,0 @@ -//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// -// -// Purpose: -// -// $NoKeywords: $ -// -//=============================================================================// -#if !defined( TEMPENT_H ) -#define TEMPENT_H -#ifdef _WIN32 -#pragma once -#endif - -#include "c_baseentity.h" -#include "c_baseanimating.h" -#include "c_sprite.h" - -// Temporary entity array -#define TENTPRIORITY_LOW 0 -#define TENTPRIORITY_HIGH 1 - -// TEMPENTITY flags -#define FTENT_NONE 0x00000000 -#define FTENT_SINEWAVE 0x00000001 -#define FTENT_GRAVITY 0x00000002 -#define FTENT_ROTATE 0x00000004 -#define FTENT_SLOWGRAVITY 0x00000008 -#define FTENT_SMOKETRAIL 0x00000010 -#define FTENT_COLLIDEWORLD 0x00000020 -#define FTENT_FLICKER 0x00000040 -#define FTENT_FADEOUT 0x00000080 -#define FTENT_SPRANIMATE 0x00000100 -#define FTENT_HITSOUND 0x00000200 -#define FTENT_SPIRAL 0x00000400 -#define FTENT_SPRCYCLE 0x00000800 -#define FTENT_COLLIDEALL 0x00001000 // will collide with world and slideboxes -#define FTENT_PERSIST 0x00002000 // tent is not removed when unable to draw -#define FTENT_COLLIDEKILL 0x00004000 // tent is removed upon collision with anything -#define FTENT_PLYRATTACHMENT 0x00008000 // tent is attached to a player (owner) -#define FTENT_SPRANIMATELOOP 0x00010000 // animating sprite doesn't die when last frame is displayed -#define FTENT_SMOKEGROWANDFADE 0x00020000 // rapid grow and fade. Very specific for gunsmoke -#define FTENT_SPARKSHOWER 0x00040000 -#define FTENT_NOMODEL 0x00080000 // Doesn't have a model, never try to draw ( it just triggers other things ) -#define FTENT_CLIENTCUSTOM 0x00100000 // Must specify callback. Callback function is responsible for killing tempent and updating fields ( unless other flags specify how to do things ) -#define FTENT_WINDBLOWN 0x00200000 // This is set when the temp entity is blown by the wind -#define FTENT_NEVERDIE 0x00400000 // Don't die as long as die != 0 -#define FTENT_BEOCCLUDED 0x00800000 // Don't draw if my specified normal's facing away from the view -#define FTENT_CHANGERENDERONCOLLIDE 0x01000000 //when we collide with something, change our rendergroup to RENDER_GROUP_OTHER -#define FTENT_COLLISIONGROUP 0x02000000 // if set, use the C_BaseEntity::GetCollisionGroup when doing collide trace - -class C_LocalTempEntity; - -typedef int (*pfnDrawHelper)( C_LocalTempEntity *entity, int flags ); - -//----------------------------------------------------------------------------- -// Purpose: Should this derive from some other class -//----------------------------------------------------------------------------- -class C_LocalTempEntity : public C_BaseAnimating, public C_SpriteRenderer -{ -public: - DECLARE_CLASS( C_LocalTempEntity, C_BaseAnimating ); - - C_LocalTempEntity(); - - virtual void Prepare( model_t *pmodel, float time ); - - virtual bool IsActive( void ); - virtual bool Frame( float frametime, int framenumber ); - - // C_BaseAnimating , etc. override - virtual int DrawModel( int flags ); - - // Sets the velocity - void SetVelocity( const Vector &vecVelocity ); - const Vector &GetVelocity() const { return m_vecTempEntVelocity; } - - void SetDrawHelper( pfnDrawHelper helper ) { m_pfnDrawHelper = helper; } - void OnRemoveTempEntity(); - -protected: - - pfnDrawHelper m_pfnDrawHelper; - -public: - int flags; - float die; - float m_flFrameMax; - float x; - float y; - float fadeSpeed; - float bounceFactor; - int hitSound; - int priority; - // if attached, this is the index of the client to stick to - // if COLLIDEALL, this is the index of the client to ignore - // TENTS with FTENT_PLYRATTACHMENT MUST set the clientindex! - short clientIndex; - - // if attached, client origin + tentOffset = tent origin. - Vector tentOffset; - - // Used by temp entities. - QAngle m_vecTempEntAngVelocity; - int tempent_renderamt; - Vector m_vecNormal; - - float m_flSpriteScale; - int m_nFlickerFrame; - - // - float m_flFrameRate; - float m_flFrame; - - RenderGroup_t m_RenderGroup; - -private: - C_LocalTempEntity( const C_LocalTempEntity & ); - - Vector m_vecTempEntVelocity; - Vector m_vecPrevLocalOrigin; - - // Draw tempent as a studio model - int DrawStudioModel( int flags ); - -}; - -#endif // TEMPENTITY_H \ No newline at end of file diff --git a/src/src/cl_dll/toolframework_client.cpp b/src/src/cl_dll/toolframework_client.cpp deleted file mode 100644 index 55404d8..0000000 --- a/src/src/cl_dll/toolframework_client.cpp +++ /dev/null @@ -1,186 +0,0 @@ -//====== Copyright © 1996-2005, Valve Corporation, All rights reserved. =====// -// -// Purpose: -// -//===========================================================================// - -#include "cbase.h" -#include "toolframework_client.h" -#include "igamesystem.h" -#include "toolframework/iclientenginetools.h" -#include "client_factorylist.h" - -class CToolFrameworkClient : public CBaseGameSystemPerFrame -{ -public: - // Methods of IGameSystem - virtual bool Init(); - virtual void LevelInitPreEntity(); - virtual void LevelInitPostEntity(); - virtual void LevelShutdownPreEntity(); - virtual void LevelShutdownPostEntity(); - virtual void PreRender(); - virtual void PostRender(); - -public: - // Other public methods - void PostToolMessage( HTOOLHANDLE hEntity, KeyValues *msg ); - void AdjustEngineViewport( int& x, int& y, int& width, int& height ); - bool SetupEngineView( Vector &origin, QAngle &angles, float &fov ); - bool SetupEngineMicrophone( Vector &origin, QAngle &angles ); - bool IsThirdPersonCamera(); - -private: - IClientEngineTools *m_pTools; -}; - - -//----------------------------------------------------------------------------- -// Singleton -//----------------------------------------------------------------------------- -static CToolFrameworkClient g_ToolFrameworkClient; - -IGameSystem *ToolFrameworkClientSystem() -{ - return &g_ToolFrameworkClient; -} - -bool CToolFrameworkClient::Init() -{ - factorylist_t list; - FactoryList_Retrieve( list ); - - m_pTools = ( IClientEngineTools * )list.appSystemFactory( VCLIENTENGINETOOLS_INTERFACE_VERSION, NULL ); - return ( m_pTools != NULL ); -} - -void CToolFrameworkClient::LevelInitPreEntity() -{ - if ( m_pTools ) - { - m_pTools->LevelInitPreEntityAllTools(); - } -} - -void CToolFrameworkClient::LevelInitPostEntity() -{ - if ( m_pTools ) - { - m_pTools->LevelInitPostEntityAllTools(); - } -} - -void CToolFrameworkClient::LevelShutdownPreEntity() -{ - if ( m_pTools ) - { - m_pTools->LevelShutdownPreEntityAllTools(); - } -} - -void CToolFrameworkClient::LevelShutdownPostEntity() -{ - if ( m_pTools ) - { - m_pTools->LevelShutdownPostEntityAllTools(); - } -} - -void CToolFrameworkClient::PreRender() -{ - if ( m_pTools ) - { - m_pTools->PreRenderAllTools(); - } -} - -void CToolFrameworkClient::PostRender() -{ - if ( m_pTools ) - { - m_pTools->PostRenderAllTools(); - } -} - - -//----------------------------------------------------------------------------- -// Should we render with a 3rd person camera? -//----------------------------------------------------------------------------- -bool CToolFrameworkClient::IsThirdPersonCamera() -{ - if ( !m_pTools ) - return false; - return m_pTools->IsThirdPersonCamera( ); -} - -bool ToolFramework_IsThirdPersonCamera( ) -{ - return g_ToolFrameworkClient.IsThirdPersonCamera( ); -} - - -//----------------------------------------------------------------------------- -// Posts a message to all tools -//----------------------------------------------------------------------------- -void CToolFrameworkClient::PostToolMessage( HTOOLHANDLE hEntity, KeyValues *msg ) -{ - if ( m_pTools ) - { - m_pTools->PostToolMessage( hEntity, msg ); - } -} - -void ToolFramework_PostToolMessage( HTOOLHANDLE hEntity, KeyValues *msg ) -{ - g_ToolFrameworkClient.PostToolMessage( hEntity, msg ); -} - - -//----------------------------------------------------------------------------- -// View manipulation -//----------------------------------------------------------------------------- -void CToolFrameworkClient::AdjustEngineViewport( int& x, int& y, int& width, int& height ) -{ - if ( m_pTools ) - { - m_pTools->AdjustEngineViewport( x, y, width, height ); - } -} - -void ToolFramework_AdjustEngineViewport( int& x, int& y, int& width, int& height ) -{ - g_ToolFrameworkClient.AdjustEngineViewport( x, y, width, height ); -} - - -//----------------------------------------------------------------------------- -// View manipulation -//----------------------------------------------------------------------------- -bool CToolFrameworkClient::SetupEngineView( Vector &origin, QAngle &angles, float &fov ) -{ - if ( !m_pTools ) - return false; - - return m_pTools->SetupEngineView( origin, angles, fov ); -} - -bool ToolFramework_SetupEngineView( Vector &origin, QAngle &angles, float &fov ) -{ - return g_ToolFrameworkClient.SetupEngineView( origin, angles, fov ); -} - -//----------------------------------------------------------------------------- -// microphone manipulation -//----------------------------------------------------------------------------- -bool CToolFrameworkClient::SetupEngineMicrophone( Vector &origin, QAngle &angles ) -{ - if ( !m_pTools ) - return false; - - return m_pTools->SetupEngineMicrophone( origin, angles ); -} - -bool ToolFramework_SetupEngineMicrophone( Vector &origin, QAngle &angles ) -{ - return g_ToolFrameworkClient.SetupEngineMicrophone( origin, angles ); -} diff --git a/src/src/cl_dll/view_scene.cpp b/src/src/cl_dll/view_scene.cpp deleted file mode 100644 index e777231..0000000 --- a/src/src/cl_dll/view_scene.cpp +++ /dev/null @@ -1,4697 +0,0 @@ -//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// -// -// Purpose: Responsible for drawing the scene -// -// $NoKeywords: $ -//===========================================================================// - - -#include "cbase.h" -#include "view.h" -#include "iviewrender.h" -#include "view_shared.h" -#include "ivieweffects.h" -#include "iinput.h" -#include "model_types.h" -#include "clientsideeffects.h" -#include "particlemgr.h" -#include "viewrender.h" -#include "iclientmode.h" -#include "voice_status.h" -#include "glow_overlay.h" -#include "materialsystem/imesh.h" -#include "materialsystem/ITexture.h" -#include "materialsystem/IMaterial.h" -#include "materialsystem/IMaterialVar.h" -#include "materialsystem/IColorCorrection.h" -#include "DetailObjectSystem.h" -#include "tier0/vprof.h" -#include "datacache/imdlcache.h" -#include "engine/IEngineTrace.h" -#include "engine/ivmodelinfo.h" -#include "vstdlib/icommandline.h" - -#include "view_scene.h" -#include "particles_ez.h" -#include "engine/IStaticPropMgr.h" -#include "engine/ivdebugoverlay.h" -#include "smoke_fog_overlay.h" -#include "c_pixel_visibility.h" -#include "ClientEffectPrecacheSystem.h" -#include "c_rope.h" -#include "c_effects.h" -#include "smoke_fog_overlay.h" -#include "materialsystem/imaterialsystemhardwareconfig.h" -#include "vgui_int.h" -#include "ienginevgui.h" -#include "datacache/imdlcache.h" -#include "ScreenSpaceEffects.h" - -#if defined( HL2_CLIENT_DLL ) || defined( CSTRIKE_DLL ) -#define USE_MONITORS -#endif - -// GR -#include "rendertexture.h" -#ifdef _XBOX -#include "tier0/mem.h" -#endif - -// memdbgon must be the last include file in a .cpp file!!! -#include "tier0/memdbgon.h" - -extern void ComputeCameraVariables( const Vector &vecOrigin, const QAngle &vecAngles, - Vector *pVecForward, Vector *pVecRight, Vector *pVecUp, VMatrix *pMatCamInverse ); - -static ConVar cl_drawmonitors( "cl_drawmonitors", "1" ); -static ConVar cl_overdraw_test( "cl_overdraw_test", "0", FCVAR_CHEAT | FCVAR_NEVER_AS_STRING ); -static ConVar r_eyewaterepsilon( "r_eyewaterepsilon", "7.0f", FCVAR_CHEAT ); - -static void SetClearColorToFogColor( unsigned char ucFogColor[3] ) -{ - materials->GetFogColor( ucFogColor ); - if( g_pMaterialSystemHardwareConfig->GetHDRType() == HDR_TYPE_INTEGER ) - { - float scale = LinearToGammaFullRange( materials->GetToneMappingScaleLinear().x ); - ucFogColor[0] *= scale; - ucFogColor[1] *= scale; - ucFogColor[2] *= scale; - } - materials->ClearColor4ub( ucFogColor[0], ucFogColor[1], ucFogColor[2], 255 ); -} - -// Used to verify frame syncing. -void GenerateOverdrawForTesting() -{ - if ( !cl_overdraw_test.GetInt() ) - return; - - for ( int i=0; i < 40; i++ ) - { - g_SmokeFogOverlayAlpha = 20 / 255.0; - DrawSmokeFogOverlay(); - } - g_SmokeFogOverlayAlpha = 0; -} - - -//----------------------------------------------------------------------------- -// Convars related to controlling rendering -//----------------------------------------------------------------------------- -static ConVar cl_maxrenderable_dist("cl_maxrenderable_dist", "3000", FCVAR_CHEAT, "Max distance from the camera at which things will be rendered" ); - -ConVar r_updaterefracttexture( "r_updaterefracttexture", "1" ); - -ConVar r_entityclips( "r_entityclips", "1" ); //FIXME: Nvidia drivers before 81.94 on cards that support user clip planes will have problems with this, require driver update? Detect and disable? - -// Matches the version in the engine -static ConVar r_drawopaqueworld( "r_drawopaqueworld", "1", FCVAR_CHEAT ); -static ConVar r_drawtranslucentworld( "r_drawtranslucentworld", "1", FCVAR_CHEAT ); -static ConVar r_3dsky( "r_3dsky","1", 0, "Enable the rendering of 3d sky boxes" ); -static ConVar r_skybox( "r_skybox","1", FCVAR_CHEAT, "Enable the rendering of sky boxes" ); -ConVar r_drawviewmodel( "r_drawviewmodel","1", FCVAR_CHEAT ); -static ConVar r_drawtranslucentrenderables( "r_drawtranslucentrenderables", "1", FCVAR_CHEAT ); -static ConVar r_drawopaquerenderables( "r_drawopaquerenderables", "1", FCVAR_CHEAT ); - -static ConVar r_flashlightdrawdepth( "r_flashlightdrawdepth", "0" ); - -ConVar r_DrawDetailProps( "r_DrawDetailProps", "1", FCVAR_CHEAT, "0=Off, 1=Normal, 2=Wireframe" ); - -ConVar mat_bloomscale( "mat_bloomscale", "1" ); - -//----------------------------------------------------------------------------- -// Convars related to fog color -//----------------------------------------------------------------------------- -static ConVar fog_override( "fog_override", "0", FCVAR_CHEAT ); -// set any of these to use the maps fog -static ConVar fog_start( "fog_start", "-1" ); -static ConVar fog_end( "fog_end", "-1" ); -static ConVar fog_color( "fog_color", "-1 -1 -1" ); -static ConVar fog_enable( "fog_enable", "1" ); -static ConVar fog_startskybox( "fog_startskybox", "-1" ); -static ConVar fog_endskybox( "fog_endskybox", "-1" ); -static ConVar fog_colorskybox( "fog_colorskybox", "-1 -1 -1" ); -static ConVar fog_enableskybox( "fog_enableskybox", "1" ); - - -//----------------------------------------------------------------------------- -// Water-related convars -//----------------------------------------------------------------------------- -static ConVar r_debugcheapwater( "r_debugcheapwater", "0", FCVAR_CHEAT ); -static ConVar r_waterforceexpensive( "r_waterforceexpensive", "0" ); -static ConVar r_waterforcereflectentities( "r_waterforcereflectentities", "0" ); -static ConVar r_WaterDrawRefraction( "r_WaterDrawRefraction", "1", 0, "Enable water refraction" ); -static ConVar r_WaterDrawReflection( "r_WaterDrawReflection", "1", 0, "Enable water reflection" ); -static ConVar r_ForceWaterLeaf( "r_ForceWaterLeaf", "1", 0, "Enable for optimization to water - considers view in leaf under water for purposes of culling" ); -static ConVar mat_drawwater( "mat_drawwater", "1", FCVAR_CHEAT ); -static ConVar mat_clipz( "mat_clipz", "1" ); - - -//----------------------------------------------------------------------------- -// debugging -//----------------------------------------------------------------------------- -static ConVar r_visocclusion( "r_visocclusion", "0", FCVAR_CHEAT ); -// (the engine owns this cvar). -ConVar mat_wireframe( "mat_wireframe", "0", FCVAR_CHEAT ); - -// sv_cheats is replicated and lives in the engine. re-declaring it here without FCVAR_REPLICATED -// breaks the linkage, and declaring it here with FCVAR_REPLICATED wants it to be declared in the server also. -const ConVar *sv_cheats = NULL; - - - -//----------------------------------------------------------------------------- -// debugging overlays -//----------------------------------------------------------------------------- -static ConVar cl_drawmaterial( "cl_drawmaterial", "", FCVAR_CHEAT, "Draw a particular material over the frame" ); -static ConVar cl_drawshadowtexture( "cl_drawshadowtexture", "0", FCVAR_CHEAT ); -static ConVar mat_showwatertextures( "mat_showwatertextures", "0", FCVAR_CHEAT ); -static ConVar mat_wateroverlaysize( "mat_wateroverlaysize", "128" ); -static ConVar mat_showframebuffertexture( "mat_showframebuffertexture", "0", FCVAR_CHEAT ); -static ConVar mat_framebuffercopyoverlaysize( "mat_framebuffercopyoverlaysize", "128" ); -static ConVar mat_showcamerarendertarget( "mat_showcamerarendertarget", "0", FCVAR_CHEAT ); -static ConVar mat_camerarendertargetoverlaysize( "mat_camerarendertargetoverlaysize", "128", FCVAR_CHEAT ); -static ConVar mat_hsv( "mat_hsv", "0" ); -static ConVar mat_yuv( "mat_yuv", "0" ); - -#ifdef _XBOX -static ConVar mat_viewTextureEnable("mat_viewTextureEnable", "", 0, "Enable view texture"); -static ConVar mat_viewTextureName("mat_viewTextureName", "", 0, "Set the view texture name"); -static ConVar mat_viewTextureScale("mat_viewTextureScale", "1", 0, "Set the view texture scale"); -#endif - -//----------------------------------------------------------------------------- -// Other convars -//----------------------------------------------------------------------------- - -ConVar r_DoCovertTransitions("r_DoCovertTransitions", "1", FCVAR_NEVER_AS_STRING ); // internally used by game code and engine to choose when to allow LOD transitions. -ConVar r_TransitionSensitivity("r_TransitionSensitivity", "6", 0, "Controls when LODs are changed. Lower numbers cause more overt LOD transitions."); - -static ConVar r_screenfademinsize( "r_screenfademinsize", "0" ); -static ConVar r_screenfademaxsize( "r_screenfademaxsize", "0" ); - - -//----------------------------------------------------------------------------- -// Globals -//----------------------------------------------------------------------------- -static Vector g_vecCurrentRenderOrigin(0,0,0); -static QAngle g_vecCurrentRenderAngles(0,0,0); -static Vector g_vecCurrentVForward(0,0,0), g_vecCurrentVRight(0,0,0), g_vecCurrentVUp(0,0,0); -static VMatrix g_matCurrentCamInverse; -static bool s_bCanAccessCurrentView = false; -IntroData_t *g_pIntroData = NULL; -static bool g_bRenderingView = false; // For debugging... -static int g_CurrentViewID = VIEW_NONE; -bool g_bRenderingScreenshot = false; -int g_viewscene_refractUpdateFrame = 0; - -// mapmaker controlled autoexposure -bool g_bUseCustomAutoExposureMin = false; -bool g_bUseCustomAutoExposureMax = false; -bool g_bUseCustomBloomScale = false; -float g_flCustomAutoExposureMin = 0; -float g_flCustomAutoExposureMax = 0; -float g_flCustomBloomScale = 0.0f; -float g_flCustomBloomScaleMinimum = 0.0f; -//----------------------------------------------------------------------------- -// Precache of necessary materials -//----------------------------------------------------------------------------- - -#ifdef HL2_CLIENT_DLL -CLIENTEFFECT_REGISTER_BEGIN( PrecacheViewRender ) - CLIENTEFFECT_MATERIAL( "scripted/intro_screenspaceeffect" ) - CLIENTEFFECT_REGISTER_END() -#endif - -#ifndef _XBOX -CLIENTEFFECT_REGISTER_BEGIN( PrecachePostProcessingEffects ) - CLIENTEFFECT_MATERIAL( "dev/downsample" ) - CLIENTEFFECT_MATERIAL( "dev/downsample_non_hdr" ) - CLIENTEFFECT_MATERIAL( "dev/blurfiltery_and_add_nohdr" ) - CLIENTEFFECT_MATERIAL( "dev/no_pixel_write" ) - CLIENTEFFECT_MATERIAL( "dev/lumcompare" ) - CLIENTEFFECT_MATERIAL( "dev/blurfilterx" ) - CLIENTEFFECT_MATERIAL( "dev/blurfilterx_nohdr" ) - CLIENTEFFECT_MATERIAL( "dev/floattoscreen_combine" ) - CLIENTEFFECT_MATERIAL( "dev/copyfullframefb_vanilla" ) - CLIENTEFFECT_MATERIAL( "dev/copyfullframefb" ) - CLIENTEFFECT_MATERIAL( "dev/blurfiltery" ) - CLIENTEFFECT_REGISTER_END_CONDITIONAL( engine->GetDXSupportLevel() >= 90) -#endif - -//----------------------------------------------------------------------------- -// Accessors to return the current view being rendered -//----------------------------------------------------------------------------- - const Vector &CurrentViewOrigin() -{ - Assert( s_bCanAccessCurrentView ); - return g_vecCurrentRenderOrigin; -} - -const QAngle &CurrentViewAngles() -{ - Assert( s_bCanAccessCurrentView ); - return g_vecCurrentRenderAngles; -} - -const Vector &CurrentViewForward() -{ - Assert( s_bCanAccessCurrentView ); - return g_vecCurrentVForward; -} - -const Vector &CurrentViewRight() -{ - Assert( s_bCanAccessCurrentView ); - return g_vecCurrentVRight; -} - -const Vector &CurrentViewUp() -{ - Assert( s_bCanAccessCurrentView ); - return g_vecCurrentVUp; -} - -const VMatrix &CurrentWorldToViewMatrix() -{ - Assert( s_bCanAccessCurrentView ); - return g_matCurrentCamInverse; -} - - -//----------------------------------------------------------------------------- -// Methods to set the current view/guard access to view parameters -//----------------------------------------------------------------------------- -void AllowCurrentViewAccess( bool allow ) -{ - s_bCanAccessCurrentView = allow; -} - -bool IsCurrentViewAccessAllowed() -{ - return s_bCanAccessCurrentView; -} - -void SetupCurrentView( const Vector &vecOrigin, const QAngle &angles, view_id_t viewID ) -{ - // Store off view origin and angles - g_vecCurrentRenderOrigin = vecOrigin; - g_vecCurrentRenderAngles = angles; - - // Compute the world->main camera transform - ComputeCameraVariables( vecOrigin, angles, - &g_vecCurrentVForward, &g_vecCurrentVRight, &g_vecCurrentVUp, &g_matCurrentCamInverse ); - - g_CurrentViewID = viewID; - s_bCanAccessCurrentView = true; - - // Cache off fade distances - float flScreenFadeMinSize, flScreenFadeMaxSize; - view->GetScreenFadeDistances( &flScreenFadeMinSize, &flScreenFadeMaxSize ); - modelinfo->SetViewScreenFadeRange( flScreenFadeMinSize, flScreenFadeMaxSize ); -} - -view_id_t CurrentViewID() -{ - return ( view_id_t )g_CurrentViewID; -} - -void FinishCurrentView() -{ - s_bCanAccessCurrentView = false; -} - - -//----------------------------------------------------------------------------- -// Constructor -//----------------------------------------------------------------------------- -CViewRender::CViewRender() -{ - m_AnglesHistoryCounter = 0; - memset(m_AnglesHistory, 0, sizeof(m_AnglesHistory)); - m_flCheapWaterStartDistance = 0.0f; - m_flCheapWaterEndDistance = 0.1f; - m_BaseDrawFlags = m_DrawFlags = 0; - m_bOverrideVisData = false; - m_iForceViewLeaf = -1; -} - - -//----------------------------------------------------------------------------- -// Purpose: -// Output : Returns true on success, false on failure. -//----------------------------------------------------------------------------- -inline bool CViewRender::ShouldDrawEntities( void ) -{ - return ( !m_pDrawEntities || (m_pDrawEntities->GetInt() != 0) ); -} - - -//----------------------------------------------------------------------------- -// Purpose: Check all conditions which would prevent drawing the view model -// Input : drawViewmodel - -// *viewmodel - -// Output : Returns true on success, false on failure. -//----------------------------------------------------------------------------- -bool CViewRender::ShouldDrawViewModel( bool bDrawViewmodel ) -{ - if ( !bDrawViewmodel ) - return false; - - if ( !r_drawviewmodel.GetBool() ) - return false; - - if ( C_BasePlayer::ShouldDrawLocalPlayer() ) - return false; - - if ( !ShouldDrawEntities() ) - return false; - - if ( render->GetViewEntity() > gpGlobals->maxClients ) - return false; - - return true; -} - - -void CViewRender::DrawRenderablesInList( CUtlVector< IClientRenderable * > &list ) -{ - int nCount = list.Count(); - for( int i=0; i < nCount; ++i ) - { - IClientUnknown *pUnk = list[i]->GetIClientUnknown(); - Assert( pUnk ); - C_BaseEntity *ent = pUnk->GetBaseEntity(); - Assert( ent ); - - // Non-view models wanting to render in view model list... - if ( ent->ShouldDraw() ) - { - ent->DrawModel( STUDIO_RENDER ); - } - } -} - - -//----------------------------------------------------------------------------- -// Purpose: Actually draw the view model -// Input : drawViewModel - -//----------------------------------------------------------------------------- -void CViewRender::DrawViewModels( const CViewSetup &view, bool drawViewmodel ) -{ - VPROF( "CViewRender::DrawViewModel" ); - - if ( !ShouldDrawViewModel( drawViewmodel ) ) - return; - - // Restore the matrices - materials->MatrixMode( MATERIAL_PROJECTION ); - materials->PushMatrix(); - - // Set up for drawing the view model - render->SetProjectionMatrix( view.fovViewmodel, view.zNearViewmodel, view.zFarViewmodel ); - - const bool bUseDepthHack = true; - - // FIXME: Add code to read the current depth range - float depthmin = 0.0f; - float depthmax = 1.0f; - - // HACK HACK: Munge the depth range to prevent view model from poking into walls, etc. - // Force clipped down range - if( bUseDepthHack ) - materials->DepthRange( 0.0f, 0.1f ); - - CUtlVector< IClientRenderable * > opaqueViewModelList( 32 ); - CUtlVector< IClientRenderable * > translucentViewModelList( 32 ); - - ClientLeafSystem()->CollateViewModelRenderables( opaqueViewModelList, translucentViewModelList ); - DrawRenderablesInList( opaqueViewModelList ); - DrawRenderablesInList( translucentViewModelList ); - - // Reset the depth range to the original values - if( bUseDepthHack ) - materials->DepthRange( depthmin, depthmax ); - - // Restore the matrices - materials->MatrixMode( MATERIAL_PROJECTION ); - materials->PopMatrix(); -} - - -//----------------------------------------------------------------------------- -// Purpose: -// Input : *pEnt - -// Output : int -//----------------------------------------------------------------------------- -VPlane* CViewRender::GetFrustum() -{ - // The frustum is only valid while in a RenderView call. - Assert(g_bRenderingView || g_bRenderingCameraView || g_bRenderingScreenshot); - return m_Frustum; -} - - -//----------------------------------------------------------------------------- -// Purpose: -// Output : Returns true on success, false on failure. -//----------------------------------------------------------------------------- -bool CViewRender::ShouldDrawBrushModels( void ) -{ - if ( m_pDrawBrushModels && !m_pDrawBrushModels->GetInt() ) - return false; - - return true; -} - - -//----------------------------------------------------------------------------- -// Sort entities in a back-to-front ordering -//----------------------------------------------------------------------------- -void SortEntities( CRenderList::CEntry *pEntities, int nEntities ) -{ - // Don't sort if we only have 1 entity - if ( nEntities <= 1 ) - return; - - float dists[CRenderList::MAX_GROUP_ENTITIES]; - - const Vector &vecRenderOrigin = CurrentViewOrigin(); - const Vector &vecRenderForward = CurrentViewForward(); - - // First get a distance for each entity. - int i; - for( i=0; i < nEntities; i++ ) - { - IClientRenderable *pRenderable = pEntities[i].m_pRenderable; - - // Compute the center of the object (needed for translucent brush models) - Vector boxcenter; - Vector mins,maxs; - pRenderable->GetRenderBounds( mins, maxs ); - VectorAdd( mins, maxs, boxcenter ); - VectorMA( pRenderable->GetRenderOrigin(), 0.5f, boxcenter, boxcenter ); - - // Compute distance... - Vector delta; - VectorSubtract( boxcenter, vecRenderOrigin, delta ); - dists[i] = DotProduct( delta, vecRenderForward ); - } - - // H-sort. - int stepSize = 4; - while( stepSize ) - { - int end = nEntities - stepSize; - for( i=0; i < end; i += stepSize ) - { - if( dists[i] > dists[i+stepSize] ) - { - swap( pEntities[i], pEntities[i+stepSize] ); - swap( dists[i], dists[i+stepSize] ); - - if( i == 0 ) - { - i = -stepSize; - } - else - { - i -= stepSize << 1; - } - } - } - - stepSize >>= 1; - } -} - - -void CViewRender::SetupRenderList( const CViewSetup *pView, ClientWorldListInfo_t& info, CRenderList &renderList ) -{ - VPROF( "CViewRender::SetupRenderList" ); - - // Clear the list. - int i; - for( i=0; i < RENDER_GROUP_COUNT; i++ ) - { - renderList.m_RenderGroupCounts[i] = 0; - } - - // Precache information used commonly in CollateRenderables - SetupRenderInfo_t setupInfo; - setupInfo.m_nRenderFrame = m_BuildRenderableListsNumber; - setupInfo.m_nDetailBuildFrame = m_BuildWorldListsNumber; - setupInfo.m_pRenderList = &renderList; - setupInfo.m_bDrawDetailObjects = g_pClientMode->ShouldDrawDetailObjects() && r_DrawDetailProps.GetInt(); - - if (pView) - { - setupInfo.m_vecRenderOrigin = pView->origin; - setupInfo.m_flRenderDistSq = cl_maxrenderable_dist.GetFloat(); - setupInfo.m_flRenderDistSq *= setupInfo.m_flRenderDistSq; - } - else - { - setupInfo.m_flRenderDistSq = 0.0f; - } - - // Now collate the entities in the leaves. - if( ShouldDrawEntities() ) - { - IClientLeafSystem *pClientLeafSystem = ClientLeafSystem(); - for( i=0; i < info.m_LeafCount; i++ ) - { - int nTranslucent = renderList.m_RenderGroupCounts[RENDER_GROUP_TRANSLUCENT_ENTITY]; - - // Add renderables from this leaf... - pClientLeafSystem->CollateRenderablesInLeaf( info.m_pLeafList[i], i, setupInfo ); - - int nNewTranslucent = renderList.m_RenderGroupCounts[RENDER_GROUP_TRANSLUCENT_ENTITY] - nTranslucent; - if( nNewTranslucent ) - { - // Sort the new translucent entities. - SortEntities( &renderList.m_RenderGroups[RENDER_GROUP_TRANSLUCENT_ENTITY][nTranslucent], nNewTranslucent ); - } - } - } -} - -static void OverlayWaterTexture( IMaterial *pMaterial, int xOffset, int yOffset, bool bFlip ) -{ -#ifndef _XBOX - float xBaseOffset = 0; - float yBaseOffset = 0; -#else - // screen safe - float xBaseOffset = 32; - float yBaseOffset = 32; -#endif - float offsetS = ( 0.5f / 256.0f ); - float offsetT = ( 0.5f / 256.0f ); - float fFlip0 = bFlip ? 1.0f : 0.0f; - float fFlip1 = bFlip ? 0.0f : 1.0f; - if( !IsErrorMaterial( pMaterial ) ) - { - materials->Bind( pMaterial ); - IMesh* pMesh = materials->GetDynamicMesh( true ); - - float w = mat_wateroverlaysize.GetFloat(); - float h = mat_wateroverlaysize.GetFloat(); - - CMeshBuilder meshBuilder; - meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 ); - - meshBuilder.Position3f( xBaseOffset + xOffset * w, yBaseOffset + yOffset * h, 0.0f ); - meshBuilder.TexCoord2f( 0, 0.0f + offsetS, fFlip1 + offsetT ); - meshBuilder.AdvanceVertex(); - - meshBuilder.Position3f( xBaseOffset + ( xOffset + 1 ) * w, yBaseOffset + yOffset * h, 0.0f ); - meshBuilder.TexCoord2f( 0, 1.0f + offsetS, fFlip1 + offsetT ); - meshBuilder.AdvanceVertex(); - - meshBuilder.Position3f( xBaseOffset + ( xOffset + 1 ) * w, yBaseOffset + ( yOffset + 1 ) * h, 0.0f ); - meshBuilder.TexCoord2f( 0, 1.0f + offsetS, fFlip0 + offsetT ); - meshBuilder.AdvanceVertex(); - - meshBuilder.Position3f( xBaseOffset + xOffset * w, yBaseOffset + ( yOffset + 1 ) * h, 0.0f ); - meshBuilder.TexCoord2f( 0, 0.0f + offsetS, fFlip0 + offsetT ); - meshBuilder.AdvanceVertex(); - - meshBuilder.End(); - pMesh->Draw(); - } -} - -static void OverlayWaterTextures( void ) -{ - OverlayWaterTexture( materials->FindMaterial( "debug/debugreflect", NULL ), 0, 0, false ); - OverlayWaterTexture( materials->FindMaterial( "debug/debugrefract", NULL ), 0, 1, true ); -} - -void OverlayCameraRenderTarget( const char *pszMaterialName, float flX, float flY, float w, float h ) -{ - float offsetS = ( 0.5f / 256.0f ); - float offsetT = ( 0.5f / 256.0f ); - IMaterial *pMaterial; - pMaterial = materials->FindMaterial( pszMaterialName, TEXTURE_GROUP_OTHER, true ); - if( !IsErrorMaterial( pMaterial ) ) - { - materials->Bind( pMaterial ); - IMesh* pMesh = materials->GetDynamicMesh( true ); - - CMeshBuilder meshBuilder; - meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 ); - - meshBuilder.Position3f( flX, flY, 0.0f ); - meshBuilder.TexCoord2f( 0, 0.0f + offsetS, 0.0f + offsetT ); - meshBuilder.AdvanceVertex(); - - meshBuilder.Position3f( flX+w, flY, 0.0f ); - meshBuilder.TexCoord2f( 0, 1.0f + offsetS, 0.0f + offsetT ); - meshBuilder.AdvanceVertex(); - - meshBuilder.Position3f( flX+w, flY+h, 0.0f ); - meshBuilder.TexCoord2f( 0, 1.0f + offsetS, 1.0f + offsetT ); - meshBuilder.AdvanceVertex(); - - meshBuilder.Position3f( flX, flY+h, 0.0f ); - meshBuilder.TexCoord2f( 0, 0.0f + offsetS, 1.0f + offsetT ); - meshBuilder.AdvanceVertex(); - - meshBuilder.End(); - pMesh->Draw(); - } -} - - -static void OverlayFrameBufferTexture( int nFrameBufferIndex ) -{ - float offsetS = ( 0.5f / 256.0f ); - float offsetT = ( 0.5f / 256.0f ); - IMaterial *pMaterial; - char buf[MAX_PATH]; - Q_snprintf( buf, MAX_PATH, "debug/debugfbtexture%d", nFrameBufferIndex ); - pMaterial = materials->FindMaterial( buf, TEXTURE_GROUP_OTHER, true ); - if( !IsErrorMaterial( pMaterial ) ) - { - materials->Bind( pMaterial ); - IMesh* pMesh = materials->GetDynamicMesh( true ); - - float w = mat_framebuffercopyoverlaysize.GetFloat(); - float h = mat_framebuffercopyoverlaysize.GetFloat(); - - CMeshBuilder meshBuilder; - meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 ); - - meshBuilder.Position3f( w * nFrameBufferIndex, 0.0f, 0.0f ); - meshBuilder.TexCoord2f( 0, 0.0f + offsetS, 0.0f + offsetT ); - meshBuilder.AdvanceVertex(); - - meshBuilder.Position3f( w * ( nFrameBufferIndex + 1 ), 0.0f, 0.0f ); - meshBuilder.TexCoord2f( 0, 1.0f + offsetS, 0.0f + offsetT ); - meshBuilder.AdvanceVertex(); - - meshBuilder.Position3f( w * ( nFrameBufferIndex + 1 ), h, 0.0f ); - meshBuilder.TexCoord2f( 0, 1.0f + offsetS, 1.0f + offsetT ); - meshBuilder.AdvanceVertex(); - - meshBuilder.Position3f( w * nFrameBufferIndex, h, 0.0f ); - meshBuilder.TexCoord2f( 0, 0.0f + offsetS, 1.0f + offsetT ); - meshBuilder.AdvanceVertex(); - - meshBuilder.End(); - pMesh->Draw(); - } -} - - - -void UpdateClientRenderableInPVSStatus() -{ - // Vis for this view should already be setup at this point. - - // For each client-only entity, notify it if it's newly coming into the PVS. - CUtlLinkedList &theList = ClientEntityList().GetPVSNotifiers(); - FOR_EACH_LL( theList, i ) - { - CClientEntityList::CPVSNotifyInfo *pInfo = &theList[i]; - - if ( pInfo->m_InPVSStatus & INPVS_YES ) - { - // Ok, this entity already thinks it's in the PVS. No need to notify it. - // We need to set the INPVS_YES_THISFRAME flag if it's in this frame at all, so we - // don't tell the entity it's not in the PVS anymore at the end of the frame. - if ( !( pInfo->m_InPVSStatus & INPVS_THISFRAME ) ) - { - if ( g_pClientLeafSystem->IsRenderableInPVS( pInfo->m_pRenderable ) ) - { - pInfo->m_InPVSStatus |= INPVS_THISFRAME; - } - } - } - else - { - // This entity doesn't think it's in the PVS yet. If it is now in the PVS, let it know. - if ( g_pClientLeafSystem->IsRenderableInPVS( pInfo->m_pRenderable ) ) - { - pInfo->m_pNotify->OnPVSStatusChanged( true ); - pInfo->m_InPVSStatus |= INPVS_YES; - pInfo->m_InPVSStatus |= INPVS_THISFRAME; - } - } - } -} - -//----------------------------------------------------------------------------- -// Debugging aid to display a texture -//----------------------------------------------------------------------------- -#ifdef _XBOX -static void OverlayShowTexture( const char* textureName, float scale ) -{ - bool foundVar; - IMaterial *pMaterial; - IMaterialVar *BaseTextureVar; - ITexture *pTex; - float x, y, w, h; - - // screen safe - x = 32; - y = 32; - - pMaterial = materials->FindMaterial( "___debug", TEXTURE_GROUP_OTHER, true ); - BaseTextureVar = pMaterial->FindVar( "$basetexture", &foundVar, false ); - if (!foundVar) - return; - - if ( textureName && textureName[0] ) - { - pTex = materials->FindTexture( textureName, TEXTURE_GROUP_OTHER, false ); - BaseTextureVar->SetTextureValue( pTex ); - - w = pTex->GetActualWidth() * scale; - h = pTex->GetActualHeight() * scale; - } - else - { - w = h = 64.0f * scale; - } - - materials->Bind( pMaterial ); - IMesh* pMesh = materials->GetDynamicMesh( true ); - - CMeshBuilder meshBuilder; - meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 ); - meshBuilder.Position3f( x, y, 0.0f ); - meshBuilder.TexCoord2f( 0, 0.0f, 0.0f ); - meshBuilder.AdvanceVertex(); - meshBuilder.Position3f( x+w, y, 0.0f ); - meshBuilder.TexCoord2f( 0, 1.0f, 0.0f ); - meshBuilder.AdvanceVertex(); - meshBuilder.Position3f( x+w, y+h, 0.0f ); - meshBuilder.TexCoord2f( 0, 1.0f, 1.0f ); - meshBuilder.AdvanceVertex(); - meshBuilder.Position3f( x, x+h, 0.0f ); - meshBuilder.TexCoord2f( 0, 0.0f, 1.0f ); - meshBuilder.AdvanceVertex(); - meshBuilder.End(); - pMesh->Draw(); -} -#endif - -extern ConVar cl_leveloverview; -//----------------------------------------------------------------------------- -// Purpose: Builds lists of things to render in the world, called once per view -//----------------------------------------------------------------------------- -void CViewRender::BuildWorldRenderLists( const CViewSetup *pView, - ClientWorldListInfo_t& info, bool bUpdateLightmaps, bool bDrawEntities, int iForceViewLeaf ) -{ - VPROF_BUDGET( "BuildWorldRenderLists", VPROF_BUDGETGROUP_WORLD_RENDERING ); - - // Server entities already know which ones are in the PVS, but client-only entities don't. - // We need to know which client-only entities are in the PVS at this point so the shadow - // manager can project/occlude their shadows correctly. - UpdateClientRenderableInPVSStatus(); - - ++m_BuildWorldListsNumber; - // Override vis data if specified this render, otherwise use default behavior with NULL - VisOverrideData_t* pVisData = (m_bOverrideVisData)?(&m_VisData):(NULL); - render->BuildWorldLists_VisOverride( &info, bUpdateLightmaps, iForceViewLeaf, pVisData ); - - // Return to default area portal behavior by using the CurrentView as the starting area - m_bOverrideVisData = false; - m_iForceViewLeaf = -1; - - if ( bDrawEntities ) - { - // Now that we have the list of all leaves, regenerate shadows cast - g_pClientShadowMgr->ComputeShadowTextures( pView, info.m_LeafCount, info.m_pLeafList ); - - // Compute the prop opacity based on the view position and fov zoom scale - float flFactor = 1.0f; - C_BasePlayer *pLocal = C_BasePlayer::GetLocalPlayer(); - if ( pLocal ) - { - flFactor = pLocal->GetFOVDistanceAdjustFactor(); - } - - if ( cl_leveloverview.GetFloat() > 0 ) - { - // disable prop fading - flFactor = -1; - } - - // When zoomed in, tweak the opacity to stay visible from further away - staticpropmgr->ComputePropOpacity( CurrentViewOrigin(), flFactor ); - - // Build a list of detail props to render - DetailObjectSystem()->BuildDetailObjectRenderLists(); - } -} - - -//----------------------------------------------------------------------------- -// Purpose: Computes the actual world list info based on the render flags -//----------------------------------------------------------------------------- -ClientWorldListInfo_t *CViewRender::ComputeActualWorldListInfo( const ClientWorldListInfo_t& info, int nDrawFlags, ClientWorldListInfo_t& tmpInfo ) -{ - // Drawing everything? Just return the world list info as-is - int nWaterDrawFlags = nDrawFlags & (DF_RENDER_UNDERWATER | DF_RENDER_ABOVEWATER); - if ( nWaterDrawFlags == (DF_RENDER_UNDERWATER | DF_RENDER_ABOVEWATER) ) - return const_cast(&info); - - tmpInfo.m_ViewFogVolume = info.m_ViewFogVolume; - tmpInfo.m_LeafCount = 0; - - // Not drawing anything? Then don't bother with renderable lists - if ( nWaterDrawFlags == 0 ) - return &tmpInfo; - - // Create a sub-list based on the actual leaves being rendered - bool bRenderingUnderwater = (nWaterDrawFlags & DF_RENDER_UNDERWATER) != 0; - for ( int i = 0; i < info.m_LeafCount; ++i ) - { - bool bLeafIsUnderwater = ( info.m_pLeafFogVolume[i] != -1 ); - if ( bRenderingUnderwater == bLeafIsUnderwater ) - { - tmpInfo.m_pLeafList[ tmpInfo.m_LeafCount ] = info.m_pLeafList[ i ]; - tmpInfo.m_pLeafFogVolume[ tmpInfo.m_LeafCount ] = info.m_pLeafFogVolume[ i ]; - tmpInfo.m_pActualLeafIndex[ tmpInfo.m_LeafCount ] = i; - ++tmpInfo.m_LeafCount; - } - } - - return &tmpInfo; -} - - -//----------------------------------------------------------------------------- -// Purpose: Builds render lists for renderables. Called once for refraction, once for over water -//----------------------------------------------------------------------------- -void CViewRender::BuildRenderableRenderLists( const CViewSetup *pView, ClientWorldListInfo_t& info, CRenderList &renderList ) -{ - MDLCACHE_CRITICAL_SECTION(); - ++m_BuildRenderableListsNumber; - - // For better sorting, find out the leaf *nearest* to the camera - // and render translucent objects as if they are in that leaf. - if( ShouldDrawEntities() ) - { - ClientLeafSystem()->ComputeTranslucentRenderLeaf( - info.m_LeafCount, info.m_pLeafList, info.m_pLeafFogVolume, m_BuildRenderableListsNumber ); - } - - SetupRenderList( pView, info, renderList ); -} - - -//----------------------------------------------------------------------------- -// Computes draw flags for the engine to build its world surface lists -//----------------------------------------------------------------------------- -static inline unsigned long BuildDrawFlags( bool bDrawSkybox, bool bDrawUnderWater, bool bDrawAboveWater, bool bDrawWaterSurface, bool bClipSkybox ) -{ - unsigned long nEngineFlags = 0; - - if ( bDrawSkybox ) - { - nEngineFlags |= DRAWWORLDLISTS_DRAW_SKYBOX; - } - - if ( bDrawAboveWater ) - { - nEngineFlags |= DRAWWORLDLISTS_DRAW_STRICTLYABOVEWATER; - nEngineFlags |= DRAWWORLDLISTS_DRAW_INTERSECTSWATER; - } - - if ( bDrawUnderWater ) - { - nEngineFlags |= DRAWWORLDLISTS_DRAW_STRICTLYUNDERWATER; - nEngineFlags |= DRAWWORLDLISTS_DRAW_INTERSECTSWATER; - } - - if ( bDrawWaterSurface ) - { - nEngineFlags |= DRAWWORLDLISTS_DRAW_WATERSURFACE; - } - - if( bClipSkybox ) - { - nEngineFlags |= DRAWWORLDLISTS_DRAW_CLIPSKYBOX; - } - - return nEngineFlags; -} - -void CViewRender::DrawWorld( ClientWorldListInfo_t& info, CRenderList &renderList, int flags, float waterZAdjust ) -{ - VPROF_INCREMENT_COUNTER( "RenderWorld", 1 ); - VPROF_BUDGET( "DrawWorld", VPROF_BUDGETGROUP_WORLD_RENDERING ); - if( !r_drawopaqueworld.GetBool() ) - { - return; - } - - bool drawSkybox = (flags & DF_DRAWSKYBOX) != 0; - bool drawUnderWater = (flags & DF_RENDER_UNDERWATER) != 0; - bool drawAboveWater = (flags & DF_RENDER_ABOVEWATER) != 0; - bool drawWaterSurface = (flags & DF_RENDER_WATER) != 0; - bool bClipSkybox = (flags & DF_CLIP_SKYBOX ) != 0; - - unsigned long engineFlags = BuildDrawFlags( drawSkybox, drawUnderWater, drawAboveWater, drawWaterSurface, bClipSkybox ); - if ( flags & DF_MAINTAINWORLDLISTS ) - { - engineFlags |= DRAWWORLDLISTS_MAINTAIN_RENDER_LISTS; - } - - int oldDrawFlags = m_DrawFlags; - m_DrawFlags |= flags; - - render->DrawWorldLists( engineFlags, waterZAdjust ); - - m_DrawFlags = oldDrawFlags; -} - -static inline void DrawOpaqueRenderable( IClientRenderable *pEnt, bool twoPass ) -{ - float color[3]; - - pEnt->GetColorModulation( color ); - render->SetColorModulation( color ); - - - int flags = STUDIO_RENDER; - if (twoPass) - { - flags |= STUDIO_TWOPASS; - } - - float *pRenderClipPlane = NULL; - - if( !materials->UsingFastClipping() && //do NOT change the fast clip plane mid-scene, depth problems result. Regular user clip planes are fine though - r_entityclips.GetBool() ) //checking here reduces the r_entityclips.GetBool() check from 2 times to 1 - pRenderClipPlane = pEnt->GetRenderClipPlane(); - - if( pRenderClipPlane ) - materials->PushCustomClipPlane( pRenderClipPlane ); - - pEnt->DrawModel( flags ); - - if( pRenderClipPlane ) - materials->PopCustomClipPlane(); -} - - -static inline void DrawTranslucentRenderable( IClientRenderable *pEnt, bool twoPass ) -{ - // Determine blending amount and tell engine - float blend = (float)( pEnt->GetFxBlend() / 255.0f ); - - // Totally gone - if ( blend <= 0.0f ) - return; - - // Tell engine - render->SetBlend( blend ); - - float color[3]; - pEnt->GetColorModulation( color ); - render->SetColorModulation( color ); - - int flags = STUDIO_RENDER | STUDIO_TRANSPARENCY; - if (twoPass) - flags |= STUDIO_TWOPASS; - -#if 0 - Vector mins, maxs; - pEnt->GetRenderBounds( mins, maxs ); - debugoverlay->AddBoxOverlay( pEnt->GetRenderOrigin(), mins, maxs, pEnt->GetRenderAngles(), 255, 255, 255, 64, 0.01 ); - if ( pEnt->GetModel() ) - { - const char *pName = modelinfo->GetModelName( pEnt->GetModel() ); - if ( Q_stricmp( pName, "models/props_c17/tv_monitor01_screen.mdl" ) ) - { - debugoverlay->AddTextOverlay( pEnt->GetRenderOrigin(), 0.01, pName ); - } - } -#endif - - - - float *pRenderClipPlane = NULL; - - if( !materials->UsingFastClipping() && //do NOT change the fast clip plane mid-scene, depth problems result. Regular user clip planes are fine though - r_entityclips.GetBool() ) //checking here reduces the r_entityclips.GetBool() check from 2 times to 1 - pRenderClipPlane = pEnt->GetRenderClipPlane(); - - if( pRenderClipPlane ) - materials->PushCustomClipPlane( pRenderClipPlane ); - - pEnt->DrawModel( flags ); - - if( pRenderClipPlane ) - materials->PopCustomClipPlane(); -} - - -//----------------------------------------------------------------------------- -// Draws all opaque renderables in leaves that were rendered -//----------------------------------------------------------------------------- -void CViewRender::DrawOpaqueRenderables( ClientWorldListInfo_t& info, CRenderList &renderList ) -{ - VPROF("CViewRender::DrawOpaqueRenderables"); - - if( !r_drawopaquerenderables.GetBool() ) - return; - - if( !ShouldDrawEntities() ) - return; - - render->SetBlend( 1 ); - - // Iterate over all leaves that were visible, and draw opaque things in them. - RopeManager()->ResetRenderCache(); - - // Iterate over all leaves that were visible, and draw opaque things in them. - int i; - - // first do the brush models - CRenderList::CEntry *pEntities = renderList.m_RenderGroups[RENDER_GROUP_OPAQUE_BRUSH]; - int nOpaque = renderList.m_RenderGroupCounts[RENDER_GROUP_OPAQUE_BRUSH]; - for( i=0; i < nOpaque; ++i ) - { - Assert(pEntities[i].m_TwoPass==0); - DrawOpaqueRenderable( pEntities[i].m_pRenderable, false ); - } - - // now the static props - pEntities = renderList.m_RenderGroups[RENDER_GROUP_OPAQUE_STATIC]; - nOpaque = renderList.m_RenderGroupCounts[RENDER_GROUP_OPAQUE_STATIC]; - if ( nOpaque ) - { - nOpaque = min( nOpaque, 512 ); - - IClientRenderable *pStatics[512]; - for( i=0; i < nOpaque; ++i ) - { - pStatics[i] = pEntities[i].m_pRenderable; - } - staticpropmgr->DrawStaticProps( pStatics, nOpaque ); - } - - - // now the other opaque entities - pEntities = renderList.m_RenderGroups[RENDER_GROUP_OPAQUE_ENTITY]; - nOpaque = renderList.m_RenderGroupCounts[RENDER_GROUP_OPAQUE_ENTITY]; - - for( i=0; i < nOpaque; ++i ) - { - DrawOpaqueRenderable( pEntities[i].m_pRenderable, (pEntities[i].m_TwoPass != 0) ); - } - - RopeManager()->DrawRenderCache(); -} - - -//----------------------------------------------------------------------------- -// Renders all translucent world + detail objects in a particular set of leaves -//----------------------------------------------------------------------------- -void CViewRender::DrawTranslucentWorldInLeaves( int iCurLeafIndex, int iFinalLeafIndex, ClientWorldListInfo_t &info, int nDrawFlags ) -{ - VPROF_BUDGET( "CViewRender::DrawTranslucentWorldInLeaves", VPROF_BUDGETGROUP_WORLD_RENDERING ); - for( ; iCurLeafIndex >= iFinalLeafIndex; iCurLeafIndex-- ) - { - int nActualLeafIndex = info.m_pActualLeafIndex ? info.m_pActualLeafIndex[ iCurLeafIndex ] : iCurLeafIndex; - Assert( nActualLeafIndex != INVALID_LEAF_INDEX ); - if ( render->LeafContainsTranslucentSurfaces( nActualLeafIndex, nDrawFlags ) ) - { - // Now draw the surfaces in this leaf - render->DrawTranslucentSurfaces( nActualLeafIndex, nDrawFlags ); - } - } -} - - -//----------------------------------------------------------------------------- -// Renders all translucent world + detail objects in a particular set of leaves -//----------------------------------------------------------------------------- -void CViewRender::DrawTranslucentWorldAndDetailPropsInLeaves( int iCurLeafIndex, int iFinalLeafIndex, - ClientWorldListInfo_t &info, int nDrawFlags, int &nDetailLeafCount, LeafIndex_t* pDetailLeafList ) -{ - VPROF_BUDGET( "CViewRender::DrawTranslucentWorldAndDetailPropsInLeaves", VPROF_BUDGETGROUP_WORLD_RENDERING ); - for( ; iCurLeafIndex >= iFinalLeafIndex; iCurLeafIndex-- ) - { - int nActualLeafIndex = info.m_pActualLeafIndex ? info.m_pActualLeafIndex[ iCurLeafIndex ] : iCurLeafIndex; - Assert( nActualLeafIndex != INVALID_LEAF_INDEX ); - if ( render->LeafContainsTranslucentSurfaces( nActualLeafIndex, nDrawFlags ) ) - { - // First draw any queued-up detail props from previously visited leaves - DetailObjectSystem()->RenderTranslucentDetailObjects( CurrentViewOrigin(), CurrentViewForward(), nDetailLeafCount, pDetailLeafList ); - nDetailLeafCount = 0; - - // Now draw the surfaces in this leaf - render->DrawTranslucentSurfaces( nActualLeafIndex, nDrawFlags ); - } - - // Queue up detail props that existed in this leaf - if ( ClientLeafSystem()->ShouldDrawDetailObjectsInLeaf( info.m_pLeafList[iCurLeafIndex], m_BuildWorldListsNumber ) ) - { - pDetailLeafList[nDetailLeafCount] = info.m_pLeafList[iCurLeafIndex]; - ++nDetailLeafCount; - } - } -} - - -//----------------------------------------------------------------------------- -// Renders all translucent entities in the render list -//----------------------------------------------------------------------------- -void CViewRender::DrawTranslucentRenderablesNoWorld( CRenderList &renderList, bool bInSkybox ) -{ - VPROF( "CViewRender::DrawTranslucentRenderablesNoWorld" ); - - if ( !ShouldDrawEntities() || !r_drawtranslucentrenderables.GetBool() ) - return; - - // Draw the particle singletons. - DrawParticleSingletons( bInSkybox ); - - CRenderList::CEntry *pEntities = renderList.m_RenderGroups[RENDER_GROUP_TRANSLUCENT_ENTITY]; - int iCurTranslucentEntity = renderList.m_RenderGroupCounts[RENDER_GROUP_TRANSLUCENT_ENTITY] - 1; - - while( iCurTranslucentEntity >= 0 ) - { - IClientRenderable *pRenderable = pEntities[iCurTranslucentEntity].m_pRenderable; - if ( pRenderable->UsesFrameBufferTexture() ) - { - UpdateRefractTexture(); - } - DrawTranslucentRenderable( pRenderable, (pEntities[iCurTranslucentEntity].m_TwoPass != 0) ); - --iCurTranslucentEntity; - } - - // Reset the blend state. - render->SetBlend( 1 ); -} - -//----------------------------------------------------------------------------- -// Renders all translucent world, entities, and detail objects in a particular set of leaves -//----------------------------------------------------------------------------- -void CViewRender::DrawTranslucentRenderables( ClientWorldListInfo_t& info, CRenderList &renderList, - int nFlags, bool bInSkybox ) -{ - if ( !r_drawtranslucentworld.GetBool() ) - { - DrawTranslucentRenderablesNoWorld( renderList, bInSkybox ); - return; - } - - VPROF( "CViewRender::DrawTranslucentRenderables" ); - int iPrevLeaf = info.m_LeafCount - 1; - int nDetailLeafCount = 0; - LeafIndex_t *pDetailLeafList = (LeafIndex_t*)stackalloc( info.m_LeafCount * sizeof(LeafIndex_t) ); - - bool bDrawUnderWater = (nFlags & DF_RENDER_UNDERWATER) != 0; - bool bDrawAboveWater = (nFlags & DF_RENDER_ABOVEWATER) != 0; - bool bDrawWater = (nFlags & DF_RENDER_WATER) != 0; - bool bClipSkybox = (nFlags & DF_CLIP_SKYBOX ) != 0; - unsigned long nDrawFlags = BuildDrawFlags( false, bDrawUnderWater, bDrawAboveWater, bDrawWater, bClipSkybox ); - - DetailObjectSystem()->BeginTranslucentDetailRendering(); - - if ( ShouldDrawEntities() && r_drawtranslucentrenderables.GetBool() ) - { - // Draw the particle singletons. - DrawParticleSingletons( bInSkybox ); - - CRenderList::CEntry *pEntities = renderList.m_RenderGroups[RENDER_GROUP_TRANSLUCENT_ENTITY]; - int iCurTranslucentEntity = renderList.m_RenderGroupCounts[RENDER_GROUP_TRANSLUCENT_ENTITY] - 1; - - bool bRenderingWaterRenderTargets = nFlags & ( DF_RENDER_REFRACTION | DF_RENDER_REFLECTION ); - - while( iCurTranslucentEntity >= 0 ) - { - // Seek the current leaf up to our current translucent-entity leaf. - int iThisLeaf = pEntities[iCurTranslucentEntity].m_iWorldListInfoLeaf; - - // First draw the translucent parts of the world up to and including those in this leaf - DrawTranslucentWorldAndDetailPropsInLeaves( iPrevLeaf, iThisLeaf, info, nDrawFlags, nDetailLeafCount, pDetailLeafList ); - - // We're traversing the leaf list backwards to get the appropriate sort ordering (back to front) - iPrevLeaf = iThisLeaf - 1; - - // Draw all the translucent entities with this leaf. - int nLeaf = info.m_pLeafList[iThisLeaf]; - - bool bDrawDetailProps = ClientLeafSystem()->ShouldDrawDetailObjectsInLeaf( nLeaf, m_BuildWorldListsNumber ); - if ( bDrawDetailProps ) - { - // Draw detail props up to but not including this leaf - Assert( nDetailLeafCount > 0 ); - --nDetailLeafCount; - Assert( pDetailLeafList[nDetailLeafCount] == nLeaf ); - DetailObjectSystem()->RenderTranslucentDetailObjects( CurrentViewOrigin(), CurrentViewForward(), nDetailLeafCount, pDetailLeafList ); - - // Draw translucent renderables in the leaf interspersed with detail props - for( ;pEntities[iCurTranslucentEntity].m_iWorldListInfoLeaf == iThisLeaf && iCurTranslucentEntity >= 0; --iCurTranslucentEntity ) - { - MDLCACHE_CRITICAL_SECTION(); - IClientRenderable *pRenderable = pEntities[iCurTranslucentEntity].m_pRenderable; - - // Draw any detail props in this leaf that's farther than the entity - const Vector &vecRenderOrigin = pRenderable->GetRenderOrigin(); - DetailObjectSystem()->RenderTranslucentDetailObjectsInLeaf( - CurrentViewOrigin(), CurrentViewForward(), nLeaf, &vecRenderOrigin ); - - if ( pRenderable->UsesFrameBufferTexture() ) - { - if( bRenderingWaterRenderTargets ) - { - continue; - } - UpdateRefractTexture(); - } - - // Then draw the translucent renderable - DrawTranslucentRenderable( pRenderable, (pEntities[iCurTranslucentEntity].m_TwoPass != 0) ); - } - - // Draw all remaining props in this leaf - DetailObjectSystem()->RenderTranslucentDetailObjectsInLeaf( CurrentViewOrigin(), CurrentViewForward(), nLeaf, NULL ); - } - else - { - // Draw queued up detail props (we know that the list of detail leaves won't include this leaf, since ShouldDrawDetailObjectsInLeaf is false) - // Therefore no fixup on nDetailLeafCount is required as in the above section - DetailObjectSystem()->RenderTranslucentDetailObjects( CurrentViewOrigin(), CurrentViewForward(), nDetailLeafCount, pDetailLeafList ); - - for( ;pEntities[iCurTranslucentEntity].m_iWorldListInfoLeaf == iThisLeaf && iCurTranslucentEntity >= 0; --iCurTranslucentEntity ) - { - - MDLCACHE_CRITICAL_SECTION(); - IClientRenderable *pRenderable = pEntities[iCurTranslucentEntity].m_pRenderable; - if ( pRenderable->UsesFrameBufferTexture() ) - { - if( bRenderingWaterRenderTargets ) - { - continue; - } - UpdateRefractTexture(); - } - DrawTranslucentRenderable( pRenderable, (pEntities[iCurTranslucentEntity].m_TwoPass != 0) ); - - } - } - - nDetailLeafCount = 0; - } - } - - // Draw the rest of the surfaces in world leaves - DrawTranslucentWorldAndDetailPropsInLeaves( iPrevLeaf, 0, info, nDrawFlags, nDetailLeafCount, pDetailLeafList ); - - // Draw any queued-up detail props from previously visited leaves - DetailObjectSystem()->RenderTranslucentDetailObjects( CurrentViewOrigin(), CurrentViewForward(), nDetailLeafCount, pDetailLeafList ); - - // Reset the blend state. - render->SetBlend( 1 ); -} - - -//----------------------------------------------------------------------------- -// Renders the shadow texture to screen... -//----------------------------------------------------------------------------- -static void RenderMaterial( const char *pMaterialName ) -{ - // So it's not in the very top left - float x = 100.0f, y = 100.0f; - // float x = 0.0f, y = 0.0f; - - IMaterial *pMaterial = materials->FindMaterial( pMaterialName, TEXTURE_GROUP_OTHER, false ); - if ( !IsErrorMaterial( pMaterial ) ) - { - materials->Bind( pMaterial ); - IMesh* pMesh = materials->GetDynamicMesh( true ); - - CMeshBuilder meshBuilder; - meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 ); - - meshBuilder.Position3f( x, y, 0.0f ); - meshBuilder.TexCoord2f( 0, 0.0f, 0.0f ); - meshBuilder.Color4ub( 255, 255, 255, 255 ); - meshBuilder.AdvanceVertex(); - - meshBuilder.Position3f( x + pMaterial->GetMappingWidth(), y, 0.0f ); - meshBuilder.TexCoord2f( 0, 1.0f, 0.0f ); - meshBuilder.Color4ub( 255, 255, 255, 255 ); - meshBuilder.AdvanceVertex(); - - meshBuilder.Position3f( x + pMaterial->GetMappingWidth(), y + pMaterial->GetMappingHeight(), 0.0f ); - meshBuilder.TexCoord2f( 0, 1.0f, 1.0f ); - meshBuilder.Color4ub( 255, 255, 255, 255 ); - meshBuilder.AdvanceVertex(); - - meshBuilder.Position3f( x, y + pMaterial->GetMappingHeight(), 0.0f ); - meshBuilder.TexCoord2f( 0, 0.0f, 1.0f ); - meshBuilder.Color4ub( 255, 255, 255, 255 ); - meshBuilder.AdvanceVertex(); - - meshBuilder.End(); - pMesh->Draw(); - } -} - - -//----------------------------------------------------------------------------- -// Draws the screen effect -//----------------------------------------------------------------------------- -static void DrawScreenEffectMaterial( IMaterial *pMaterial, int x, int y, int w, int h ) -{ - Rect_t actualRect; - UpdateScreenEffectTexture( 0, x, y, w, h, false, &actualRect ); - ITexture *pTexture = GetFullFrameFrameBufferTexture( 0 ); - - materials->DrawScreenSpaceRectangle( pMaterial, x, y, w, h, - actualRect.x, actualRect.y, actualRect.x+actualRect.width-1, actualRect.y+actualRect.height-1, - pTexture->GetActualWidth(), pTexture->GetActualHeight() ); -} - -//----------------------------------------------------------------------------- -// Purpose: Performs screen space effects, if any -//----------------------------------------------------------------------------- -void CViewRender::PerformScreenSpaceEffects( int x, int y, int w, int h ) -{ - VPROF("CViewRender::PerformScreenSpaceEffects()"); - - // FIXME: Screen-space effects are busted in the editor - if ( engine->IsHammerRunning() ) - return; - - g_pScreenSpaceEffects->RenderEffects( x, y, w, h ); -} - - -//----------------------------------------------------------------------------- -// Purpose: Sets the screen space effect material (can't be done during rendering) -//----------------------------------------------------------------------------- -void CViewRender::SetScreenOverlayMaterial( IMaterial *pMaterial ) -{ - m_ScreenOverlayMaterial.Init( pMaterial ); -} - -IMaterial *CViewRender::GetScreenOverlayMaterial( ) -{ - return m_ScreenOverlayMaterial; -} - - -//----------------------------------------------------------------------------- -// Purpose: Performs screen space effects, if any -//----------------------------------------------------------------------------- -void CViewRender::PerformScreenOverlay( int x, int y, int w, int h ) -{ - VPROF("CViewRender::PerformScreenOverlay()"); - - if (m_ScreenOverlayMaterial) - { - if ( m_ScreenOverlayMaterial->NeedsFullFrameBufferTexture() ) - { - DrawScreenEffectMaterial( m_ScreenOverlayMaterial, x, y, w, h ); - } - else if ( m_ScreenOverlayMaterial->NeedsPowerOfTwoFrameBufferTexture() ) - { - // First copy the FB off to the offscreen texture - UpdateRefractTexture( x, y, w, h, true ); - - // Now draw the entire screen using the material... - ITexture *pTexture = GetPowerOfTwoFrameBufferTexture( ); - int sw = pTexture->GetActualWidth(); - int sh = pTexture->GetActualHeight(); - materials->DrawScreenSpaceRectangle( m_ScreenOverlayMaterial, x, y, w, h, - 0, 0, sw-1, sh-1, sw, sh ); - } - else - { - byte color[4] = { 255, 255, 255, 255 }; - render->ViewDrawFade( color, m_ScreenOverlayMaterial ); - } - } -} - - -//----------------------------------------------------------------------------- -// Purpose: Renders world and all entities, etc. -//----------------------------------------------------------------------------- -#include "tier0/memdbgoff.h" - -void CViewRender::DrawWorldAndEntities( bool bDrawSkybox, const CViewSetup &view, int nClearFlags ) -{ - VPROF("CViewRender::DrawWorldAndEntities"); - MDLCACHE_CRITICAL_SECTION(); - - ClientWorldListInfo_t info; -#ifndef _XBOX - CRenderList renderList; -#else - void *ptr = MemAllocScratch(sizeof(CRenderList)); - CRenderList *renderList = new (ptr) CRenderList; -#endif - - EnableWorldFog(); - - int nFlags = DF_RENDER_UNDERWATER | DF_RENDER_ABOVEWATER | DF_RENDER_WATER; - if (bDrawSkybox) - { - nFlags |= DF_DRAWSKYBOX; - } - - render->Push3DView( view, nClearFlags, false, NULL, m_Frustum ); - - BuildWorldRenderLists( &view, info, true, true, m_iForceViewLeaf ); -#ifndef _XBOX - BuildRenderableRenderLists( &view, info, renderList ); -#else - BuildRenderableRenderLists( &view, info, *renderList ); -#endif - - // Make sure sound doesn't stutter - engine->Sound_ExtraUpdate(); - - m_DrawFlags = m_BaseDrawFlags; -#ifndef _XBOX - DrawWorld( info, renderList, nFlags, 0.0f ); - DrawOpaqueRenderables( info, renderList ); - DrawTranslucentRenderables( info, renderList, nFlags, false ); -#else - DrawWorld( info, *renderList, nFlags, 0.0f ); - DrawOpaqueRenderables( info, *renderList ); - DrawTranslucentRenderables( info, *renderList, nFlags, false ); - MemFreeScratch(); -#endif - - m_DrawFlags = 0; - - ParticleMgr()->DrawBeforeViewModelEffects(); - - render->PopView( m_Frustum ); -} - -#include "tier0/memdbgon.h" - - -//----------------------------------------------------------------------------- -// Computes us some geometry to render the frustum planes -//----------------------------------------------------------------------------- -void CViewRender::ComputeFrustumRenderGeometry( Vector pRenderPoint[8] ) -{ - Vector viewPoint = CurrentViewOrigin(); - - // Find lines along each of the plane intersections. - // We know these lines are perpendicular to both plane normals, - // so we can take the cross product to find them. - static int edgeIdx[4][2] = - { - { 0, 2 }, { 0, 3 }, { 1, 3 }, { 1, 2 } - }; - - int i; - Vector edges[4]; - for ( i = 0; i < 4; ++i) - { - CrossProduct( GetFrustum()[edgeIdx[i][0]].m_Normal, - GetFrustum()[edgeIdx[i][1]].m_Normal, edges[i] ); - VectorNormalize( edges[i] ); - } - - // Figure out four near points by intersection lines with the near plane - // Figure out four far points by intersection with lines against far plane - for (i = 0; i < 4; ++i) - { - float t = (GetFrustum()[4].m_Dist - DotProduct(GetFrustum()[4].m_Normal, viewPoint)) / - DotProduct(GetFrustum()[4].m_Normal, edges[i]); - VectorMA( viewPoint, t, edges[i], pRenderPoint[i] ); - - /* - t = (m_FrustumPlanes[5][3] - DotProduct(GetFrustum()[5], viewPoint)) / - DotProduct(GetFrustum()[5], edges[i]); - VectorMA( viewPoint, t, edges[i], pRenderPoint[i + 4] ); - */ - if (t < 0) - { - edges[i] *= -1; - } - - VectorMA( pRenderPoint[i], 200.0, edges[i], pRenderPoint[i + 4] ); - } -} - - -//----------------------------------------------------------------------------- -// renders the frustum -//----------------------------------------------------------------------------- -void CViewRender::RenderFrustum( ) -{ - static int indices[] = - { - 0, 1, 1, 2, 2, 3, 3, 0, // near square - 4, 5, 5, 6, 6, 7, 7, 4, // far square - 0, 4, 1, 5, 2, 6, 3, 7 // connections between them - }; - - int numIndices = sizeof(indices) / sizeof(int); - - Vector vecFrustumRenderPoint[8]; - ComputeFrustumRenderGeometry( vecFrustumRenderPoint ); - - int i; - for ( i = 0; i < numIndices; i += 2 ) - { - debugoverlay->AddLineOverlay( vecFrustumRenderPoint[indices[i]], - vecFrustumRenderPoint[indices[i+1]], 0, 0, 255, 255, 1.0f ); - } -} - - -//----------------------------------------------------------------------------- -// Draws all the debugging info -//----------------------------------------------------------------------------- -void CViewRender::Draw3DDebuggingInfo( const CViewSetup &view ) -{ - VPROF("CViewRender::Draw3DDebuggingInfo"); - - // Draw 3d overlays - render->Draw3DDebugOverlays(); - - // Draw the line file used for debugging leaks - render->DrawLineFile(); - - // Draw client side effects - // NOTE: These are not sorted against the rest of the frame - clienteffects->DrawEffects( gpGlobals->frametime ); - - // Mark the frame as locked down for client fx additions - SetFXCreationAllowed( false ); -} - - -//----------------------------------------------------------------------------- -// Draws all the debugging info -//----------------------------------------------------------------------------- -void CViewRender::Draw2DDebuggingInfo( const CViewSetup &view ) -{ - if ( IsXbox() && IsRetail() ) - return; - - // HDRFIXME: Assert NULL rendertarget - if ( mat_yuv.GetInt() && (engine->GetDXSupportLevel() >= 80) ) - { - IMaterial *pMaterial; - pMaterial = materials->FindMaterial( "debug/yuv", TEXTURE_GROUP_OTHER, true ); - if( !IsErrorMaterial( pMaterial ) ) - { - DrawScreenEffectMaterial( pMaterial, view.x, view.y, view.width, view.height ); - } - } - -#ifndef _XBOX - if ( mat_hsv.GetInt() && (engine->GetDXSupportLevel() >= 90) ) - { - IMaterial *pMaterial; - pMaterial = materials->FindMaterial( "debug/hsv", TEXTURE_GROUP_OTHER, true ); - if( !IsErrorMaterial( pMaterial ) ) - { - DrawScreenEffectMaterial( pMaterial, view.x, view.y, view.width, view.height ); - } - } -#endif - - // Draw debugging lightmaps - render->DrawLightmaps(); - - if ( cl_drawshadowtexture.GetInt() ) - { - g_pClientShadowMgr->RenderShadowTexture( 256, 256 ); - } - - const char *pDrawMaterial = cl_drawmaterial.GetString(); - if ( pDrawMaterial && pDrawMaterial[0] ) - { - RenderMaterial( pDrawMaterial ); - } - - if ( mat_showwatertextures.GetBool() ) - { - OverlayWaterTextures(); - } - - if ( mat_showcamerarendertarget.GetBool() ) - { - float w = mat_wateroverlaysize.GetFloat(); - float h = mat_wateroverlaysize.GetFloat(); - OverlayCameraRenderTarget( "debug/debugcamerarendertarget", 0, 0, w, h ); - } - - if ( mat_showframebuffertexture.GetBool() ) - { - // HDRFIXME: Get rid of these rendertarget sets assuming that the assert at the top of this function is true. - materials->PushRenderTargetAndViewport( NULL ); - OverlayFrameBufferTexture( 0 ); - OverlayFrameBufferTexture( 1 ); - materials->PopRenderTargetAndViewport( ); - } - -#ifdef _XBOX - if ( mat_viewTextureEnable.GetBool() ) - { - OverlayShowTexture( mat_viewTextureName.GetString(), mat_viewTextureScale.GetFloat() ); - } -#endif - - if( r_flashlightdrawdepth.GetBool() ) - { - shadowmgr->DrawFlashlightDepthTexture( ); - } -} - - -//----------------------------------------------------------------------------- -// Purpose: Returns the min/max fade distances -//----------------------------------------------------------------------------- -void CViewRender::GetScreenFadeDistances( float *min, float *max ) -{ - if ( min ) - { - *min = r_screenfademinsize.GetFloat(); - } - - if ( max ) - { - *max = r_screenfademaxsize.GetFloat(); - } -} - - -//----------------------------------------------------------------------------- -// Purpose: Renders world and all entities, etc. -//----------------------------------------------------------------------------- -void CViewRender::ViewDrawScene( bool bDrew3dSkybox, bool bSkyboxVisible, const CViewSetup &view, - int nClearFlags, view_id_t viewID, bool bDrawViewModel, int baseDrawFlags ) -{ - VPROF( "CViewRender::ViewDrawScene" ); - - m_BaseDrawFlags = baseDrawFlags; - m_DrawFlags = 0; - - SetupCurrentView( view.origin, view.angles, viewID ); - - // Invoke pre-render methods - IGameSystem::PreRenderAllSystems(); - - // Start view - unsigned int visFlags; - SetupVis( view, visFlags ); - - if ( !bDrew3dSkybox && - !bSkyboxVisible && ( visFlags & IVRenderView::VIEW_SETUP_VIS_EX_RETURN_FLAGS_USES_RADIAL_VIS ) ) - { - // This covers the case where we don't see a 3dskybox, yet radial vis is clipping - // the far plane. Need to clear to fog color in this case. - nClearFlags |= VIEW_CLEAR_COLOR; - unsigned char ucFogColor[3]; - SetClearColorToFogColor( ucFogColor ); - } - - bool drawSkybox = r_skybox.GetBool(); - if ( bDrew3dSkybox || !bSkyboxVisible ) - { - drawSkybox = false; - } - - ParticleMgr()->IncrementFrameCode(); - - WaterDrawWorldAndEntities( drawSkybox, view, nClearFlags ); - - // Disable fog for the rest of the stuff - DisableFog(); - - // UNDONE: Don't do this with masked brush models, they should probably be in a separate list - // render->DrawMaskEntities() - - // Here are the overlays... - - // This is an overlay that goes over everything else - - CGlowOverlay::DrawOverlays( view.m_bCacheFullSceneState ); - - // issue the pixel visibility tests - PixelVisibility_EndCurrentView(); - - // Draw rain.. - DrawPrecipitation(); - - // Make sure sound doesn't stutter - engine->Sound_ExtraUpdate(); - - // Debugging info goes over the top - Draw3DDebuggingInfo( view ); - - // Invoke post-render methods - IGameSystem::PostRenderAllSystems(); - - FinishCurrentView(); - - m_DrawFlags = 0; -} - -void CheckAndTransitionColor( float flPercent, float *pColor, float *pLerpToColor ) -{ - if ( pLerpToColor[0] != pColor[0] || pLerpToColor[1] != pColor[1] || pLerpToColor[2] != pColor[2] ) - { - float flDestColor[3]; - - flDestColor[0] = pLerpToColor[0]; - flDestColor[1] = pLerpToColor[1]; - flDestColor[2] = pLerpToColor[2]; - - pColor[0] = FLerp( pColor[0], flDestColor[0], flPercent ); - pColor[1] = FLerp( pColor[1], flDestColor[1], flPercent ); - pColor[2] = FLerp( pColor[2], flDestColor[2], flPercent ); - } - else - { - pColor[0] = pLerpToColor[0]; - pColor[1] = pLerpToColor[1]; - pColor[2] = pLerpToColor[2]; - } -} - -static void GetFogColorTransition( CPlayerLocalData *local, float *pColorPrimary, float *pColorSecondary ) -{ - if ( local == NULL ) - return; - - if ( local->m_fog.lerptime >= gpGlobals->curtime ) - { - float flPercent = 1.0f - (( local->m_fog.lerptime - gpGlobals->curtime ) / local->m_fog.duration ); - - float flPrimaryColorLerp[3] = { local->m_fog.colorPrimaryLerpTo.GetR(), local->m_fog.colorPrimaryLerpTo.GetG(), local->m_fog.colorPrimaryLerpTo.GetB() }; - float flSecondaryColorLerp[3] = { local->m_fog.colorSecondaryLerpTo.GetR(), local->m_fog.colorSecondaryLerpTo.GetG(), local->m_fog.colorSecondaryLerpTo.GetB() }; - - CheckAndTransitionColor( flPercent, pColorPrimary, flPrimaryColorLerp ); - CheckAndTransitionColor( flPercent, pColorSecondary, flSecondaryColorLerp ); - } -} - -//----------------------------------------------------------------------------- -// Purpose: Returns the fog color to use in rendering the current frame. -//----------------------------------------------------------------------------- -static void GetFogColor( float *pColor ) -{ - C_BasePlayer *pbp = C_BasePlayer::GetLocalPlayer(); - if( !pbp ) - { - return; - } - CPlayerLocalData *local = &pbp->m_Local; - - const char *fogColorString = fog_color.GetString(); - if( fog_override.GetInt() && fogColorString ) - { - sscanf( fogColorString, "%f%f%f", pColor, pColor+1, pColor+2 ); - } - else - { - float flPrimaryColor[3] = { local->m_fog.colorPrimary.GetR(), local->m_fog.colorPrimary.GetG(), local->m_fog.colorPrimary.GetB() }; - float flSecondaryColor[3] = { local->m_fog.colorSecondary.GetR(), local->m_fog.colorSecondary.GetG(), local->m_fog.colorSecondary.GetB() }; - - GetFogColorTransition( local, flPrimaryColor, flSecondaryColor ); - - if( local->m_fog.blend ) - { - // - // Blend between two fog colors based on viewing angle. - // The secondary fog color is at 180 degrees to the primary fog color. - // - Vector forward; - AngleVectors(pbp->GetAbsAngles(), &forward); - - Vector vNormalized = local->m_fog.dirPrimary; - VectorNormalize( vNormalized ); - local->m_fog.dirPrimary = vNormalized; - - float flBlendFactor = 0.5 * forward.Dot( local->m_fog.dirPrimary ) + 0.5; - - // FIXME: convert to linear colorspace - pColor[0] = flPrimaryColor[0] * flBlendFactor + flSecondaryColor[0] * ( 1 - flBlendFactor ); - pColor[1] = flPrimaryColor[1] * flBlendFactor + flSecondaryColor[1] * ( 1 - flBlendFactor ); - pColor[2] = flPrimaryColor[2] * flBlendFactor + flSecondaryColor[2] * ( 1 - flBlendFactor ); - } - else - { - pColor[0] = flPrimaryColor[0]; - pColor[1] = flPrimaryColor[1]; - pColor[2] = flPrimaryColor[2]; - } - } - - VectorScale( pColor, 1.0f / 255.0f, pColor ); -} - - -static float GetFogStart( void ) -{ - C_BasePlayer *pbp = C_BasePlayer::GetLocalPlayer(); - if( !pbp ) - { - return 0.0f; - } - CPlayerLocalData *local = &pbp->m_Local; - - if( fog_override.GetInt() ) - { - if( fog_start.GetFloat() == -1.0f ) - { - return local->m_fog.start; - } - else - { - return fog_start.GetFloat(); - } - } - else - { - if ( local->m_fog.lerptime > gpGlobals->curtime ) - { - if ( local->m_fog.start != local->m_fog.startLerpTo ) - { - if ( local->m_fog.lerptime > gpGlobals->curtime ) - { - float flPercent = 1.0f - (( local->m_fog.lerptime - gpGlobals->curtime ) / local->m_fog.duration ); - - return FLerp( local->m_fog.start, local->m_fog.startLerpTo, flPercent ); - } - else - { - if ( local->m_fog.start != local->m_fog.startLerpTo ) - { - local->m_fog.start = local->m_fog.startLerpTo; - } - } - } - } - - return local->m_fog.start; - } -} - -static float GetFogEnd( void ) -{ - C_BasePlayer *pbp = C_BasePlayer::GetLocalPlayer(); - if( !pbp ) - { - return 0.0f; - } - CPlayerLocalData *local = &pbp->m_Local; - - if( fog_override.GetInt() ) - { - if( fog_end.GetFloat() == -1.0f ) - { - return local->m_fog.end; - } - else - { - return fog_end.GetFloat(); - } - } - else - { - if ( local->m_fog.lerptime > gpGlobals->curtime ) - { - if ( local->m_fog.end != local->m_fog.endLerpTo ) - { - if ( local->m_fog.lerptime > gpGlobals->curtime ) - { - float flPercent = 1.0f - (( local->m_fog.lerptime - gpGlobals->curtime ) / local->m_fog.duration ); - - return FLerp( local->m_fog.end, local->m_fog.endLerpTo, flPercent ); - } - else - { - if ( local->m_fog.end != local->m_fog.endLerpTo ) - { - local->m_fog.end = local->m_fog.endLerpTo; - } - } - } - } - - return local->m_fog.end; - } -} - -static bool GetFogEnable( void ) -{ - C_BasePlayer *pbp = C_BasePlayer::GetLocalPlayer(); - if( !pbp ) - { - return false; - } - CPlayerLocalData *local = &pbp->m_Local; - - if ( cl_leveloverview.GetFloat() > 0 ) - return false; - - // Ask the clientmode - if ( g_pClientMode->ShouldDrawFog() == false ) - return false; - - if( fog_override.GetInt() ) - { - if( fog_enable.GetInt() ) - { - return true; - } - else - { - return false; - } - } - else - { - return local->m_fog.enable != false; - } -} - - -//----------------------------------------------------------------------------- -// Purpose: Returns the skybox fog color to use in rendering the current frame. -//----------------------------------------------------------------------------- -static void GetSkyboxFogColor( float *pColor ) -{ - C_BasePlayer *pbp = C_BasePlayer::GetLocalPlayer(); - if( !pbp ) - { - return; - } - CPlayerLocalData *local = &pbp->m_Local; - - const char *fogColorString = fog_colorskybox.GetString(); - if( fog_override.GetInt() && fogColorString ) - { - sscanf( fogColorString, "%f%f%f", pColor, pColor+1, pColor+2 ); - } - else - { - if( local->m_skybox3d.fog.blend ) - { - // - // Blend between two fog colors based on viewing angle. - // The secondary fog color is at 180 degrees to the primary fog color. - // - Vector forward; - AngleVectors( pbp->GetAbsAngles(), &forward ); - - Vector vNormalized = local->m_fog.dirPrimary; - VectorNormalize( vNormalized ); - local->m_fog.dirPrimary = vNormalized; - - float flBlendFactor = 0.5 * forward.Dot( local->m_fog.dirPrimary ) + 0.5; - - // FIXME: convert to linear colorspace - pColor[0] = local->m_skybox3d.fog.colorPrimary.GetR() * flBlendFactor + local->m_skybox3d.fog.colorSecondary.GetR() * ( 1 - flBlendFactor ); - pColor[1] = local->m_skybox3d.fog.colorPrimary.GetG() * flBlendFactor + local->m_skybox3d.fog.colorSecondary.GetG() * ( 1 - flBlendFactor ); - pColor[2] = local->m_skybox3d.fog.colorPrimary.GetB() * flBlendFactor + local->m_skybox3d.fog.colorSecondary.GetB() * ( 1 - flBlendFactor ); - } - else - { - pColor[0] = local->m_skybox3d.fog.colorPrimary.GetR(); - pColor[1] = local->m_skybox3d.fog.colorPrimary.GetG(); - pColor[2] = local->m_skybox3d.fog.colorPrimary.GetB(); - } - } - - VectorScale( pColor, 1.0f / 255.0f, pColor ); -} - - -static float GetSkyboxFogStart( void ) -{ - C_BasePlayer *pbp = C_BasePlayer::GetLocalPlayer(); - if( !pbp ) - { - return 0.0f; - } - CPlayerLocalData *local = &pbp->m_Local; - - if( fog_override.GetInt() ) - { - if( fog_startskybox.GetFloat() == -1.0f ) - { - return local->m_skybox3d.fog.start; - } - else - { - return fog_startskybox.GetFloat(); - } - } - else - { - return local->m_skybox3d.fog.start; - } -} - -static float GetSkyboxFogEnd( void ) -{ - C_BasePlayer *pbp = C_BasePlayer::GetLocalPlayer(); - if( !pbp ) - { - return 0.0f; - } - CPlayerLocalData *local = &pbp->m_Local; - - if( fog_override.GetInt() ) - { - if( fog_endskybox.GetFloat() == -1.0f ) - { - return local->m_skybox3d.fog.end; - } - else - { - return fog_endskybox.GetFloat(); - } - } - else - { - return local->m_skybox3d.fog.end; - } -} - -static bool GetSkyboxFogEnable( void ) -{ - C_BasePlayer *pbp = C_BasePlayer::GetLocalPlayer(); - if( !pbp ) - { - return false; - } - CPlayerLocalData *local = &pbp->m_Local; - - if( fog_override.GetInt() ) - { - if( fog_enableskybox.GetInt() ) - { - return true; - } - else - { - return false; - } - } - else - { - return !!local->m_skybox3d.fog.enable; - } -} - -void CViewRender::EnableWorldFog( void ) -{ - VPROF("CViewRender::EnableWorldFog"); - if( GetFogEnable() ) - { - float fogColor[3]; - GetFogColor( fogColor ); - materials->FogMode( MATERIAL_FOG_LINEAR ); - materials->FogColor3fv( fogColor ); - materials->FogStart( GetFogStart() ); - materials->FogEnd( GetFogEnd() ); - } - else - { - materials->FogMode( MATERIAL_FOG_NONE ); - } -} - -void CViewRender::Enable3dSkyboxFog( void ) -{ - C_BasePlayer *pbp = C_BasePlayer::GetLocalPlayer(); - if( !pbp ) - { - return; - } - CPlayerLocalData *local = &pbp->m_Local; - - if( GetSkyboxFogEnable() ) - { - float fogColor[3]; - GetSkyboxFogColor( fogColor ); - float scale = 1.0f; - if ( local->m_skybox3d.scale > 0.0f ) - { - scale = 1.0f / local->m_skybox3d.scale; - } - materials->FogMode( MATERIAL_FOG_LINEAR ); - materials->FogColor3fv( fogColor ); - materials->FogStart( GetSkyboxFogStart() * scale ); - materials->FogEnd( GetSkyboxFogEnd() * scale ); - } - else - { - materials->FogMode( MATERIAL_FOG_NONE ); - } -} - -void CViewRender::DisableFog( void ) -{ - VPROF("CViewRander::DisableFog()"); - - materials->FogMode( MATERIAL_FOG_NONE ); -} - -#include "tier0/memdbgoff.h" - -void CViewRender::Draw3dSkyboxworld( const CViewSetup &view, int &nClearFlags, - bool &bDrew3dSkybox, bool &bSkyboxVisible ) -{ - VPROF_BUDGET( "CViewRender::Draw3dSkyboxworld", "3D Skybox" ); - - bDrew3dSkybox = false; - - // The skybox might not be visible from here - bSkyboxVisible = engine->IsSkyboxVisibleFromPoint( view.origin ); - - if ( !bSkyboxVisible && r_3dsky.GetInt() != 2 ) - { - return; - } - - // render the 3D skybox - if ( !r_3dsky.GetInt() ) - { - return; - } - - C_BasePlayer *pbp = C_BasePlayer::GetLocalPlayer(); - - // No local player object yet... - if ( !pbp ) - return; - - CPlayerLocalData* local = &pbp->m_Local; - if ( local->m_skybox3d.area == 255 ) - return; - - unsigned char **areabits = render->GetAreaBits(); - unsigned char *savebits; - unsigned char tmpbits[ 32 ]; - savebits = *areabits; - memset( tmpbits, 0, sizeof(tmpbits) ); - - // set the sky area bit - tmpbits[local->m_skybox3d.area>>3] |= 1 << (local->m_skybox3d.area&7); - - *areabits = tmpbits; - CViewSetup skyView = view; - skyView.zNear = 0.5; - skyView.zFar = 18000; - - // scale origin by sky scale - if ( local->m_skybox3d.scale > 0 ) - { - float scale = 1.0f / local->m_skybox3d.scale; - VectorScale( skyView.origin, scale, skyView.origin ); - } - Enable3dSkyboxFog(); - VectorAdd( skyView.origin, local->m_skybox3d.origin, skyView.origin ); - - skyView.m_vUnreflectedOrigin = skyView.origin; - - // BUGBUG: Fix this!!! We shouldn't need to call setup vis for the sky if we're connecting - // the areas. We'd have to mark all the clusters in the skybox area in the PVS of any - // cluster with sky. Then we could just connect the areas to do our vis. - //m_bOverrideVisOrigin could hose us here, so call direct - render->ViewSetupVis( false, 1, &local->m_skybox3d.origin.Get() ); - render->Push3DView( skyView, nClearFlags, false, NULL, m_Frustum ); - - // At this point, we've cleared everything we need to clear - // The next path will need to clear depth, though. - nClearFlags &= ~(VIEW_CLEAR_COLOR | VIEW_CLEAR_DEPTH | VIEW_CLEAR_FULL_TARGET); - nClearFlags |= VIEW_CLEAR_DEPTH; - - // Store off view origin and angles - SetupCurrentView( skyView.origin, skyView.angles, VIEW_3DSKY ); - - // Invoke pre-render methods - IGameSystem::PreRenderAllSystems(); - - ClientWorldListInfo_t info; -#ifndef _XBOX - CRenderList renderList; - CRenderList *pRenderList = &renderList; -#else - void *ptr = MemAllocScratch(sizeof(CRenderList)); - CRenderList *pRenderList = new (ptr) CRenderList; -#endif - - BuildWorldRenderLists( NULL, info, true, true, m_iForceViewLeaf ); - BuildRenderableRenderLists( NULL, info, *pRenderList ); - - int flags = DF_RENDER_UNDERWATER | DF_RENDER_ABOVEWATER | DF_RENDER_WATER; - if( r_skybox.GetBool() ) - { - flags |= DF_DRAWSKYBOX; - } - - int oldDrawFlags = m_DrawFlags; - m_DrawFlags |= flags; - DrawWorld( info, *pRenderList, flags, 0.0f ); - - // Iterate over all leaves and render objects in those leaves - DrawOpaqueRenderables( info, *pRenderList ); - - // Iterate over all leaves and render objects in those leaves - DrawTranslucentRenderables( info, *pRenderList, flags, true ); - - DisableFog(); - - CGlowOverlay::UpdateSkyOverlays( skyView.zFar, view.m_bCacheFullSceneState ); - - PixelVisibility_EndCurrentView(); - - // restore old area bits - *areabits = savebits; - - // Invoke post-render methods - IGameSystem::PostRenderAllSystems(); - - FinishCurrentView(); - - m_DrawFlags = oldDrawFlags; - -#ifdef _XBOX - MemFreeScratch(); -#endif - - render->PopView( m_Frustum ); - bDrew3dSkybox = true; -} - -#include "tier0/memdbgon.h" - - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CViewRender::SetupVis( const CViewSetup& view, unsigned int &visFlags ) -{ - VPROF( "CViewRender::SetupVis" ); - - if ( m_bOverrideVisOrigin ) - { - // Pass array or vis origins to merge - render->ViewSetupVisEx( m_bForceNoVis, m_nNumVisOrigins, m_rgVisOrigins, visFlags ); - } - else - { - // Use render origin as vis origin by default - render->ViewSetupVisEx( m_bForceNoVis, 1, &view.origin, visFlags ); - } -} - -#ifndef _XBOX - -// hdr parameters -ConVar mat_hdr_level( "mat_hdr_level", "2" ); -ConVar mat_bloomamount_rate( "mat_bloomamount_rate", "0.05f" ); -static ConVar debug_postproc( "mat_debug_postprocessing_effects", "0" ); -static ConVar split_postproc( "mat_debug_process_halfscreen", "0" ); -static ConVar mat_dynamic_tonemapping( "mat_dynamic_tonemapping", "0" ); -static ConVar mat_show_ab_hdr( "mat_show_ab_hdr", "0" ); -static ConVar mat_tonemapping_occlusion_use_stencil( "mat_tonemapping_occlusion_use_stencil", "1" ); -ConVar mat_debug_autoexposure("mat_debug_autoexposure","0"); -static ConVar mat_autoexposure_max( "mat_autoexposure_max", "2" ); -static ConVar mat_autoexposure_min( "mat_autoexposure_min", "0.5" ); -static ConVar mat_show_histogram( "mat_show_histogram", "0" ); -ConVar mat_hdr_tonemapscale( "mat_hdr_tonemapscale", "1.0", FCVAR_CHEAT ); -ConVar mat_force_bloom("mat_force_bloom","0"); -ConVar mat_disable_bloom("mat_disable_bloom","0"); -ConVar mat_debug_bloom("mat_debug_bloom","0"); - -// fudge factor to make non-hdr bloom more closely match hdr bloom. Because of auto-exposure, high -// bloomscales don't blow out as much in hdr. this factor was derived by comparing images in a -// reference scene. -ConVar mat_non_hdr_bloom_scalefactor("mat_non_hdr_bloom_scalefactor",".3"); - - -enum PostProcessingCondition { - PPP_ALWAYS, - PPP_IF_COND_VAR, - PPP_IF_NOT_COND_VAR -}; - -struct PostProcessingPass { - PostProcessingCondition ppp_test; - ConVar const *cvar_to_test; - char const *material_name; // terminate list with null - char const *dest_rendering_target; - char const *src_rendering_target; // can be null. needed for source scaling - int xdest_scale,ydest_scale; // allows scaling down - int xsrc_scale,ysrc_scale; // allows scaling down - CMaterialReference m_mat_ref; // so we don't have to keep searching -}; - -#define PPP_PROCESS_PARTIAL_SRC(srcmatname,dest_rt_name,src_tname,scale) \ - {PPP_ALWAYS,0,srcmatname,dest_rt_name,src_tname,1,1,scale,scale} -#define PPP_PROCESS_PARTIAL_DEST(srcmatname,dest_rt_name,src_tname,scale) \ - {PPP_ALWAYS,0,srcmatname,dest_rt_name,src_tname,scale,scale,1,1} -#define PPP_PROCESS_PARTIAL_SRC_PARTIAL_DEST(srcmatname,dest_rt_name,src_tname,srcscale,destscale) \ - {PPP_ALWAYS,0,srcmatname,dest_rt_name,src_tname,destscale,destscale,srcscale,srcscale} -#define PPP_END {PPP_ALWAYS,0,NULL,NULL,0,0,0,0,0} -#define PPP_PROCESS(srcmatname,dest_rt_name) {PPP_ALWAYS,0,srcmatname,dest_rt_name,0,1,1,1,1} -#define PPP_PROCESS_IF_CVAR(cvarptr,srcmatname,dest_rt_name) \ - {PPP_IF_COND_VAR,cvarptr,srcmatname,dest_rt_name,0,1,1,1,1} -#define PPP_PROCESS_IF_NOT_CVAR(cvarptr,srcmatname,dest_rt_name) \ - {PPP_IF_NOT_COND_VAR,cvarptr,srcmatname,dest_rt_name,0,1,1,1,1} -#define PPP_PROCESS_IF_NOT_CVAR_SRCTEXTURE(cvarptr,srcmatname,src_tname,dest_rt_name) \ - {PPP_IF_NOT_COND_VAR,cvarptr,srcmatname,dest_rt_name,src_tname,1,1,1,1} -#define PPP_PROCESS_IF_CVAR_SRCTEXTURE(cvarptr,srcmatname,src_txtrname,dest_rt_name) \ - {PPP_IF_COND_VAR,cvarptr,srcmatname,dest_rt_name,src_txtrname,1,1,1,1} -#define PPP_PROCESS_SRCTEXTURE(srcmatname,src_tname,dest_rt_name) \ - {PPP_ALWAYS,0,srcmatname,dest_rt_name,src_tname,1,1,1,1} - -struct ClipBox -{ - int m_minx, m_miny; - int m_maxx, m_maxy; -}; - -static void DrawClippedScreenSpaceRectangle( - IMaterial *pMaterial, - int destx, int desty, - int width, int height, - float src_texture_x0, float src_texture_y0, // which texel you want to appear at - // destx/y - float src_texture_x1, float src_texture_y1, // which texel you want to appear at - // destx+width-1, desty+height-1 - int src_texture_width, int src_texture_height, // needed for fixup - ClipBox const *clipbox - ) -{ - if (clipbox) - { - if ((destx>clipbox->m_maxx) || (desty>clipbox->m_maxy)) - return; - if ((destx+width-1m_minx) || (desty+height-1m_miny)) - return; - // left clip - if (destxm_minx) - { - src_texture_x0=FLerp(src_texture_x0,src_texture_x1,destx,destx+width-1,clipbox->m_minx); - width-=(clipbox->m_minx-destx); - destx=clipbox->m_minx; - } - // top clip - if (destym_miny) - { - src_texture_y0=FLerp(src_texture_y0,src_texture_y1,desty,desty+height-1,clipbox->m_miny); - height-=(clipbox->m_miny-desty); - desty=clipbox->m_miny; - } - // right clip - if (destx+width-1>clipbox->m_maxx) - { - src_texture_x1=FLerp(src_texture_x0,src_texture_x1,destx,destx+width-1,clipbox->m_maxx); - width=clipbox->m_maxx-destx; - } - // bottom clip - if (desty+height-1>clipbox->m_maxy) - { - src_texture_y1=FLerp(src_texture_y0,src_texture_y1,desty,desty+height-1,clipbox->m_maxy); - height=clipbox->m_maxy-desty; - } - } - materials->DrawScreenSpaceRectangle(pMaterial,destx,desty,width,height,src_texture_x0, - src_texture_y0,src_texture_x1,src_texture_y1, - src_texture_width,src_texture_height); -} - -void ApplyPostProcessingPasses(PostProcessingPass *pass_list, // table of effects to apply - ClipBox const *clipbox=0, // clipping box for these effects - ClipBox *dest_coords_out=0) // receives dest coords of last blit -{ - ITexture *pSaveRenderTarget = materials->GetRenderTarget(); - int pcount=0; - if ( debug_postproc.GetInt() ) - { - materials->SetRenderTarget(NULL); - int dest_width,dest_height; - materials->GetRenderTargetDimensions( dest_width, dest_height ); - materials->Viewport( 0, 0, dest_width, dest_height ); - materials->ClearColor3ub(255,0,0); -// materials->ClearBuffers(true,true); - } - while(pass_list->material_name) - { - bool do_it=true; - - switch(pass_list->ppp_test) - { - case PPP_IF_COND_VAR: - do_it=(pass_list->cvar_to_test)->GetBool(); - break; - case PPP_IF_NOT_COND_VAR: - do_it=! ((pass_list->cvar_to_test)->GetBool()); - break; - } - if ((pass_list->dest_rendering_target==0) && (debug_postproc.GetInt())) - do_it=0; - if (do_it) - { - ClipBox const *cb=0; - if (pass_list->dest_rendering_target==0) - { - cb=clipbox; - } - - IMaterial *src_mat=pass_list->m_mat_ref; - if (! src_mat) - { - src_mat=materials->FindMaterial(pass_list->material_name, - TEXTURE_GROUP_OTHER,true); - if (src_mat) - { - pass_list->m_mat_ref.Init(src_mat); - } - } - if (pass_list->dest_rendering_target) - { - ITexture *dest_rt=materials->FindTexture(pass_list->dest_rendering_target, - TEXTURE_GROUP_RENDER_TARGET); - materials->SetRenderTarget( dest_rt); - } - else - { - materials->SetRenderTarget( NULL ); - } - int dest_width,dest_height; - materials->GetRenderTargetDimensions( dest_width, dest_height ); - materials->Viewport( 0, 0, dest_width, dest_height ); - dest_width/=pass_list->xdest_scale; - dest_height/=pass_list->ydest_scale; - - if (pass_list->src_rendering_target) - { - ITexture *src_rt=materials->FindTexture(pass_list->src_rendering_target, - TEXTURE_GROUP_RENDER_TARGET); - int src_width=src_rt->GetActualWidth(); - int src_height=src_rt->GetActualHeight(); - int ssrc_width=(src_width-1)/pass_list->xsrc_scale; - int ssrc_height=(src_height-1)/pass_list->ysrc_scale; - DrawClippedScreenSpaceRectangle( - src_mat,0,0,dest_width,dest_height, - 0,0,ssrc_width,ssrc_height,src_width,src_height,cb); - if ((pass_list->dest_rendering_target) && debug_postproc.GetInt()) - { - materials->SetRenderTarget(NULL); - int row=pcount/2; - int col=pcount %2; - int vdest_width,vdest_height; - materials->GetRenderTargetDimensions( vdest_width, vdest_height ); - materials->Viewport( 0, 0, vdest_width, vdest_height ); - materials->DrawScreenSpaceRectangle( - src_mat,col*400,200+row*300,dest_width,dest_height, - 0,0,ssrc_width,ssrc_height,src_width,src_height); - } - } - else - { - // just draw the whole source - if ((pass_list->dest_rendering_target==0) && split_postproc.GetInt()) - { - DrawClippedScreenSpaceRectangle(src_mat,0,0,dest_width/2,dest_height, - 0,0,.5,1,1,1,cb); - } - else - { - DrawClippedScreenSpaceRectangle(src_mat,0,0,dest_width,dest_height, - 0,0,1,1,1,1,cb); - } - if ((pass_list->dest_rendering_target) && debug_postproc.GetInt()) - { - materials->SetRenderTarget(NULL); - int row=pcount/4; - int col=pcount %4; - int dest_width,dest_height; - materials->GetRenderTargetDimensions( dest_width, dest_height ); - materials->Viewport( 0, 0, dest_width, dest_height ); - DrawClippedScreenSpaceRectangle(src_mat,10+col*220,10+row*220, - 200,200, - 0,0,1,1,1,1,cb); - } - } - if (dest_coords_out) - { - dest_coords_out->m_minx=0; - dest_coords_out->m_maxx=dest_width-1; - dest_coords_out->m_miny=0; - dest_coords_out->m_maxy=dest_height-1; - } - } - pass_list++; - pcount++; - } - materials->SetRenderTarget(pSaveRenderTarget); -} - -PostProcessingPass HDRFinal_Float[] = -{ - PPP_PROCESS_SRCTEXTURE("dev/downsample","_rt_FullFrameFB", "_rt_SmallFB0"), - PPP_PROCESS("dev/blurfilterx","_rt_SmallFB1"), - PPP_PROCESS("dev/blurfiltery","_rt_SmallFB0"), - PPP_PROCESS("dev/floattoscreen_combine",NULL), - PPP_END -}; - -PostProcessingPass HDRFinal_Float_NoBloom[] = -{ - PPP_PROCESS_SRCTEXTURE("dev/copyfullframefb", "_rt_FullFrameFB",NULL), - PPP_END -}; - -PostProcessingPass HDRSimulate_NonHDR[]={ - PPP_PROCESS("dev/copyfullframefb_vanilla",NULL), - PPP_END -}; - -static bool IsSplitScreenHDR(void) -{ - return ( mat_show_ab_hdr.GetInt() && - (g_pMaterialSystemHardwareConfig->GetHDRType() != HDR_TYPE_NONE) ); -} - -static void SetRenderTargetAndViewPort(ITexture *rt) -{ - materials->SetRenderTarget(rt); - materials->Viewport(0,0,rt->GetActualWidth(),rt->GetActualHeight()); -} - -#define FILTER_KERNEL_SLOP 20 - -// Note carefully about the downsampling: the first downsampling samples from the full rendertarget -// down to a temp. When doing this sampling, the texture source clamping will take care of the out -// of bounds sampling done because of the filter kernels's width. However, on any of the subsequent -// sampling operations, we will be sampling from a partially filled render target. So, texture -// coordinate clamping cannot help us here. So, we need to always render a few more pixels to the -// destination than we actually intend to, so as to replicate the border pixels so that garbage -// pixels do not get sucked into the sampling. To deal with this, we always add FILTER_KERNEL_SLOP -// to our widths/heights if there is room for them in the destination. -static void DrawScreenSpaceRectangleWithSlop( - ITexture *dest_rt, - IMaterial *pMaterial, - int destx, int desty, - int width, int height, - float src_texture_x0, float src_texture_y0, // which texel you want to appear at - // destx/y - float src_texture_x1, float src_texture_y1, // which texel you want to appear at - // destx+width-1, desty+height-1 - int src_texture_width, int src_texture_height // needed for fixup - ) -{ - // add slop - int slopwidth=width+FILTER_KERNEL_SLOP; //min(dest_rt->GetActualWidth()-destx,width+FILTER_KERNEL_SLOP); - int slopheight=height+FILTER_KERNEL_SLOP; //min(dest_rt->GetActualHeight()-desty,height+FILTER_KERNEL_SLOP); - // adjust coordinates for slop - src_texture_x1=FLerp(src_texture_x0,src_texture_x1,destx,destx+width-1,destx+slopwidth-1); - src_texture_y1=FLerp(src_texture_y0,src_texture_y1,desty,desty+height-1,desty+slopheight-1); - width=slopwidth; - height=slopheight; - materials->DrawScreenSpaceRectangle(pMaterial,destx,desty,width,height, - src_texture_x0,src_texture_y0, - src_texture_x1,src_texture_y1, - src_texture_width,src_texture_height); - -} - - - -enum Histogram_entry_state_t -{ - HESTATE_INITIAL=0, - HESTATE_FIRST_QUERY_IN_FLIGHT, - HESTATE_QUERY_IN_FLIGHT, - HESTATE_QUERY_DONE, -}; - - -ConVar mat_exposure_center_region_x( "mat_exposure_center_region_x","0.75", FCVAR_CHEAT ); -ConVar mat_exposure_center_region_y( "mat_exposure_center_region_y","0.80", FCVAR_CHEAT ); -ConVar mat_exposure_center_region_x_flashlight( "mat_exposure_center_region_x_flashlight","0.33", FCVAR_CHEAT ); -ConVar mat_exposure_center_region_y_flashlight( "mat_exposure_center_region_y_flashlight","0.33", FCVAR_CHEAT ); - -#define N_LUMINANCE_RANGES 31 -#define MAX_QUERIES_PER_FRAME 1 - -class CHistogram_entry_t -{ -public: - Histogram_entry_state_t m_state; - OcclusionQueryObjectHandle_t m_occ_handle; // the occlusion query handle - int m_frame_queued; // when this query was last queued - int m_npixels; // # of pixels this histogram represents - int m_npixels_in_range; - float m_min_lum, m_max_lum; // the luminance range this entry was queried with - float m_minx,m_miny,m_maxx,m_maxy; // range is 0..1 in fractions of the screen - - bool ContainsValidData( void ) - { - return ( m_state==HESTATE_QUERY_DONE ) || ( m_state==HESTATE_QUERY_IN_FLIGHT ); - } - - void IssueQuery( int frm_num ) - { - if ( ! m_occ_handle) - m_occ_handle=materials->CreateOcclusionQueryObject(); - int xl,yl,dest_width,dest_height; - materials->GetViewport( xl,yl,dest_width,dest_height); - // first, set stencil bits where the colors match - IMaterial *test_mat=materials->FindMaterial( - "dev/lumcompare", - TEXTURE_GROUP_OTHER,true); - IMaterialVar *pMinVar = test_mat->FindVar( "$C0_X", NULL ); - pMinVar->SetFloatValue( m_min_lum); - IMaterialVar *pMaxVar = test_mat->FindVar( "$C0_Y", NULL ); - if (m_max_lum==1.0) - pMaxVar->SetFloatValue( 10000.0); // count all pixels >1.0 as 1.0 - else - pMaxVar->SetFloatValue( m_max_lum); - int scrx_min=FLerp(xl,xl+dest_width-1,0,1,m_minx); - int scrx_max=FLerp(xl,xl+dest_width-1,0,1,m_maxx); - int scry_min=FLerp(yl,yl+dest_height-1,0,1,m_miny); - int scry_max=FLerp(yl,yl+dest_height-1,0,1,m_maxy); - - float exposure_width_scale, exposure_height_scale; - - // now, shrink region of interest if the flashlight is on - C_BasePlayer *pLocal = C_BasePlayer::GetLocalPlayer(); - if ( pLocal->IsEffectActive( EF_DIMLIGHT ) ) // check flashlight - { - exposure_width_scale= - (0.5*(1.0-mat_exposure_center_region_x_flashlight.GetFloat())); - exposure_height_scale= - (0.5*(1.0-mat_exposure_center_region_y_flashlight.GetFloat())); - } - else - { - exposure_width_scale= - (0.5*(1.0-mat_exposure_center_region_x.GetFloat())); - exposure_height_scale= - (0.5*(1.0-mat_exposure_center_region_y.GetFloat())); - } - int skip_edgex=(1+scrx_max-scrx_min)*exposure_width_scale; - int skip_edgey=(1+scry_max-scry_min)*exposure_height_scale; - - // now, do luminance compare - float tscale=1.0; - if (g_pMaterialSystemHardwareConfig->GetHDRType()==HDR_TYPE_FLOAT) - { - tscale=materials->GetToneMappingScaleLinear().x; - } - IMaterialVar *use_t_scale = test_mat->FindVar( "$C0_Z", NULL ); - use_t_scale->SetFloatValue( tscale); - - - m_npixels=(1+scrx_max-scrx_min)*(1+scry_max-scry_min); - if (mat_tonemapping_occlusion_use_stencil.GetInt()) - { - materials->SetStencilWriteMask(1); - materials->ClearStencilBufferRectangle(scrx_min,scry_min,scrx_max,scry_max,0); - materials->SetStencilEnable(true); - materials->SetStencilPassOperation(STENCILOPERATION_REPLACE); - materials->SetStencilCompareFunction(STENCILCOMPARISONFUNCTION_ALWAYS); - materials->SetStencilFailOperation(STENCILOPERATION_KEEP); - materials->SetStencilZFailOperation(STENCILOPERATION_KEEP); - materials->SetStencilReferenceValue(1); - } - else - materials->BeginOcclusionQueryDrawing(m_occ_handle); - scrx_min+=skip_edgex; - scry_min+=skip_edgey; - scrx_max-=skip_edgex; - scry_max-=skip_edgey; - materials->DrawScreenSpaceRectangle(test_mat, - scrx_min,scry_min, - 1+scrx_max-scrx_min, - 1+scry_max-scry_min, - scrx_min,scry_min, - scrx_max, scry_max, - dest_width,dest_height); - - if (mat_tonemapping_occlusion_use_stencil.GetInt()) - { - // now, start counting how many pixels had their stencil bit set via an occlusion query - materials->BeginOcclusionQueryDrawing(m_occ_handle); - // now, issue an occlusion query using stencil as the mask - materials->SetStencilEnable(true); - materials->SetStencilTestMask(1); - materials->SetStencilPassOperation(STENCILOPERATION_KEEP); - materials->SetStencilCompareFunction(STENCILCOMPARISONFUNCTION_EQUAL); - materials->SetStencilFailOperation(STENCILOPERATION_KEEP); - materials->SetStencilZFailOperation(STENCILOPERATION_KEEP); - materials->SetStencilReferenceValue(1); - IMaterial *stest_mat=materials->FindMaterial( - "dev/no_pixel_write", - TEXTURE_GROUP_OTHER,true); - materials->DrawScreenSpaceRectangle(stest_mat, - scrx_min,scry_min, - 1+scrx_max-scrx_min, - 1+scry_max-scry_min, - scrx_min,scry_min, - scrx_max, scry_max, - dest_width,dest_height); - materials->SetStencilEnable(false); - } - materials->EndOcclusionQueryDrawing(m_occ_handle); - if (m_state==HESTATE_INITIAL) - m_state=HESTATE_FIRST_QUERY_IN_FLIGHT; - else - m_state=HESTATE_QUERY_IN_FLIGHT; - m_frame_queued=frm_num; - } - -}; - - -#define HISTOGRAM_BAR_SIZE 200 - -class CLuminanceHistogramSystem -{ - CHistogram_entry_t CurHistogram[N_LUMINANCE_RANGES]; - int cur_query_frame; -public: - float GetAverageLuminance( void ) - { - float total=0; - int total_pixels=0; - float scale_value=1.0; - if (CurHistogram[N_LUMINANCE_RANGES-1].ContainsValidData()) - { - scale_value=CurHistogram[N_LUMINANCE_RANGES-1].m_npixels* - (1.0/CurHistogram[N_LUMINANCE_RANGES-1].m_npixels_in_range); - if (mat_debug_autoexposure.GetInt()) - Warning("scale value=%f\n",scale_value); - } - else - return 0.5; - - for(int i=0;i 0) - return total*(1.0/total_pixels); - else - return 0.5; - } - - void Update(void) - { - // find which histogram entries should have something done this frame - int n_queries_issued_this_frame=0; - cur_query_frame++; - - for(int i=0;iCurHistogram[i].m_frame_queued+2 ) - { - int np= materials->OcclusionQuery_GetNumPixelsRendered( - CurHistogram[i].m_occ_handle); - if (np!=-1) // -1=query not finished. wait until - // next time - { - CurHistogram[i].m_npixels_in_range=np; - // if (mat_debug_autoexposure.GetInt()) - // Warning("min=%f max=%f np = %d\n",CurHistogram[i].m_min_lum,CurHistogram[i].m_max_lum,np); - CurHistogram[i].m_state=HESTATE_QUERY_DONE; - } - } - break; - } - } - // now, issue queries for the oldest finished queries we have - while( n_queries_issued_this_frameViewport(xp,HISTOGRAM_BAR_SIZE-height,width,height); - materials->ClearColor3ub(255,0,0); - materials->ClearBuffers(true,true); - } - xp+=width+2; - } - } - - CLuminanceHistogramSystem(void) - { - cur_query_frame=0; - for(int bucket=0;bucketResetToneMappingScale(value); -} - -static void SetToneMapScale(float newvalue, float minvalue, float maxvalue) -{ - mat_hdr_tonemapscale.SetValue(newvalue); -#if 1 - if (s_nInAverage= 1); - if ( !engine->MapHasHDRLighting() ) - bloom_enabled = false; - if ( mat_force_bloom.GetInt() ) - bloom_enabled = true; - if ( mat_disable_bloom.GetInt() ) - bloom_enabled = false; - if ( building_cubemaps.GetBool() ) - bloom_enabled = false; - - HDRType_t hdrType = g_pMaterialSystemHardwareConfig->GetHDRType(); - - float bloom_coeff=0.0; - if (bloom_enabled) - { - static float currentBloomAmount = 1.0f; - float rate = mat_bloomamount_rate.GetFloat(); - - // Use the appropriate bloom scale settings. Mapmakers's overrides the convar settings. - float flCurrentBloomScale = 1.0f; - if ( g_bUseCustomBloomScale ) - { - flCurrentBloomScale = g_flCustomBloomScale; - } - else - { - flCurrentBloomScale = mat_bloomscale.GetFloat(); - } - - currentBloomAmount = flCurrentBloomScale * rate + ( 1.0f - rate ) * currentBloomAmount; - bloom_coeff=currentBloomAmount; - } - - if ( hdrType == HDR_TYPE_NONE ) - bloom_coeff *= mat_non_hdr_bloom_scalefactor.GetFloat(); - - // Use the appropriate autoexposure min / max settings. - // Mapmaker's overrides the convar settings. - float flAutoExposureMin; - float flAutoExposureMax; - if ( g_bUseCustomAutoExposureMin ) - { - flAutoExposureMin = g_flCustomAutoExposureMin; - } - else - { - flAutoExposureMin = mat_autoexposure_min.GetFloat(); - } - if ( g_bUseCustomAutoExposureMax ) - { - flAutoExposureMax = g_flCustomAutoExposureMax; - } - else - { - flAutoExposureMax = mat_autoexposure_max.GetFloat(); - } - - switch( hdrType ) - { - case HDR_TYPE_NONE: - case HDR_TYPE_INTEGER: - { - if (mat_debug_bloom.GetInt()==1) - { - static int wx=0; - wx=(wx+1) & 63; - materials->SetRenderTarget(NULL); - int dest_width,dest_height; - materials->GetRenderTargetDimensions( dest_width, dest_height ); - materials->Viewport( 0, 0, dest_width, dest_height ); - materials->ClearColor3ub(0,0,0); - materials->ClearBuffers(true,true); - materials->Viewport( wx+100, 100, 20,20 ); - materials->ClearColor3ub(255,255,255); - materials->ClearBuffers(true,true); - materials->Viewport( 20,20,20,20 ); - materials->ClearBuffers(true,true); - materials->Viewport( 950,20,20,20 ); - materials->ClearBuffers(true,true); - materials->Viewport( 950,950,20,20 ); - materials->ClearBuffers(true,true); - materials->Viewport( 20,950,20,20 ); - materials->ClearBuffers(true,true); - materials->Viewport( 0, 0, dest_width, dest_height ); - } - bool did_update=false; - if ( ( hdrType != HDR_TYPE_NONE && mat_dynamic_tonemapping.GetInt() ) || mat_show_histogram.GetInt()) - { - did_update=true; -// if (mat_debug_autoexposure.GetInt()) -// { -// materials->ClearColor3ub(128,0,0); -// materials->ClearBuffers(true,true); -// } - Rect_t actualRect; - UpdateScreenEffectTexture( 0, x, y, w, h, false, &actualRect ); -// UpdateScreenEffectTexture( 0, x, y, w, h, true ); - int dest_width,dest_height; - materials->GetRenderTargetDimensions( dest_width, dest_height ); - g_HDR_HistogramSystem.Update(); - float avg_lum=g_HDR_HistogramSystem.GetAverageLuminance(); - float last_scale=materials->GetToneMappingScaleLinear().x; - float actual_unscaled_luminance=avg_lum*(1.0/last_scale); - actual_unscaled_luminance=max(0.000000001,avg_lum); - float target_scale=0.005/actual_unscaled_luminance; - float scalevalue=max(flAutoExposureMin, - min(flAutoExposureMax,target_scale)); - if (mat_debug_autoexposure.GetInt()) - Warning("avg_lum=%f ra=%f target=%f adj target=%f\n", - avg_lum,actual_unscaled_luminance,target_scale,scalevalue); - if (mat_dynamic_tonemapping.GetInt()) - SetToneMapScale(scalevalue,flAutoExposureMin,flAutoExposureMax); - } - // bloom - if ( bloom_enabled && ( bloom_coeff > 0.0 ) && ( engine->GetDXSupportLevel() >= 80 ) ) - { - materials->SetRenderTarget(NULL); - int dest_width,dest_height; - materials->GetRenderTargetDimensions( dest_width, dest_height ); - materials->Viewport( 0, 0, dest_width, dest_height ); - if ( !did_update ) - { - UpdateScreenEffectTexture( 0, x, y, w, h, true ); - did_update=true; - } - - IMaterial *downsample_mat = materials->FindMaterial( "dev/downsample_non_hdr", TEXTURE_GROUP_OTHER, true); - IMaterial *xblur_mat = materials->FindMaterial( "dev/blurfilterx_nohdr", TEXTURE_GROUP_OTHER, true ); - IMaterial *yblur_mat = materials->FindMaterial( "dev/blurfiltery_and_add_nohdr", TEXTURE_GROUP_OTHER, true ); - ITexture *dest_rt0 = materials->FindTexture( "_rt_SmallFB0", TEXTURE_GROUP_RENDER_TARGET ); - ITexture *dest_rt1 = materials->FindTexture( "_rt_SmallFB1", TEXTURE_GROUP_RENDER_TARGET ); - - // downsample fb to rt0 - SetRenderTargetAndViewPort( dest_rt0 ); - // note the -2's below. Thats because we are downsampling on each axis and the shader - // accesses pixels on both sides of the source coord - materials->DrawScreenSpaceRectangle( downsample_mat, 0, 0, dest_width/4, dest_height/4, - 0, 0, dest_width-2, dest_height-2, - dest_width, dest_height ); - // guassian blur x rt0 to rt1 - SetRenderTargetAndViewPort( dest_rt1 ); - materials->DrawScreenSpaceRectangle( xblur_mat, 0, 0, dest_width/4, dest_height/4, - 0, 0, dest_width/4-1, dest_height/4-1, - dest_width/4, dest_height/4 ); - // gaussian blur y and add rt1 to frame buffer - materials->Viewport( 0, 0, dest_width, dest_height ); - materials->SetRenderTarget( NULL ); - IMaterialVar *pBloomAmountVar = yblur_mat->FindVar( "$bloomamount", NULL ); - pBloomAmountVar->SetFloatValue( bloom_coeff ); - int bloomadd_x=0; - int bloomadd_y=0; - int bloomadd_width=dest_width; - int bloomadd_height=dest_height; - float bloomsrc_x=0; - float bloomsrc_y=-.5; // compensate for phase shift due to mismatched input/output sizes - float bloomsrc_maxx=dest_width/4-1; - float bloomsrc_maxy=dest_height/4-1; - if ( IsSplitScreenHDR() ) - { - bloomadd_x+=dest_width/2; - bloomadd_width-=dest_width/2; - bloomsrc_x+=dest_width/8; - } - materials->DrawScreenSpaceRectangle(yblur_mat,bloomadd_x,bloomadd_y, - bloomadd_width,bloomadd_height, - bloomsrc_x,bloomsrc_y, - bloomsrc_maxx,bloomsrc_maxy, - dest_rt1->GetActualWidth(), - dest_rt1->GetActualHeight()); - } - - if ( mat_show_histogram.GetInt() && ( engine->GetDXSupportLevel() >= 90 ) ) - { - g_HDR_HistogramSystem.DisplayHistogram(); - } - } - break; - - case HDR_TYPE_FLOAT: - { - int dest_width,dest_height; - materials->GetRenderTargetDimensions( dest_width, dest_height ); - if (mat_dynamic_tonemapping.GetInt() || mat_show_histogram.GetInt()) - { - g_HDR_HistogramSystem.Update(); -// Warning("avg_lum=%f\n",g_HDR_HistogramSystem.GetAverageLuminance()); - if (mat_dynamic_tonemapping.GetInt()) - { - float avg_lum=max(0.0001,g_HDR_HistogramSystem.GetAverageLuminance()); - float scalevalue=max(flAutoExposureMin, - min(flAutoExposureMax,0.18/avg_lum)); - mat_hdr_tonemapscale.SetValue(scalevalue); - } - } - IMaterial *pBloomMaterial; - pBloomMaterial = materials->FindMaterial( "dev/floattoscreen_combine", "" ); - IMaterialVar *pBloomAmountVar = pBloomMaterial->FindVar( "$bloomamount", NULL ); - pBloomAmountVar->SetFloatValue( bloom_coeff); - if ( IsSplitScreenHDR() ) - { - // do split screen - ClipBox mycb; - mycb.m_minx=mycb.m_miny=0; - mycb.m_maxx=dest_width/2; - mycb.m_maxy=dest_height-1; - ApplyPostProcessingPasses(HDRSimulate_NonHDR,&mycb); - mycb.m_minx=mycb.m_maxx; - mycb.m_maxx=dest_width-1; - ApplyPostProcessingPasses(HDRFinal_Float,&mycb); - } - else - { - if( bloom_enabled) - ApplyPostProcessingPasses(HDRFinal_Float); - else - ApplyPostProcessingPasses(HDRFinal_Float_NoBloom); - } - materials->SetRenderTarget(NULL); - if ( mat_show_histogram.GetInt() && (engine->GetDXSupportLevel()>=90)) - g_HDR_HistogramSystem.DisplayHistogram(); - if (mat_dynamic_tonemapping.GetInt()) - { - float avg_lum=max(0.0001,g_HDR_HistogramSystem.GetAverageLuminance()); - float scalevalue=max(flAutoExposureMin, - min(flAutoExposureMax,0.023/avg_lum)); - SetToneMapScale(scalevalue,flAutoExposureMin,flAutoExposureMax); - } - materials->SetRenderTarget( NULL ); - break; - } - } -} -#else -void ResetToneMapping(float value) -{ -} -#endif // !_XBOX - -#ifdef _XBOX - -#define FULLSCREEN_WIDTH 640 -#define FULLSCREEN_HEIGHT 480 -#define DOWNSAMPLE_WIDTH (FULLSCREEN_WIDTH>>1) -#define DOWNSAMPLE_HEIGHT (FULLSCREEN_HEIGHT>>1) - -void CViewRender::DoScreenSpaceBloom() -{ - int rt_width, rt_height; - - if ( !mat_bloomscale.GetFloat() || !m_BloomDownsample.IsValid() ) - { - return; - } - - // rt_waterReflection = DownSample( backBuffer ) - ITexture *dest_rt = GetWaterReflectionTexture(); - materials->PushRenderTargetAndViewport( dest_rt ); - materials->GetRenderTargetDimensions( rt_width, rt_height ); - Assert( rt_width >= DOWNSAMPLE_WIDTH && rt_height >= DOWNSAMPLE_HEIGHT ); - materials->DrawScreenSpaceRectangle( - m_BloomDownsample, 0, 0, DOWNSAMPLE_WIDTH, DOWNSAMPLE_HEIGHT, - 0, 0, FULLSCREEN_WIDTH, FULLSCREEN_HEIGHT, 1, 1 ); - - // rt_waterRefraction = BlurX( rt_waterReflection ) - dest_rt = GetWaterRefractionTexture(); - materials->SetRenderTarget( dest_rt ); - materials->DrawScreenSpaceRectangle( - m_BloomBlurX, 0, 0, DOWNSAMPLE_WIDTH, DOWNSAMPLE_HEIGHT, - 0, 0, DOWNSAMPLE_WIDTH, DOWNSAMPLE_HEIGHT, rt_width, rt_height ); - - // rt_waterReflection = BlurY( rt_waterRefraction ) - dest_rt = GetWaterReflectionTexture(); - materials->SetRenderTarget( dest_rt ); - materials->DrawScreenSpaceRectangle( - m_BloomBlurY, 0, 0, DOWNSAMPLE_WIDTH, DOWNSAMPLE_HEIGHT, - 0, 0, DOWNSAMPLE_WIDTH, DOWNSAMPLE_HEIGHT, rt_width, rt_height ); - - // restore screen - materials->PopRenderTargetAndViewport(); - - // FrameBuffer += rt_waterReflection - materials->DrawScreenSpaceRectangle( - m_BloomAdd, 0, 0, FULLSCREEN_WIDTH, FULLSCREEN_HEIGHT, - 0, 0, DOWNSAMPLE_WIDTH, DOWNSAMPLE_HEIGHT, rt_width, rt_height ); -} -#endif - -//----------------------------------------------------------------------------- -// Purpose: Renders voice feedback and other sprites attached to players -// Input : none -//----------------------------------------------------------------------------- -void CViewRender::RenderPlayerSprites() -{ -#ifndef _XBOX - GetClientVoiceMgr()->DrawHeadLabels(); -#endif -} - -//----------------------------------------------------------------------------- -// Sets up, cleans up the main 3D view -//----------------------------------------------------------------------------- -void CViewRender::SetupMain3DView( const CViewSetup &view, int &nClearFlags ) -{ - // FIXME: I really want these fields removed from CViewSetup - // and passed in as independent flags - // Clear the color here if requested. - nClearFlags &= ~VIEW_CLEAR_DEPTH; - if ( nClearFlags & VIEW_CLEAR_COLOR ) - { - nClearFlags |= VIEW_CLEAR_DEPTH; - } - - // If we are using HDR, we render to the HDR full frame buffer texture - // instead of whatever was previously the render target - if( g_pMaterialSystemHardwareConfig->GetHDRType() == HDR_TYPE_FLOAT ) - { - render->Push3DView( view, nClearFlags, true, GetFullFrameFrameBufferTexture( 0 ), m_Frustum ); - } - else - { - render->Push3DView( view, nClearFlags, false, NULL, m_Frustum ); - } - - // If we didn't clear the depth here, we'll need to clear it later - nClearFlags ^= VIEW_CLEAR_DEPTH; - if ( nClearFlags & VIEW_CLEAR_COLOR ) - { - // If we cleared the color here, we don't need to clear it later - nClearFlags &= ~( VIEW_CLEAR_COLOR | VIEW_CLEAR_FULL_TARGET ); - } -} - -void CViewRender::CleanupMain3DView( const CViewSetup &view ) -{ - render->PopView( m_Frustum ); -} - - -//----------------------------------------------------------------------------- -// Queues up an overlay rendering -//----------------------------------------------------------------------------- -void CViewRender::QueueOverlayRenderView( const CViewSetup &view, int nClearFlags, int whatToDraw ) -{ -#ifndef _XBOX - // Can't have 2 in a single scene - Assert( !m_bDrawOverlay ); - m_bDrawOverlay = true; - m_OverlayViewSetup = view; - m_OverlayClearFlags = nClearFlags; - m_OverlayDrawFlags = whatToDraw; -#endif -} - - -//----------------------------------------------------------------------------- -// Purpose: This renders the entire 3D view and the in-game hud/viewmodel -// Input : &view - -// whatToDraw - -//----------------------------------------------------------------------------- -// This renders the entire 3D view. -void CViewRender::RenderViewEx( const CViewSetup &view, int nClearFlags, int whatToDraw ) -{ - m_CurrentView = view; - - VPROF( "CViewRender::RenderViewEx" ); - - ITexture *saveRenderTarget = materials->GetRenderTarget(); - - g_pClientShadowMgr->AdvanceFrame(); - -#ifdef USE_MONITORS - if ( cl_drawmonitors.GetBool() && g_pMaterialSystemHardwareConfig->GetDXSupportLevel() >= 70 ) - { - DrawMonitors( view ); - } -#endif - - g_bRenderingView = true; - - // Must be first - render->SceneBegin(); - materials->TurnOnToneMapping(); - - // clear happens here probably - SetupMain3DView( view, nClearFlags ); - - bool bDrew3dSkybox = false; - bool bSkyboxVisible = false; - - // if the 3d skybox world is drawn, then don't draw the normal skybox - Draw3dSkyboxworld( view, nClearFlags, bDrew3dSkybox, bSkyboxVisible ); - - // Force it to clear the framebuffer if they're in solid space. - if ( ( nClearFlags & VIEW_CLEAR_COLOR ) == 0 ) - { - if ( enginetrace->GetPointContents( view.origin ) == CONTENTS_SOLID ) - { - nClearFlags |= VIEW_CLEAR_COLOR; - } - } - - // Render world and all entities, particles, etc. - if( !g_pIntroData ) - { - ViewDrawScene( bDrew3dSkybox, bSkyboxVisible, view, nClearFlags, VIEW_MAIN, whatToDraw & RENDERVIEW_DRAWVIEWMODEL ); - } - else - { - ViewDrawScene_Intro( view, nClearFlags, *g_pIntroData ); - } - - // We can still use the 'current view' stuff set up in ViewDrawScene - s_bCanAccessCurrentView = true; - - if ( !IsXbox() ) - { - engine->DrawPortals(); - } - - DisableFog(); - - // Finish scene - render->SceneEnd(); - - // Draw lightsources if enabled - render->DrawLights(); - - RenderPlayerSprites(); - - // Now actually draw the viewmodel - DrawViewModels( view, whatToDraw & RENDERVIEW_DRAWVIEWMODEL ); - - PixelVisibility_EndScene(); - - // Draw fade over entire screen if needed - byte color[4]; - bool blend; - vieweffects->GetFadeParams( view.context, &color[0], &color[1], &color[2], &color[3], &blend ); - - // Draw an overlay to make it even harder to see inside smoke particle systems. - DrawSmokeFogOverlay(); - - // Overlay screen fade on entire screen - IMaterial* pMaterial = blend ? m_ModulateSingleColor : m_TranslucentSingleColor; - render->ViewDrawFade( color, pMaterial ); - PerformScreenOverlay( view.x, view.y, view.width, view.height ); - - // Prevent sound stutter if going slow - engine->Sound_ExtraUpdate(); - -#ifndef _XBOX - if ( !building_cubemaps.GetBool() && view.m_bDoBloomAndToneMapping ) - { - DoPostProcessingEffects( view.x, view.y, view.width, view.height ); - } -#else - DoScreenSpaceBloom(); -#endif - - // And here are the screen-space effects - - // Grab the pre-color corrected frame for editing purposes - engine->GrabPreColorCorrectedFrame( view.x, view.y, view.width, view.height ); - - PerformScreenSpaceEffects( view.x, view.y, view.width, view.height ); - if ( !IsXbox() && g_pMaterialSystemHardwareConfig->GetHDRType() == HDR_TYPE_INTEGER ) - { - materials->SetToneMappingScaleLinear(Vector(1,1,1)); - } - - CleanupMain3DView( view ); - - materials->SetRenderTarget( saveRenderTarget ); - -#ifndef _XBOX - // Draw the overlay - if ( m_bDrawOverlay ) - { - // This allows us to be ok if there are nested overlay views - CViewSetup currentView = m_CurrentView; - CViewSetup tempView = m_OverlayViewSetup; - tempView.fov = ScaleFOVByWidthRatio( tempView.fov, tempView.m_flAspectRatio / ( 4.0f / 3.0f ) ); - tempView.m_bDoBloomAndToneMapping = false; // FIXME: Hack to get Mark up and running - m_bDrawOverlay = false; - RenderViewEx( tempView, m_OverlayClearFlags, m_OverlayDrawFlags ); - m_CurrentView = currentView; - } -#endif - - // Draw the 2D graphics - render->Push2DView( view, 0, false, NULL, m_Frustum ); - - Render2DEffectsPreHUD( view ); - - if ( whatToDraw & RENDERVIEW_DRAWHUD ) - { - VPROF_BUDGET( "VGui_DrawHud", VPROF_BUDGETGROUP_OTHER_VGUI ); - // paint the vgui screen - VGui_PreRender(); - - // Make sure the client .dll root panel is at the proper point before doing the "SolveTraverse" calls - vgui::VPANEL root = enginevgui->GetPanel( PANEL_CLIENTDLL ); - if ( root != 0 ) - { - vgui::ipanel()->SetPos( root, view.x, view.y ); - vgui::ipanel()->SetSize( root, view.width, view.height ); - } - // Same for client .dll tools - root = enginevgui->GetPanel( PANEL_CLIENTDLL_TOOLS ); - if ( root != 0 ) - { - vgui::ipanel()->SetPos( root, view.x, view.y ); - vgui::ipanel()->SetSize( root, view.width, view.height ); - } - - // The crosshair, etc. needs to get at the current setup stuff - AllowCurrentViewAccess( true ); - - // Draw the in-game stuff based on the actual viewport being used - render->VGui_Paint( PAINT_INGAMEPANELS ); - - AllowCurrentViewAccess( false ); - - VGui_PostRender(); - - g_pClientMode->PostRenderVGui(); - materials->Flush(); - } - - Draw2DDebuggingInfo( view ); - - m_AnglesHistory[m_AnglesHistoryCounter] = view.angles; - m_AnglesHistoryCounter = (m_AnglesHistoryCounter+1) & ANGLESHISTORY_MASK; - - // If the angles are moving fast enough, allow LOD transitions. - float angleMovementDelta = 0; - for(int i=0; i < ANGLESHISTORY_SIZE; i++) - { - angleMovementDelta += (m_AnglesHistory[(i+1) & ANGLESHISTORY_MASK] - m_AnglesHistory[i]).Length(); - } - - angleMovementDelta /= ANGLESHISTORY_SIZE; - if(angleMovementDelta > r_TransitionSensitivity.GetFloat()) - { - r_DoCovertTransitions.SetValue(1); - } - else - { - r_DoCovertTransitions.SetValue(0); - } - - Render2DEffectsPostHUD( view ); - - g_bRenderingView = false; - - // We can no longer use the 'current view' stuff set up in ViewDrawScene - s_bCanAccessCurrentView = false; - - // Next frame! - ++m_FrameNumber; - - if ( !IsXbox() ) - { - GenerateOverdrawForTesting(); - } - - render->PopView( m_Frustum ); -} - -//----------------------------------------------------------------------------- -// Purpose: Renders extra 2D effects in derived classes while the 2D view is on the stack -//----------------------------------------------------------------------------- -void CViewRender::Render2DEffectsPreHUD( const CViewSetup &view ) -{ -} - -//----------------------------------------------------------------------------- -// Purpose: Renders extra 2D effects in derived classes while the 2D view is on the stack -//----------------------------------------------------------------------------- -void CViewRender::Render2DEffectsPostHUD( const CViewSetup &view ) -{ -} - -//----------------------------------------------------------------------------- -// Purpose: Renders entire view -// Input : &view - -// drawViewModel - -//----------------------------------------------------------------------------- -void CViewRender::RenderView( const CViewSetup &view, int nClearFlags, bool bDrawViewModel ) -{ - int flags = RENDERVIEW_DRAWHUD; - if ( bDrawViewModel ) - { - flags |= RENDERVIEW_DRAWVIEWMODEL; - } - RenderViewEx( view, nClearFlags, flags ); -} - - -int CViewRender::GetDrawFlags() -{ - return m_DrawFlags; -} - - -void ViewTransform( const Vector &worldSpace, Vector &viewSpace ) -{ - const VMatrix &viewMatrix = engine->WorldToViewMatrix(); - Vector3DMultiplyPosition( viewMatrix, worldSpace, viewSpace ); -} - - -//----------------------------------------------------------------------------- -// Purpose: UNDONE: Clean this up some, handle off-screen vertices -// Input : *point - -// *screen - -// Output : int -//----------------------------------------------------------------------------- -int ScreenTransform( const Vector& point, Vector& screen ) -{ -// UNDONE: Clean this up some, handle off-screen vertices - float w; - const VMatrix &worldToScreen = engine->WorldToScreenMatrix(); - - screen.x = worldToScreen[0][0] * point[0] + worldToScreen[0][1] * point[1] + worldToScreen[0][2] * point[2] + worldToScreen[0][3]; - screen.y = worldToScreen[1][0] * point[0] + worldToScreen[1][1] * point[1] + worldToScreen[1][2] * point[2] + worldToScreen[1][3]; -// z = worldToScreen[2][0] * point[0] + worldToScreen[2][1] * point[1] + worldToScreen[2][2] * point[2] + worldToScreen[2][3]; - w = worldToScreen[3][0] * point[0] + worldToScreen[3][1] * point[1] + worldToScreen[3][2] * point[2] + worldToScreen[3][3]; - - // Just so we have something valid here - screen.z = 0.0f; - - bool behind; - if( w < 0.001f ) - { - behind = true; - screen.x *= 100000; - screen.y *= 100000; - } - else - { - behind = false; - float invw = 1.0f / w; - screen.x *= invw; - screen.y *= invw; - } - - return behind; -} - - - -//----------------------------------------------------------------------------- -// -// NOTE: Below here is all of the stuff that needs to be done for water rendering -// -//----------------------------------------------------------------------------- - - -//----------------------------------------------------------------------------- -// Determines what kind of water we're going to use -//----------------------------------------------------------------------------- -void CViewRender::DetermineWaterRenderInfo( const VisibleFogVolumeInfo_t &fogVolumeInfo, CViewRender::WaterRenderInfo_t &info ) -{ - // By default, assume cheap water (even if there's no water in the scene!) - info.m_bCheapWater = true; - info.m_bRefract = false; - info.m_bReflect = false; - info.m_bReflectEntities = false; - info.m_bDrawWaterSurface = false; - info.m_bOpaqueWater = true; - - IMaterial *pWaterMaterial = fogVolumeInfo.m_pFogVolumeMaterial; - if (( fogVolumeInfo.m_nVisibleFogVolume == -1 ) || !pWaterMaterial ) - return; - - // Use cheap water if mat_drawwater is set - info.m_bDrawWaterSurface = mat_drawwater.GetBool(); - if ( !info.m_bDrawWaterSurface ) - { - info.m_bOpaqueWater = false; - return; - } - - // Determine if the water surface is opaque or not - info.m_bOpaqueWater = !pWaterMaterial->IsTranslucent(); - - // DX level 70 can't handle anything but cheap water - if (engine->GetDXSupportLevel() < 80) - return; - - bool bForceCheap = false; - bool bForceExpensive = r_waterforceexpensive.GetBool(); - - // The material can override the default settings though - IMaterialVar *pForceCheapVar = pWaterMaterial->FindVar( "$forcecheap", NULL, false ); - IMaterialVar *pForceExpensiveVar = pWaterMaterial->FindVar( "$forceexpensive", NULL, false ); - if ( pForceCheapVar && pForceCheapVar->IsDefined() ) - { - bForceCheap = ( pForceCheapVar->GetIntValue() != 0 ); - if ( bForceCheap ) - { - bForceExpensive = false; - } - } - if ( !bForceCheap && pForceExpensiveVar && pForceExpensiveVar->IsDefined() ) - { - bForceExpensive = bForceExpensive || ( pForceExpensiveVar->GetIntValue() != 0 ); - } - - bool bDebugCheapWater = r_debugcheapwater.GetBool(); - if( bDebugCheapWater ) - { - Msg( "Water material: %s dist to water: %f\nforcecheap: %s forceexpensive: %s\n", - pWaterMaterial->GetName(), fogVolumeInfo.m_flDistanceToWater, - bForceCheap ? "true" : "false", bForceExpensive ? "true" : "false" ); - } - - // Unless expensive water is active, reflections are off. - bool bLocalReflection; - if( !bForceExpensive || !r_WaterDrawReflection.GetBool() ) - { - bLocalReflection = false; - } - else - { - IMaterialVar *pReflectTextureVar = pWaterMaterial->FindVar( "$reflecttexture", NULL, false ); - bLocalReflection = pReflectTextureVar && (pReflectTextureVar->GetType() == MATERIAL_VAR_TYPE_TEXTURE); - } - - // FIXME: I disabled cheap water LOD when local specular is specified. - // There are very few places that appear to actually - // take advantage of it (places where water is in the PVS, but outside of LOD range). - // It was 2 hours before code lock, and I had the choice of either doubling fill-rate everywhere - // by making cheap water lod actually work (the water LOD wasn't actually rendering!!!) - // or to just always render the reflection + refraction if there's a local specular specified. - // Note that water LOD *does* work with refract-only water - - // Check if the water is out of the cheap water LOD range; if so, use cheap water - if ( ( (fogVolumeInfo.m_flDistanceToWater >= m_flCheapWaterEndDistance) && !bLocalReflection ) || bForceCheap ) - return; - - // Get the material that is for the water surface that is visible and check to see - // what render targets need to be rendered, if any. - if ( !r_WaterDrawRefraction.GetBool() ) - { - info.m_bRefract = false; - } - else - { - IMaterialVar *pRefractTextureVar = pWaterMaterial->FindVar( "$refracttexture", NULL, false ); - info.m_bRefract = pRefractTextureVar && (pRefractTextureVar->GetType() == MATERIAL_VAR_TYPE_TEXTURE); - - // Refractive water can be seen through - if ( info.m_bRefract ) - { - info.m_bOpaqueWater = false; - } - } - -#ifndef _XBOX - info.m_bReflect = bLocalReflection; - if ( info.m_bReflect ) - { - if( r_waterforcereflectentities.GetBool() ) - { - info.m_bReflectEntities = true; - } - else - { - IMaterialVar *pReflectEntitiesVar = pWaterMaterial->FindVar( "$reflectentities", NULL, false ); - info.m_bReflectEntities = pReflectEntitiesVar && (pReflectEntitiesVar->GetIntValue() != 0); - } - } -#endif - - info.m_bCheapWater = !info.m_bReflect && !info.m_bRefract; - - if( bDebugCheapWater ) - { - Warning( "refract: %s reflect: %s\n", info.m_bRefract ? "true" : "false", info.m_bReflect ? "true" : "false" ); - } -} - -//----------------------------------------------------------------------------- -// Draws the world and all entities -//----------------------------------------------------------------------------- -void CViewRender::WaterDrawWorldAndEntities( bool bDrawSkybox, const CViewSetup &viewIn, int nClearFlags ) -{ - MDLCACHE_CRITICAL_SECTION(); - - VisibleFogVolumeInfo_t fogVolumeInfo; - render->GetVisibleFogVolume( viewIn.origin, &fogVolumeInfo ); - - WaterRenderInfo_t info; - DetermineWaterRenderInfo( fogVolumeInfo, info ); - - if ( info.m_bCheapWater ) - { - ViewDrawScene_NoWater( bDrawSkybox, viewIn, nClearFlags, fogVolumeInfo, info ); - return; - } - - // Blat out the visible fog leaf if we're not going to use it - if ( !r_ForceWaterLeaf.GetBool() ) - { - fogVolumeInfo.m_nVisibleFogVolumeLeaf = -1; - } - - // We can see water of some sort - if ( !fogVolumeInfo.m_bEyeInFogVolume ) - { - ViewDrawScene_EyeAboveWater( bDrawSkybox, viewIn, nClearFlags, fogVolumeInfo, info ); - } - else - { - ViewDrawScene_EyeUnderWater( bDrawSkybox, viewIn, nClearFlags, fogVolumeInfo, info ); - } -} - - -//----------------------------------------------------------------------------- -// Pushes a water render target -//----------------------------------------------------------------------------- -static Vector SavedLinearLightMapScale(-1,-1,-1); // x<0 = no saved scale - -static void SetLightmapScaleForWater(void) -{ - if (g_pMaterialSystemHardwareConfig->GetHDRType()==HDR_TYPE_INTEGER) - { - SavedLinearLightMapScale=materials->GetToneMappingScaleLinear(); - Vector t25=SavedLinearLightMapScale; - t25*=0.25; - materials->SetToneMappingScaleLinear(t25); - } -} -void CViewRender::PushWaterRenderTarget( CViewSetup &view, int nClearFlags, float waterHeight, int flags ) -{ - float spread = 2.0f; - float origWaterHeight = waterHeight; - if( flags & DF_FUDGE_UP ) - { - waterHeight += spread; - } - else - { - waterHeight -= spread; - } - - MaterialHeightClipMode_t clipMode = MATERIAL_HEIGHTCLIPMODE_DISABLE; - if ( ( flags & DF_CLIP_Z ) && mat_clipz.GetBool() ) - { - if( flags & DF_CLIP_BELOW ) - { - clipMode = MATERIAL_HEIGHTCLIPMODE_RENDER_ABOVE_HEIGHT; - } - else - { - clipMode = MATERIAL_HEIGHTCLIPMODE_RENDER_BELOW_HEIGHT; - } - } - - if( flags & DF_RENDER_REFRACTION ) - { - ITexture *pTexture = GetWaterRefractionTexture(); - - // Use the aspect ratio of the main view! So, don't recompute it here - view.x = view.y = 0; - view.width = pTexture->GetActualWidth(); - view.height = pTexture->GetActualHeight(); - - materials->SetFogZ( waterHeight ); - materials->SetHeightClipZ( waterHeight ); - materials->SetHeightClipMode( clipMode ); - - // Have to re-set up the view since we reset the size - render->Push3DView( view, nClearFlags, true, pTexture, m_Frustum ); - return; - } - - if( flags & DF_RENDER_REFLECTION ) - { - ITexture *pTexture = GetWaterReflectionTexture(); - - materials->SetFogZ( waterHeight ); - - // Use the aspect ratio of the main view! So, don't recompute it here - view.x = view.y = 0; - view.width = pTexture->GetActualWidth(); - view.height = pTexture->GetActualHeight(); - view.angles[0] = -view.angles[0]; - view.angles[2] = -view.angles[2]; - view.origin[2] -= 2.0f * ( view.origin[2] - (origWaterHeight)); - bool bSoftwareUserClipPlane = g_pMaterialSystemHardwareConfig->UseFastClipping(); - if( bSoftwareUserClipPlane && ( view.origin[2] > waterHeight - r_eyewaterepsilon.GetFloat() ) ) - { - waterHeight = view.origin[2] + r_eyewaterepsilon.GetFloat(); - } - - materials->SetHeightClipZ( waterHeight ); - materials->SetHeightClipMode( clipMode ); - - render->Push3DView( view, nClearFlags, true, pTexture, m_Frustum ); - SetLightmapScaleForWater(); - return; - } - - if ( nClearFlags & (VIEW_CLEAR_DEPTH | VIEW_CLEAR_COLOR) ) - { - materials->ClearBuffers( nClearFlags & VIEW_CLEAR_COLOR, nClearFlags & VIEW_CLEAR_DEPTH ); - } - - materials->SetHeightClipMode( clipMode ); - if ( clipMode != MATERIAL_HEIGHTCLIPMODE_DISABLE ) - { - materials->SetHeightClipZ( waterHeight ); - } -} - - -//----------------------------------------------------------------------------- -// Pops a water render target -//----------------------------------------------------------------------------- -void CViewRender::PopWaterRenderTarget( int nFlags ) -{ - materials->SetHeightClipMode( MATERIAL_HEIGHTCLIPMODE_DISABLE ); - if( nFlags & (DF_RENDER_REFRACTION | DF_RENDER_REFLECTION) ) - { - render->PopView( m_Frustum ); - if (SavedLinearLightMapScale.x>=0) - { - materials->SetToneMappingScaleLinear(SavedLinearLightMapScale); - SavedLinearLightMapScale.x=-1; - } - } -} - - -//----------------------------------------------------------------------------- -// Draws the world + entities -//----------------------------------------------------------------------------- -void CViewRender::WaterDrawHelper( const CViewSetup &view, ClientWorldListInfo_t &info, CRenderList &renderList, - float waterHeight, int flags, view_id_t viewID, float waterZAdjust, int iForceViewLeaf ) -{ - int savedViewID = g_CurrentViewID; - g_CurrentViewID = viewID; - - // Need a copy of the view since pushing a water render target - // make change the aspect ratio of the projection space transform - CViewSetup actualView = view; - - int nClearFlags = 0; - if ( flags & DF_CLEARDEPTH ) - { - nClearFlags |= VIEW_CLEAR_DEPTH; - } - if ( flags & DF_CLEARCOLOR ) - { - nClearFlags |= VIEW_CLEAR_COLOR; - } - - PushWaterRenderTarget( actualView, nClearFlags, waterHeight, flags ); - - if( flags & DF_BUILDWORLDLISTS ) - { - bool bDrawEntities = ( flags & DF_DRAW_ENTITITES ) != 0; - bool bUpdateLightmaps = ( flags & DF_UPDATELIGHTMAPS ) != 0; - BuildWorldRenderLists( &actualView, info, bUpdateLightmaps, bDrawEntities, iForceViewLeaf ); - } - - // Make sure sound doesn't stutter - engine->Sound_ExtraUpdate(); - - // Update our render view flags. - m_DrawFlags = flags | m_BaseDrawFlags; - - ITexture *pSaveFrameBufferCopyTexture = materials->GetFrameBufferCopyTexture( 0 ); - if ( engine->GetDXSupportLevel() >= 80 ) - { - materials->SetFrameBufferCopyTexture( GetPowerOfTwoFrameBufferTexture() ); - } - - DrawWorld( info, renderList, m_DrawFlags, waterZAdjust ); - - // FIXME: This may have to be static, not sure if we'll get a stack overflow - ClientWorldListInfo_t tmpInfo; - tmpInfo.m_pLeafList = (LeafIndex_t*)stackalloc( info.m_LeafCount * sizeof(LeafIndex_t) ); - tmpInfo.m_pLeafFogVolume = (LeafFogVolume_t*)stackalloc( info.m_LeafCount * sizeof(LeafFogVolume_t) ); - tmpInfo.m_pActualLeafIndex = (LeafIndex_t*)stackalloc( info.m_LeafCount * sizeof(LeafIndex_t) ); - ClientWorldListInfo_t *pInfo = ComputeActualWorldListInfo( info, m_DrawFlags, tmpInfo ); - - - if ( flags & DF_DRAW_ENTITITES ) - { - BuildRenderableRenderLists( &actualView, *pInfo, renderList ); - DrawOpaqueRenderables( *pInfo, renderList ); - DrawTranslucentRenderables( *pInfo, renderList, m_DrawFlags, false ); - } - else - { - // Draw translucent world brushes only, no entities - DrawTranslucentWorldInLeaves( pInfo->m_LeafCount - 1, 0, *pInfo, m_DrawFlags ); - } - - // issue the pixel visibility tests - if ( CurrentViewID() != VIEW_MAIN ) - { - PixelVisibility_EndCurrentView(); - } - - materials->SetFrameBufferCopyTexture( pSaveFrameBufferCopyTexture ); - PopWaterRenderTarget( m_DrawFlags ); - - m_DrawFlags = m_BaseDrawFlags; - g_CurrentViewID = savedViewID; -} - - -//----------------------------------------------------------------------------- -// Returns true if the view plane intersects the water -//----------------------------------------------------------------------------- -bool DoesViewPlaneIntersectWater( float waterZ, int leafWaterDataID ) -{ - if ( leafWaterDataID == -1 ) - return false; - - VMatrix viewMatrix, projectionMatrix, viewProjectionMatrix, inverseViewProjectionMatrix; - materials->GetMatrix( MATERIAL_VIEW, &viewMatrix ); - materials->GetMatrix( MATERIAL_PROJECTION, &projectionMatrix ); - MatrixMultiply( projectionMatrix, viewMatrix, viewProjectionMatrix ); - MatrixInverseGeneral( viewProjectionMatrix, inverseViewProjectionMatrix ); - - Vector mins, maxs; - ClearBounds( mins, maxs ); - Vector testPoint[4]; - testPoint[0].Init( -1.0f, -1.0f, 0.0f ); - testPoint[1].Init( -1.0f, 1.0f, 0.0f ); - testPoint[2].Init( 1.0f, -1.0f, 0.0f ); - testPoint[3].Init( 1.0f, 1.0f, 0.0f ); - int i; - bool bAbove = false; - bool bBelow = false; - float fudge = 7.0f; - for( i = 0; i < 4; i++ ) - { - Vector worldPos; - Vector3DMultiplyPositionProjective( inverseViewProjectionMatrix, testPoint[i], worldPos ); - AddPointToBounds( worldPos, mins, maxs ); -// Warning( "viewplanez: %f waterZ: %f\n", worldPos.z, waterZ ); - if( worldPos.z + fudge > waterZ ) - { - bAbove = true; - } - if( worldPos.z - fudge < waterZ ) - { - bBelow = true; - } - } - - // early out if the near plane doesn't cross the z plane of the water. - if( !( bAbove && bBelow ) ) - return false; - - Vector vecFudge( fudge, fudge, fudge ); - mins -= vecFudge; - maxs += vecFudge; - - // the near plane does cross the z value for the visible water volume. Call into - // the engine to find out if the near plane intersects the water volume. - return render->DoesBoxIntersectWaterVolume( mins, maxs, leafWaterDataID ); -} - -static void CalcWaterEyeAdjustments( const CViewSetup &view, const VisibleFogVolumeInfo_t &fogInfo, - float &newWaterHeight, float &waterZAdjust, bool bSoftwareUserClipPlane ) -{ - if( !bSoftwareUserClipPlane ) - { - newWaterHeight = fogInfo.m_flWaterHeight; - waterZAdjust = 0.0f; - return; - } - - newWaterHeight = fogInfo.m_flWaterHeight; - float eyeToWaterZDelta = view.origin[2] - fogInfo.m_flWaterHeight; - float epsilon = r_eyewaterepsilon.GetFloat(); - waterZAdjust = 0.0f; - if( fabs( eyeToWaterZDelta ) < epsilon ) - { - if( eyeToWaterZDelta > 0 ) - { - newWaterHeight = view.origin[2] - epsilon; - } - else - { - newWaterHeight = view.origin[2] + epsilon; - } - waterZAdjust = newWaterHeight - fogInfo.m_flWaterHeight; - } - -// Warning( "view.origin[2]: %f newWaterHeight: %f fogInfo.m_flWaterHeight: %f waterZAdjust: %f\n", -// ( float )view.origin[2], newWaterHeight, fogInfo.m_flWaterHeight, waterZAdjust ); -} - - -#ifdef _XBOX -//----------------------------------------------------------------------------- -// Draws a perspective-correct dudv map into the reflection texture -//----------------------------------------------------------------------------- -void CViewRender::DrawScreenSpaceWaterDuDv( const CViewSetup &view, float waterZAdjust ) -{ - ITexture *pTexture = GetWaterReflectionTexture(); - - // Use the aspect ratio of the main view! So, don't recompute it here - CViewSetup actualView = view; - actualView.width = pTexture->GetActualWidth(); - actualView.height = pTexture->GetActualHeight(); - - // these DU/DV constants need to be 64, not 128 on xbox because the texture is signed and we only use the positive half of that space - materials->ClearColor4ub( 255, 64, 64, 0 ); - render->Push3DView( actualView, VIEW_CLEAR_DEPTH | VIEW_CLEAR_COLOR, true, pTexture, m_Frustum ); - materials->SetHeightClipMode( MATERIAL_HEIGHTCLIPMODE_DISABLE ); - - // Make sure sound doesn't stutter - engine->Sound_ExtraUpdate(); - - render->DrawWaterDuDv( waterZAdjust ); - - render->PopView( m_Frustum ); -} -#endif // _XBOX - -//----------------------------------------------------------------------------- -// Draws the scene when the view point is above the level of the water -//----------------------------------------------------------------------------- -#include "tier0/memdbgoff.h" - -void CViewRender::ViewDrawScene_EyeAboveWater( bool bDrawSkybox, const CViewSetup &view, - int nClearFlags, const VisibleFogVolumeInfo_t &fogInfo, const WaterRenderInfo_t& waterInfo ) -{ - VPROF( "CViewRender::ViewDrawScene_EyeAboveWater" ); - - bool bSoftwareUserClipPlane = g_pMaterialSystemHardwareConfig->UseFastClipping(); - - ClientWorldListInfo_t info; -#ifndef _XBOX - CRenderList renderList; - CRenderList *pRenderList = &renderList; -#else - void *ptr = MemAllocScratch(sizeof(CRenderList)); - CRenderList *pRenderList = new (ptr) CRenderList; -#endif - - float newWaterHeight, waterZAdjust; - CalcWaterEyeAdjustments( view, fogInfo, newWaterHeight, waterZAdjust, bSoftwareUserClipPlane ); - - // eye is outside of water - - // render the reflection - if( waterInfo.m_bReflect ) - { - // NOTE: Clearing the color is unnecessary since we're drawing the skybox - // and dest-alpha is never used in the reflection - int nFlags = DF_RENDER_REFLECTION | DF_CLIP_Z | DF_CLIP_BELOW | - DF_RENDER_ABOVEWATER | DF_CLEARDEPTH | DF_UPDATELIGHTMAPS | DF_BUILDWORLDLISTS; - - // NOTE: This will cause us to draw the 2d skybox in the reflection - // (which we want to do instead of drawing the 3d skybox) - nFlags |= DF_DRAWSKYBOX; - - if( waterInfo.m_bReflectEntities ) - { - nFlags |= DF_DRAW_ENTITITES; - } - - // Disable occlusion visualization in reflection - bool bVisOcclusion = r_visocclusion.GetInt(); - r_visocclusion.SetValue( 0 ); - - EnableWorldFog(); - WaterDrawHelper( view, info, *pRenderList, fogInfo.m_flWaterHeight, nFlags, VIEW_REFLECTION, - 0.0f, fogInfo.m_nVisibleFogVolumeLeaf ); - - r_visocclusion.SetValue( bVisOcclusion ); - - materials->Flush(); - } - - unsigned char ucFogColor[3]; - - int nFlags; - bool bViewIntersectsWater = false; - // render refraction - int nFirstPassFlags = DF_BUILDWORLDLISTS | DF_UPDATELIGHTMAPS | DF_CLEARCOLOR; - if ( waterInfo.m_bRefract ) - { - nFlags = nFirstPassFlags | DF_RENDER_REFRACTION | DF_CLIP_Z | - DF_RENDER_UNDERWATER | DF_FUDGE_UP | - DF_DRAW_ENTITITES | DF_MAINTAINWORLDLISTS | DF_CLEARDEPTH; - nFirstPassFlags = 0; - - render->SetFogVolumeState( fogInfo.m_nVisibleFogVolume, true ); - - SetClearColorToFogColor( ucFogColor ); - WaterDrawHelper( view, info, *pRenderList, newWaterHeight, nFlags, VIEW_REFRACTION, - waterZAdjust, -1 ); - if( !bSoftwareUserClipPlane ) - { - bViewIntersectsWater = DoesViewPlaneIntersectWater( fogInfo.m_flWaterHeight, fogInfo.m_nVisibleFogVolume ); - } - -#ifdef _XBOX - // This is a workaround for the lack of perspective correction on the XBox for dudv maps - EnableWorldFog(); - DrawScreenSpaceWaterDuDv( view, waterZAdjust ); -#endif - - materials->ClearColor4ub( 0, 0, 0, 255 ); - } - - materials->Flush(); - - EnableWorldFog(); - - // render the world - nFlags = nFirstPassFlags | DF_RENDER_ABOVEWATER | DF_CLEARDEPTH | DF_DRAW_ENTITITES | DF_MAINTAINWORLDLISTS; - if( bViewIntersectsWater && !bSoftwareUserClipPlane ) - { - // This is necessary to keep the non-water fogged world from drawing underwater in - // the case where we want to partially see into the water. - nFlags |= DF_CLIP_Z | DF_CLIP_BELOW; - } - - if ( bDrawSkybox ) - { - nFlags |= DF_DRAWSKYBOX; - nFlags &= ~DF_CLEARCOLOR; - } - if ( waterInfo.m_bDrawWaterSurface ) - { - nFlags |= DF_RENDER_WATER; - } - if ( !waterInfo.m_bRefract && !waterInfo.m_bOpaqueWater ) - { - nFlags |= DF_RENDER_UNDERWATER; - } - - WaterDrawHelper( view, info, *pRenderList, newWaterHeight, nFlags, CurrentViewID(), waterZAdjust, -1 ); - - if( waterZAdjust != 0.0f && bSoftwareUserClipPlane && waterInfo.m_bRefract ) - { - nFlags = DF_RENDER_UNDERWATER; - WaterDrawHelper( view, info, *pRenderList, newWaterHeight, nFlags, CurrentViewID(), waterZAdjust,-1 ); - } - else if( bViewIntersectsWater ) - { - materials->ClearColor4ub( ucFogColor[0], ucFogColor[1], ucFogColor[2], 255 ); - render->SetFogVolumeState( fogInfo.m_nVisibleFogVolume, true ); - nFlags = DF_RENDER_UNDERWATER | DF_CLIP_Z | DF_DRAW_ENTITITES; - WaterDrawHelper( view, info, *pRenderList, fogInfo.m_flWaterHeight, nFlags, VIEW_NONE, 0.0f, -1 ); - } - materials->ClearColor4ub( 0, 0, 0, 255 ); - -#ifdef _XBOX - MemFreeScratch(); -#endif -} - -#include "tier0/memdbgon.h" - - -//----------------------------------------------------------------------------- -// Draws the scene when the view point is under the level of the water -//----------------------------------------------------------------------------- -#include "tier0/memdbgoff.h" - -void CViewRender::ViewDrawScene_EyeUnderWater( bool bDrawSkybox, const CViewSetup &view, - int nClearFlags, const VisibleFogVolumeInfo_t &fogInfo, const WaterRenderInfo_t& waterInfo ) -{ - // FIXME: The 3d skybox shouldn't be drawn when the eye is under water - - VPROF( "CViewRender::ViewDrawScene_EyeUnderWater" ); - - bool bSoftwareUserClipPlane = g_pMaterialSystemHardwareConfig->UseFastClipping(); - - float newWaterHeight, waterZAdjust; - CalcWaterEyeAdjustments( view, fogInfo, newWaterHeight, waterZAdjust, bSoftwareUserClipPlane ); - - ClientWorldListInfo_t info; - -#ifndef _XBOX - CRenderList renderList; - CRenderList *pRenderList = &renderList; -#else - void *ptr = MemAllocScratch(sizeof(CRenderList)); - CRenderList *pRenderList = new (ptr) CRenderList; -#endif - - int nFirstPassFlags = DF_BUILDWORLDLISTS | DF_UPDATELIGHTMAPS; - - render->SetFogVolumeState( fogInfo.m_nVisibleFogVolume, true ); - unsigned char ucFogColor[3]; - materials->GetFogColor( ucFogColor ); - materials->ClearColor4ub( ucFogColor[0], ucFogColor[1], ucFogColor[2], 255 ); - - // render refraction (out of water) - if ( waterInfo.m_bRefract ) - { - // NOTE: Refraction renders into the back buffer, over the top of the 3D skybox - // It is then blitted out into the refraction target. This is so that - // we only have to set up 3d sky vis once, and only render it once also! - int nFlags = nFirstPassFlags | DF_CLIP_Z | - DF_CLIP_BELOW | DF_RENDER_ABOVEWATER | - DF_DRAW_ENTITITES | DF_MAINTAINWORLDLISTS | DF_CLEARDEPTH; - - if ( bDrawSkybox ) - { - nFlags |= DF_DRAWSKYBOX | DF_CLIP_SKYBOX | DF_CLEARCOLOR; - } - nFirstPassFlags = 0; - - EnableWorldFog(); - WaterDrawHelper( view, info, *pRenderList, newWaterHeight, nFlags, VIEW_REFRACTION, waterZAdjust, -1 ); - - Rect_t srcRect; - srcRect.x = view.x; - srcRect.y = view.y; - srcRect.width = view.width; - srcRect.height = view.height; - - ITexture *pTexture = GetWaterRefractionTexture(); - materials->CopyRenderTargetToTextureEx( pTexture, 0, &srcRect, NULL ); - -#ifdef _XBOX - // This is a workaround for the lack of perspective correction on the XBox for dudv maps - render->SetFogVolumeState( fogInfo.m_nVisibleFogVolume, false ); - DrawScreenSpaceWaterDuDv( view, waterZAdjust ); - materials->ClearColor4ub( ucFogColor[0], ucFogColor[1], ucFogColor[2], 255 ); -#endif - } - - // NOTE: We're not drawing the 2d skybox under water since it's assumed to not be visible. - - // render the world underwater - // Clear the color to get the appropriate underwater fog color - int nFlags = nFirstPassFlags | DF_MAINTAINWORLDLISTS | DF_FUDGE_UP | - DF_RENDER_UNDERWATER | DF_CLEARDEPTH | DF_DRAW_ENTITITES; - - if( !bSoftwareUserClipPlane ) - { - nFlags |= DF_CLIP_Z; - } - if ( waterInfo.m_bDrawWaterSurface ) - { - nFlags |= DF_RENDER_WATER; - } - if ( !waterInfo.m_bRefract && !waterInfo.m_bOpaqueWater ) - { - nFlags |= DF_RENDER_ABOVEWATER; - } - - render->SetFogVolumeState( fogInfo.m_nVisibleFogVolume, false ); - WaterDrawHelper( view, info, *pRenderList, newWaterHeight, nFlags, CurrentViewID(), waterZAdjust, -1 ); - - if( waterZAdjust != 0.0f && bSoftwareUserClipPlane && waterInfo.m_bRefract ) - { - nFlags = DF_RENDER_ABOVEWATER; - WaterDrawHelper( view, info, *pRenderList, newWaterHeight, nFlags, CurrentViewID(), waterZAdjust, -1 ); - } - materials->ClearColor4ub( 0, 0, 0, 255 ); - -#ifdef _XBOX - MemFreeScratch(); -#endif -} - -//----------------------------------------------------------------------------- -// Draws the scene when there's no water or cheap water -//----------------------------------------------------------------------------- -void CViewRender::ViewDrawScene_NoWater( bool bDrawSkybox, const CViewSetup &view, int nClearFlags, - const VisibleFogVolumeInfo_t &fogInfo, const WaterRenderInfo_t& waterInfo ) -{ - VPROF( "CViewRender::ViewDrawScene_NoWater" ); - - ClientWorldListInfo_t info; -#ifndef _XBOX - CRenderList renderList; - CRenderList *pRenderList = &renderList; -#else - void *ptr = MemAllocScratch(sizeof(CRenderList)); - CRenderList *pRenderList = new (ptr) CRenderList; -#endif - - int nFlags = DF_BUILDWORLDLISTS | DF_DRAW_ENTITITES | DF_UPDATELIGHTMAPS; - if ( nClearFlags & VIEW_CLEAR_COLOR ) - { - nFlags |= DF_CLEARCOLOR; - } - if ( nClearFlags & VIEW_CLEAR_DEPTH ) - { - nFlags |= DF_CLEARDEPTH; - } - - if ( !waterInfo.m_bOpaqueWater ) - { - nFlags |= DF_RENDER_UNDERWATER | DF_RENDER_ABOVEWATER; - } - else - { - bool bViewIntersectsWater = DoesViewPlaneIntersectWater( fogInfo.m_flWaterHeight, fogInfo.m_nVisibleFogVolume ); - if( bViewIntersectsWater ) - { - // have to draw both sides if we can see both. - nFlags |= DF_RENDER_UNDERWATER | DF_RENDER_ABOVEWATER; - } - else if ( fogInfo.m_bEyeInFogVolume ) - { - nFlags |= DF_RENDER_UNDERWATER; - } - else - { - nFlags |= DF_RENDER_ABOVEWATER; - } - } - if ( waterInfo.m_bDrawWaterSurface ) - { - nFlags |= DF_RENDER_WATER; - } - - if ( !fogInfo.m_bEyeInFogVolume ) - { - if ( bDrawSkybox ) - { - nFlags |= DF_DRAWSKYBOX; - } - EnableWorldFog(); - } - else - { - nFlags |= DF_CLEARCOLOR; - - render->SetFogVolumeState( fogInfo.m_nVisibleFogVolume, false ); - - unsigned char ucFogColor[3]; - materials->GetFogColor( ucFogColor ); - materials->ClearColor4ub( ucFogColor[0], ucFogColor[1], ucFogColor[2], 255 ); - } - - WaterDrawHelper( view, info, *pRenderList, 0.0f, nFlags, CurrentViewID(), 0.0f, m_iForceViewLeaf ); - materials->ClearColor4ub( 0, 0, 0, 255 ); - -#ifdef _XBOX - MemFreeScratch(); -#endif -} - -#include "tier0/memdbgon.h" - -//----------------------------------------------------------------------------- -// Methods related to controlling the cheap water distance -//----------------------------------------------------------------------------- -void CViewRender::SetCheapWaterStartDistance( float flCheapWaterStartDistance ) -{ - m_flCheapWaterStartDistance = flCheapWaterStartDistance; -} - -void CViewRender::SetCheapWaterEndDistance( float flCheapWaterEndDistance ) -{ - m_flCheapWaterEndDistance = flCheapWaterEndDistance; -} - -void CViewRender::GetWaterLODParams( float &flCheapWaterStartDistance, float &flCheapWaterEndDistance ) -{ - flCheapWaterStartDistance = m_flCheapWaterStartDistance; - flCheapWaterEndDistance = m_flCheapWaterEndDistance; -} - -static void CheapWaterStart_f( void ) -{ - if( engine->Cmd_Argc() == 2 ) - { - float dist = atof( engine->Cmd_Argv( 1 ) ); - view->SetCheapWaterStartDistance( dist ); - } - else - { - float start, end; - view->GetWaterLODParams( start, end ); - Warning( "r_cheapwaterstart: %f\n", start ); - } -} - -static void CheapWaterEnd_f( void ) -{ - if( engine->Cmd_Argc() == 2 ) - { - float dist = atof( engine->Cmd_Argv( 1 ) ); - view->SetCheapWaterEndDistance( dist ); - } - else - { - float start, end; - view->GetWaterLODParams( start, end ); - Warning( "r_cheapwaterend: %f\n", end ); - } -} - - -//----------------------------------------------------------------------------- -// A console command allowing you to draw a material as an overlay -//----------------------------------------------------------------------------- -static void ScreenOverlay_f( void ) -{ - if( engine->Cmd_Argc() == 2 ) - { - if ( !Q_stricmp( "off", engine->Cmd_Argv(1) ) ) - { - view->SetScreenOverlayMaterial( NULL ); - } - else - { - IMaterial *pMaterial = materials->FindMaterial( engine->Cmd_Argv(1), TEXTURE_GROUP_OTHER, false ); - if ( !IsErrorMaterial( pMaterial ) ) - { - view->SetScreenOverlayMaterial( pMaterial ); - } - else - { - view->SetScreenOverlayMaterial( NULL ); - } - } - } - else - { - IMaterial *pMaterial = view->GetScreenOverlayMaterial(); - Warning( "r_screenoverlay: %s\n", pMaterial ? pMaterial->GetName() : "off" ); - } -} - - -//----------------------------------------------------------------------------- -// Purpose: -// Input : &view - -// &introData - -//----------------------------------------------------------------------------- -void CViewRender::ViewDrawScene_Intro( const CViewSetup &view, int nClearFlags, const IntroData_t &introData ) -{ - VPROF( "CViewRender::ViewDrawScene" ); - - // ----------------------------------------------------------------------- - // Set the clear color to black since we are going to be adding up things - // in the frame buffer. - // ----------------------------------------------------------------------- - // Clear alpha to 255 so that masking with the vortigaunts (0) works properly. - materials->ClearColor4ub( 0, 0, 0, 255 ); - - // ----------------------------------------------------------------------- - // Draw the primary scene and copy it to the first framebuffer texture - // ----------------------------------------------------------------------- - CViewSetup playerView = view; - playerView.origin = introData.m_vecCameraView; - playerView.m_vUnreflectedOrigin = introData.m_vecCameraView; - playerView.angles = introData.m_vecCameraViewAngles; - if ( introData.m_playerViewFOV ) - { - playerView.fov = ScaleFOVByWidthRatio( introData.m_playerViewFOV, engine->GetScreenAspectRatio() / ( 4.0f / 3.0f ) ); - } - SetupCurrentView( playerView.origin, playerView.angles, VIEW_INTRO_PLAYER ); - - // Invoke pre-render methods - IGameSystem::PreRenderAllSystems(); - - // Start view, clear frame/z buffer if necessary - unsigned int visFlags; - SetupVis( playerView, visFlags ); - - if( introData.m_bDrawSecondary ) - { - // NOTE: We only increment this once since time doesn't move forward. - ParticleMgr()->IncrementFrameCode(); - } - - if( introData.m_bDrawPrimary ) - { - DrawWorldAndEntities( true /* drawSkybox */, playerView, VIEW_CLEAR_COLOR | VIEW_CLEAR_DEPTH ); - } - else - { - materials->ClearBuffers( true, true ); - } - - Rect_t actualRect; - UpdateScreenEffectTexture( 0, view.x, view.y, view.width, view.height, false, &actualRect ); - - // ----------------------------------------------------------------------- - // Draw the secondary scene and copy it to the second framebuffer texture - // ----------------------------------------------------------------------- - CViewSetup cameraView = view; - SetupCurrentView( cameraView.origin, cameraView.angles, VIEW_INTRO_CAMERA ); - - // Invoke pre-render methods - IGameSystem::PreRenderAllSystems(); - - // Start view, clear frame/z buffer if necessary - SetupVis( cameraView, visFlags ); - - // Clear alpha to 255 so that masking with the vortigaunts (0) works properly. - materials->ClearColor4ub( 0, 0, 0, 255 ); - - if( introData.m_bDrawSecondary ) - { - DrawWorldAndEntities( true /* drawSkybox */, cameraView, VIEW_CLEAR_COLOR | VIEW_CLEAR_DEPTH ); - } - else - { - materials->ClearBuffers( true, true ); - } - UpdateScreenEffectTexture( 1, view.x, view.y, view.width, view.height ); - - // ----------------------------------------------------------------------- - // Draw quads on the screen for each screenspace pass. - // ----------------------------------------------------------------------- - // Find the material that we use to render the overlays - IMaterial *pOverlayMaterial = materials->FindMaterial( "scripted/intro_screenspaceeffect", TEXTURE_GROUP_OTHER ); - IMaterialVar *pModeVar = pOverlayMaterial->FindVar( "$mode", NULL ); - IMaterialVar *pAlphaVar = pOverlayMaterial->FindVar( "$alpha", NULL ); - - materials->ClearBuffers( true, true ); - - materials->MatrixMode( MATERIAL_VIEW ); - materials->PushMatrix(); - materials->LoadIdentity(); - - materials->MatrixMode( MATERIAL_PROJECTION ); - materials->PushMatrix(); - materials->LoadIdentity(); - - int passID; - for( passID = 0; passID < introData.m_Passes.Count(); passID++ ) - { - const IntroDataBlendPass_t& pass = introData.m_Passes[passID]; - if ( pass.m_Alpha == 0 ) - continue; - - // Pick one of the blend modes for the material. - if( pass.m_BlendMode >= 0 && pass.m_BlendMode < 9 ) - { - pModeVar->SetIntValue( pass.m_BlendMode ); - } - else - { - Assert(0); - } - // Set the alpha value for the material. - pAlphaVar->SetFloatValue( pass.m_Alpha ); - - // Draw a quad for this pass. - ITexture *pTexture = GetFullFrameFrameBufferTexture( 0 ); - materials->DrawScreenSpaceRectangle( pOverlayMaterial, view.x, view.y, view.width, view.height, - actualRect.x, actualRect.y, actualRect.x+actualRect.width-1, actualRect.y+actualRect.height-1, - pTexture->GetActualWidth(), pTexture->GetActualHeight() ); - } - - materials->MatrixMode( MATERIAL_VIEW ); - materials->PopMatrix(); - - materials->MatrixMode( MATERIAL_PROJECTION ); - materials->PopMatrix(); - - // Draw the starfield - // FIXME - // blur? - - // Disable fog for the rest of the stuff - DisableFog(); - - // Here are the overlays... - CGlowOverlay::DrawOverlays( view.m_bCacheFullSceneState ); - - // issue the pixel visibility tests - PixelVisibility_EndCurrentView(); - - // And here are the screen-space effects - PerformScreenSpaceEffects( view.x, view.y, view.width, view.height ); - - // Make sure sound doesn't stutter - engine->Sound_ExtraUpdate(); - - // Debugging info goes over the top - Draw3DDebuggingInfo( view ); - - // Let the particle manager simulate things that haven't been simulated. - ParticleMgr()->PostRender(); - - FinishCurrentView(); -} - -#ifdef _XBOX -void ViewTexture_f() -{ - int argc; - char* enable; - - argc = engine->Cmd_Argc(); - if (argc == 1) - { - // toggle - enable = mat_viewTextureEnable.GetInt() ? "0" : "1"; - } - else - { - // force on - enable = "1"; - } - - mat_viewTextureEnable.SetValue(enable); - if (argc >= 2) - mat_viewTextureName.SetValue(engine->Cmd_Argv(1)); - if (argc >= 3) - mat_viewTextureScale.SetValue(engine->Cmd_Argv(2)); -} -static ConCommand mat_viewTexture("mat_viewTexture", ViewTexture_f, "Show/Hide texture [name] [scale]"); -#endif - - -static ConCommand r_cheapwaterstart( "r_cheapwaterstart", CheapWaterStart_f ); -static ConCommand r_cheapwaterend( "r_cheapwaterend", CheapWaterEnd_f ); -static ConCommand r_screenspacematerial( "r_screenoverlay", ScreenOverlay_f ); - - diff --git a/src/src/common/compiledcaptionswap.cpp b/src/src/common/compiledcaptionswap.cpp new file mode 100644 index 0000000..e2d083e --- /dev/null +++ b/src/src/common/compiledcaptionswap.cpp @@ -0,0 +1,103 @@ +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: Swap a compiled caption file. +// +// $NoKeywords: $ +//=============================================================================// + +#include "utlbuffer.h" +#include "byteswap.h" +#include "filesystem.h" +#include "tier2/fileutils.h" +#include "captioncompiler.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +BEGIN_BYTESWAP_DATADESC( CompiledCaptionHeader_t ) + DEFINE_FIELD( magic, FIELD_INTEGER ), + DEFINE_FIELD( version, FIELD_INTEGER ), + DEFINE_FIELD( numblocks, FIELD_INTEGER ), + DEFINE_FIELD( blocksize, FIELD_INTEGER ), + DEFINE_FIELD( directorysize, FIELD_INTEGER ), + DEFINE_FIELD( dataoffset, FIELD_INTEGER ), +END_BYTESWAP_DATADESC() + +BEGIN_BYTESWAP_DATADESC( CaptionLookup_t ) + DEFINE_FIELD( hash, FIELD_INTEGER ), + DEFINE_FIELD( blockNum, FIELD_INTEGER ), + DEFINE_FIELD( offset, FIELD_SHORT ), + DEFINE_FIELD( length, FIELD_SHORT ), +END_BYTESWAP_DATADESC() + +//----------------------------------------------------------------------------- +// Swap a compiled closecaption file +//----------------------------------------------------------------------------- +bool SwapClosecaptionFile( void *pData ) +{ + CByteswap swap; + swap.ActivateByteSwapping( true ); + + CompiledCaptionHeader_t *pHdr = (CompiledCaptionHeader_t*)pData; + + if ( IsX360() ) + { + // pre-swap file header + swap.SwapFieldsToTargetEndian( pHdr ); + } + + if ( pHdr->magic != COMPILED_CAPTION_FILEID || pHdr->version != COMPILED_CAPTION_VERSION ) + { + // bad data + return false; + } + + // lookup headers + pData = (byte*)pData + sizeof(CompiledCaptionHeader_t); + swap.SwapFieldsToTargetEndian( (CaptionLookup_t*)pData, pHdr->directorysize ); + + // unicode data + pData = (byte*)pHdr + pHdr->dataoffset; + swap.SwapBufferToTargetEndian( (wchar_t*)pData, (wchar_t*)pData, pHdr->numblocks * pHdr->blocksize / sizeof(wchar_t) ); + + if ( IsPC() ) + { + // post-swap file header + swap.SwapFieldsToTargetEndian( pHdr ); + } + + return true; +} + +#if defined( CLIENT_DLL ) +//----------------------------------------------------------------------------- +// Callback for UpdateOrCreate - generates .360 file +//----------------------------------------------------------------------------- +static bool CaptionCreateCallback( const char *pSourceName, const char *pTargetName, const char *pPathID, void *pExtraData ) +{ + // Generate the file + CUtlBuffer buf; + bool bOk = g_pFullFileSystem->ReadFile( pSourceName, pPathID, buf ); + if ( bOk ) + { + bOk = SwapClosecaptionFile( buf.Base() ); + if ( bOk ) + { + bOk = g_pFullFileSystem->WriteFile( pTargetName, pPathID, buf ); + } + else + { + Warning( "Failed to create %s\n", pTargetName ); + } + } + return bOk; +} + +//----------------------------------------------------------------------------- +// Calls utility function UpdateOrCreate +//----------------------------------------------------------------------------- +int UpdateOrCreateCaptionFile( const char *pSourceName, char *pTargetName, int maxLen, bool bForce ) +{ + return ::UpdateOrCreate( pSourceName, pTargetName, maxLen, "GAME", CaptionCreateCallback, bForce ); +} +#endif \ No newline at end of file diff --git a/src/src/common/gameui/igameui.h b/src/src/common/gameui/igameui.h new file mode 100644 index 0000000..0642444 --- /dev/null +++ b/src/src/common/gameui/igameui.h @@ -0,0 +1,113 @@ +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef IGAMEUI_H +#define IGAMEUI_H +#ifdef _WIN32 +#pragma once +#endif + +#include "interface.h" +#include "vgui/IPanel.h" + +#if !defined( _X360 ) +#include "xbox/xboxstubs.h" +#endif + +// reasons why the user can't connect to a game server +enum ESteamLoginFailure +{ + STEAMLOGINFAILURE_NONE, + STEAMLOGINFAILURE_BADTICKET, + STEAMLOGINFAILURE_NOSTEAMLOGIN, + STEAMLOGINFAILURE_VACBANNED, + STEAMLOGINFAILURE_LOGGED_IN_ELSEWHERE +}; + +enum ESystemNotify +{ + SYSTEMNOTIFY_STORAGEDEVICES_CHANGED, + SYSTEMNOTIFY_USER_SIGNEDIN, + SYSTEMNOTIFY_USER_SIGNEDOUT, + SYSTEMNOTIFY_XUIOPENING, + SYSTEMNOTIFY_XUICLOSED, + SYSTEMNOTIFY_INVITE_SHUTDOWN, // Cross-game invite is causing us to shutdown +}; + +//----------------------------------------------------------------------------- +// Purpose: contains all the functions that the GameUI dll exports +//----------------------------------------------------------------------------- +abstract_class IGameUI +{ +public: + // initialization/shutdown + virtual void Initialize( CreateInterfaceFn appFactory ) = 0; + virtual void PostInit() = 0; + + // connect to other interfaces at the same level (gameui.dll/server.dll/client.dll) + virtual void Connect( CreateInterfaceFn gameFactory ) = 0; + + virtual void Start() = 0; + virtual void Shutdown() = 0; + virtual void RunFrame() = 0; + + // notifications + virtual void OnGameUIActivated() = 0; + virtual void OnGameUIHidden() = 0; + + // OLD: Use OnConnectToServer2 + virtual void OLD_OnConnectToServer(const char *game, int IP, int port) = 0; + + virtual void OnDisconnectFromServer_OLD( uint8 eSteamLoginFailure, const char *username ) = 0; + virtual void OnLevelLoadingStarted(bool bShowProgressDialog) = 0; + virtual void OnLevelLoadingFinished(bool bError, const char *failureReason, const char *extendedReason) = 0; + + // level loading progress, returns true if the screen needs updating + virtual bool UpdateProgressBar(float progress, const char *statusText) = 0; + // Shows progress desc, returns previous setting... (used with custom progress bars ) + virtual bool SetShowProgressText( bool show ) = 0; + + // !!!!!!!!!members added after "GameUI011" initial release!!!!!!!!!!!!!!!!!!! + virtual void ShowNewGameDialog( int chapter ) = 0; + + // Xbox 360 + virtual void SessionNotification( const int notification, const int param = 0 ) = 0; + virtual void SystemNotification( const int notification ) = 0; + virtual void ShowMessageDialog( const uint nType, vgui::Panel *pOwner ) = 0; + virtual void UpdatePlayerInfo( uint64 nPlayerId, const char *pName, int nTeam, byte cVoiceState, int nPlayersNeeded, bool bHost ) = 0; + virtual void SessionSearchResult( int searchIdx, void *pHostData, XSESSION_SEARCHRESULT *pResult, int ping ) = 0; + virtual void OnCreditsFinished( void ) = 0; + + // inserts specified panel as background for level load dialog + virtual void SetLoadingBackgroundDialog( vgui::VPANEL panel ) = 0; + + // Bonus maps interfaces + virtual void BonusMapUnlock( const char *pchFileName = NULL, const char *pchMapName = NULL ) = 0; + virtual void BonusMapComplete( const char *pchFileName = NULL, const char *pchMapName = NULL ) = 0; + virtual void BonusMapChallengeUpdate( const char *pchFileName, const char *pchMapName, const char *pchChallengeName, int iBest ) = 0; + virtual void BonusMapChallengeNames( char *pchFileName, char *pchMapName, char *pchChallengeName ) = 0; + virtual void BonusMapChallengeObjectives( int &iBronze, int &iSilver, int &iGold ) = 0; + virtual void BonusMapDatabaseSave( void ) = 0; + virtual int BonusMapNumAdvancedCompleted( void ) = 0; + virtual void BonusMapNumMedals( int piNumMedals[ 3 ] ) = 0; + + virtual void OnConnectToServer2(const char *game, int IP, int connectionPort, int queryPort) = 0; + + // X360 Storage device validation: + // returns true right away if storage device has been previously selected. + // otherwise returns false and will set the variable pointed by pStorageDeviceValidated to 1 + // once the storage device is selected by user. + virtual bool ValidateStorageDevice( int *pStorageDeviceValidated ) = 0; + + virtual void SetProgressOnStart() = 0; + virtual void OnDisconnectFromServer( uint8 eSteamLoginFailure ) = 0; + +}; + +#define GAMEUI_INTERFACE_VERSION "GameUI011" + +#endif // IGAMEUI_H diff --git a/src/src/common/hl2orange.spa.h b/src/src/common/hl2orange.spa.h new file mode 100644 index 0000000..8d0d19d --- /dev/null +++ b/src/src/common/hl2orange.spa.h @@ -0,0 +1,363 @@ +//////////////////////////////////////////////////////////////////// +// +// hl2orange.spa.h +// +// Auto-generated on Thursday, 13 September 2007 at 16:59:17 +// XLAST project version 1.0.402.0 +// SPA Compiler version 2.0.6274.0 +// +//////////////////////////////////////////////////////////////////// + +#ifndef __THE_ORANGE_BOX_SPA_H__ +#define __THE_ORANGE_BOX_SPA_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +// +// Title info +// + +#define TITLEID_THE_ORANGE_BOX 0x4541080F + +// +// Context ids +// +// These values are passed as the dwContextId to XUserSetContext. +// + +#define CONTEXT_CHAPTER_HL2 0 +#define CONTEXT_SCENARIO 1 +#define CONTEXT_GAME 2 +#define CONTEXT_CHAPTER_EP1 3 +#define CONTEXT_CHAPTER_EP2 4 +#define CONTEXT_CHAPTER_PORTAL 5 + +// +// Context values +// +// These values are passed as the dwContextValue to XUserSetContext. +// + +// Values for CONTEXT_CHAPTER_HL2 + +#define CONTEXT_CHAPTER_HL2_POINT_INSERTION 0 +#define CONTEXT_CHAPTER_HL2_A_RED_LETTER_DAY 1 +#define CONTEXT_CHAPTER_HL2_ROUTE_KANAL 2 +#define CONTEXT_CHAPTER_HL2_WATER_HAZARD 3 +#define CONTEXT_CHAPTER_HL2_BLACK_MESA_EAST 4 +#define CONTEXT_CHAPTER_HL2_RAVENHOLM 5 +#define CONTEXT_CHAPTER_HL2_HIGHWAY_17 6 +#define CONTEXT_CHAPTER_HL2_SANDTRAPS 7 +#define CONTEXT_CHAPTER_HL2_NOVA_PROSPEKT 8 +#define CONTEXT_CHAPTER_HL2_ENTANGLEMENT 9 +#define CONTEXT_CHAPTER_HL2_ANTICITIZEN_ONE 10 +#define CONTEXT_CHAPTER_HL2_FOLLOW_FREEMAN 11 +#define CONTEXT_CHAPTER_HL2_OUR_BENEFACTORS 12 +#define CONTEXT_CHAPTER_HL2_DARK_ENERGY 13 + +// Values for CONTEXT_SCENARIO + +#define CONTEXT_SCENARIO_CTF_2FORT 0 +#define CONTEXT_SCENARIO_CP_DUSTBOWL 1 +#define CONTEXT_SCENARIO_CP_GRANARY 2 +#define CONTEXT_SCENARIO_CP_WELL 3 +#define CONTEXT_SCENARIO_CP_GRAVELPIT 4 +#define CONTEXT_SCENARIO_TC_HYDRO 5 +#define CONTEXT_SCENARIO_CTF_CLOAK 6 +#define CONTEXT_SCENARIO_CP_CLOAK 7 + +// Values for CONTEXT_GAME + +#define CONTEXT_GAME_GAME_HALF_LIFE_2 0 +#define CONTEXT_GAME_GAME_EPISODE_ONE 1 +#define CONTEXT_GAME_GAME_EPISODE_TWO 2 +#define CONTEXT_GAME_GAME_PORTAL 3 +#define CONTEXT_GAME_GAME_TEAM_FORTRESS 4 + +// Values for CONTEXT_CHAPTER_EP1 + +#define CONTEXT_CHAPTER_EP1_UNDUE_ALARM 0 +#define CONTEXT_CHAPTER_EP1_DIRECT_INTERVENTION 1 +#define CONTEXT_CHAPTER_EP1_LOWLIFE 2 +#define CONTEXT_CHAPTER_EP1_URBAN_FLIGHT 3 +#define CONTEXT_CHAPTER_EP1_EXIT_17 4 + +// Values for CONTEXT_CHAPTER_EP2 + +#define CONTEXT_CHAPTER_EP2_TO_THE_WHITE_FOREST 0 +#define CONTEXT_CHAPTER_EP2_THIS_VORTAL_COIL 1 +#define CONTEXT_CHAPTER_EP2_FREEMAN_PONTIFEX 2 +#define CONTEXT_CHAPTER_EP2_RIDING_SHOTGUN 3 +#define CONTEXT_CHAPTER_EP2_UNDER_THE_RADAR 4 +#define CONTEXT_CHAPTER_EP2_OUR_MUTUAL_FIEND 5 +#define CONTEXT_CHAPTER_EP2_T_MINUS_ONE 6 + +// Values for CONTEXT_CHAPTER_PORTAL + +#define CONTEXT_CHAPTER_PORTAL_TESTCHAMBER_00 0 +#define CONTEXT_CHAPTER_PORTAL_TESTCHAMBER_04 1 +#define CONTEXT_CHAPTER_PORTAL_TESTCHAMBER_08 2 +#define CONTEXT_CHAPTER_PORTAL_TESTCHAMBER_10 3 +#define CONTEXT_CHAPTER_PORTAL_TESTCHAMBER_13 4 +#define CONTEXT_CHAPTER_PORTAL_TESTCHAMBER_14 5 +#define CONTEXT_CHAPTER_PORTAL_TESTCHAMBER_15 6 +#define CONTEXT_CHAPTER_PORTAL_TESTCHAMBER_16 7 +#define CONTEXT_CHAPTER_PORTAL_TESTCHAMBER_17 8 +#define CONTEXT_CHAPTER_PORTAL_TESTCHAMBER_18 9 +#define CONTEXT_CHAPTER_PORTAL_TESTCHAMBER_19 10 + +// Values for X_CONTEXT_PRESENCE + +#define CONTEXT_PRESENCE_TF_CP 0 +#define CONTEXT_PRESENCE_TF_CTF_LOSING 1 +#define CONTEXT_PRESENCE_TF_CTF_TIED 2 +#define CONTEXT_PRESENCE_TF_CTF_WINNING 3 +#define CONTEXT_PRESENCE_APPCHOOSER 4 +#define CONTEXT_PRESENCE_MENU 5 +#define CONTEXT_PRESENCE_EP1_INGAME 6 +#define CONTEXT_PRESENCE_HL2_INGAME 7 +#define CONTEXT_PRESENCE_EP2_INGAME 8 +#define CONTEXT_PRESENCE_PORTAL_INGAME 9 +#define CONTEXT_PRESENCE_COMMENTARY 10 +#define CONTEXT_PRESENCE_IDLE 11 + +// Values for X_CONTEXT_GAME_MODE + +#define CONTEXT_GAME_MODE_MULTIPLAYER 0 +#define CONTEXT_GAME_MODE_SINGLEPLAYER 1 + +// +// Property ids +// +// These values are passed as the dwPropertyId value to XUserSetProperty +// and as the dwPropertyId value in the XUSER_PROPERTY structure. +// + +#define PROPERTY_CAPS_OWNED 0x10000000 +#define PROPERTY_CAPS_TOTAL 0x10000001 +#define PROPERTY_PLAYER_TEAM_SCORE 0x10000002 +#define PROPERTY_OPPONENT_TEAM_SCORE 0x10000003 +#define PROPERTY_FLAG_CAPTURE_LIMIT 0x1000000B +#define PROPERTY_NUMBER_OF_ROUNDS 0x1000000C +#define PROPERTY_GAME_SIZE 0x1000000D +#define PROPERTY_AUTOBALANCE 0x1000000E +#define PROPERTY_PRIVATE_SLOTS 0x1000000F +#define PROPERTY_MAX_GAME_TIME 0x10000010 +#define PROPERTY_NUMBER_OF_KILLS 0x10000011 +#define PROPERTY_DAMAGE_DEALT 0x10000012 +#define PROPERTY_PLAY_TIME 0x10000013 +#define PROPERTY_POINT_CAPTURES 0x10000014 +#define PROPERTY_POINT_DEFENSES 0x10000015 +#define PROPERTY_DOMINATIONS 0x10000016 +#define PROPERTY_REVENGE 0x10000017 +#define PROPERTY_BUILDINGS_DESTROYED 0x10000019 +#define PROPERTY_HEADSHOTS 0x1000001A +#define PROPERTY_HEALTH_POINTS_HEALED 0x1000001B +#define PROPERTY_INVULNS 0x1000001C +#define PROPERTY_KILL_ASSISTS 0x1000001D +#define PROPERTY_BACKSTABS 0x1000001E +#define PROPERTY_HEALTH_POINTS_LEACHED 0x1000001F +#define PROPERTY_BUILDINGS_BUILT 0x10000020 +#define PROPERTY_SENTRY_KILLS 0x10000021 +#define PROPERTY_TELEPORTS 0x10000022 +#define PROPERTY_KILLS 0x10000023 +#define PROPERTY_NUMBER_OF_TEAMS 0x10000025 +#define PROPERTY_TEAM_RED 0x10000026 +#define PROPERTY_TEAM_BLUE 0x10000027 +#define PROPERTY_TEAM_SPECTATOR 0x10000028 +#define PROPERTY_TEAM 0x10000029 +#define PROPERTY_WIN_LIMIT 0x1000002A +#define PROPERTY_RANKING_TEST 0x2000000A +#define PROPERTY_POINTS_SCORED 0x20000018 + +// +// Achievement ids +// +// These values are used in the dwAchievementId member of the +// XUSER_ACHIEVEMENT structure that is used with +// XUserWriteAchievements and XUserCreateAchievementEnumerator. +// + +#define ACHIEVEMENT_HLX_KILL_ENEMIES_WITHPHYSICS 43 +#define ACHIEVEMENT_HLX_KILL_ENEMY_WITHHOPPERMINE 44 +#define ACHIEVEMENT_HLX_KILL_ENEMIES_WITHMANHACK 45 +#define ACHIEVEMENT_HLX_KILL_SOLDIER_WITHHISGRENADE 46 +#define ACHIEVEMENT_HLX_KILL_ENEMIES_WITHONEENERGYBALL 47 +#define ACHIEVEMENT_HLX_KILL_ELITESOLDIER_WITHHISENERGYBALL 48 +#define ACHIEVEMENT_EPX_GET_ZOMBINEGRENADE 50 +#define ACHIEVEMENT_EPX_KILL_ZOMBIES_WITHFLARES 51 +#define ACHIEVEMENT_HL2_HIT_CANCOP_WITHCAN 52 +#define ACHIEVEMENT_HL2_PUT_CANINTRASH 53 +#define ACHIEVEMENT_HL2_ESCAPE_APARTMENTRAID 54 +#define ACHIEVEMENT_HL2_BREAK_MINITELEPORTER 55 +#define ACHIEVEMENT_HL2_GET_CROWBAR 56 +#define ACHIEVEMENT_HL2_KILL_BARNACLESWITHBARREL 57 +#define ACHIEVEMENT_HL2_GET_AIRBOAT 58 +#define ACHIEVEMENT_HL2_GET_AIRBOATGUN 60 +#define ACHIEVEMENT_HL2_FIND_VORTIGAUNTCAVE 61 +#define ACHIEVEMENT_HL2_KILL_CHOPPER 62 +#define ACHIEVEMENT_HL2_FIND_HEVFACEPLATE 63 +#define ACHIEVEMENT_HL2_GET_GRAVITYGUN 64 +#define ACHIEVEMENT_HL2_MAKEABASKET 65 +#define ACHIEVEMENT_HL2_BEAT_RAVENHOLM_NOWEAPONS 66 +#define ACHIEVEMENT_HL2_BEAT_CEMETERY 67 +#define ACHIEVEMENT_HL2_KILL_ENEMIES_WITHCRANE 68 +#define ACHIEVEMENT_HL2_PIN_SOLDIER_TOBILLBOARD 69 +#define ACHIEVEMENT_HL2_KILL_ODESSAGUNSHIP 70 +#define ACHIEVEMENT_HL2_KILL_THREEGUNSHIPS 71 +#define ACHIEVEMENT_HL2_BEAT_DONTTOUCHSAND 72 +#define ACHIEVEMENT_HL2_KILL_ENEMIES_WITHANTLIONS 74 +#define ACHIEVEMENT_HL2_KILL_ENEMY_WITHTOILET 75 +#define ACHIEVEMENT_HL2_BEAT_TURRETSTANDOFF2 76 +#define ACHIEVEMENT_HL2_BEAT_TOXICTUNNEL 78 +#define ACHIEVEMENT_HL2_BEAT_PLAZASTANDOFF 79 +#define ACHIEVEMENT_HL2_KILL_ALLC1709SNIPERS 80 +#define ACHIEVEMENT_HL2_BEAT_SUPRESSIONDEVICE 81 +#define ACHIEVEMENT_HL2_BEAT_C1713STRIDERSTANDOFF 82 +#define ACHIEVEMENT_HL2_BEAT_GAME 84 +#define ACHIEVEMENT_HL2_FIND_ALLLAMBDAS 86 +#define ACHIEVEMENT_EP1_BEAT_MAINELEVATOR 87 +#define ACHIEVEMENT_EP1_BEAT_CITADELCORE 88 +#define ACHIEVEMENT_EP1_BEAT_CITADELCORE_NOSTALKERKILLS 89 +#define ACHIEVEMENT_EP1_KILL_ANTLIONS_WITHCARS 90 +#define ACHIEVEMENT_EP1_BEAT_GARAGEELEVATORSTANDOFF 91 +#define ACHIEVEMENT_EP1_KILL_ENEMIES_WITHSNIPERALYX 92 +#define ACHIEVEMENT_EP1_BEAT_HOSPITALATTICGUNSHIP 93 +#define ACHIEVEMENT_EP1_BEAT_CITIZENESCORT_NOCITIZENDEATHS 94 +#define ACHIEVEMENT_EP1_BEAT_GAME 95 +#define ACHIEVEMENT_EP1_BEAT_GAME_ONEBULLET 96 +#define ACHIEVEMENT_EP2_KILL_POISONANTLION 97 +#define ACHIEVEMENT_EP2_KILL_ALLGRUBS 98 +#define ACHIEVEMENT_EP2_BREAK_ALLWEBS 99 +#define ACHIEVEMENT_EP2_BEAT_ANTLIONINVASION 100 +#define ACHIEVEMENT_EP2_BEAT_ANTLIONGUARDS 101 +#define ACHIEVEMENT_EP2_KILL_ENEMIES_WITHCAR 102 +#define ACHIEVEMENT_EP2_BEAT_HUNTERAMBUSH 103 +#define ACHIEVEMENT_EP2_KILL_CHOPPER_NOMISSES 104 +#define ACHIEVEMENT_EP2_KILL_COMBINECANNON 105 +#define ACHIEVEMENT_EP2_FIND_ALLRADARCACHES 106 +#define ACHIEVEMENT_EP2_BEAT_ROCKETCACHEPUZZLE 107 +#define ACHIEVEMENT_EP2_BEAT_RACEWITHDOG 108 +#define ACHIEVEMENT_EP2_BEAT_WHITEFORESTINN 109 +#define ACHIEVEMENT_EP2_PUT_ITEMINROCKET 110 +#define ACHIEVEMENT_EP2_BEAT_MISSILESILO2 111 +#define ACHIEVEMENT_EP2_BEAT_OUTLAND12_NOBUILDINGSDESTROYED 112 +#define ACHIEVEMENT_EP2_BEAT_GAME 113 +#define ACHIEVEMENT_EP2_KILL_HUNTER_WITHFLECHETTES 114 +#define ACHIEVEMENT_PORTAL_GET_PORTALGUNS 115 +#define ACHIEVEMENT_PORTAL_KILL_COMPANIONCUBE 116 +#define ACHIEVEMENT_PORTAL_ESCAPE_TESTCHAMBERS 117 +#define ACHIEVEMENT_PORTAL_BEAT_GAME 118 +#define ACHIEVEMENT_PORTAL_INFINITEFALL 119 +#define ACHIEVEMENT_PORTAL_LONGJUMP 120 +#define ACHIEVEMENT_PORTAL_BEAT_2ADVANCEDMAPS 121 +#define ACHIEVEMENT_PORTAL_BEAT_4ADVANCEDMAPS 122 +#define ACHIEVEMENT_PORTAL_BEAT_6ADVANCEDMAPS 123 +#define ACHIEVEMENT_PORTAL_GET_ALLBRONZE 124 +#define ACHIEVEMENT_PORTAL_GET_ALLSILVER 125 +#define ACHIEVEMENT_PORTAL_GET_ALLGOLD 126 +#define ACHIEVEMENT_TF_GET_TURRETKILLS 127 +#define ACHIEVEMENT_TF_KILL_NEMESIS 128 +#define ACHIEVEMENT_TF_GET_CONSECUTIVEKILLS_NODEATHS 129 +#define ACHIEVEMENT_TF_GET_HEALED_BYENEMY 130 +#define ACHIEVEMENT_TF_PLAY_GAME_FRIENDSONLY 131 +#define ACHIEVEMENT_TF_WIN_MULTIPLEGAMES 132 +#define ACHIEVEMENT_TF_GET_MULTIPLEKILLS 133 +#define ACHIEVEMENT_TF_WIN_2FORT_NOENEMYCAPS 134 +#define ACHIEVEMENT_TF_WIN_WELL_MINIMUMTIME 135 +#define ACHIEVEMENT_TF_WIN_HYDRO_NOENEMYCAPS 136 +#define ACHIEVEMENT_TF_WIN_DUSTBOWL_NOENEMYCAPS 137 +#define ACHIEVEMENT_TF_WIN_GRAVELPIT_NOENEMYCAPS 138 +#define ACHIEVEMENT_TF_PLAY_GAME_EVERYCLASS 139 +#define ACHIEVEMENT_TF_PLAY_GAME_EVERYMAP 140 +#define ACHIEVEMENT_TF_GET_HEALPOINTS 141 +#define ACHIEVEMENT_TF_BURN_PLAYERSINMINIMIMTIME 142 +#define ACHIEVEMENT_HL2_DISINTEGRATE_SOLDIERSINFIELD 143 +#define ACHIEVEMENT_HL2_FOLLOW_FREEMAN 144 +#define ACHIEVEMENT_TF_GET_HEADSHOTS 145 +#define ACHIEVEMENT_PORTAL_DETACH_ALL_CAMERAS 146 +#define ACHIEVEMENT_PORTAL_HIT_TURRET_WITH_TURRET 148 + +// +// Stats view ids +// +// These are used in the dwViewId member of the XUSER_STATS_SPEC structure +// passed to the XUserReadStats* and XUserCreateStatsEnumerator* functions. +// + +// Skill leaderboards for ranked game modes + +#define STATS_VIEW_SKILL_RANKED_MULTIPLAYER 0xFFFF0000 +#define STATS_VIEW_SKILL_RANKED_SINGLEPLAYER 0xFFFF0001 + +// Skill leaderboards for unranked (standard) game modes + +#define STATS_VIEW_SKILL_STANDARD_MULTIPLAYER 0xFFFE0000 +#define STATS_VIEW_SKILL_STANDARD_SINGLEPLAYER 0xFFFE0001 + +// Title defined leaderboards + +#define STATS_VIEW_PLAYER_MAX_UNRANKED 1 +#define STATS_VIEW_PLAYER_MAX_RANKED 2 + +// +// Stats view column ids +// +// These ids are used to read columns of stats views. They are specified in +// the rgwColumnIds array of the XUSER_STATS_SPEC structure. Rank, rating +// and gamertag are not retrieved as custom columns and so are not included +// in the following definitions. They can be retrieved from each row's +// header (e.g., pStatsResults->pViews[x].pRows[y].dwRank, etc.). +// + +// Column ids for PLAYER_MAX_UNRANKED + +#define STATS_COLUMN_PLAYER_MAX_UNRANKED_POINTS_SCORED 2 +#define STATS_COLUMN_PLAYER_MAX_UNRANKED_KILLS 3 +#define STATS_COLUMN_PLAYER_MAX_UNRANKED_POINTS_CAPPED 1 +#define STATS_COLUMN_PLAYER_MAX_UNRANKED_DAMAGE_DEALT 4 +#define STATS_COLUMN_PLAYER_MAX_UNRANKED_PLAY_TIME 5 +#define STATS_COLUMN_PLAYER_MAX_UNRANKED_POINT_DEFENSES 6 +#define STATS_COLUMN_PLAYER_MAX_UNRANKED_DOMINATIONS 7 +#define STATS_COLUMN_PLAYER_MAX_UNRANKED_REVENGE 8 +#define STATS_COLUMN_PLAYER_MAX_UNRANKED_BUILDINGS_DESTROYED 9 +#define STATS_COLUMN_PLAYER_MAX_UNRANKED_HEADSHOTS 10 +#define STATS_COLUMN_PLAYER_MAX_UNRANKED_HEALTH_POINTS_HEALED 11 +#define STATS_COLUMN_PLAYER_MAX_UNRANKED_INVULNS 12 +#define STATS_COLUMN_PLAYER_MAX_UNRANKED_KILL_ASSISTS 13 +#define STATS_COLUMN_PLAYER_MAX_UNRANKED_BACKSTABS 14 +#define STATS_COLUMN_PLAYER_MAX_UNRANKED_HEALTH_POINTS_LEACHED 15 +#define STATS_COLUMN_PLAYER_MAX_UNRANKED_BUILDINGS_BUILT 16 +#define STATS_COLUMN_PLAYER_MAX_UNRANKED_SENTRY_KILLS 17 +#define STATS_COLUMN_PLAYER_MAX_UNRANKED_TELEPORTS 18 + +// Column ids for PLAYER_MAX_RANKED + +#define STATS_COLUMN_PLAYER_MAX_RANKED_POINTS_SCORED 2 + +// +// Matchmaking queries +// +// These values are passed as the dwProcedureIndex parameter to +// XSessionSearch to indicate which matchmaking query to run. +// + +#define SESSION_MATCH_QUERY_PLAYER_MATCH 0 + +// +// Gamer pictures +// +// These ids are passed as the dwPictureId parameter to XUserAwardGamerTile. +// + + + +#ifdef __cplusplus +} +#endif + +#endif // __THE_ORANGE_BOX_SPA_H__ + + diff --git a/src/src/common/studiobyteswap.cpp b/src/src/common/studiobyteswap.cpp new file mode 100644 index 0000000..d44d300 --- /dev/null +++ b/src/src/common/studiobyteswap.cpp @@ -0,0 +1,3133 @@ +//========= Copyright © 1996-2006, Valve Corporation, All rights reserved. ============// +// +// Purpose: Swaps the bytes in all file types generated by studiomdl +// (.vvd, .vtx, .mdl, .phy, .ani) so the files can be loaded +// on a big-endian machine, specifically the Xbox360. A new file is generated +// with an extra extension in the form of .360. +// +//=============================================================================// + +#include "studio.h" +#include "optimize.h" +#include "phyfile.h" +#include "studiobyteswap.h" +#include "vphysics_interface.h" + +#undef ALIGN16 +#undef ALIGN32 +#define ALIGN4( a ) a = (byte *)((int)((byte *)a + 3) & ~ 3) +#define ALIGN16( a ) a = (byte *)((int)((byte *)a + 15) & ~ 15) +#define ALIGN32( a ) a = (byte *)((int)((byte *)a + 31) & ~ 31) +#define ALIGN64( a ) a = (byte *)((int)((byte *)a + 63) & ~ 63) + +// Fixup macros create variables that may not be referenced +#pragma warning( push ) +#pragma warning( disable:4189 ) // local variable is initialized but not referenced +#pragma warning( disable:4366 ) // The result of the unary '&' operator may be unaligned + +namespace StudioByteSwap +{ + +static bool g_bVerbose = true; +static bool g_bNativeSrc; +static CByteswap g_Swap; +static IPhysicsCollision *pCollision; +static CompressFunc_t g_pCompressFunc; + +void ActivateByteSwapping( bool activate ) +{ + g_Swap.ActivateByteSwapping( activate ); + SourceIsNative( IsPC() ); +} + +void SourceIsNative( bool bNative ) +{ + g_bNativeSrc = bNative; +} + +void SetCollisionInterface( IPhysicsCollision *pPhysicsCollision ) +{ + pCollision = pPhysicsCollision; +} + +void SetVerbose( bool bVerbose ) +{ + g_bVerbose = bVerbose; +} + +//---------------------------------------------------------------------- +// Helper to write a chunk of objects of the same type, and increment the buffer pointers. +//---------------------------------------------------------------------- +template inline void WriteObjects( byte **pOutputBuffer, byte **pBaseData, int objectCount = 1 ) +{ + T tempObject; + for ( int i = 0; i < objectCount; ++i ) + { + Q_memcpy( &tempObject, *pBaseData, sizeof(T) ); + g_Swap.SwapFieldsToTargetEndian( &tempObject, &tempObject ); + Q_memcpy( *pOutputBuffer, &tempObject, sizeof(T) ); + *pOutputBuffer += sizeof(T); + *pBaseData += sizeof(T); + } +} + +//---------------------------------------------------------------------- +// Helper to write a chunk of objects of the same type, and increment the buffer pointers. +//---------------------------------------------------------------------- +template inline void WriteObjects( T **pOutputBuffer, T **pBaseData, int objectCount = 1 ) +{ + T tempObject; + for ( int i = 0; i < objectCount; ++i ) + { + Q_memcpy( &tempObject, *pBaseData, sizeof(T) ); + g_Swap.SwapFieldsToTargetEndian( &tempObject, &tempObject ); + Q_memcpy( *pOutputBuffer, &tempObject, sizeof(T) ); + ++*pOutputBuffer; + ++*pBaseData; + } +} + +//---------------------------------------------------------------------- +// Helper to write a chunk of objects of the same type. +//---------------------------------------------------------------------- +template inline void WriteObjects( byte *pOutputBuffer, byte *pBaseData, int objectCount = 1 ) +{ + T tempObject; + for ( int i = 0; i < objectCount; ++i ) + { + Q_memcpy( &tempObject, pBaseData, sizeof(T) ); + g_Swap.SwapFieldsToTargetEndian( &tempObject, &tempObject ); + Q_memcpy( pOutputBuffer, &tempObject, sizeof(T) ); + pOutputBuffer += sizeof(T); + pBaseData += sizeof(T); + } +} + +//---------------------------------------------------------------------- +// Helper to write a chunk of objects of the same type. +//---------------------------------------------------------------------- +template inline void WriteObjects( T *pOutputBuffer, T *pBaseData, int objectCount = 1 ) +{ + T tempObject; + for ( int i = 0; i < objectCount; ++i ) + { + Q_memcpy( &tempObject, pBaseData, sizeof(T) ); + g_Swap.SwapFieldsToTargetEndian( &tempObject, &tempObject ); + Q_memcpy( pOutputBuffer, &tempObject, sizeof(T) ); + ++pOutputBuffer; + ++pBaseData; + } +} + +//---------------------------------------------------------------------- +// Helper to write a buffer of some integral type, and increment the buffer pointers. +//---------------------------------------------------------------------- +template inline void WriteBuffer( byte **pOutputBuffer, byte **pBaseData, int objectCount = 1 ) +{ + T tempObject; + for ( int i = 0; i < objectCount; ++i ) + { + Q_memcpy( &tempObject, *pBaseData, sizeof(T) ); + g_Swap.SwapBufferToTargetEndian( &tempObject, &tempObject ); + Q_memcpy( *pOutputBuffer, &tempObject, sizeof(T) ); + *pOutputBuffer += sizeof(T); + *pBaseData += sizeof(T); + } +} + +//---------------------------------------------------------------------- +// Helper to write a buffer of some integral type +//---------------------------------------------------------------------- +template inline void WriteBuffer( byte *pOutputBuffer, byte *pBaseData, int objectCount = 1 ) +{ + T tempObject; + for ( int i = 0; i < objectCount; ++i ) + { + Q_memcpy( &tempObject, pBaseData, sizeof(T) ); + g_Swap.SwapBufferToTargetEndian( &tempObject, &tempObject ); + Q_memcpy( pOutputBuffer, &tempObject, sizeof(T) ); + pOutputBuffer += sizeof(T); + pBaseData += sizeof(T); + } +} + +//---------------------------------------------------------------------- +// For getting values in the correct source/dest endian format +//---------------------------------------------------------------------- +template< class T > +T SrcNative( T *idx ) +{ + T ret = *idx; + if ( !g_bNativeSrc ) + { + g_Swap.SwapBuffer( &ret, idx ); + } + return ret; +} + +template< class T > +T DestNative( T *idx ) +{ + T ret = *idx; + if ( g_bNativeSrc ) + { + g_Swap.SwapBuffer( &ret, idx ); + } + return ret; +} + +//---------------------------------------------------------------------- +// Declares objects pointers for src/dest buffer +//---------------------------------------------------------------------- +#define DECLARE_OBJECT_POINTERS( objPtr, base, type ) \ + type* objPtr##Src = (type*)base##Src; \ + type* objPtr##Dest = (type*)base##Dest; \ + type* objPtr = objPtr##Src; + +//---------------------------------------------------------------------- +// Declares src/dest byte pointers and sets them to some index offset in the buffers. +//---------------------------------------------------------------------- +#define DECLARE_INDEX_POINTERS( ptr, base, index ) \ + byte *ptr##Src = (byte*)base##Src + SrcNative( &base##Src->index ); \ + byte *ptr##Dest = (byte*)base##Dest + SrcNative( &base##Src->index ); + +//---------------------------------------------------------------------- +// Declares src/dest byte pointers and sets them to some index offset in the buffers. +// If src pointer is misaligned, the fixup method is called. +//---------------------------------------------------------------------- +#define DECLARE_INDEX_POINTERS_FIXUP( ptr, base, index ) \ + byte *ptr##Src = (byte*)base##Src + SrcNative( &base##Src->index ); \ + byte *ptr##Dest = (byte*)base##Dest + SrcNative( &base##Src->index ); \ + FIXUP_OFFSETS( ptr, base, index ) + +//---------------------------------------------------------------------- +// Same as DECLARE_OBJECT_POINTERS, but reuses existing type pointers. +//---------------------------------------------------------------------- +#define SET_OBJECT_POINTERS( objPtr, base, type ) \ + objPtr##Src = (type*)base##Src; \ + objPtr##Dest = (type*)base##Dest; \ + objPtr = objPtr##Src; + +//---------------------------------------------------------------------- +// Same as DECLARE_INDEX_POINTERS, but reuses existing byte pointers. +//---------------------------------------------------------------------- +#define SET_INDEX_POINTERS( ptr, base, index ) \ + ptr##Src = (byte*)base##Src + SrcNative( &base##Src->index ); \ + ptr##Dest = (byte*)base##Dest + SrcNative( &base##Src->index ); + +//---------------------------------------------------------------------- +// Same as DECLARE_INDEX_POINTERS, but reuses existing byte pointers. +// If src pointer is misaligned, the fixup method is called. +//---------------------------------------------------------------------- +#define SET_INDEX_POINTERS_FIXUP( ptr, base, index ) \ + ptr##Src = (byte*)base##Src + SrcNative( &base##Src->index ); \ + ptr##Dest = (byte*)base##Dest + SrcNative( &base##Src->index ); \ + FIXUP_OFFSETS( ptr, base, index ) + +//---------------------------------------------------------------------- +// for() loop header, updates all three object pointers (src,dest,native) +//---------------------------------------------------------------------- +#define ITERATE_BLOCK( objPtr, count ) \ + for ( int objPtr##_idx = 0; objPtr##_idx < SrcNative( &count ); ++objPtr##_idx, ++objPtr, ++objPtr##Src, ++objPtr##Dest ) + +//---------------------------------------------------------------------- +// Checks for misaligned source pointer, then calculates the necessary fixup, +// calls the fixup function, and sets the src pointer to the new position. +//---------------------------------------------------------------------- +#define FIXUP_OFFSETS( ptr, base, index ) \ + { \ + byte *ptr##Fixup = ptr##Src; \ + ALIGN4( ptr##Fixup ); \ + if ( ptr##Fixup != ptr##Src ) \ + { \ + int nShiftBytes = ptr##Fixup - ptr##Src; \ + if ( g_bVerbose ) \ + Warning( "Shifting misaligned data block by %d bytes at " #base "->" #index "\n", nShiftBytes ); \ + int prevBytes = (byte*)ptr##Src - (byte*)g_pDataSrcBase; \ + Q_memmove( (byte*)ptr##Src + nShiftBytes, ptr##Src, fixedFileSize - prevBytes ); \ + g_pFixPoint = ptr##Src; \ + g_nFixupBytes = nShiftBytes; \ + fixedFileSize += nShiftBytes; \ + if ( fixedFileSize > fileSize + BYTESWAP_ALIGNMENT_PADDING ) \ + { \ + Error( "Byteswap buffer overrun - increase BYTESWAP_ALIGNMENT_PADDING!\n" ); \ + return 0; \ + } \ + g_pfnFileProcessFunc( pHdrSrc, UpdateSrcIndexFields ); \ + g_pFixPoint = NULL; \ + g_nFixupBytes = 0; \ + ptr##Src = ptr##Fixup; \ + } \ + } + + +typedef void ( *datadescProcessFunc_t)( void *pBase, void *pData, typedescription_t *pFields ); +typedef void ( *pfnFixupFunc_t )( void *pDestBase, datadescProcessFunc_t ); + +static pfnFixupFunc_t g_pfnFileProcessFunc; +static studiohdr_t *g_pHdr; +static const void *g_pDataSrcBase; +static void *g_pFixPoint; +static int g_nFixupBytes; + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +bool UpdateIndex( void *pBase, int *indexMember ) +{ + bool bUpdateIndex = false; + int idx = *indexMember; + + // Update the index fields + if ( pBase < g_pFixPoint ) + { + if ( (byte*)pBase + idx >= g_pFixPoint ) + { + bUpdateIndex = true; + } + } + else + { + if ( (byte*)pBase + idx < g_pFixPoint ) + { + bUpdateIndex = true; + } + } + + // Update the member offset by the global fixup + if ( bUpdateIndex && *indexMember ) + { + *indexMember = idx + g_nFixupBytes * Sign(idx); + return true; + } + return false; +} + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +int GetIntegerFromField( void *pData, int fieldType ) +{ + if ( fieldType == FIELD_INTEGER ) + { + return SrcNative( (int*)pData ); + } + else if ( fieldType == FIELD_SHORT ) + { + return SrcNative( (short*)pData ); + } + Error( "Byteswap macro DEFINE_INDEX using unsupported fieldType %d\n", fieldType ); + return 0; +} + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +void PutIntegerInField( void *pData, int index, int fieldType ) +{ + if ( fieldType == FIELD_INTEGER ) + { + *(int*)pData = SrcNative( &index ); + } + else if ( fieldType == FIELD_SHORT ) + { + *(short*)pData = SrcNative( &index ); + } + else + { + Error( "Byteswap macro DEFINE_INDEX using unsupported fieldType %d\n", fieldType ); + } +} + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +void UpdateSrcIndexFields( void *pBase, void *pData, typedescription_t *pField ) +{ + if ( pField->flags & FTYPEDESC_INDEX ) + { + int index = GetIntegerFromField( pData, pField->fieldType ); + if ( UpdateIndex( pBase, &index ) ) + { + PutIntegerInField( pData, index, pField->fieldType ); + } + } +} + +//----------------------------------------------------------------------------- +// Pass a datadesc field to a processing function +//----------------------------------------------------------------------------- +void ProcessField( void *pBase, void *pData, typedescription_t *pField, datadescProcessFunc_t pfn ) +{ + if ( pfn ) + { + pfn( pBase, pData, pField ); + } +} + +//----------------------------------------------------------------------------- +// Process the fields of a datadesc. +//----------------------------------------------------------------------------- +void ProcessFields( void *pBaseAddress, void *pData, datamap_t *pDataMap, datadescProcessFunc_t pfnProcessFunc ) +{ + // deal with base class first + if ( pDataMap->baseMap ) + { + ProcessFields( pBaseAddress, pData, pDataMap->baseMap, pfnProcessFunc ); + } + + typedescription_t *pFields = pDataMap->dataDesc; + int fieldCount = pDataMap->dataNumFields; + for ( int i = 0; i < fieldCount; ++i ) + { + typedescription_t *pField = &pFields[i]; + ProcessField( pBaseAddress, (BYTE*)pData + pField->fieldOffset[ TD_OFFSET_NORMAL ], pField, pfnProcessFunc ); + } +} + +//----------------------------------------------------------------------------- +// Process the fields of a datadesc. +//----------------------------------------------------------------------------- +void ProcessFields( void *pData, datamap_t *pDataMap, datadescProcessFunc_t pfnProcessFunc ) +{ + ProcessFields( pData, pData, pDataMap, pfnProcessFunc ); +} + +//----------------------------------------------------------------------------- +// Process a datadesc field by name +//----------------------------------------------------------------------------- +void ProcessFieldByName( void *pBaseAddress, void *pData, datamap_t *pDataMap, const char *pName, datadescProcessFunc_t pfnProcessFunc ) +{ + // deal with base class first + if ( pDataMap->baseMap ) + { + ProcessFieldByName( pBaseAddress, pData, pDataMap->baseMap, pName, pfnProcessFunc ); + } + + typedescription_t *pFields = pDataMap->dataDesc; + int fieldCount = pDataMap->dataNumFields; + for ( int i = 0; i < fieldCount; ++i ) + { + typedescription_t *pField = &pFields[i]; + if ( !Q_stricmp( pField->fieldName, pName ) ) + { + ProcessField( pBaseAddress, (BYTE*)pData + pField->fieldOffset[ TD_OFFSET_NORMAL ], pField, pfnProcessFunc ); + break; + } + } +} + +//----------------------------------------------------------------------------- +// Process a datadesc field by name. +//----------------------------------------------------------------------------- +void ProcessFieldByName( void *pData, datamap_t *pDataMap, const char *pName, datadescProcessFunc_t pfnProcessFunc ) +{ + ProcessFieldByName( pData, pData, pDataMap, pName, pfnProcessFunc ); +} + +void ProcessANIFields( void *pDataBase, datadescProcessFunc_t pfnProcessFunc ); +void ProcessMDLFields( void *pDataBase, datadescProcessFunc_t pfnProcessFunc ); + +// Fake header declaration for easier phy swapping +struct swapcompactsurfaceheader_t +{ + DECLARE_BYTESWAP_DATADESC(); + int size; + int vphysicsID; + short version; + short modelType; + int surfaceSize; + Vector dragAxisAreas; + int axisMapSize; +}; + +BEGIN_BYTESWAP_DATADESC( swapcompactsurfaceheader_t ) + DEFINE_FIELD( size, FIELD_INTEGER ), + DEFINE_FIELD( vphysicsID, FIELD_INTEGER ), + DEFINE_FIELD( version, FIELD_SHORT ), + DEFINE_FIELD( modelType, FIELD_SHORT ), + DEFINE_FIELD( surfaceSize, FIELD_INTEGER ), + DEFINE_FIELD( dragAxisAreas, FIELD_VECTOR ), + DEFINE_FIELD( axisMapSize, FIELD_INTEGER ), +END_BYTESWAP_DATADESC() + +// Fake header declaration for old style phy format +#if defined( _X360 ) +#pragma bitfield_order( push, lsb_to_msb ) +#endif +struct legacysurfaceheader_t +{ + DECLARE_BYTESWAP_DATADESC(); + int size; + float mass_center[3]; + float rotation_inertia[3]; + float upper_limit_radius; + BEGIN_BITFIELD( bf ) + int max_deviation : 8; + int byte_size : 24; + END_BITFIELD() + int offset_ledgetree_root; + int dummy[3]; +}; +#if defined( _X360 ) +#pragma bitfield_order( pop ) +#endif + +BEGIN_BYTESWAP_DATADESC( legacysurfaceheader_t ) + DEFINE_FIELD( size, FIELD_INTEGER ), + DEFINE_ARRAY( mass_center, FIELD_FLOAT, 3 ), + DEFINE_ARRAY( rotation_inertia, FIELD_FLOAT, 3 ), + DEFINE_FIELD( upper_limit_radius, FIELD_FLOAT ), + DEFINE_BITFIELD( bf, FIELD_INTEGER, 32 ), + DEFINE_FIELD( offset_ledgetree_root, FIELD_INTEGER ), + DEFINE_ARRAY( dummy, FIELD_INTEGER, 3 ), +END_BYTESWAP_DATADESC() + +//---------------------------------------------------------------------- +// Swap a .phy file +// Fixes alignment errors +//---------------------------------------------------------------------- +int ByteswapPHY( void *pDestBase, const void *pSrcBase, const int fileSize ) +{ + Assert( pCollision ); + if ( !pCollision ) + return 0; + + Q_memset( pDestBase, 0, fileSize ); + + byte *pSrc = (byte*)pSrcBase; + byte *pDest = (byte*)pDestBase; + vcollide_t collide = {0}; + + // file header + phyheader_t *pHdr = (phyheader_t*)( g_bNativeSrc ? pSrc : pDest ); + WriteObjects( &pDest, &pSrc ); + + if ( g_bNativeSrc ) + { + // Reset the pointers and let ivp swap the binary physics data + pSrc = (byte*)pSrcBase + pHdr->size; + pDest = (byte*)pDestBase + pHdr->size; + + int bufSize = fileSize - pHdr->size; + pCollision->VCollideLoad( &collide, pHdr->solidCount, (const char *)pSrc, bufSize, false ); + } + + // Swap the collision data headers + for ( int i = 0; i < pHdr->solidCount; ++i ) + { + swapcompactsurfaceheader_t *baseHdr = (swapcompactsurfaceheader_t*)( g_bNativeSrc ? pSrc : pDest ); + WriteObjects( pDest, pSrc ); + + int srcIncrement = baseHdr->surfaceSize + sizeof(swapcompactsurfaceheader_t); + int destIncrement = srcIncrement; + bool bCopyToSrc = !g_bNativeSrc; + + if ( baseHdr->vphysicsID != MAKEID('V','P','H','Y') ) + { + // May be old phy format + legacysurfaceheader_t *legacyHdr = (legacysurfaceheader_t*)( g_bNativeSrc ? pSrc : pDest ); + WriteObjects( pDest, pSrc ); + if ( legacyHdr->dummy[2] == MAKEID('I','V','P','S') || legacyHdr->dummy[2] == 0 ) + { + srcIncrement = legacyHdr->byte_size + sizeof(int); + destIncrement = legacyHdr->byte_size + sizeof(swapcompactsurfaceheader_t); + bCopyToSrc = false; + + if ( !g_bNativeSrc ) + { + // src needs the size member to be native to load vcollides + Q_memcpy( pSrc, pDest, sizeof(int) ); + } + } + else + { + // Not recognized + Assert(0); + return 0; + } + } + + if ( bCopyToSrc ) + { + // src needs the native header data to load the vcollides + Q_memcpy( pSrc, pDest, sizeof(swapcompactsurfaceheader_t) ); + } + + pSrc += srcIncrement; + pDest += destIncrement; + } + + // the rest of the file is text + int currPos = pSrc - (byte*)pSrcBase; + int remainingBytes = fileSize - currPos; + WriteBuffer( &pDest, &pSrc, remainingBytes ); + + if ( !g_bNativeSrc ) + { + // let ivp swap the ledge tree + pSrc = (byte*)pSrcBase + pHdr->size; + int bufSize = fileSize - pHdr->size; + pCollision->VCollideLoad( &collide, pHdr->solidCount, (const char *)pSrc, bufSize, true ); + } + + // Write out the ledge tree data + pDest = (byte*)pDestBase + pHdr->size; + for ( int i = 0; i < collide.solidCount; ++i ) + { + // skip over the size + pDest += sizeof(int); + int offset = pCollision->CollideWrite( (char*)pDest, collide.solids[i], g_bNativeSrc ); + int destSize = g_bNativeSrc ? SwapLong( offset ) : offset; + Q_memcpy( pDest - sizeof(int), &destSize, sizeof(int) ); + pDest += offset; + } + + // Free the memory + pCollision->VCollideUnload( &collide ); + + int newFileSize = pDest - (byte*)pDestBase + remainingBytes; + + if ( g_pCompressFunc ) + { + // compress entire swapped PHY + void *pInput = pDestBase; + int inputSize = newFileSize; + void *pOutput; + int outputSize; + if ( g_pCompressFunc( pInput, inputSize, &pOutput, &outputSize ) ) + { + // put the compressed version in its place + V_memcpy( pDestBase, pOutput, outputSize ); + free( pOutput ); + newFileSize = outputSize; + } + } + + return newFileSize; +} + +//---------------------------------------------------------------------- +// Swap a .vvd file +// Doesn't do any alignment fixups +//---------------------------------------------------------------------- +int ByteswapVVD( void *pDestBase, const void *pSrcBase, const int fileSize ) +{ + Q_memset( pDestBase, 0, fileSize ); + + byte *pDataSrc = (byte*)pSrcBase; + byte *pDataDest = (byte*)pDestBase; + + /** FILE HEADER **/ + + DECLARE_OBJECT_POINTERS( pHdr, pData, vertexFileHeader_t ) + WriteObjects( &pDataDest, &pDataSrc ); + + /** FIXUP TABLE **/ + + SET_INDEX_POINTERS( pData, pHdr, fixupTableStart ) + WriteObjects( &pDataDest, &pDataSrc, SrcNative( &pHdr->numFixups ) ); + + /** VERTEX DATA **/ + + SET_INDEX_POINTERS( pData, pHdr, vertexDataStart ) + WriteObjects( &pDataDest, &pDataSrc, SrcNative( &pHdr->numLODVertexes[0] ) ); + + /** TANGENT DATA **/ + + if ( pHdr->tangentDataStart != 0 ) + { + SET_INDEX_POINTERS( pData, pHdr, tangentDataStart ) + WriteBuffer( &pDataDest, &pDataSrc, 4 * SrcNative( &pHdr->numLODVertexes[0] ) ); + } + + int newFileSize = pDataDest - (byte*)pDestBase; + + if ( g_pCompressFunc ) + { + void *pInput = (byte*)pDestBase + sizeof( vertexFileHeader_t ); + int inputSize = newFileSize - sizeof( vertexFileHeader_t ); + void *pOutput; + int outputSize; + if ( g_pCompressFunc( pInput, inputSize, &pOutput, &outputSize ) ) + { + // place the compressed data after the header + V_memcpy( pInput, pOutput, outputSize ); + free( pOutput ); + newFileSize = sizeof( vertexFileHeader_t ) + outputSize; + } + } + + return newFileSize; +} + + +//---------------------------------------------------------------------- +// Swap a .vtx file +// Doesn't do any alignment fixups +//---------------------------------------------------------------------- +int ByteswapVTX( void *pDestBase, const void *pSrcBase, const int fileSize ) +{ + Q_memset( pDestBase, 0, fileSize ); + + // Do a straight copy first so the string table is transferred + memcpy( pDestBase, pSrcBase, fileSize ); + + // Start writing the file + byte *pDataSrc = (byte*)pSrcBase; + byte *pDataDest = (byte*)pDestBase; + + DECLARE_OBJECT_POINTERS( pVtxHeader, pData, OptimizedModel::FileHeader_t ) + WriteObjects( pVtxHeaderDest, pVtxHeaderSrc ); + + /** BODY PARTS **/ + + SET_INDEX_POINTERS( pData, pVtxHeader, bodyPartOffset ) + DECLARE_OBJECT_POINTERS( pBodyPartHeader, pData, OptimizedModel::BodyPartHeader_t ) + ITERATE_BLOCK( pBodyPartHeader, pVtxHeader->numBodyParts ) + { + WriteObjects( pBodyPartHeaderDest, pBodyPartHeaderSrc ); + + /** MODELS **/ + + SET_INDEX_POINTERS( pData, pBodyPartHeader, modelOffset ) + DECLARE_OBJECT_POINTERS( pModelHeader, pData, OptimizedModel::ModelHeader_t ) + ITERATE_BLOCK( pModelHeader, pBodyPartHeader->numModels ) + { + WriteObjects( pModelHeaderDest, pModelHeaderSrc ); + + /** MODEL LODS **/ + + unsigned int meshOffset = 0; + SET_INDEX_POINTERS( pData, pModelHeader, lodOffset ) + DECLARE_OBJECT_POINTERS( pModelLODHeader, pData, OptimizedModel::ModelLODHeader_t ) + ITERATE_BLOCK( pModelLODHeader, pModelHeader->numLODs ) + { + WriteObjects( pModelLODHeaderDest, pModelLODHeaderSrc ); + + /** MESHES **/ + + unsigned int prevOffset = meshOffset; + meshOffset = SrcNative( &pModelLODHeader->meshOffset ); + if ( prevOffset - sizeof(OptimizedModel::ModelLODHeader_t) == meshOffset ) + { + // This LOD shares data with the previous LOD - don't reswap. + continue; + } + + SET_INDEX_POINTERS( pData, pModelLODHeader, meshOffset ) + DECLARE_OBJECT_POINTERS( pMeshHeader, pData, OptimizedModel::MeshHeader_t ) + ITERATE_BLOCK( pMeshHeader, pModelLODHeader->numMeshes ) + { + WriteObjects( pMeshHeaderDest, pMeshHeaderSrc ); + + /** STRIP GROUPS **/ + + SET_INDEX_POINTERS( pData, pMeshHeader, stripGroupHeaderOffset ) + DECLARE_OBJECT_POINTERS( pStripGroupHeader, pData, OptimizedModel::StripGroupHeader_t ) + ITERATE_BLOCK( pStripGroupHeader, pMeshHeader->numStripGroups ) + { + WriteObjects( pStripGroupHeaderDest, pStripGroupHeaderSrc ); + + /** STRIP VERTS **/ + + SET_INDEX_POINTERS( pData, pStripGroupHeader, vertOffset ) + WriteObjects( pDataDest, pDataSrc, SrcNative( &pStripGroupHeader->numVerts ) ); + + /** VERT INDICES **/ + + SET_INDEX_POINTERS( pData, pStripGroupHeader, indexOffset ) + WriteBuffer( pDataDest, pDataSrc, SrcNative( &pStripGroupHeader->numIndices ) ); + + /** STRIPS **/ + + SET_INDEX_POINTERS( pData, pStripGroupHeader, stripOffset ) + DECLARE_OBJECT_POINTERS( pStripHeader, pData, OptimizedModel::StripHeader_t ) + ITERATE_BLOCK( pStripHeader, pStripGroupHeader->numStrips ) + { + WriteObjects( pStripHeaderDest, pStripHeaderSrc ); + + /** BONE STATE CHANGES **/ + + SET_INDEX_POINTERS( pData, pStripHeader, boneStateChangeOffset ) + WriteObjects( pDataDest, pDataSrc, SrcNative( &pStripHeader->numBoneStateChanges ) ); + } + } + } + } + } + } + + /** MATERIAL REPLACEMENT HEADERS **/ + + SET_INDEX_POINTERS( pData, pVtxHeader, materialReplacementListOffset ) + DECLARE_OBJECT_POINTERS( pMatRepListHeader, pData, OptimizedModel::MaterialReplacementListHeader_t ) + ITERATE_BLOCK( pMatRepListHeader, pVtxHeader->numLODs ) + { + WriteObjects( pMatRepListHeaderDest, pMatRepListHeaderSrc ); + + /** MATERIAL REPLACEMENTS **/ + + SET_INDEX_POINTERS( pData, pMatRepListHeader, replacementOffset ) + WriteObjects( &pDataDest, &pDataSrc, SrcNative( &pMatRepListHeader->numReplacements ) ); + } + + int newFileSize = fileSize; + + if ( g_pCompressFunc ) + { + void *pInput = (byte*)pDestBase + sizeof( OptimizedModel::FileHeader_t ); + int inputSize = fileSize - sizeof( OptimizedModel::FileHeader_t ); + void *pOutput; + int outputSize; + if ( g_pCompressFunc( pInput, inputSize, &pOutput, &outputSize ) ) + { + // place the compressed data after the header + V_memcpy( pInput, pOutput, outputSize ); + free( pOutput ); + newFileSize = sizeof( OptimizedModel::FileHeader_t ) + outputSize; + } + } + + return newFileSize; +} + +//---------------------------------------------------------------------- +// Swap animation data +// Fixes alignment errors +//---------------------------------------------------------------------- + +void ByteswapAnimData( mstudioanimdesc_t *pAnimDesc, int section, byte *&pDataSrc, byte *&pDataDest ) +{ + /** ANIMATIONS **/ + DECLARE_OBJECT_POINTERS( pAnimation, pData, mstudioanim_t ) + WriteObjects( pAnimationDest, pAnimationSrc ); + if ( pAnimation->bone == 255 ) + { + // No animation data + pAnimation = 0; + } + + while( pAnimation ) + { + if ( pAnimation->flags & ( STUDIO_ANIM_RAWROT | STUDIO_ANIM_RAWPOS | STUDIO_ANIM_RAWROT2 ) ) + { + if ( pAnimation->flags & STUDIO_ANIM_RAWROT ) + { + int offset = (byte*)pAnimation->pQuat48() - (byte*)pAnimation; + pDataSrc = (byte*)pAnimationSrc + offset; + pDataDest = (byte*)pAnimationDest + offset; + + // Write the quaternion (bit fields contained in 3 unsigned shorts) + WriteBuffer( &pDataDest, &pDataSrc, 3 ); + } + + if ( pAnimation->flags & STUDIO_ANIM_RAWROT2 ) + { + int offset = (byte*)pAnimation->pQuat64() - (byte*)pAnimation; + pDataSrc = (byte*)pAnimationSrc + offset; + pDataDest = (byte*)pAnimationDest + offset; + + // Write the quaternion (bit fields contained in 1 64 bit int + WriteBuffer( &pDataDest, &pDataSrc, 1 ); + } + + if ( pAnimation->flags & STUDIO_ANIM_RAWPOS ) + { + int offset = (byte*)pAnimation->pPos() - (byte*)pAnimation; + pDataSrc = (byte*)pAnimationSrc + offset; + pDataDest = (byte*)pAnimationDest + offset; + + // Write the vector (3 float16) + WriteBuffer( &pDataDest, &pDataSrc, 3 ); + } + } + else + { + int offset = (byte*)pAnimation->pRotV() - (byte*)pAnimation; + pDataSrc = (byte*)pAnimationSrc + offset; + pDataDest = (byte*)pAnimationDest + offset; + + mstudioanim_valueptr_t *rotvptr = (mstudioanim_valueptr_t*)pDataSrc; + WriteObjects( &pDataDest, &pDataSrc ); + + int animValueCt = 0; + for ( int idx = 0; idx < 3; ++idx ) + { + animValueCt += rotvptr->offset[idx] ? 1 : 0; + } + + if ( pAnimation->flags & STUDIO_ANIM_ANIMPOS ) + { + int offset = (byte*)pAnimation->pPosV() - (byte*)pAnimation; + pDataSrc = (byte*)pAnimationSrc + offset; + pDataDest = (byte*)pAnimationDest + offset; + + mstudioanim_valueptr_t *posvptr = (mstudioanim_valueptr_t*)pDataSrc; + WriteObjects( &pDataDest, &pDataSrc ); + + for ( int idx = 0; idx < 3; ++idx ) + { + animValueCt += posvptr->offset[idx] ? 1 : 0; + } + } + + // Write position and rotation animations + + // Note: destanimvalue_t is a union that can be either two bytes or a short. + // This structure is used to compress animation data using RLE. + // The first object of a chunk acts as the header, and uses the two bytes to + // store how many objects follow, and how many frames are encoded by them. + // The objects that follow use the short to store a value. + // The total number of chunks has been determined by counting the number of valid (non-zero) offsets. + for ( int animValue = 0; animValue < animValueCt; ++animValue ) + { + int encodedFrames = 0; + int totalFrames = SrcNative( &pAnimDesc->numframes ); + int sectionFrames = SrcNative( &pAnimDesc->sectionframes ); + if ( sectionFrames ) + { + int iStartFrame = section * sectionFrames; + int iEndFrame = (section + 1) * sectionFrames; + + iStartFrame = min( iStartFrame, totalFrames - 1 ); + iEndFrame = min( iEndFrame, totalFrames - 1 ); + + totalFrames = iEndFrame - iStartFrame + 1; + } + + while ( encodedFrames < totalFrames ) + { + // Write the first animation value (struct of 2 bytes) + mstudioanimvalue_t *pDestAnimvalue = (mstudioanimvalue_t*)( g_bNativeSrc ? pDataSrc : pDataDest ); + WriteBuffer( &pDataDest, &pDataSrc, 2 ); + + // Write the remaining animation values from this group (shorts) + WriteBuffer( &pDataDest, &pDataSrc, pDestAnimvalue->num.valid ); + + encodedFrames += pDestAnimvalue->num.total; + } + } + } + + // TODOKD: Could add a fixup here with some more work, hasn't been necessary yet + if ( pAnimation->nextoffset ) + { + // Set pointers to the next animation + pAnimationSrc = (mstudioanim_t*)( (byte*)pAnimationSrc + SrcNative( &pAnimation->nextoffset ) ); + pAnimationDest = (mstudioanim_t*)( (byte*)pAnimationDest + SrcNative( &pAnimation->nextoffset ) ); + pAnimation = pAnimationSrc; + + // Swap the next animation + WriteObjects( pAnimationDest, pAnimationSrc ); + } + else + { + pAnimation = 0; + pDataSrc += sizeof( mstudioanim_t ); + pDataDest += sizeof( mstudioanim_t ); + } + } + + ALIGN4( pDataSrc ); + ALIGN4( pDataDest ); +} + + +int ByteswapIKRules( studiohdr_t *&pHdrSrc, int numikrules, int numFrames, byte *&pDataSrc, byte *&pDataDest, int &fixedFileSize, const int fileSize ) +{ + DECLARE_OBJECT_POINTERS( pIKRule, pData, mstudioikrule_t ) + + ITERATE_BLOCK( pIKRule, numikrules ) + { + WriteObjects( pIKRuleDest, pIKRuleSrc ); + + /** IK ERROR KEYS **/ + + // Calculate the number of ikerrors by converting the ikerror start and end float values to + // frame numbers. (See the generation of these values in simplify.cpp: ProcessIKRules()). + float start = floorf( SrcNative( &pIKRule->start ) * (numFrames - 1) + 0.5f ); + float end = floorf( SrcNative( &pIKRule->end ) * (numFrames - 1) + 0.5f ); + int totalerror = (int)( end - start + 1 ); + if ( end >= numFrames ) + totalerror += 2; + + // Uncompressed - only found in some older models (shipped hl2) + if ( pIKRule->ikerrorindex ) + { + SET_INDEX_POINTERS_FIXUP( pData, pIKRule, ikerrorindex ) + WriteObjects( pDataDest, pDataSrc, totalerror ); + } + + // Compressed - all models since hl2 + if ( pIKRule->compressedikerrorindex ) + { + SET_INDEX_POINTERS_FIXUP( pData, pIKRule, compressedikerrorindex ) + WriteObjects( pDataDest, pDataSrc ); + + mstudiocompressedikerror_t *pCompressed = (mstudiocompressedikerror_t *)pDataSrc; + + // Write the animvalues. + for ( int idx = 0; idx < 6; ++idx ) + { + if ( pCompressed->offset[idx] ) + { + byte *pAnimvalueSrc = pDataSrc + SrcNative( &pCompressed->offset[idx] ); + byte *pAnimvalueDest = pDataDest + SrcNative( &pCompressed->offset[idx] ); + + int numerror = 0; + while ( numerror < totalerror ) + { + // Write the first animation value (struct of 2 bytes) + mstudioanimvalue_t *pDestAnimvalue = (mstudioanimvalue_t*)( g_bNativeSrc ? pAnimvalueSrc : pAnimvalueDest ); + WriteBuffer( &pAnimvalueDest, &pAnimvalueSrc, 2 ); + + // Write the remaining animation values from this group (shorts) + WriteBuffer( &pAnimvalueDest, &pAnimvalueSrc, pDestAnimvalue->num.valid ); + + numerror += pDestAnimvalue->num.total; + } + } + } + + if ( pIKRule->szattachmentindex ) + { + SET_INDEX_POINTERS( pData, pIKRule, szattachmentindex ) + int size = strlen( (char*)pDataSrc ) + 1; + WriteBuffer( pDataDest, pDataSrc, size ); + } + } + } + return fixedFileSize; +} + + + +//---------------------------------------------------------------------- +// Swap an .ani file +// Fixes alignment errors +//---------------------------------------------------------------------- +int ByteswapANIFile( studiohdr_t* pHdr, void *pDestBase, const void *pSrcBase, const int fileSize ) +{ + // Note, pHdr came from a native .mdl - + // so the header, animdescs and animblocks are already in native format. + Assert( pHdr ); + if ( !pHdr ) + return false; + + Q_memset( pDestBase, 0, fileSize ); + + // swap file header + { + byte *pHeaderSrc = (byte *)pSrcBase; + byte *pHeaderDest = (byte *)pDestBase; + DECLARE_OBJECT_POINTERS( pAniHeader, pHeader, studiohdr_t ) + WriteObjects( pAniHeaderDest, pAniHeaderSrc ); + } + + // for fixup functions + int fixedFileSize = fileSize; + g_pfnFileProcessFunc = ProcessANIFields; + g_pDataSrcBase = pSrcBase; + g_pHdr = pHdr; + studiohdr_t *pHdrSrc = pHdr; + + // The animdesc_t header is always contained in the mdl file, but its data may be in + // the mdl or the ani. When the data is contained in the mdl, the animdesc index fields + // represent offsets from the location of the animdesc header. When the data is in the ani, + // the index fields contain offsets from the start of the animblock in which the animdesc data is contained. + + mstudioanimdesc_t *pAnimDesc = pHdr->pLocalAnimdesc( 0 ); + for ( int i = 0; i < pHdr->numlocalanim; ++i, ++pAnimDesc ) + { + // printf("anim %d : %d : %d\n", i, pAnimDesc->animblock, pAnimDesc->sectionframes ); + if ( pAnimDesc->animblock == -1) + { + // out of date model format + continue; + } + + if ( pAnimDesc->animblock == 0 && pAnimDesc->sectionframes == 0) + { + // already saved out + continue; + } + + if ( pAnimDesc->sectionframes == 0 ) + { + mstudioanimblock_t *pAnimBlock = pHdr->pAnimBlock( pAnimDesc->animblock ); + + // printf("block %d : start %d + %d\n", pAnimDesc->animblock, pAnimBlock->datastart, pAnimDesc->animindex ); + // Base address of the animblock + byte *pBlockBaseSrc = (byte*)pSrcBase + pAnimBlock->datastart; + byte *pBlockBaseDest = (byte*)pDestBase + pAnimBlock->datastart; + + // Base address of the animation in the animblock + byte *pDataSrc = pBlockBaseSrc + pAnimDesc->animindex; + byte *pDataDest = pBlockBaseDest + pAnimDesc->animindex; + + ByteswapAnimData( pAnimDesc, 0, pDataSrc, pDataDest ); + } + else + { + int numsections = pAnimDesc->numframes / pAnimDesc->sectionframes + 2; + + for ( int i = 0; i < numsections; ++i ) + { + int block = pAnimDesc->pSection( i )->animblock; + int index = pAnimDesc->pSection( i )->animindex; + + if ( block != 0 ) + { + // printf("%s %d %d\n", pAnimDesc->pszName(), block, index ); + + mstudioanimblock_t *pAnimBlock = pHdr->pAnimBlock( block ); + + // Base address of the animblock + byte *pBlockBaseSrc = (byte*)pSrcBase + pAnimBlock->datastart; + byte *pBlockBaseDest = (byte*)pDestBase + pAnimBlock->datastart; + FIXUP_OFFSETS( pBlockBase, pAnimBlock, datastart ) + + // Base address of the animation in the animblock + byte *pDataSrc = pBlockBaseSrc + index; + byte *pDataDest = pBlockBaseDest + index; + + ByteswapAnimData( pAnimDesc, i, pDataSrc, pDataDest ); + } + } + } + + if ( pAnimDesc->animblock == 0) + { + // already saved out + continue; + } + + mstudioanimblock_t *pAnimBlock = pHdr->pAnimBlock( pAnimDesc->animblock ); + // Base address of the animblock + byte *pBlockBaseSrc = (byte*)pSrcBase + pAnimBlock->datastart; + byte *pBlockBaseDest = (byte*)pDestBase + pAnimBlock->datastart; + FIXUP_OFFSETS( pBlockBase, pAnimBlock, datastart ) + + // Base address of the animation in the animblock + byte *pDataSrc = pBlockBaseSrc + pAnimDesc->animindex; + byte *pDataDest = pBlockBaseDest + pAnimDesc->animindex; + FIXUP_OFFSETS( pData, pAnimDesc, animindex ) + + /** IK RULES **/ + + if ( pAnimDesc->animblockikruleindex ) + { + pDataSrc = (byte*)pBlockBaseSrc + pAnimDesc->animblockikruleindex; + pDataDest = (byte*)pBlockBaseDest + pAnimDesc->animblockikruleindex; + FIXUP_OFFSETS( pData, pAnimDesc, animblockikruleindex ) + + int numikrules = SrcNative( &pAnimDesc->numikrules ); + ByteswapIKRules( pHdrSrc, pAnimDesc->numikrules, pAnimDesc->numframes, pDataSrc, pDataDest, fixedFileSize, fileSize ); + } + + /** LOCAL HIERARCHY **/ + + if ( pAnimDesc->localhierarchyindex ) + { + pDataSrc = (byte*)pBlockBaseSrc + pAnimDesc->localhierarchyindex; + pDataDest = (byte*)pBlockBaseDest + pAnimDesc->localhierarchyindex; + DECLARE_OBJECT_POINTERS( pLocalHierarchy, pData, mstudiolocalhierarchy_t ) + + // HACK: Since animdescs are already native, pre-swap pAnimDesc->numlocalhierarchy + // here so the automatic swap inside ITERATE_BLOCK will restore it + int numlocalhierarchy = SrcNative( &pAnimDesc->numlocalhierarchy ); + ITERATE_BLOCK( pLocalHierarchy, numlocalhierarchy ) + { + WriteObjects( pLocalHierarchyDest, pLocalHierarchySrc, pAnimDesc->numlocalhierarchy ); + + /** COMPRESSED IK ERRORS **/ + + if ( pLocalHierarchy->localanimindex != 0 ) + { + // Calculate the number of ikerrors by converting the ikerror start and end float values to + // frame numbers. (See the generation of these values in simplify.cpp: ProcessIKRules()). + int numFrames = pAnimDesc->numframes; + float start = floorf( SrcNative( &pLocalHierarchy->start ) * (numFrames - 1) + 0.5f ); + float end = floorf( SrcNative( &pLocalHierarchy->end ) * (numFrames - 1) + 0.5f ); + int totalerror = (int)( end - start + 1 ); + if ( end >= numFrames ) + totalerror += 2; + + SET_INDEX_POINTERS( pData, pLocalHierarchy, localanimindex ) + WriteObjects( pDataDest, pDataSrc ); + + mstudiocompressedikerror_t *pCompressed = (mstudiocompressedikerror_t *)pDataSrc; + + // Write the animvalues. + for ( int idx = 0; idx < 6; ++idx ) + { + if ( pCompressed->offset[idx] ) + { + byte *pAnimvalueSrc = pDataSrc + SrcNative( &pCompressed->offset[idx] ); + byte *pAnimvalueDest = pDataDest + SrcNative( &pCompressed->offset[idx] ); + + int numerror = 0; + while ( numerror < totalerror ) + { + // Write the first animation value (struct of 2 bytes) + mstudioanimvalue_t *pDestAnimvalue = (mstudioanimvalue_t*)( g_bNativeSrc ? pAnimvalueSrc : pAnimvalueDest ); + WriteBuffer( &pAnimvalueDest, &pAnimvalueSrc, 2 ); + + // Write the remaining animation values from this group (shorts) + WriteBuffer( &pAnimvalueDest, &pAnimvalueSrc, pDestAnimvalue->num.valid ); + + numerror += pDestAnimvalue->num.total; + } + } + } + } + } // Local Hierarchy block + } + } + + // printf("returning %d\n", fixedFileSize ); + + return fixedFileSize; +} + +int ByteswapANI( studiohdr_t* pHdr, void *pDestBase, const void *pSrcBase, const int fileSize ) +{ + // Make a working copy of the source to allow for alignment fixups + void *pNewSrcBase = malloc( fileSize + BYTESWAP_ALIGNMENT_PADDING ); + Q_memcpy( pNewSrcBase, pSrcBase, fileSize ); + + int fixedFileSize = ByteswapANIFile( pHdr, pDestBase, pNewSrcBase, fileSize ); + if ( fixedFileSize != fileSize ) + { + int finalSize = ByteswapANIFile( pHdr, pDestBase, pNewSrcBase, fixedFileSize ); + if ( finalSize != fixedFileSize ) + { + if ( g_bVerbose ) + Warning( "Alignment fixups failed on ANI swap!\n" ); + fixedFileSize = 0; + } + } + + free( pNewSrcBase ); + + // the compression needs to happen on the final or "fixed" pass + if ( g_pCompressFunc && pHdr->numanimblocks >= 2 && fixedFileSize ) + { + // assemble a new anim of compressed anim blocks + // start with original size, with room for alignment padding + fixedFileSize += (pHdr->numanimblocks + 1) * 2048; + byte *pNewDestBase = (byte *)malloc( fixedFileSize ); + Q_memset( pNewDestBase, 0, fixedFileSize ); + byte *pNewDest = pNewDestBase; + + // get the header payload as is + // assuming the header is up to the first anim block + mstudioanimblock_t *pAnimBlock = pHdr->pAnimBlock( 1 ); + V_memcpy( pNewDest, pDestBase, pAnimBlock->datastart ); + pNewDest += pAnimBlock->datastart; + + int padding = AlignValue( (unsigned int)pNewDest - (unsigned int)pNewDestBase, 2048 ); + padding -= (unsigned int)pNewDest - (unsigned int)pNewDestBase; + pNewDest += padding; + + // iterate and compress anim blocks + for ( int i = 1; i < pHdr->numanimblocks; ++i ) + { + pAnimBlock = pHdr->pAnimBlock( i ); + + void *pInput = (byte *)pDestBase + pAnimBlock->datastart; + int inputSize = pAnimBlock->dataend - pAnimBlock->datastart; + + pAnimBlock->datastart = (unsigned int)pNewDest - (unsigned int)pNewDestBase; + + void *pOutput; + int outputSize; + if ( g_pCompressFunc( pInput, inputSize, &pOutput, &outputSize ) ) + { + V_memcpy( pNewDest, pOutput, outputSize ); + pNewDest += outputSize; + free( pOutput ); + } + else + { + // as is + V_memcpy( pNewDest, pInput, inputSize ); + pNewDest += inputSize; + } + + padding = AlignValue( (unsigned int)pNewDest - (unsigned int)pNewDestBase, 2048 ); + padding -= (unsigned int)pNewDest - (unsigned int)pNewDestBase; + pNewDest += padding; + + pAnimBlock->dataend = (unsigned int)pNewDest - (unsigned int)pNewDestBase; + } + + fixedFileSize = pNewDest - pNewDestBase; + V_memcpy( pDestBase, pNewDestBase, fixedFileSize ); + free( pNewDestBase ); + } + + return fixedFileSize; +} + +//---------------------------------------------------------------------- +// Write a .mdl file in big-endian format +//---------------------------------------------------------------------- +int ByteswapMDLFile( void *pDestBase, void *pSrcBase, const int fileSize ) +{ + // Needed by fixup functions + g_pDataSrcBase = pSrcBase; + g_pfnFileProcessFunc = ProcessMDLFields; + int fixedFileSize = fileSize; + + Q_memset( pDestBase, 0, fileSize ); + + byte *pDataSrc = (byte*)pSrcBase; + byte *pDataDest = (byte*)pDestBase; + + /** FILE HEADER **/ + + DECLARE_OBJECT_POINTERS( pHdr, pData, studiohdr_t ) + WriteObjects( pHdrDest, pHdrSrc ); + + /** BONES **/ + + SET_INDEX_POINTERS_FIXUP( pData, pHdr, boneindex ) + DECLARE_OBJECT_POINTERS( pStudioBone, pData, mstudiobone_t ) + ITERATE_BLOCK( pStudioBone, pHdr->numbones ) + { + WriteObjects( pStudioBoneDest, pStudioBoneSrc ); + + if ( pStudioBone->procindex ) + { + SET_INDEX_POINTERS_FIXUP( pData, pStudioBone, procindex ) + + unsigned int index = SrcNative( &pStudioBone->proctype ); + switch( index ) + { + case STUDIO_PROC_AXISINTERP: + { + /** AXIS-INTERP BONES **/ + DECLARE_OBJECT_POINTERS( pAxisInterpBone, pData, mstudioaxisinterpbone_t ) + WriteObjects( pAxisInterpBoneDest, pAxisInterpBoneSrc ); + break; + } + case STUDIO_PROC_QUATINTERP: + { + /** QUAT-INTERP BONES **/ + DECLARE_OBJECT_POINTERS( pQuatInterpBone, pData, mstudioquatinterpbone_t ) + WriteObjects( pQuatInterpBoneDest, pQuatInterpBoneSrc ); + + /** QUAT-INTERP TRIGGERS **/ + SET_INDEX_POINTERS_FIXUP( pData, pQuatInterpBone, triggerindex ) + WriteObjects( pDataDest, pDataSrc, SrcNative( &pQuatInterpBone->numtriggers ) ); + break; + } + case STUDIO_PROC_JIGGLE: + { + /** JIGGLE BONES **/ + DECLARE_OBJECT_POINTERS( pJiggleBone, pData, mstudiojigglebone_t ) + WriteObjects( pJiggleBoneDest, pJiggleBoneSrc ); + break; + } + case STUDIO_PROC_AIMATBONE: + case STUDIO_PROC_AIMATATTACH: + { + /** AIM AT BONES **/ + DECLARE_OBJECT_POINTERS( pAimAtBone, pData, mstudioaimatbone_t ) + WriteObjects( pAimAtBoneDest, pAimAtBoneSrc ); + break; + } + default: + Assert( 0 ); + Warning( "Unknown bone type %d found!\n", index ); + } + } + } + + /** BONE CONTROLLERS **/ + + SET_INDEX_POINTERS_FIXUP( pData, pHdr, bonecontrollerindex ) + WriteObjects( pDataDest, pDataSrc, SrcNative( &pHdr->numbonecontrollers ) ); + + /** ATTACHMENTS **/ + + SET_INDEX_POINTERS_FIXUP( pData, pHdr, localattachmentindex ) + WriteObjects( pDataDest, pDataSrc, SrcNative( &pHdr->numlocalattachments ) ); + + /** HITBOX SETS **/ + + SET_INDEX_POINTERS_FIXUP( pData, pHdr, hitboxsetindex ) + DECLARE_OBJECT_POINTERS( pHitboxSet, pData, mstudiohitboxset_t ) + ITERATE_BLOCK( pHitboxSet, pHdr->numhitboxsets ) + { + WriteObjects( pHitboxSetDest, pHitboxSetSrc ); + + /** HITBOXES **/ + + SET_INDEX_POINTERS_FIXUP( pData, pHitboxSet, hitboxindex ) + WriteObjects( pDataDest, pDataSrc, SrcNative( &pHitboxSet->numhitboxes ) ); + } + + /** BONE TABLE **/ + + SET_INDEX_POINTERS( pData, pHdr, bonetablebynameindex ) + WriteBuffer( pDataDest, pDataSrc, SrcNative( &pHdr->numbones ) ); + + /** ANIMATION DESCRIPTIONS **/ + + SET_INDEX_POINTERS_FIXUP( pData, pHdr, localanimindex ) + DECLARE_OBJECT_POINTERS( pAnimDesc, pData, mstudioanimdesc_t ) + ITERATE_BLOCK( pAnimDesc, pHdr->numlocalanim ) + { + WriteObjects( pAnimDescDest, pAnimDescSrc ); + + if ( pAnimDesc->animblock == -1 ) + { + // out of date model format + continue; + } + + // section data can point to both internal and external blocks + int numsections = 0; + if ( pAnimDesc->sectionframes != 0 ) + { + numsections = pAnimDesc->numframes / pAnimDesc->sectionframes + 2; + + SET_INDEX_POINTERS( pData, pAnimDesc, sectionindex ) + DECLARE_OBJECT_POINTERS( pSection, pData, mstudioanimsections_t ) + + WriteObjects( pSectionDest, pSectionSrc, numsections ); + } + + if ( pAnimDesc->animblock == 0 ) + { + if ( numsections == 0 ) + { + SET_INDEX_POINTERS( pData, pAnimDesc, animindex ) + ByteswapAnimData( pAnimDesc, 0, pDataSrc, pDataDest ); + } + else + { + for ( int i = 0; i < numsections; ++i ) + { + if ( pAnimDesc->pSection( i )->animblock == 0 ) + { + int index = pAnimDesc->pSection( i )->animindex; + + // Base address of the animation in the animblock + byte *pDataSrc = (byte *)pAnimDescSrc + index; + byte *pDataDest = (byte *)pAnimDescDest + index; + + ByteswapAnimData( pAnimDesc, i, pDataSrc, pDataDest ); + } + } + } + + /** IK RULES **/ + + if ( pAnimDesc->ikruleindex ) + { + SET_INDEX_POINTERS_FIXUP( pData, pAnimDesc, ikruleindex ) + DECLARE_OBJECT_POINTERS( pIKRule, pData, mstudioikrule_t ) + + int numframes = SrcNative( &pAnimDesc->numframes ); + ByteswapIKRules( pHdrSrc, pAnimDesc->numikrules, numframes, pDataSrc, pDataDest, fixedFileSize, fileSize ); + } + + /** LOCAL HIERARCHY **/ + + if ( pAnimDesc->localhierarchyindex ) + { + SET_INDEX_POINTERS( pData, pAnimDesc, localhierarchyindex ) + DECLARE_OBJECT_POINTERS( pLocalHierarchy, pData, mstudiolocalhierarchy_t ) + ITERATE_BLOCK( pLocalHierarchy, pAnimDesc->numlocalhierarchy ) + { + WriteObjects( pLocalHierarchyDest, pLocalHierarchySrc, SrcNative( &pAnimDesc->numlocalhierarchy ) ); + + /** COMPRESSED IK ERRORS **/ + + if ( pLocalHierarchy->localanimindex != 0 ) + { + // Calculate the number of ikerrors by converting the ikerror start and end float values to + // frame numbers. (See the generation of these values in simplify.cpp: ProcessIKRules()). + int numFrames = SrcNative( &pAnimDesc->numframes ); + float start = floorf( SrcNative( &pLocalHierarchy->start ) * (numFrames - 1) + 0.5f ); + float end = floorf( SrcNative( &pLocalHierarchy->end ) * (numFrames - 1) + 0.5f ); + int totalerror = (int)( end - start + 1 ); + if ( end >= numFrames ) + totalerror += 2; + + SET_INDEX_POINTERS( pData, pLocalHierarchy, localanimindex ) + WriteObjects( pDataDest, pDataSrc ); + + mstudiocompressedikerror_t *pCompressed = (mstudiocompressedikerror_t *)pDataSrc; + + // Write the animvalues. + for ( int idx = 0; idx < 6; ++idx ) + { + if ( pCompressed->offset[idx] ) + { + byte *pAnimvalueSrc = pDataSrc + SrcNative( &pCompressed->offset[idx] ); + byte *pAnimvalueDest = pDataDest + SrcNative( &pCompressed->offset[idx] ); + + int numerror = 0; + while ( numerror < totalerror ) + { + // Write the first animation value (struct of 2 bytes) + mstudioanimvalue_t *pDestAnimvalue = (mstudioanimvalue_t*)( g_bNativeSrc ? pAnimvalueSrc : pAnimvalueDest ); + WriteBuffer( &pAnimvalueDest, &pAnimvalueSrc, 2 ); + + // Write the remaining animation values from this group (shorts) + WriteBuffer( &pAnimvalueDest, &pAnimvalueSrc, pDestAnimvalue->num.valid ); + + numerror += pDestAnimvalue->num.total; + } + } + } + } + } + } // Local Hierarchy block + } + } // Animdesc block + + /** MOVEMENTS **/ + + // Separate loop required by format of mstudioanimdesc_t data + SET_INDEX_POINTERS( pData, pHdr, localanimindex ) + SET_OBJECT_POINTERS( pAnimDesc, pData, mstudioanimdesc_t ) + ITERATE_BLOCK( pAnimDesc, pHdr->numlocalanim ) + { + if ( pAnimDesc->nummovements ) + { + SET_INDEX_POINTERS_FIXUP( pData, pAnimDesc, movementindex ) + WriteObjects( pDataDest, pDataSrc, SrcNative( &pAnimDesc->nummovements ) ); + } + } + + /** IK RULES (2nd pass) **/ + + // This is required to support older models that had these lumps in a different + // order - the model version didn't change, so there's no reliable way to detect it. + SET_INDEX_POINTERS( pData, pHdr, localanimindex ) + SET_OBJECT_POINTERS( pAnimDesc, pData, mstudioanimdesc_t ) + ITERATE_BLOCK( pAnimDesc, pHdr->numlocalanim ) + { + if ( pAnimDesc->ikruleindex ) + { + // Only need to write the data again if a fixup happens + byte *pTest = (byte*)pAnimDesc + SrcNative( &pAnimDesc->ikruleindex ); + SET_INDEX_POINTERS_FIXUP( pData, pAnimDesc, ikruleindex ) + if ( pTest == pDataSrc ) + continue; + + DECLARE_OBJECT_POINTERS( pIKRule, pData, mstudioikrule_t ) + ITERATE_BLOCK( pIKRule, pAnimDesc->numikrules ) + { + WriteObjects( pIKRuleDest, pIKRuleSrc ); + + /** IK ERROR KEYS **/ + + // Calculate the number of ikerrors by converting the ikerror start and end float values to + // frame numbers. (See the generation of these values in simplify.cpp: ProcessIKRules()). + int numFrames = SrcNative( &pAnimDesc->numframes ); + float start = floorf( SrcNative( &pIKRule->start ) * (numFrames - 1) + 0.5f ); + float end = floorf( SrcNative( &pIKRule->end ) * (numFrames - 1) + 0.5f ); + int totalerror = (int)( end - start + 1 ); + if ( end >= numFrames ) + totalerror += 2; + + // Uncompressed - only found in some older models (shipped hl2) + if ( pIKRule->ikerrorindex ) + { + SET_INDEX_POINTERS_FIXUP( pData, pIKRule, ikerrorindex ) + WriteObjects( pDataDest, pDataSrc, totalerror ); + } + + // Compressed - all models since hl2 + if ( pIKRule->compressedikerrorindex ) + { + SET_INDEX_POINTERS_FIXUP( pData, pIKRule, compressedikerrorindex ) + WriteObjects( pDataDest, pDataSrc ); + + mstudiocompressedikerror_t *pCompressed = (mstudiocompressedikerror_t *)pDataSrc; + + // Write the animvalues. + for ( int idx = 0; idx < 6; ++idx ) + { + if ( pCompressed->offset[idx] ) + { + byte *pAnimvalueSrc = pDataSrc + SrcNative( &pCompressed->offset[idx] ); + byte *pAnimvalueDest = pDataDest + SrcNative( &pCompressed->offset[idx] ); + + int numerror = 0; + while ( numerror < totalerror ) + { + // Write the first animation value (struct of 2 bytes) + mstudioanimvalue_t *pDestAnimvalue = (mstudioanimvalue_t*)( g_bNativeSrc ? pAnimvalueSrc : pAnimvalueDest ); + WriteBuffer( &pAnimvalueDest, &pAnimvalueSrc, 2 ); + + // Write the remaining animation values from this group (shorts) + WriteBuffer( &pAnimvalueDest, &pAnimvalueSrc, pDestAnimvalue->num.valid ); + + numerror += pDestAnimvalue->num.total; + } + } + } + + if ( pIKRule->szattachmentindex ) + { + SET_INDEX_POINTERS( pData, pIKRule, szattachmentindex ) + int size = strlen( (char*)pDataSrc ) + 1; + WriteBuffer( pDataDest, pDataSrc, size ); + } + } + } + } + + // Local hierarchy keys don't exist in older models + } + + /** ZERO FRAMES **/ + + SET_INDEX_POINTERS( pData, pHdr, localanimindex ) + SET_OBJECT_POINTERS( pAnimDesc, pData, mstudioanimdesc_t ) + ITERATE_BLOCK( pAnimDesc, pHdr->numlocalanim ) + { + if ( pAnimDesc->pZeroFrameData( ) != NULL ) + { + int offset = pAnimDesc->pZeroFrameData( ) - (byte *)pAnimDesc; + + // Base address of the animation in the animblock + byte *pZeroFrameSrc = (byte *)pAnimDescSrc + offset; + byte *pZeroFrameDest = (byte *)pAnimDescDest + offset; + + SET_INDEX_POINTERS( pData, pHdr, boneindex ) + SET_OBJECT_POINTERS( pStudioBone, pData, mstudiobone_t ) + ITERATE_BLOCK( pStudioBone, pHdr->numbones ) + { + if ( pStudioBone->flags & BONE_HAS_SAVEFRAME_POS ) + { + for ( int j = 0; j < pAnimDesc->zeroframecount; j++) + { + WriteBuffer( &pZeroFrameDest, &pZeroFrameSrc, 3 ); + } + } + if ( pStudioBone->flags & BONE_HAS_SAVEFRAME_ROT ) + { + for ( int j = 0; j < pAnimDesc->zeroframecount; j++) + { + WriteBuffer( &pZeroFrameDest, &pZeroFrameSrc, 1 ); + } + } + } + } + } + + /** SEQUENCE INFO **/ + + SET_INDEX_POINTERS_FIXUP( pData, pHdr, localseqindex ) + DECLARE_OBJECT_POINTERS( pSequence, pData, mstudioseqdesc_t ) + ITERATE_BLOCK( pSequence, pHdr->numlocalseq ) + { + WriteObjects( pSequenceDest, pSequenceSrc ); + + /** POSE KEYS **/ + + if ( pSequence->posekeyindex ) + { + SET_INDEX_POINTERS_FIXUP( pData, pSequence, posekeyindex ) + WriteBuffer( pDataDest, pDataSrc, SrcNative( &pSequence->groupsize[0] ) + SrcNative( &pSequence->groupsize[1] ) ); + } + + /** STUDIO EVENTS **/ + + SET_INDEX_POINTERS_FIXUP( pData, pSequence, eventindex ) + WriteObjects( pDataDest, pDataSrc, SrcNative( &pSequence->numevents ) ); + + /** AUTOLAYERS **/ + + SET_INDEX_POINTERS_FIXUP( pData, pSequence, autolayerindex ) + WriteObjects( pDataDest, pDataSrc, SrcNative( &pSequence->numautolayers ) ); + + /** BONE WEIGHTS **/ + + // Data may be shared across sequences + DECLARE_INDEX_POINTERS_FIXUP( pWeight, pSequence, weightlistindex ) + if ( pWeightSrc >= pDataSrc ) + { + int numBoneWeights = ( SrcNative( &pSequence->iklockindex ) - SrcNative( &pSequence->weightlistindex ) ) / sizeof(float); + WriteBuffer( pWeightDest, pWeightSrc, numBoneWeights ); + } + + /** IK LOCKS **/ + + SET_INDEX_POINTERS_FIXUP( pData, pSequence, iklockindex ) + WriteObjects( pDataDest, pDataSrc, SrcNative( &pSequence->numiklocks ) ); + + /** ANIMATION INDICES **/ + + if ( pSequence->animindexindex ) + { + SET_INDEX_POINTERS( pData, pSequence, animindexindex ) + WriteBuffer( pDataDest, pDataSrc, SrcNative( &pSequence->groupsize[0] ) * SrcNative( &pSequence->groupsize[1] ) ); + } + + /** KEYVALUES **/ + + SET_INDEX_POINTERS( pData, pSequence, keyvalueindex ) + WriteBuffer( pDataDest, pDataSrc, SrcNative( &pSequence->keyvaluesize ) ); + } + + /** TRANSITION GRAPH **/ + + int numLocalNodes = SrcNative( &pHdr->numlocalnodes ); + SET_INDEX_POINTERS_FIXUP( pData, pHdr, localnodenameindex ) + WriteBuffer( pDataDest, pDataSrc, numLocalNodes ); + + /** LOCAL NODES **/ + + SET_INDEX_POINTERS( pData, pHdr, localnodeindex ) + WriteBuffer( pDataDest, pDataSrc, numLocalNodes * numLocalNodes ); + + /** BODYPART INFO **/ + + SET_INDEX_POINTERS_FIXUP( pData, pHdr, bodypartindex ) + DECLARE_OBJECT_POINTERS( pBodypart, pData, mstudiobodyparts_t ) + ITERATE_BLOCK( pBodypart, pHdr->numbodyparts ) + { + WriteObjects( pBodypartDest, pBodypartSrc ); + + /** MODEL INFO **/ + + SET_INDEX_POINTERS_FIXUP( pData, pBodypart, modelindex ) + DECLARE_OBJECT_POINTERS( pModel, pData, mstudiomodel_t ) + ITERATE_BLOCK( pModel, pBodypart->nummodels ) + { + WriteObjects( pModelDest, pModelSrc ); + + /** MESHES **/ + + SET_INDEX_POINTERS_FIXUP( pData, pModel, meshindex ) + DECLARE_OBJECT_POINTERS( pMesh, pData, mstudiomesh_t ) + ITERATE_BLOCK( pMesh, pModel->nummeshes ) + { + WriteObjects( pMeshDest, pMeshSrc ); + + if ( !pMesh->numflexes ) + continue; + + /** FLEXES **/ + + SET_INDEX_POINTERS_FIXUP( pData, pMesh, flexindex ) + DECLARE_OBJECT_POINTERS( pFlex, pData, mstudioflex_t ) + ITERATE_BLOCK( pFlex, pMesh->numflexes ) + { + WriteObjects( pFlexDest, pFlexSrc ); + + /** VERT ANIMS **/ + + SET_INDEX_POINTERS_FIXUP( pData, pFlex, vertindex ) + WriteObjects( pDataDest, pDataSrc, SrcNative( &pFlex->numverts ) ); + } + } + + /** EYEBALLS **/ + + SET_INDEX_POINTERS_FIXUP( pData, pModel, eyeballindex ) + WriteObjects( pDataDest, pDataSrc, SrcNative( &pModel->numeyeballs ) ); + } + } + + /** GLOBAL FLEX NAMES **/ + + SET_INDEX_POINTERS_FIXUP( pData, pHdr, flexdescindex ) + WriteObjects( pDataDest, pDataSrc, SrcNative( &pHdr->numflexdesc ) ); + + /** GLOBAL FLEX CONTROLLERS **/ + + SET_INDEX_POINTERS_FIXUP( pData, pHdr, flexcontrollerindex ) + WriteObjects( pDataDest, pDataSrc, SrcNative( &pHdr->numflexcontrollers ) ); + + /** GLOBAL FLEX CONTROLLER REMAPS **/ + + SET_INDEX_POINTERS_FIXUP( pData, pHdr, flexcontrolleruiindex ) + WriteObjects( pDataDest, pDataSrc, SrcNative( &pHdr->numflexcontrollerui ) ); + + // TODOKD: The remap indices after the flex controller remap headers need to be swapped as well? + + /** FLEX RULES **/ + + SET_INDEX_POINTERS_FIXUP( pData, pHdr, flexruleindex ) + DECLARE_OBJECT_POINTERS( pFlexRule, pData, mstudioflexrule_t ) + ITERATE_BLOCK( pFlexRule, pHdr->numflexrules ) + { + WriteObjects( pFlexRuleDest, pFlexRuleSrc ); + + /** FLEX OPS **/ + + SET_INDEX_POINTERS_FIXUP( pData, pFlexRule, opindex ) + WriteObjects( pDataDest, pDataSrc, SrcNative( &pFlexRule->numops ) ); + } + + /** IK CHAINS **/ + + SET_INDEX_POINTERS_FIXUP( pData, pHdr, ikchainindex ) + DECLARE_OBJECT_POINTERS( pIKChain, pData, mstudioikchain_t ) + ITERATE_BLOCK( pIKChain, pHdr->numikchains ) + { + WriteObjects( pIKChainDest, pIKChainSrc ); + + /** IK LINKS **/ + + SET_INDEX_POINTERS( pData, pIKChain, linkindex ) + WriteObjects( pDataDest, pDataSrc, SrcNative( &pIKChain->numlinks ) ); + } + + /** IK AUTOPLAY LOCKS **/ + + SET_INDEX_POINTERS_FIXUP( pData, pHdr, localikautoplaylockindex ) + WriteObjects( pDataDest, pDataSrc, SrcNative( &pHdr->numlocalikautoplaylocks ) ); + + /** MOUTH INFO **/ + + SET_INDEX_POINTERS_FIXUP( pData, pHdr, mouthindex ) + WriteObjects( pDataDest, pDataSrc, SrcNative( &pHdr->nummouths ) ); + + /** POSE PARAMATERS **/ + + SET_INDEX_POINTERS_FIXUP( pData, pHdr, localposeparamindex ) + WriteObjects( pDataDest, pDataSrc, SrcNative( &pHdr->numlocalposeparameters ) ); + + /** MODEL GROUPS **/ + + SET_INDEX_POINTERS_FIXUP( pData, pHdr, includemodelindex ) + WriteObjects( pDataDest, pDataSrc, SrcNative( &pHdr->numincludemodels ) ); + + /** ANIMBLOCK GROUP INFO **/ + + SET_INDEX_POINTERS_FIXUP( pData, pHdr, animblockindex ) + WriteObjects( pDataDest, pDataSrc, SrcNative( &pHdr->numanimblocks ) ); + + /** TEXTURE INFO **/ + + // While swapping, kill off unwanted textures by name + SET_INDEX_POINTERS_FIXUP( pData, pHdr, textureindex ) + DECLARE_OBJECT_POINTERS( pTexture, pData, mstudiotexture_t ) + int textureCt = SrcNative( &pHdr->numtextures ); + int nameOffset = 0; + for ( int i = 0; i < SrcNative( &pHdr->numtextures ); ++i, ++pTexture, ++pTextureSrc ) + { + WriteObjects( pTextureDest, pTextureSrc ); + + int destnameindex = SrcNative( &pTexture->sznameindex ) + nameOffset; + pTextureDest->sznameindex = DestNative( &destnameindex ); + char *pName = (char*)pTexture + SrcNative( &pTexture->sznameindex ); +#if 0 // Undone: Killing textures here can cause crashes at runtime. + // Don't need pupil textures + if ( Q_stristr( pName, "pupil_" ) || !Q_stricmp( pName, "pupil" ) ) + { + --textureCt; + nameOffset += sizeof(mstudiotexture_t); + } + else +#endif + { + ++pTextureDest; + } + } + pHdrDest->numtextures = DestNative( &textureCt ); + + /** TEXTURE INDICES **/ + + SET_INDEX_POINTERS_FIXUP( pData, pHdr, cdtextureindex ) + WriteBuffer( &pDataDest, &pDataSrc, SrcNative( &pHdr->numcdtextures ) ); + + /** TEXTURE DICTIONARY **/ + + SET_INDEX_POINTERS( pData, pHdr, skinindex ) + WriteBuffer( &pDataDest, &pDataSrc, SrcNative( &pHdr->numskinfamilies ) * SrcNative( &pHdr->numskinref ) ); + + /** KEYVALUES **/ + + SET_INDEX_POINTERS( pData, pHdr, keyvalueindex ) + WriteBuffer( &pDataDest, &pDataSrc, SrcNative( &pHdr->keyvaluesize ) ); + + /** STUDIOHDR2 **/ + + if ( pHdr->studiohdr2index ) + { + DECLARE_INDEX_POINTERS_FIXUP( pLocalData, pHdr, studiohdr2index ) + DECLARE_OBJECT_POINTERS( pStudioHdr2, pLocalData, studiohdr2_t ) + + // HACK: Pre-swap the constant "1" here so the automatic swap inside ITERATE_BLOCK will restore it + int studiohdr2ct = 1; + studiohdr2ct = SrcNative( &studiohdr2ct ); + ITERATE_BLOCK( pStudioHdr2, studiohdr2ct ) + { + WriteObjects( pStudioHdr2Dest, pStudioHdr2Src ); + + /** SRC BONE TRANSFORMS **/ + + if ( pStudioHdr2->numsrcbonetransform ) + { + // Note, srcbonetransformindex is an offset from the start of the file, not the start of the studiohdr2 + // as is the convention. That's why the macros can't be used here. + pDataSrc = (byte*)pHdrSrc + SrcNative( &pStudioHdr2->srcbonetransformindex ); + pDataDest = (byte*)pHdrDest + SrcNative( &pStudioHdr2->srcbonetransformindex ); + WriteObjects( &pDataDest, &pDataSrc, SrcNative( &pStudioHdr2->numsrcbonetransform ) ); + } + + if ( pStudioHdr2->linearboneindex ) + { + SET_INDEX_POINTERS_FIXUP( pData, pStudioHdr2, linearboneindex ) + DECLARE_OBJECT_POINTERS( pLinearBone, pData, mstudiolinearbone_t ) + + WriteObjects( pLinearBoneDest, pLinearBoneSrc ); + + int numBones = SrcNative( &pLinearBone->numbones ); + SET_INDEX_POINTERS_FIXUP( pData, pLinearBone, flagsindex ) + WriteBuffer( &pDataDest, &pDataSrc, numBones ); + + SET_INDEX_POINTERS_FIXUP( pData, pLinearBone, parentindex ) + WriteBuffer( &pDataDest, &pDataSrc, numBones ); + + SET_INDEX_POINTERS_FIXUP( pData, pLinearBone, posindex ) + WriteBuffer( &pDataDest, &pDataSrc, 3*numBones ); + + SET_INDEX_POINTERS_FIXUP( pData, pLinearBone, quatindex ) + WriteBuffer( &pDataDest, &pDataSrc, 4*numBones ); + + SET_INDEX_POINTERS_FIXUP( pData, pLinearBone, rotindex ) + WriteBuffer( &pDataDest, &pDataSrc, 3*numBones ); + + SET_INDEX_POINTERS_FIXUP( pData, pLinearBone, posetoboneindex ) + WriteBuffer( &pDataDest, &pDataSrc, 12*numBones ); + + SET_INDEX_POINTERS_FIXUP( pData, pLinearBone, posscaleindex ) + WriteBuffer( &pDataDest, &pDataSrc, 3*numBones ); + + SET_INDEX_POINTERS_FIXUP( pData, pLinearBone, rotscaleindex ) + WriteBuffer( &pDataDest, &pDataSrc, 3*numBones ); + + SET_INDEX_POINTERS_FIXUP( pData, pLinearBone, qalignmentindex ) + WriteBuffer( &pDataDest, &pDataSrc, 4*numBones ); + } + } + } + + /** STRING TABLE **/ + + // NOTE: The block of data (above) swapped immediately before the string table MUST update the + // pDataSrc pointer position, in order for this string table offset calculation to work correctly. + // To update the pointer position, pass the pointer address to WriteObjects(). + int offset = pDataSrc - (byte*)pSrcBase; + int stringTableBytes = fixedFileSize - offset; + WriteBuffer( pDataDest, pDataSrc, stringTableBytes ); + + pHdrDest->length = DestNative( &fixedFileSize ); + + // Cleanup texture paths + // Some older MDL's have double terminal slashes + SET_INDEX_POINTERS( pData, pHdr, cdtextureindex ) + int numCdTextures = SrcNative( &pHdr->numcdtextures ); + for ( int i = 0; i < numCdTextures; ++i ) + { + char *pPath = (char*)pHdrDest + SrcNative( &((int *)pDataSrc)[i] ); + int len = strlen( pPath ); + if ( len >= 2 && ( pPath[len-1] == '\\' || pPath[len-1] == '/' ) && ( pPath[len-2] == '\\' || pPath[len-2] == '/' ) ) + { + pPath[len-1] = '\0'; + } + } + + return fixedFileSize; +} + +//---------------------------------------------------------------------- +// Swap a .mdl in two passes - first pass fixes alignment errors by shifting +// the data and updating offsets, then the second pass does the final swap. +//---------------------------------------------------------------------- +int ByteswapMDL( void *pDestBase, const void *pSrcBase, const int fileSize ) +{ + // Make a working copy of the source to allow for alignment fixups + void *pNewSrcBase = malloc( fileSize + BYTESWAP_ALIGNMENT_PADDING ); + Q_memcpy( pNewSrcBase, pSrcBase, fileSize ); + + int fixedFileSize = ByteswapMDLFile( pDestBase, pNewSrcBase, fileSize ); + if ( fixedFileSize != fileSize ) + { + int finalSize = ByteswapMDLFile( pDestBase, pNewSrcBase, fixedFileSize ); + if ( finalSize != fixedFileSize ) + { + Warning( "Alignment fixups failed on MDL swap!\n" ); + fixedFileSize = 0; + } + } + + free( pNewSrcBase ); + + // the compression needs to happen on the final or "fixed" pass + if ( g_pCompressFunc && fixedFileSize ) + { + void *pInput = pDestBase; + int inputSize = fixedFileSize; + void *pOutput; + int outputSize; + if ( g_pCompressFunc( pInput, inputSize, &pOutput, &outputSize ) ) + { + V_memcpy( pDestBase, pOutput, outputSize ); + free( pOutput ); + fixedFileSize = outputSize; + } + } + + return fixedFileSize; +} + +//---------------------------------------------------------------------- +// Determines what kind of file this is and calls the correct swap function +//---------------------------------------------------------------------- +int ByteswapStudioFile( const char *pFilename, void *pOutBase, const void *pFileBase, int fileSize, studiohdr_t *pHdr, CompressFunc_t pCompressFunc ) +{ + assert( pFilename ); + assert( pOutBase != pFileBase ); + + g_pCompressFunc = pCompressFunc; + + int retVal = 0; + + if ( Q_stristr( pFilename, ".mdl" ) ) + { + retVal = ByteswapMDL( pOutBase, pFileBase, fileSize ); + } + else if ( Q_stristr( pFilename, ".vvd" ) ) + { + retVal = ByteswapVVD( pOutBase, pFileBase, fileSize ); + } + else if ( Q_stristr( pFilename, ".vtx" ) ) + { + retVal = ByteswapVTX( pOutBase, pFileBase, fileSize ); + } + else if ( Q_stristr( pFilename, ".phy" ) ) + { + retVal = ByteswapPHY( pOutBase, pFileBase, fileSize ); + } + else if ( Q_stristr( pFilename, ".ani" ) ) + { + // some dead .ani files exist in the tree + // only process valid .ani files properly hooked to their .mdl + if ( pHdr && pHdr->numanimblocks != 0 ) + { + retVal = ByteswapANI( pHdr, pOutBase, pFileBase, fileSize ); + } + } + + g_pCompressFunc = NULL; + + return retVal; +} + + +//---------------------------------------------------------------------- +// LEGACY ANI FIXUPS - No need to update this function +// +// If model data needs to be shifted to fix a misalignment, this function is +// called with the process func "UpdateSrcIndexFields" to update every datadesc field +// that was marked as FIELD_INDEX. Any index that "points" across +// the shifted data location will have its value incremented or decremented +// by the appropriate number of bytes. This misalignment issue only +// applies to some pre-EP2 models, as all newly compiled models are guaranteed +// to be aligned correctly. Therefore, this function should not need to change +// when model formats are updated, as any model compiled with a new format will +// naturally not require this fixup function to be called. +//---------------------------------------------------------------------- +void ProcessANIFields( void *pDataBase, datadescProcessFunc_t pfnProcessFunc ) +{ + studiohdr_t *pHdr = g_pHdr; + byte *pData = (byte*)pDataBase; + byte *pSrcBase = (byte*)g_pDataSrcBase; + + // Since the animblocks and animdescs are native data, trick the system + // into not swapping their index values during processing. + bool bNativeSrc = g_bNativeSrc; + g_bNativeSrc = true; + + // Update the .mdl's animblock offsets into the .ani file + mstudioanimblock_t *pAnimBlock = pHdr->pAnimBlock( 1 ); + for ( int i = 1; i < pHdr->numanimblocks; ++i, ++pAnimBlock ) + { + ProcessFields( pSrcBase, pAnimBlock, &mstudioanimblock_t::m_DataMap, pfnProcessFunc ); + } + + // Update the .mdl's animindex offsets into the .ani file + // Don't bother with local hierarchy keys - they only exist in newer, properly aligned models + mstudioanimdesc_t *pAnimDesc = pHdr->pLocalAnimdesc( 0 ); + for ( int i = 0; i < pHdr->numlocalanim; ++i, ++pAnimDesc ) + { + mstudioanimblock_t *pAnimBlock = pHdr->pAnimBlock( pAnimDesc->animblock ); + byte *pBlockBase = (byte*)pSrcBase + pAnimBlock->datastart; + + ProcessFieldByName( pBlockBase, pAnimDesc, &mstudioanimdesc_t::m_DataMap, "animindex", pfnProcessFunc ); + ProcessFieldByName( pBlockBase, pAnimDesc, &mstudioanimdesc_t::m_DataMap, "animblockikruleindex", pfnProcessFunc ); + } + + // Restore the correct native setting + g_bNativeSrc = bNativeSrc; + + // Update the .ani file's internal offsets + pAnimDesc = pHdr->pLocalAnimdesc( 0 ); + for ( int i = 0; i < pHdr->numlocalanim; ++i, ++pAnimDesc ) + { + pAnimBlock = pHdr->pAnimBlock( pAnimDesc->animblock ); + byte *pBlockBase = (byte*)pSrcBase + pAnimBlock->datastart; + + byte *pData = pBlockBase + pAnimDesc->animindex; + mstudioanim_t* pAnimation = (mstudioanim_t*)pData; + if ( pAnimation->bone == 255 ) + { + // No animation data + pAnimation = 0; + } + + while( pAnimation ) + { + ProcessFields( pAnimation, &mstudioanim_t::m_DataMap, pfnProcessFunc ); + + if ( pAnimation->nextoffset ) + { + pData = (byte*)pAnimation + SrcNative( &pAnimation->nextoffset ); + pAnimation = (mstudioanim_t*)pData; + } + else + { + pAnimation = NULL; + } + } + + if ( pAnimDesc->animblockikruleindex ) + { + pData = (byte*)pBlockBase + pAnimDesc->animblockikruleindex; + + mstudioikrule_t *pIKRule = (mstudioikrule_t *)pData; + for ( int i = 0; i < pAnimDesc->numikrules; ++i, ++pIKRule ) + { + ProcessFields( pIKRule, &mstudioikrule_t::m_DataMap, pfnProcessFunc ); + } + } + } +} + +//---------------------------------------------------------------------- +// LEGACY MDL FIXUPS - No need to update this function +// +// If model data needs to be shifted to fix a misalignment, this function is +// called with the process func "UpdateSrcIndexFields" to update every datadesc field +// that was marked as FIELD_INDEX. Any index that "points" across +// the shifted data location will have its value incremented or decremented +// by the appropriate number of bytes. This misalignment issue only +// applies to some pre-EP2 models, as all newly compiled models are guaranteed +// to be aligned correctly. Therefore, this function should not need to change +// when model formats are updated, as any model compiled with a new format will +// naturally not require this fixup function to be called. +//---------------------------------------------------------------------- +void ProcessMDLFields( void *pDataBase, datadescProcessFunc_t pfnProcessFunc ) +{ + byte *pData = (byte*)pDataBase; + + /** FILE HEADER **/ + + studiohdr_t *pHdr = (studiohdr_t*)pData; + ProcessFields( pHdr, &studiohdr_t::m_DataMap, pfnProcessFunc ); + + /** BONES **/ + + pData = (byte*)pHdr + SrcNative( &pHdr->boneindex ); + mstudiobone_t *pBone = (mstudiobone_t*)pData; + for ( int i = 0; i < SrcNative( &pHdr->numbones ); ++i, ++pBone ) + { + ProcessFields( pBone, &mstudiobone_t::m_DataMap, pfnProcessFunc ); + + if ( pBone->procindex ) + { + pData = (byte*)pBone + SrcNative( &pBone->procindex ); + + unsigned int proctype = SrcNative( &pBone->proctype ); + switch( proctype ) + { + case STUDIO_PROC_AXISINTERP: + + /** AXIS-INTERP BONES **/ + ProcessFields( pData, &mstudioaxisinterpbone_t::m_DataMap, pfnProcessFunc ); + break; + + case STUDIO_PROC_QUATINTERP: + + /** QUAT-INTERP BONES **/ + ProcessFields( pData, &mstudioquatinterpbone_t::m_DataMap, pfnProcessFunc ); + break; + + case STUDIO_PROC_JIGGLE: + + /** JIGGLE BONES **/ + ProcessFields( pData, &mstudiojigglebone_t::m_DataMap, pfnProcessFunc ); + break; + + case STUDIO_PROC_AIMATBONE: + case STUDIO_PROC_AIMATATTACH: + + /** AIM AT BONES **/ + ProcessFields( pData, &mstudioaimatbone_t::m_DataMap, pfnProcessFunc ); + break; + + } + } + } + + /** ATTACHMENTS **/ + + pData = (byte*)pHdr + SrcNative( &pHdr->localattachmentindex ); + mstudioattachment_t *pAttachment = (mstudioattachment_t*)pData; + for ( int i = 0; i < SrcNative( &pHdr->numlocalattachments ); ++i, ++pAttachment ) + { + ProcessFields( pAttachment, &mstudioattachment_t::m_DataMap, pfnProcessFunc ); + } + + /** HITBOX SETS **/ + + pData = (byte*)pHdr + SrcNative( &pHdr->hitboxsetindex ); + mstudiohitboxset_t* pHitboxSet = (mstudiohitboxset_t*)pData; + for ( int i = 0; i < SrcNative( &pHdr->numhitboxsets ); ++i, ++pHitboxSet ) + { + ProcessFields( pHitboxSet, &mstudiohitboxset_t::m_DataMap, pfnProcessFunc ); + + /** HITBOXES **/ + pData = (byte*)pHitboxSet + SrcNative( &pHitboxSet->hitboxindex ); + mstudiobbox_t *pBBox = (mstudiobbox_t*)pData; + for ( int i = 0; i < SrcNative( &pHitboxSet->numhitboxes ); ++i, ++pBBox ) + { + ProcessFields( pBBox, &mstudiobbox_t::m_DataMap, pfnProcessFunc ); + } + } + + /** ANIMATION DESCRIPTIONS **/ + + pData = (byte*)pHdr + SrcNative( &pHdr->localanimindex ); + mstudioanimdesc_t* pAnimDesc = (mstudioanimdesc_t*)pData; + for ( int i = 0; i < SrcNative( &pHdr->numlocalanim ); ++i, ++pAnimDesc ) + { + // Can't update animindex or animblockindex for animations that are in a separate .ani file + ProcessFieldByName( pAnimDesc, &mstudioanimdesc_t::m_DataMap, "baseptr", pfnProcessFunc ); + ProcessFieldByName( pAnimDesc, &mstudioanimdesc_t::m_DataMap, "sznameindex", pfnProcessFunc ); + ProcessFieldByName( pAnimDesc, &mstudioanimdesc_t::m_DataMap, "movementindex", pfnProcessFunc ); + ProcessFieldByName( pAnimDesc, &mstudioanimdesc_t::m_DataMap, "ikruleindex", pfnProcessFunc ); + + /** ANIMATIONS **/ + + if ( pAnimDesc->animblock == 0 ) + { + // Now it's safe to update the animindex + ProcessFieldByName( pAnimDesc, &mstudioanimdesc_t::m_DataMap, "animindex", pfnProcessFunc ); + + pData = (byte*)pAnimDesc + SrcNative( &pAnimDesc->animindex ); + mstudioanim_t* pAnimation = (mstudioanim_t*)pData; + while( pAnimation ) + { + ProcessFields( pAnimation, &mstudioanim_t::m_DataMap, pfnProcessFunc ); + + if ( pAnimation->nextoffset ) + { + pData = (byte*)pAnimation + SrcNative( &pAnimation->nextoffset ); + pAnimation = (mstudioanim_t*)pData; + } + else + { + pAnimation = NULL; + } + } + } + + if ( pAnimDesc->ikruleindex ) + { + pData = (byte*)pAnimDesc + SrcNative( &pAnimDesc->ikruleindex ); + + mstudioikrule_t *pIKRule = (mstudioikrule_t *)pData; + for ( int i = 0; i < SrcNative( &pAnimDesc->numikrules ); ++i, ++pIKRule ) + { + ProcessFields( pIKRule, &mstudioikrule_t::m_DataMap, pfnProcessFunc ); + } + } + } + + /** SEQUENCE INFO **/ + + pData = (byte*)pHdr + SrcNative( &pHdr->localseqindex ); + mstudioseqdesc_t *pSequenceHdr = (mstudioseqdesc_t*)pData; + for ( int i = 0; i < SrcNative( &pHdr->numlocalseq ); ++i, ++pSequenceHdr ) + { + ProcessFields( pSequenceHdr, &mstudioseqdesc_t::m_DataMap, pfnProcessFunc ); + + /** STUDIO EVENTS **/ + + pData = (byte*)pHdr + SrcNative( &pSequenceHdr->eventindex ); + mstudioevent_t *pEvent = (mstudioevent_t*)pData; + for ( int i = 0; i < SrcNative( &pSequenceHdr->numevents ); ++i, ++pEvent ) + { + ProcessFields( pSequenceHdr, &mstudioevent_t::m_DataMap, pfnProcessFunc ); + } + } + + /** BODYPART INFO **/ + + pData = (byte*)pHdr + SrcNative( &pHdr->bodypartindex ); + mstudiobodyparts_t *pBodypart = (mstudiobodyparts_t*)pData; + for ( int i = 0; i < SrcNative( &pHdr->numbodyparts ); ++i, ++pBodypart ) + { + ProcessFields( pBodypart, &mstudiobodyparts_t::m_DataMap, pfnProcessFunc ); + + /** MODEL INFO **/ + + byte *pData = (byte*)pBodypart + SrcNative( &pBodypart->modelindex ); + mstudiomodel_t *pModel = (mstudiomodel_t*)pData; + for ( int i = 0; i < SrcNative( &pBodypart->nummodels ); ++i, ++pModel ) + { + ProcessFields( pModel, &mstudiomodel_t::m_DataMap, pfnProcessFunc ); + + /** MESHES **/ + + pData = (byte*)pModel + SrcNative( &pModel->meshindex ); + mstudiomesh_t *pMesh = (mstudiomesh_t*)pData; + for ( int i = 0; i < SrcNative( &pModel->nummeshes ); ++i, ++pMesh ) + { + ProcessFields( pMesh, &mstudiomesh_t::m_DataMap, pfnProcessFunc ); + + if ( !pMesh->numflexes ) + continue; + + /** FLEXES **/ + + pData = (byte*)pMesh + SrcNative( &pMesh->flexindex ); + mstudioflex_t *pFlex = (mstudioflex_t*)pData; + for ( int i = 0; i < SrcNative( &pMesh->numflexes ); ++i, ++pFlex ) + { + ProcessFields( pFlex, &mstudioflex_t::m_DataMap, pfnProcessFunc ); + } + } + + /** EYEBALLS **/ + + pData= (byte*)pModel + SrcNative( &pModel->eyeballindex ); + mstudioeyeball_t *pEyeball = (mstudioeyeball_t*)pData; + for ( int i = 0; i < SrcNative( &pModel->numeyeballs ); ++i, ++pEyeball ) + { + ProcessFields( pEyeball, &mstudioeyeball_t::m_DataMap, pfnProcessFunc ); + } + } + } + + /** GLOBAL FLEX NAMES **/ + + pData = (byte*)pHdr + SrcNative( &pHdr->flexdescindex ); + mstudioflexdesc_t *pFlexDesc = (mstudioflexdesc_t*)pData; + for ( int i = 0; i < SrcNative( &pHdr->numflexdesc ); ++i, ++pFlexDesc ) + { + ProcessFields( pFlexDesc, &mstudioflexdesc_t::m_DataMap, pfnProcessFunc ); + } + + /** GLOBAL FLEX CONTROLLERS **/ + + pData = (byte*)pHdr + SrcNative( &pHdr->flexcontrollerindex ); + mstudioflexcontroller_t *pFlexController = (mstudioflexcontroller_t*)pData; + for ( int i = 0; i < SrcNative( &pHdr->numflexcontrollers ); ++i, ++pFlexController ) + { + ProcessFields( pFlexController, &mstudioflexcontroller_t::m_DataMap, pfnProcessFunc ); + } + + /** GLOBAL FLEX CONTROLLER REMAPS **/ + + pData = (byte*)pHdr + SrcNative( &pHdr->flexcontrolleruiindex ); + mstudioflexcontrollerui_t *pFlexControllerRemap = (mstudioflexcontrollerui_t*)pData; + for ( int i = 0; i < SrcNative( &pHdr->numflexcontrollerui ); ++i, ++pFlexControllerRemap ) + { + ProcessFields( pFlexControllerRemap, &mstudioflexcontrollerui_t::m_DataMap, pfnProcessFunc ); + } + + /** FLEX RULES **/ + + pData = (byte*)pHdr + SrcNative( &pHdr->flexruleindex ); + mstudioflexrule_t *pFlexRule = (mstudioflexrule_t*)pData; + for ( int i = 0; i < SrcNative( &pHdr->numflexrules ); ++i, ++pFlexRule ) + { + ProcessFields( pFlexRule, &mstudioflexrule_t::m_DataMap, pfnProcessFunc ); + } + + /** IK CHAINS **/ + + pData = (byte*)pHdr + SrcNative( &pHdr->ikchainindex ); + mstudioikchain_t *pIKChain = (mstudioikchain_t*)pData; + for ( int i = 0; i < SrcNative( &pHdr->numikchains ); ++i, ++pIKChain ) + { + ProcessFields( pIKChain, &mstudioikchain_t::m_DataMap, pfnProcessFunc ); + } + + /** POSE PARAMATERS **/ + + pData = (byte*)pHdr + SrcNative( &pHdr->localposeparamindex ); + mstudioposeparamdesc_t *pPoseParam = (mstudioposeparamdesc_t*)pData; + for ( int i = 0; i < SrcNative( &pHdr->numlocalposeparameters ); ++i, ++pPoseParam ) + { + ProcessFields( pPoseParam, &mstudioposeparamdesc_t::m_DataMap, pfnProcessFunc ); + } + + /** MODEL GROUPS **/ + + pData = (byte*)pHdr + SrcNative( &pHdr->includemodelindex ); + mstudiomodelgroup_t *pMdl = (mstudiomodelgroup_t*)pData; + for ( int i = 0; i < SrcNative( &pHdr->numincludemodels ); ++i, ++pMdl ) + { + ProcessFields( pMdl, &mstudiomodelgroup_t::m_DataMap, pfnProcessFunc ); + } + + /** TEXTURE INFO **/ + + pData = (byte*)pHdr + SrcNative( &pHdr->textureindex ); + mstudiotexture_t *pTexture = (mstudiotexture_t*)pData; + for ( int i = 0; i < SrcNative( &pHdr->numtextures ); ++i, ++pTexture ) + { + ProcessFields( pTexture, &mstudiotexture_t::m_DataMap, pfnProcessFunc ); + } + + /** CDTEXTURE OFFSETS **/ + + pData = (byte*)pHdr + SrcNative( &pHdr->cdtextureindex ); + int *pIdx = (int*)pData; + for ( int i = 0; i < SrcNative( &pHdr->numcdtextures ); ++i, ++pIdx ) + { + int idx = SrcNative( pIdx ); + UpdateIndex( pHdr, &idx ); + *pIdx = SrcNative( &idx ); + } + + /** STUDIOHDR2 **/ + + if ( pHdr->studiohdr2index ) + { + pData = (byte*)pHdr + SrcNative( &pHdr->studiohdr2index ); + studiohdr2_t *pStudioHdr2 = (studiohdr2_t*)pData; + for ( int i = 0; i < 1; ++i, ++pStudioHdr2 ) + { + ProcessFields( pStudioHdr2, &studiohdr2_t::m_DataMap, pfnProcessFunc ); + + /** SRC BONE TRANSFORMS **/ + + pData = (byte*)pHdr + SrcNative( &pStudioHdr2->srcbonetransformindex ); + mstudiosrcbonetransform_t *pSrcBoneTransform = (mstudiosrcbonetransform_t*)pData; + for ( int i = 0; i < SrcNative( &pStudioHdr2->numsrcbonetransform ); ++i, ++pSrcBoneTransform ) + { + ProcessFields( pSrcBoneTransform, &mstudiosrcbonetransform_t::m_DataMap, pfnProcessFunc ); + } + } + } +} + + +#pragma warning( pop ) // local variable is initialized but not referenced + +} // namespace StudioByteSwap + +// Data descriptions for byte swapping - only needed +// for structures that are written to file for use by the game. +// For any fields that reference other data in the file, use the +// DEFINE_INDEX macro to identify them as such. +BEGIN_BYTESWAP_DATADESC( studiohdr_t ) + DEFINE_FIELD( id, FIELD_INTEGER ), + DEFINE_FIELD( version, FIELD_INTEGER ), + DEFINE_FIELD( checksum, FIELD_INTEGER ), + DEFINE_ARRAY( name, FIELD_CHARACTER, 64 ), + DEFINE_FIELD( length, FIELD_INTEGER ), + DEFINE_FIELD( eyeposition, FIELD_VECTOR ), + DEFINE_FIELD( illumposition, FIELD_VECTOR ), + DEFINE_FIELD( hull_min, FIELD_VECTOR ), + DEFINE_FIELD( hull_max, FIELD_VECTOR ), + DEFINE_FIELD( view_bbmin, FIELD_VECTOR ), + DEFINE_FIELD( view_bbmax, FIELD_VECTOR ), + DEFINE_FIELD( flags, FIELD_INTEGER ), + DEFINE_FIELD( numbones, FIELD_INTEGER ), // bones + DEFINE_INDEX( boneindex, FIELD_INTEGER ), + DEFINE_FIELD( numbonecontrollers, FIELD_INTEGER ), // bone controllers + DEFINE_INDEX( bonecontrollerindex, FIELD_INTEGER ), + DEFINE_FIELD( numhitboxsets, FIELD_INTEGER ), + DEFINE_INDEX( hitboxsetindex, FIELD_INTEGER ), + DEFINE_FIELD( numlocalanim, FIELD_INTEGER ), // animations/poses + DEFINE_INDEX( localanimindex, FIELD_INTEGER ), // animation descriptions + DEFINE_FIELD( numlocalseq, FIELD_INTEGER ), // sequences + DEFINE_INDEX( localseqindex, FIELD_INTEGER ), + DEFINE_FIELD( activitylistversion, FIELD_INTEGER ), // initialization flag - have the sequences been indexed? + DEFINE_FIELD( eventsindexed, FIELD_INTEGER ), + DEFINE_FIELD( numtextures, FIELD_INTEGER ), + DEFINE_INDEX( textureindex, FIELD_INTEGER ), + DEFINE_FIELD( numcdtextures, FIELD_INTEGER ), + DEFINE_INDEX( cdtextureindex, FIELD_INTEGER ), + DEFINE_FIELD( numskinref, FIELD_INTEGER ), + DEFINE_FIELD( numskinfamilies, FIELD_INTEGER ), + DEFINE_INDEX( skinindex, FIELD_INTEGER ), + DEFINE_FIELD( numbodyparts, FIELD_INTEGER ), + DEFINE_INDEX( bodypartindex, FIELD_INTEGER ), + DEFINE_FIELD( numlocalattachments, FIELD_INTEGER ), + DEFINE_INDEX( localattachmentindex, FIELD_INTEGER ), + DEFINE_FIELD( numlocalnodes, FIELD_INTEGER ), + DEFINE_INDEX( localnodeindex, FIELD_INTEGER ), + DEFINE_INDEX( localnodenameindex, FIELD_INTEGER ), + DEFINE_FIELD( numflexdesc, FIELD_INTEGER ), + DEFINE_INDEX( flexdescindex, FIELD_INTEGER ), + DEFINE_FIELD( numflexcontrollers, FIELD_INTEGER ), + DEFINE_INDEX( flexcontrollerindex, FIELD_INTEGER ), + DEFINE_FIELD( numflexrules, FIELD_INTEGER ), + DEFINE_INDEX( flexruleindex, FIELD_INTEGER ), + DEFINE_FIELD( numikchains, FIELD_INTEGER ), + DEFINE_INDEX( ikchainindex, FIELD_INTEGER ), + DEFINE_FIELD( nummouths, FIELD_INTEGER ), + DEFINE_INDEX( mouthindex, FIELD_INTEGER ), + DEFINE_FIELD( numlocalposeparameters, FIELD_INTEGER ), + DEFINE_INDEX( localposeparamindex, FIELD_INTEGER ), + DEFINE_INDEX( surfacepropindex, FIELD_INTEGER ), + DEFINE_INDEX( keyvalueindex, FIELD_INTEGER ), + DEFINE_FIELD( keyvaluesize, FIELD_INTEGER ), + DEFINE_FIELD( numlocalikautoplaylocks, FIELD_INTEGER ), + DEFINE_INDEX( localikautoplaylockindex, FIELD_INTEGER ), + DEFINE_FIELD( mass, FIELD_FLOAT ), + DEFINE_FIELD( contents, FIELD_INTEGER ), + DEFINE_FIELD( numincludemodels, FIELD_INTEGER ), + DEFINE_INDEX( includemodelindex, FIELD_INTEGER ), + DEFINE_FIELD( virtualModel, FIELD_INTEGER ), // void* + DEFINE_INDEX( szanimblocknameindex, FIELD_INTEGER ), + DEFINE_FIELD( numanimblocks, FIELD_INTEGER ), + DEFINE_INDEX( animblockindex, FIELD_INTEGER ), + DEFINE_FIELD( animblockModel, FIELD_INTEGER ), // void* + DEFINE_INDEX( bonetablebynameindex, FIELD_INTEGER ), + DEFINE_FIELD( pVertexBase, FIELD_INTEGER ), // void* + DEFINE_FIELD( pIndexBase, FIELD_INTEGER ), // void* + DEFINE_FIELD( constdirectionallightdot, FIELD_CHARACTER ), // byte + DEFINE_FIELD( rootLOD, FIELD_CHARACTER ), // byte + DEFINE_FIELD( numAllowedRootLODs, FIELD_CHARACTER ), // byte + DEFINE_ARRAY( unused, FIELD_CHARACTER, 1 ), // byte + DEFINE_INDEX( unused4, FIELD_INTEGER ), + DEFINE_FIELD( numflexcontrollerui, FIELD_INTEGER ), + DEFINE_INDEX( flexcontrolleruiindex, FIELD_INTEGER ), + DEFINE_ARRAY( unused3, FIELD_INTEGER, 2 ), + DEFINE_INDEX( studiohdr2index, FIELD_INTEGER ), + DEFINE_ARRAY( unused2, FIELD_INTEGER, 1 ), +END_BYTESWAP_DATADESC() + +// NOTE! Next time we up the .mdl file format, remove studiohdr2_t +// and insert all fields in this structure into studiohdr_t. +BEGIN_BYTESWAP_DATADESC( studiohdr2_t ) + DEFINE_FIELD( numsrcbonetransform, FIELD_INTEGER ), + DEFINE_INDEX( srcbonetransformindex, FIELD_INTEGER ), + DEFINE_FIELD( illumpositionattachmentindex, FIELD_INTEGER ), + DEFINE_FIELD( flMaxEyeDeflection, FIELD_FLOAT ), + DEFINE_INDEX( linearboneindex, FIELD_INTEGER ), + DEFINE_ARRAY( reserved, FIELD_INTEGER, 59 ), +END_BYTESWAP_DATADESC() + +BEGIN_BYTESWAP_DATADESC( mstudiobone_t ) + DEFINE_INDEX( sznameindex, FIELD_INTEGER ), + DEFINE_FIELD( parent, FIELD_INTEGER ), + DEFINE_ARRAY( bonecontroller, FIELD_INTEGER, 6 ), + DEFINE_FIELD( pos, FIELD_VECTOR ), + DEFINE_FIELD( quat, FIELD_QUATERNION ), + DEFINE_ARRAY( rot, FIELD_FLOAT, 3 ), // RadianEuler + DEFINE_FIELD( posscale, FIELD_VECTOR ), + DEFINE_FIELD( rotscale, FIELD_VECTOR ), + DEFINE_ARRAY( poseToBone, FIELD_FLOAT, 12 ), // matrix3x4_t + DEFINE_FIELD( qAlignment, FIELD_QUATERNION ), + DEFINE_FIELD( flags, FIELD_INTEGER ), + DEFINE_FIELD( proctype, FIELD_INTEGER ), + DEFINE_INDEX( procindex, FIELD_INTEGER ), + DEFINE_INDEX( physicsbone, FIELD_INTEGER ), + DEFINE_INDEX( surfacepropidx, FIELD_INTEGER ), + DEFINE_FIELD( contents, FIELD_INTEGER ), + DEFINE_ARRAY( unused, FIELD_INTEGER, 8 ), +END_BYTESWAP_DATADESC() + +BEGIN_BYTESWAP_DATADESC( mstudiolinearbone_t ) + DEFINE_FIELD( numbones, FIELD_INTEGER ), + DEFINE_INDEX( flagsindex, FIELD_INTEGER ), + DEFINE_INDEX( parentindex, FIELD_INTEGER ), + DEFINE_INDEX( posindex, FIELD_INTEGER ), + DEFINE_INDEX( quatindex, FIELD_INTEGER ), + DEFINE_INDEX( rotindex, FIELD_INTEGER ), + DEFINE_INDEX( posetoboneindex, FIELD_INTEGER ), + DEFINE_INDEX( posscaleindex, FIELD_INTEGER ), + DEFINE_INDEX( rotscaleindex, FIELD_INTEGER ), + DEFINE_INDEX( qalignmentindex, FIELD_INTEGER ), + DEFINE_ARRAY( unused, FIELD_INTEGER, 6 ), +END_BYTESWAP_DATADESC() + +BEGIN_BYTESWAP_DATADESC( mstudioaxisinterpbone_t ) + DEFINE_FIELD( control, FIELD_INTEGER ), + DEFINE_FIELD( axis, FIELD_INTEGER ), + DEFINE_ARRAY( pos, FIELD_VECTOR, 6 ), + DEFINE_ARRAY( quat, FIELD_QUATERNION, 6 ), +END_BYTESWAP_DATADESC() + +BEGIN_BYTESWAP_DATADESC( mstudioquatinterpbone_t ) + DEFINE_FIELD( control, FIELD_INTEGER ), + DEFINE_FIELD( numtriggers, FIELD_INTEGER ), + DEFINE_INDEX( triggerindex, FIELD_INTEGER ), +END_BYTESWAP_DATADESC() + +BEGIN_BYTESWAP_DATADESC( mstudiojigglebone_t ) + DEFINE_FIELD( flags, FIELD_INTEGER ), + DEFINE_FIELD( length, FIELD_FLOAT ), + DEFINE_FIELD( tipMass, FIELD_FLOAT ), + DEFINE_FIELD( yawStiffness, FIELD_FLOAT ), + DEFINE_FIELD( yawDamping, FIELD_FLOAT ), + DEFINE_FIELD( pitchStiffness, FIELD_FLOAT ), + DEFINE_FIELD( pitchDamping, FIELD_FLOAT ), + DEFINE_FIELD( alongStiffness, FIELD_FLOAT ), + DEFINE_FIELD( alongDamping, FIELD_FLOAT ), + DEFINE_FIELD( angleLimit, FIELD_FLOAT ), + DEFINE_FIELD( minYaw, FIELD_FLOAT ), + DEFINE_FIELD( maxYaw, FIELD_FLOAT ), + DEFINE_FIELD( yawFriction, FIELD_FLOAT ), + DEFINE_FIELD( yawBounce, FIELD_FLOAT ), + DEFINE_FIELD( minPitch, FIELD_FLOAT ), + DEFINE_FIELD( maxPitch, FIELD_FLOAT ), + DEFINE_FIELD( pitchFriction, FIELD_FLOAT ), + DEFINE_FIELD( pitchBounce, FIELD_FLOAT ), + DEFINE_FIELD( baseMass, FIELD_FLOAT ), + DEFINE_FIELD( baseStiffness, FIELD_FLOAT ), + DEFINE_FIELD( baseDamping, FIELD_FLOAT ), + DEFINE_FIELD( baseMinLeft, FIELD_FLOAT ), + DEFINE_FIELD( baseMaxLeft, FIELD_FLOAT ), + DEFINE_FIELD( baseLeftFriction, FIELD_FLOAT ), + DEFINE_FIELD( baseMinUp, FIELD_FLOAT ), + DEFINE_FIELD( baseMaxUp, FIELD_FLOAT ), + DEFINE_FIELD( baseUpFriction, FIELD_FLOAT ), + DEFINE_FIELD( baseMinForward, FIELD_FLOAT ), + DEFINE_FIELD( baseMaxForward, FIELD_FLOAT ), + DEFINE_FIELD( baseForwardFriction, FIELD_FLOAT ), +END_BYTESWAP_DATADESC() + +BEGIN_BYTESWAP_DATADESC( mstudioaimatbone_t ) + DEFINE_FIELD( parent, FIELD_INTEGER ), + DEFINE_FIELD( aim, FIELD_INTEGER ), + DEFINE_ARRAY( aimvector, FIELD_FLOAT, 3 ), + DEFINE_ARRAY( upvector, FIELD_FLOAT, 3 ), + DEFINE_ARRAY( basepos, FIELD_FLOAT, 3 ), +END_BYTESWAP_DATADESC() + +BEGIN_BYTESWAP_DATADESC( mstudioquatinterpinfo_t ) + DEFINE_FIELD( inv_tolerance, FIELD_FLOAT ), + DEFINE_FIELD( trigger, FIELD_QUATERNION ), + DEFINE_FIELD( pos, FIELD_VECTOR ), + DEFINE_FIELD( quat, FIELD_QUATERNION ), +END_BYTESWAP_DATADESC() + +BEGIN_BYTESWAP_DATADESC( mstudiobonecontroller_t ) + DEFINE_FIELD( bone, FIELD_INTEGER ), + DEFINE_FIELD( type, FIELD_INTEGER ), + DEFINE_FIELD( start, FIELD_FLOAT ), + DEFINE_FIELD( end, FIELD_FLOAT ), + DEFINE_FIELD( rest, FIELD_INTEGER ), + DEFINE_FIELD( inputfield, FIELD_INTEGER ), + DEFINE_ARRAY( unused, FIELD_INTEGER, 8 ), +END_BYTESWAP_DATADESC() + +BEGIN_BYTESWAP_DATADESC( mstudioattachment_t ) + DEFINE_INDEX( sznameindex, FIELD_INTEGER ), + DEFINE_FIELD( flags, FIELD_INTEGER ), + DEFINE_FIELD( localbone, FIELD_INTEGER ), + DEFINE_ARRAY( local, FIELD_FLOAT, 12 ), // matrix3x4_t + DEFINE_ARRAY( unused, FIELD_INTEGER, 8 ), +END_BYTESWAP_DATADESC() + +BEGIN_BYTESWAP_DATADESC( mstudiohitboxset_t ) + DEFINE_INDEX( sznameindex, FIELD_INTEGER ), + DEFINE_FIELD( numhitboxes, FIELD_INTEGER ), + DEFINE_INDEX( hitboxindex, FIELD_INTEGER ), +END_BYTESWAP_DATADESC() + +BEGIN_BYTESWAP_DATADESC( mstudiosrcbonetransform_t ) + DEFINE_INDEX( sznameindex, FIELD_INTEGER ), + DEFINE_ARRAY( pretransform, FIELD_FLOAT, 12 ), // matrix3x4_t + DEFINE_ARRAY( posttransform, FIELD_FLOAT, 12 ), // matrix3x4_t +END_BYTESWAP_DATADESC() + +BEGIN_BYTESWAP_DATADESC( mstudiobbox_t ) + DEFINE_FIELD( bone, FIELD_INTEGER ), + DEFINE_FIELD( group, FIELD_INTEGER ), + DEFINE_FIELD( bbmin, FIELD_VECTOR ), + DEFINE_FIELD( bbmax, FIELD_VECTOR ), + DEFINE_INDEX( szhitboxnameindex, FIELD_INTEGER ), + DEFINE_ARRAY( unused, FIELD_INTEGER, 8 ), +END_BYTESWAP_DATADESC() + +BEGIN_BYTESWAP_DATADESC( mstudioanim_valueptr_t ) + DEFINE_ARRAY( offset, FIELD_SHORT, 3 ), +END_BYTESWAP_DATADESC() + +BEGIN_BYTESWAP_DATADESC( mstudiolocalhierarchy_t ) + DEFINE_FIELD( iBone, FIELD_INTEGER ), + DEFINE_FIELD( iNewParent, FIELD_INTEGER ), + DEFINE_FIELD( start, FIELD_FLOAT ), + DEFINE_FIELD( peak, FIELD_FLOAT ), + DEFINE_FIELD( tail, FIELD_FLOAT ), + DEFINE_FIELD( end, FIELD_FLOAT ), + DEFINE_FIELD( iStart, FIELD_INTEGER ), + DEFINE_INDEX( localanimindex, FIELD_INTEGER ), + DEFINE_ARRAY( unused, FIELD_INTEGER, 4 ), +END_BYTESWAP_DATADESC() + +BEGIN_BYTESWAP_DATADESC( mstudioanimsections_t ) + DEFINE_FIELD( animblock, FIELD_INTEGER ), + DEFINE_INDEX( animindex, FIELD_INTEGER ), +END_BYTESWAP_DATADESC() + +BEGIN_BYTESWAP_DATADESC( mstudioanimdesc_t ) + DEFINE_INDEX( baseptr, FIELD_INTEGER ), + DEFINE_INDEX( sznameindex, FIELD_INTEGER ), + DEFINE_FIELD( fps, FIELD_FLOAT ), + DEFINE_FIELD( flags, FIELD_INTEGER ), + DEFINE_FIELD( numframes, FIELD_INTEGER ), + DEFINE_FIELD( nummovements, FIELD_INTEGER ), + DEFINE_INDEX( movementindex, FIELD_INTEGER ), + DEFINE_ARRAY( unused1, FIELD_INTEGER, 6 ), + DEFINE_FIELD( animblock, FIELD_INTEGER ), + DEFINE_INDEX( animindex, FIELD_INTEGER ), + DEFINE_FIELD( numikrules, FIELD_INTEGER ), + DEFINE_INDEX( ikruleindex, FIELD_INTEGER ), + DEFINE_INDEX( animblockikruleindex, FIELD_INTEGER ), + DEFINE_FIELD( numlocalhierarchy, FIELD_INTEGER ), + DEFINE_INDEX( localhierarchyindex, FIELD_INTEGER ), + DEFINE_INDEX( sectionindex, FIELD_INTEGER ), + DEFINE_FIELD( sectionframes, FIELD_INTEGER ), + DEFINE_FIELD( zeroframespan, FIELD_SHORT ), + DEFINE_FIELD( zeroframecount, FIELD_SHORT ), + DEFINE_INDEX( zeroframeindex, FIELD_INTEGER ), + DEFINE_FIELD( zeroframestalltime, FIELD_FLOAT ), +END_BYTESWAP_DATADESC() + +BEGIN_BYTESWAP_DATADESC( mstudioanim_t ) + DEFINE_FIELD( bone, FIELD_CHARACTER ), + DEFINE_FIELD( flags, FIELD_CHARACTER ), + DEFINE_INDEX( nextoffset, FIELD_SHORT ), +END_BYTESWAP_DATADESC() + +BEGIN_BYTESWAP_DATADESC( mstudioikerror_t ) + DEFINE_FIELD( pos, FIELD_VECTOR ), + DEFINE_FIELD( q, FIELD_QUATERNION ), +END_BYTESWAP_DATADESC() + +BEGIN_BYTESWAP_DATADESC( mstudiocompressedikerror_t ) + DEFINE_ARRAY( scale, FIELD_FLOAT, 6 ), + DEFINE_ARRAY( offset, FIELD_SHORT, 6 ), +END_BYTESWAP_DATADESC() + +BEGIN_BYTESWAP_DATADESC( mstudioikrule_t ) + DEFINE_FIELD( index, FIELD_INTEGER ), + DEFINE_FIELD( type, FIELD_INTEGER ), + DEFINE_FIELD( chain, FIELD_INTEGER ), + DEFINE_FIELD( bone, FIELD_INTEGER ), + DEFINE_FIELD( slot, FIELD_INTEGER ), + DEFINE_FIELD( height, FIELD_FLOAT ), + DEFINE_FIELD( radius, FIELD_FLOAT ), + DEFINE_FIELD( floor, FIELD_FLOAT ), + DEFINE_FIELD( pos, FIELD_VECTOR ), + DEFINE_FIELD( q, FIELD_QUATERNION ), + DEFINE_INDEX( compressedikerrorindex, FIELD_INTEGER ), + DEFINE_FIELD( unused2, FIELD_INTEGER ), + DEFINE_FIELD( iStart, FIELD_INTEGER ), + DEFINE_INDEX( ikerrorindex, FIELD_INTEGER ), + DEFINE_FIELD( start, FIELD_FLOAT ), + DEFINE_FIELD( peak, FIELD_FLOAT ), + DEFINE_FIELD( tail, FIELD_FLOAT ), + DEFINE_FIELD( end, FIELD_FLOAT ), + DEFINE_FIELD( unused3, FIELD_FLOAT ), + DEFINE_FIELD( contact, FIELD_FLOAT ), + DEFINE_FIELD( drop, FIELD_FLOAT ), + DEFINE_FIELD( top, FIELD_FLOAT ), + DEFINE_FIELD( unused6, FIELD_INTEGER ), + DEFINE_FIELD( unused7, FIELD_INTEGER ), + DEFINE_FIELD( unused8, FIELD_INTEGER ), + DEFINE_INDEX( szattachmentindex, FIELD_INTEGER ), + DEFINE_ARRAY( unused, FIELD_INTEGER, 7 ), +END_BYTESWAP_DATADESC() + +BEGIN_BYTESWAP_DATADESC( mstudiomovement_t ) + DEFINE_FIELD( endframe, FIELD_INTEGER ), + DEFINE_FIELD( motionflags, FIELD_INTEGER ), + DEFINE_FIELD( v0, FIELD_FLOAT ), + DEFINE_FIELD( v1, FIELD_FLOAT ), + DEFINE_FIELD( angle, FIELD_FLOAT ), + DEFINE_FIELD( vector, FIELD_VECTOR ), + DEFINE_FIELD( position, FIELD_VECTOR ), +END_BYTESWAP_DATADESC() + +BEGIN_BYTESWAP_DATADESC( mstudioseqdesc_t ) + DEFINE_INDEX( baseptr, FIELD_INTEGER ), + DEFINE_INDEX( szlabelindex, FIELD_INTEGER ), + DEFINE_INDEX( szactivitynameindex, FIELD_INTEGER ), + DEFINE_FIELD( flags, FIELD_INTEGER ), // looping/non-looping flags + DEFINE_FIELD( activity, FIELD_INTEGER ), // initialized at loadtime to game DLL values + DEFINE_FIELD( actweight, FIELD_INTEGER ), + DEFINE_FIELD( numevents, FIELD_INTEGER ), + DEFINE_INDEX( eventindex, FIELD_INTEGER ), + DEFINE_FIELD( bbmin, FIELD_VECTOR ), + DEFINE_FIELD( bbmax, FIELD_VECTOR ), + DEFINE_FIELD( numblends, FIELD_INTEGER ), + DEFINE_INDEX( animindexindex, FIELD_INTEGER ), + DEFINE_INDEX( movementindex, FIELD_INTEGER ), // [blend] float array for blended movement + DEFINE_ARRAY( groupsize, FIELD_INTEGER, 2 ), + DEFINE_ARRAY( paramindex, FIELD_INTEGER, 2 ), // X, Y, Z, XR, YR, ZR + DEFINE_ARRAY( paramstart, FIELD_FLOAT, 2 ), // local (0..1) starting value + DEFINE_ARRAY( paramend, FIELD_FLOAT, 2 ), // local (0..1) ending value + DEFINE_FIELD( paramparent, FIELD_INTEGER ), + DEFINE_FIELD( fadeintime, FIELD_FLOAT ), // ideal cross fate in time (0.2 default) + DEFINE_FIELD( fadeouttime, FIELD_FLOAT ), // ideal cross fade out time (0.2 default) + DEFINE_FIELD( localentrynode, FIELD_INTEGER ), // transition node at entry + DEFINE_FIELD( localexitnode, FIELD_INTEGER ), // transition node at exit + DEFINE_FIELD( nodeflags, FIELD_INTEGER ), // transition rules + DEFINE_FIELD( entryphase, FIELD_FLOAT ), // used to match entry gait + DEFINE_FIELD( exitphase, FIELD_FLOAT ), // used to match exit gait + DEFINE_FIELD( lastframe, FIELD_FLOAT ), // frame that should generation EndOfSequence + DEFINE_FIELD( nextseq, FIELD_INTEGER ), // auto advancing sequences + DEFINE_FIELD( pose, FIELD_INTEGER ), // index of delta animation between end and nextseq + DEFINE_FIELD( numikrules, FIELD_INTEGER ), + DEFINE_FIELD( numautolayers, FIELD_INTEGER ), + DEFINE_INDEX( autolayerindex, FIELD_INTEGER ), + DEFINE_INDEX( weightlistindex, FIELD_INTEGER ), + DEFINE_INDEX( posekeyindex, FIELD_INTEGER ), + DEFINE_FIELD( numiklocks, FIELD_INTEGER ), + DEFINE_INDEX( iklockindex, FIELD_INTEGER ), + DEFINE_INDEX( keyvalueindex, FIELD_INTEGER ), + DEFINE_FIELD( keyvaluesize, FIELD_INTEGER ), + DEFINE_INDEX( cycleposeindex, FIELD_INTEGER ), + DEFINE_ARRAY( unused, FIELD_INTEGER, 7 ), // remove/add as appropriate (grow back to 8 ints on version change!) +END_BYTESWAP_DATADESC() + +BEGIN_BYTESWAP_DATADESC( mstudioevent_t ) + DEFINE_FIELD( cycle, FIELD_FLOAT ), + DEFINE_FIELD( event, FIELD_INTEGER ), + DEFINE_FIELD( type, FIELD_INTEGER ), + DEFINE_ARRAY( options, FIELD_CHARACTER, 64 ), + DEFINE_INDEX( szeventindex, FIELD_INTEGER ), +END_BYTESWAP_DATADESC() + +BEGIN_BYTESWAP_DATADESC( mstudioautolayer_t ) + DEFINE_FIELD( iSequence, FIELD_SHORT ), + DEFINE_FIELD( iPose, FIELD_SHORT ), + DEFINE_FIELD( flags, FIELD_INTEGER ), + DEFINE_FIELD( start, FIELD_FLOAT ), + DEFINE_FIELD( peak, FIELD_FLOAT ), + DEFINE_FIELD( tail, FIELD_FLOAT ), + DEFINE_FIELD( end, FIELD_FLOAT ), +END_BYTESWAP_DATADESC() + +BEGIN_BYTESWAP_DATADESC( mstudioiklock_t ) + DEFINE_FIELD( chain, FIELD_INTEGER ), + DEFINE_FIELD( flPosWeight, FIELD_FLOAT ), + DEFINE_FIELD( flLocalQWeight, FIELD_FLOAT ), + DEFINE_FIELD( flags, FIELD_INTEGER ), + DEFINE_ARRAY( unused, FIELD_INTEGER, 4 ), +END_BYTESWAP_DATADESC() + +BEGIN_BYTESWAP_DATADESC( mstudiobodyparts_t ) + DEFINE_INDEX( sznameindex, FIELD_INTEGER ), + DEFINE_FIELD( nummodels, FIELD_INTEGER ), + DEFINE_FIELD( base, FIELD_INTEGER ), + DEFINE_INDEX( modelindex, FIELD_INTEGER ), +END_BYTESWAP_DATADESC() + +BEGIN_BYTESWAP_DATADESC( mstudiomodel_t ) + DEFINE_ARRAY( name, FIELD_CHARACTER, 64 ), + DEFINE_FIELD( type, FIELD_INTEGER ), + DEFINE_FIELD( boundingradius, FIELD_FLOAT ), + DEFINE_FIELD( nummeshes, FIELD_INTEGER ), + DEFINE_INDEX( meshindex, FIELD_INTEGER ), + DEFINE_FIELD( numvertices, FIELD_INTEGER ), + DEFINE_INDEX( vertexindex, FIELD_INTEGER ), + DEFINE_INDEX( tangentsindex, FIELD_INTEGER ), + DEFINE_FIELD( numattachments, FIELD_INTEGER ), + DEFINE_INDEX( attachmentindex, FIELD_INTEGER ), + DEFINE_FIELD( numeyeballs, FIELD_INTEGER ), + DEFINE_INDEX( eyeballindex, FIELD_INTEGER ), + DEFINE_EMBEDDED( vertexdata ), + DEFINE_ARRAY( unused, FIELD_INTEGER, 8 ), +END_BYTESWAP_DATADESC() + +BEGIN_BYTESWAP_DATADESC( mstudio_modelvertexdata_t ) + DEFINE_FIELD( pVertexData, FIELD_INTEGER ), // void* + DEFINE_FIELD( pTangentData, FIELD_INTEGER ), // void* +END_BYTESWAP_DATADESC() + +BEGIN_BYTESWAP_DATADESC( mstudioflexdesc_t ) + DEFINE_INDEX( szFACSindex, FIELD_INTEGER ), +END_BYTESWAP_DATADESC() + +BEGIN_BYTESWAP_DATADESC( mstudioflexcontroller_t ) + DEFINE_INDEX( sztypeindex, FIELD_INTEGER ), + DEFINE_INDEX( sznameindex, FIELD_INTEGER ), + DEFINE_FIELD( localToGlobal, FIELD_INTEGER ), + DEFINE_FIELD( min, FIELD_FLOAT ), + DEFINE_FIELD( max, FIELD_FLOAT ), +END_BYTESWAP_DATADESC() + +BEGIN_BYTESWAP_DATADESC( mstudioflexcontrollerui_t ) + DEFINE_INDEX( sznameindex, FIELD_INTEGER ), + DEFINE_INDEX( szindex0, FIELD_INTEGER ), + DEFINE_INDEX( szindex1, FIELD_INTEGER ), + DEFINE_INDEX( szindex2, FIELD_INTEGER ), + DEFINE_FIELD( remaptype, FIELD_CHARACTER ), + DEFINE_FIELD( stereo, FIELD_BOOLEAN ), + DEFINE_ARRAY( unused, FIELD_CHARACTER, 2 ), +END_BYTESWAP_DATADESC() + +BEGIN_BYTESWAP_DATADESC( mstudioflexrule_t ) + DEFINE_FIELD( flex, FIELD_INTEGER ), + DEFINE_FIELD( numops, FIELD_INTEGER ), + DEFINE_INDEX( opindex, FIELD_INTEGER ), +END_BYTESWAP_DATADESC() + +BEGIN_BYTESWAP_DATADESC( mstudioflexop_t ) + DEFINE_FIELD( op, FIELD_INTEGER ), + DEFINE_FIELD( d, FIELD_INTEGER ), // int/float union +END_BYTESWAP_DATADESC() + +BEGIN_BYTESWAP_DATADESC( mstudioikchain_t ) + DEFINE_INDEX( sznameindex, FIELD_INTEGER ), + DEFINE_FIELD( linktype, FIELD_INTEGER ), + DEFINE_FIELD( numlinks, FIELD_INTEGER ), + DEFINE_INDEX( linkindex, FIELD_INTEGER ), +END_BYTESWAP_DATADESC() + +BEGIN_BYTESWAP_DATADESC( mstudioiklink_t ) + DEFINE_FIELD( bone, FIELD_INTEGER ), + DEFINE_FIELD( kneeDir, FIELD_VECTOR ), + DEFINE_FIELD( unused0, FIELD_VECTOR ), +END_BYTESWAP_DATADESC() + +BEGIN_BYTESWAP_DATADESC( mstudiomouth_t ) + DEFINE_FIELD( bone, FIELD_INTEGER ), + DEFINE_FIELD( forward, FIELD_VECTOR ), + DEFINE_FIELD( flexdesc, FIELD_INTEGER ), +END_BYTESWAP_DATADESC() + +BEGIN_BYTESWAP_DATADESC( mstudioposeparamdesc_t ) + DEFINE_INDEX( sznameindex, FIELD_INTEGER ), + DEFINE_FIELD( flags, FIELD_INTEGER ), + DEFINE_FIELD( start, FIELD_FLOAT ), + DEFINE_FIELD( end, FIELD_FLOAT ), + DEFINE_FIELD( loop, FIELD_FLOAT ), +END_BYTESWAP_DATADESC() + +BEGIN_BYTESWAP_DATADESC( mstudiomesh_t ) + DEFINE_FIELD( material, FIELD_INTEGER ), + DEFINE_INDEX( modelindex, FIELD_INTEGER ), + DEFINE_FIELD( numvertices, FIELD_INTEGER ), + DEFINE_FIELD( vertexoffset, FIELD_INTEGER ), + DEFINE_FIELD( numflexes, FIELD_INTEGER ), + DEFINE_INDEX( flexindex, FIELD_INTEGER ), + DEFINE_FIELD( materialtype, FIELD_INTEGER ), + DEFINE_FIELD( materialparam, FIELD_INTEGER ), + DEFINE_FIELD( meshid, FIELD_INTEGER ), + DEFINE_FIELD( center, FIELD_VECTOR ), + DEFINE_EMBEDDED( vertexdata ), + DEFINE_ARRAY( unused, FIELD_INTEGER, 8 ), +END_BYTESWAP_DATADESC() + +BEGIN_BYTESWAP_DATADESC( mstudio_meshvertexdata_t ) + DEFINE_FIELD( modelvertexdata, FIELD_INTEGER ), // mstudio_modelvertexdata_t* + DEFINE_ARRAY( numLODVertexes, FIELD_INTEGER, MAX_NUM_LODS ), +END_BYTESWAP_DATADESC() + +BEGIN_BYTESWAP_DATADESC( mstudioeyeball_t ) + DEFINE_INDEX( sznameindex, FIELD_INTEGER ), + DEFINE_FIELD( bone, FIELD_INTEGER ), + DEFINE_FIELD( org, FIELD_VECTOR ), + DEFINE_FIELD( zoffset, FIELD_FLOAT ), + DEFINE_FIELD( radius, FIELD_FLOAT ), + DEFINE_FIELD( up, FIELD_VECTOR ), + DEFINE_FIELD( forward, FIELD_VECTOR ), + DEFINE_FIELD( texture, FIELD_INTEGER ), + DEFINE_FIELD( unused1, FIELD_INTEGER ), + DEFINE_FIELD( iris_scale, FIELD_FLOAT ), + DEFINE_FIELD( unused2, FIELD_INTEGER ), + DEFINE_ARRAY( upperflexdesc, FIELD_INTEGER, 3 ), + DEFINE_ARRAY( lowerflexdesc, FIELD_INTEGER, 3 ), + DEFINE_ARRAY( uppertarget, FIELD_FLOAT, 3 ), + DEFINE_ARRAY( lowertarget, FIELD_FLOAT, 3 ), + DEFINE_FIELD( upperlidflexdesc, FIELD_INTEGER ), + DEFINE_FIELD( lowerlidflexdesc, FIELD_INTEGER ), + DEFINE_ARRAY( unused, FIELD_INTEGER, 4 ), + DEFINE_FIELD( m_bNonFACS, FIELD_BOOLEAN ), + DEFINE_ARRAY( unused3, FIELD_CHARACTER, 3 ), + DEFINE_ARRAY( unused4, FIELD_INTEGER, 7 ), +END_BYTESWAP_DATADESC() + +BEGIN_BYTESWAP_DATADESC( mstudioflex_t ) + DEFINE_FIELD( flexdesc, FIELD_INTEGER ), + DEFINE_FIELD( target0, FIELD_FLOAT ), + DEFINE_FIELD( target1, FIELD_FLOAT ), + DEFINE_FIELD( target2, FIELD_FLOAT ), + DEFINE_FIELD( target3, FIELD_FLOAT ), + DEFINE_FIELD( numverts, FIELD_INTEGER ), + DEFINE_INDEX( vertindex, FIELD_INTEGER ), + DEFINE_FIELD( flexpair, FIELD_INTEGER ), + DEFINE_FIELD( vertanimtype, FIELD_CHARACTER ), + DEFINE_ARRAY( unusedchar, FIELD_CHARACTER, 3 ), + DEFINE_ARRAY( unused, FIELD_INTEGER, 6 ), +END_BYTESWAP_DATADESC() + +BEGIN_BYTESWAP_DATADESC( mstudiovertanim_t ) + DEFINE_FIELD( index, FIELD_SHORT ), + DEFINE_FIELD( speed, FIELD_CHARACTER ), + DEFINE_FIELD( side, FIELD_CHARACTER ), + DEFINE_ARRAY( delta, FIELD_SHORT, 3 ), // short[3]/float16[3]union + DEFINE_ARRAY( ndelta, FIELD_SHORT, 3 ), // short[3]/float16[3] union +END_BYTESWAP_DATADESC() + +BEGIN_BYTESWAP_DATADESC( mstudiomodelgroup_t ) + DEFINE_INDEX( szlabelindex, FIELD_INTEGER ), + DEFINE_INDEX( sznameindex, FIELD_INTEGER ), +END_BYTESWAP_DATADESC() + +BEGIN_BYTESWAP_DATADESC( mstudioanimblock_t ) + DEFINE_INDEX( datastart, FIELD_INTEGER ), + DEFINE_INDEX( dataend, FIELD_INTEGER ), +END_BYTESWAP_DATADESC() + +BEGIN_BYTESWAP_DATADESC( mstudiotexture_t ) + DEFINE_INDEX( sznameindex, FIELD_INTEGER ), + DEFINE_FIELD( flags, FIELD_INTEGER ), + DEFINE_FIELD( used, FIELD_INTEGER ), + DEFINE_FIELD( unused1, FIELD_INTEGER ), + DEFINE_FIELD( material, FIELD_INTEGER ), // IMaterial* + DEFINE_FIELD( clientmaterial, FIELD_INTEGER ), // void* + DEFINE_ARRAY( unused, FIELD_INTEGER, 10 ), +END_BYTESWAP_DATADESC() + +BEGIN_BYTESWAP_DATADESC( vertexFileHeader_t ) + DEFINE_FIELD( id, FIELD_INTEGER ), + DEFINE_FIELD( version, FIELD_INTEGER ), + DEFINE_FIELD( checksum, FIELD_INTEGER ), + DEFINE_FIELD( numLODs, FIELD_INTEGER ), + DEFINE_ARRAY( numLODVertexes, FIELD_INTEGER, MAX_NUM_LODS ), + DEFINE_FIELD( numFixups, FIELD_INTEGER ), + DEFINE_FIELD( fixupTableStart, FIELD_INTEGER ), + DEFINE_FIELD( vertexDataStart, FIELD_INTEGER ), + DEFINE_FIELD( tangentDataStart, FIELD_INTEGER ), +END_BYTESWAP_DATADESC() + +BEGIN_BYTESWAP_DATADESC( vertexFileFixup_t ) + DEFINE_FIELD( lod, FIELD_INTEGER ), + DEFINE_FIELD( sourceVertexID, FIELD_INTEGER ), + DEFINE_FIELD( numVertexes, FIELD_INTEGER ), +END_BYTESWAP_DATADESC() + +BEGIN_BYTESWAP_DATADESC( mstudioboneweight_t ) + DEFINE_ARRAY( weight, FIELD_FLOAT, MAX_NUM_BONES_PER_VERT ), + DEFINE_ARRAY( bone, FIELD_CHARACTER, MAX_NUM_BONES_PER_VERT ), + DEFINE_FIELD( numbones, FIELD_CHARACTER ), +END_BYTESWAP_DATADESC() + +BEGIN_BYTESWAP_DATADESC( mstudiovertex_t ) + DEFINE_EMBEDDED( m_BoneWeights ), + DEFINE_FIELD( m_vecPosition, FIELD_VECTOR ), + DEFINE_FIELD( m_vecNormal, FIELD_VECTOR ), + DEFINE_ARRAY( m_vecTexCoord, FIELD_FLOAT, 2 ), +END_BYTESWAP_DATADESC() + +// Data descriptions from OptimizedModel.h +namespace OptimizedModel +{ + +BEGIN_BYTESWAP_DATADESC( BoneStateChangeHeader_t ) + DEFINE_FIELD( hardwareID, FIELD_INTEGER ), + DEFINE_FIELD( newBoneID, FIELD_INTEGER ), +END_BYTESWAP_DATADESC() + +BEGIN_BYTESWAP_DATADESC( Vertex_t ) + DEFINE_ARRAY( boneWeightIndex, FIELD_CHARACTER, MAX_NUM_BONES_PER_VERT ), + DEFINE_FIELD( numBones, FIELD_CHARACTER ), + DEFINE_FIELD( origMeshVertID, FIELD_SHORT ), + DEFINE_ARRAY( boneID, FIELD_CHARACTER, MAX_NUM_BONES_PER_VERT ), +END_BYTESWAP_DATADESC() + +BEGIN_BYTESWAP_DATADESC( StripHeader_t ) + DEFINE_FIELD( numIndices, FIELD_INTEGER ), + DEFINE_FIELD( indexOffset, FIELD_INTEGER ), + DEFINE_FIELD( numVerts, FIELD_INTEGER ), + DEFINE_FIELD( vertOffset, FIELD_INTEGER ), + DEFINE_FIELD( numBones, FIELD_SHORT ), + DEFINE_FIELD( flags, FIELD_CHARACTER ), + DEFINE_FIELD( numBoneStateChanges, FIELD_INTEGER ), + DEFINE_FIELD( boneStateChangeOffset, FIELD_INTEGER ), +END_BYTESWAP_DATADESC() + +BEGIN_BYTESWAP_DATADESC( StripGroupHeader_t ) + DEFINE_FIELD( numVerts, FIELD_INTEGER ), + DEFINE_FIELD( vertOffset, FIELD_INTEGER ), + DEFINE_FIELD( numIndices, FIELD_INTEGER ), + DEFINE_FIELD( indexOffset, FIELD_INTEGER ), + DEFINE_FIELD( numStrips, FIELD_INTEGER ), + DEFINE_FIELD( stripOffset, FIELD_INTEGER ), + DEFINE_FIELD( flags, FIELD_CHARACTER ), +END_BYTESWAP_DATADESC() + +BEGIN_BYTESWAP_DATADESC( MeshHeader_t ) + DEFINE_FIELD( numStripGroups, FIELD_INTEGER ), + DEFINE_FIELD( stripGroupHeaderOffset, FIELD_INTEGER ), + DEFINE_FIELD( flags, FIELD_CHARACTER ), +END_BYTESWAP_DATADESC() + +BEGIN_BYTESWAP_DATADESC( ModelLODHeader_t ) + DEFINE_FIELD( numMeshes, FIELD_INTEGER ), + DEFINE_FIELD( meshOffset, FIELD_INTEGER ), + DEFINE_FIELD( switchPoint, FIELD_FLOAT ), +END_BYTESWAP_DATADESC() + +BEGIN_BYTESWAP_DATADESC( ModelHeader_t ) + DEFINE_FIELD( numLODs, FIELD_INTEGER ), + DEFINE_FIELD( lodOffset, FIELD_INTEGER ), +END_BYTESWAP_DATADESC() + +BEGIN_BYTESWAP_DATADESC( BodyPartHeader_t ) + DEFINE_FIELD( numModels, FIELD_INTEGER ), + DEFINE_FIELD( modelOffset, FIELD_INTEGER ), +END_BYTESWAP_DATADESC() + +BEGIN_BYTESWAP_DATADESC( MaterialReplacementHeader_t ) + DEFINE_FIELD( materialID, FIELD_SHORT ), + DEFINE_FIELD( replacementMaterialNameOffset, FIELD_INTEGER ), +END_BYTESWAP_DATADESC() + +BEGIN_BYTESWAP_DATADESC( MaterialReplacementListHeader_t ) + DEFINE_FIELD( numReplacements, FIELD_INTEGER ), + DEFINE_FIELD( replacementOffset, FIELD_INTEGER ), +END_BYTESWAP_DATADESC() + +BEGIN_BYTESWAP_DATADESC( FileHeader_t ) + DEFINE_FIELD( version, FIELD_INTEGER ), + DEFINE_FIELD( vertCacheSize, FIELD_INTEGER ), + DEFINE_FIELD( maxBonesPerStrip, FIELD_SHORT ), + DEFINE_FIELD( maxBonesPerTri, FIELD_SHORT ), + DEFINE_FIELD( maxBonesPerVert, FIELD_INTEGER ), + DEFINE_FIELD( checkSum, FIELD_INTEGER ), + DEFINE_FIELD( numLODs, FIELD_INTEGER ), + DEFINE_FIELD( materialReplacementListOffset, FIELD_INTEGER ), + DEFINE_FIELD( numBodyParts, FIELD_INTEGER ), + DEFINE_FIELD( bodyPartOffset, FIELD_INTEGER ), +END_BYTESWAP_DATADESC() + +} // namespace OptimizedModel + +// Data descriptions from phyfile.h +BEGIN_BYTESWAP_DATADESC( phyheader_t ) + DEFINE_FIELD( size, FIELD_INTEGER ), + DEFINE_FIELD( id, FIELD_INTEGER ), + DEFINE_FIELD( solidCount, FIELD_INTEGER ), + DEFINE_FIELD( checkSum, FIELD_INTEGER ), +END_BYTESWAP_DATADESC() diff --git a/src/src/common/studiobyteswap.h b/src/src/common/studiobyteswap.h new file mode 100644 index 0000000..edc6eab --- /dev/null +++ b/src/src/common/studiobyteswap.h @@ -0,0 +1,38 @@ +//========= Copyright © 1996-2006, Valve LLC, All rights reserved. ============ +// +// Purpose: StudioMDL byteswapping functions. +// +// $NoKeywords: $ +//============================================================================= +#ifndef STUDIOBYTESWAP_H +#define STUDIOBYTESWAP_H + +#if defined(_WIN32) +#pragma once +#endif + +#include "byteswap.h" +struct studiohdr_t; +class IPhysicsCollision; + +namespace StudioByteSwap +{ +typedef bool (*CompressFunc_t)( const void *pInput, int inputSize, void **pOutput, int *pOutputSize ); + +//void SetTargetBigEndian( bool bigEndian ); +void ActivateByteSwapping( bool bActivate ); +void SourceIsNative( bool bActivate ); +void SetVerbose( bool bVerbose ); +void SetCollisionInterface( IPhysicsCollision *pPhysicsCollision ); + +int ByteswapStudioFile( const char *pFilename, void *pOutBase, const void *pFileBase, int fileSize, studiohdr_t *pHdr, CompressFunc_t pCompressFunc = NULL ); +int ByteswapPHY( void *pOutBase, const void *pFileBase, int fileSize ); +int ByteswapANI( studiohdr_t* pHdr, void *pOutBase, const void *pFileBase, int filesize ); +int ByteswapVVD( void *pOutBase, const void *pFileBase, int fileSize ); +int ByteswapVTX( void *pOutBase, const void *pFileBase, int fileSize ); +int ByteswapMDL( void *pOutBase, const void *pFileBase, int fileSize ); + +#define BYTESWAP_ALIGNMENT_PADDING 4096 +} + +#endif // STUDIOBYTESWAP_H \ No newline at end of file diff --git a/src/src/common/xbox/xboxstubs.h b/src/src/common/xbox/xboxstubs.h index caf326a..7309563 100644 --- a/src/src/common/xbox/xboxstubs.h +++ b/src/src/common/xbox/xboxstubs.h @@ -1,56 +1,47 @@ //========= Copyright © 1996-2004, Valve LLC, All rights reserved. ============ // -// Purpose: Win32 replacements for Xbox code +// Purpose: Win32 replacements for XBox. // //============================================================================= -#ifndef XBOXSTUBS_H + +#if !defined( XBOXSTUBS_H ) && !defined( _X360 ) #define XBOXSTUBS_H + #ifdef _WIN32 #pragma once #endif #include "tier0/platform.h" -#define XDEVICE_TYPE_GAMEPAD 0 -#define XDEVICE_TYPE_MEMORY_UNIT 1 -#define XDEVICE_TYPE_VOICE_MICROPHONE 2 -#define XDEVICE_TYPE_VOICE_HEADPHONE 3 -#define XDEVICE_TYPE_HIGHFIDELITY_MICROPHONE 4 +// Content creation/open flags +#define XCONTENTFLAG_NONE 0x00 +#define XCONTENTFLAG_CREATENEW 0x00 +#define XCONTENTFLAG_CREATEALWAYS 0x00 +#define XCONTENTFLAG_OPENEXISTING 0x00 +#define XCONTENTFLAG_OPENALWAYS 0x00 +#define XCONTENTFLAG_TRUNCATEEXISTING 0x00 -#define XINPUT_GAMEPAD_DPAD_UP 0x0001 -#define XINPUT_GAMEPAD_DPAD_DOWN 0x0002 -#define XINPUT_GAMEPAD_DPAD_LEFT 0x0004 -#define XINPUT_GAMEPAD_DPAD_RIGHT 0x0008 -#define XINPUT_GAMEPAD_START 0x0010 -#define XINPUT_GAMEPAD_BACK 0x0020 -#define XINPUT_GAMEPAD_LEFT_THUMB 0x0040 -#define XINPUT_GAMEPAD_RIGHT_THUMB 0x0080 -#define XINPUT_LIGHTGUN_ONSCREEN 0x2000 -#define XINPUT_LIGHTGUN_FRAME_DOUBLER 0x4000 -#define XINPUT_LIGHTGUN_LINE_DOUBLER 0x8000 - -#define XINPUT_GAMEPAD_A 0 -#define XINPUT_GAMEPAD_B 1 -#define XINPUT_GAMEPAD_X 2 -#define XINPUT_GAMEPAD_Y 3 -#define XINPUT_GAMEPAD_BLACK 4 -#define XINPUT_GAMEPAD_WHITE 5 -#define XINPUT_GAMEPAD_LEFT_TRIGGER 6 -#define XINPUT_GAMEPAD_RIGHT_TRIGGER 7 +// Content attributes +#define XCONTENTFLAG_NOPROFILE_TRANSFER 0x00 +#define XCONTENTFLAG_NODEVICE_TRANSFER 0x00 +#define XCONTENTFLAG_STRONG_SIGNED 0x00 +#define XCONTENTFLAG_ALLOWPROFILE_TRANSFER 0x00 +#define XCONTENTFLAG_MOVEONLY_TRANSFER 0x00 +// Console device ports #define XDEVICE_PORT0 0 #define XDEVICE_PORT1 1 #define XDEVICE_PORT2 2 #define XDEVICE_PORT3 3 -#define XBX_MAX_DPORTS 4 +#define XUSER_MAX_COUNT 4 +#define XUSER_INDEX_NONE 0x000000FE -#define XDEVICE_NO_SLOT 0 -#define XDEVICE_TOP_SLOT 0 -#define XDEVICE_BOTTOM_SLOT 1 +#define XBX_CLR_DEFAULT 0xFF000000 +#define XBX_CLR_WARNING 0x0000FFFF +#define XBX_CLR_ERROR 0x000000FF -#define CLR_DEFAULT 0xFF000000 -#define CLR_WARNING 0x0000FFFF -#define CLR_ERROR 0x000000FF +#define XBOX_MINBORDERSAFE 0 +#define XBOX_MAXBORDERSAFE 0 typedef enum { @@ -67,8 +58,8 @@ typedef enum XK_BUTTON_B, XK_BUTTON_X, XK_BUTTON_Y, - XK_BUTTON_BLACK, - XK_BUTTON_WHITE, + XK_BUTTON_LEFT_SHOULDER, + XK_BUTTON_RIGHT_SHOULDER, XK_BUTTON_LTRIGGER, XK_BUTTON_RTRIGGER, XK_STICK1_UP, @@ -82,93 +73,164 @@ typedef enum XK_MAX_KEYS, } xKey_t; -typedef enum -{ - XVRB_NONE, // off - XVRB_ERROR, // fatal error - XVRB_ALWAYS, // no matter what - XVRB_WARNING, // non-fatal warnings - XVRB_STATUS, // status reports - XVRB_ALL, -} xverbose_e; +//typedef enum +//{ +// XVRB_NONE, // off +// XVRB_ERROR, // fatal error +// XVRB_ALWAYS, // no matter what +// XVRB_WARNING, // non-fatal warnings +// XVRB_STATUS, // status reports +// XVRB_ALL, +//} xverbose_e; typedef unsigned short WORD; #ifndef _LINUX typedef unsigned long DWORD; -#endif typedef void* HANDLE; -typedef DWORD COLORREF; +#endif -typedef struct _XINPUT_RUMBLE +#ifdef _LINUX +typedef int32 COLORREF; +#endif + +#ifndef INVALID_HANDLE_VALUE +#define INVALID_HANDLE_VALUE ((HANDLE)-1) +#endif + +// typedef struct { +// IN_ADDR ina; // IP address (zero if not static/DHCP) +// IN_ADDR inaOnline; // Online IP address (zero if not online) +// WORD wPortOnline; // Online port +// BYTE abEnet[6]; // Ethernet MAC address +// BYTE abOnline[20]; // Online identification +// } XNADDR; + +typedef int XNADDR; +typedef uint64 XUID; + +typedef struct { + BYTE ab[8]; // xbox to xbox key identifier +} XNKID; + +typedef struct { + BYTE ab[16]; // xbox to xbox key exchange key +} XNKEY; + +typedef struct _XSESSION_INFO { - WORD wLeftMotorSpeed; - WORD wRightMotorSpeed; -} XINPUT_RUMBLE, *PXINPUT_RUMBLE; + XNKID sessionID; // 8 bytes + XNADDR hostAddress; // 36 bytes + XNKEY keyExchangeKey; // 16 bytes +} XSESSION_INFO, *PXSESSION_INFO; -#define XINPUT_FEEDBACK_HEADER_INTERNAL_SIZE 58 -typedef struct _XINPUT_FEEDBACK_HEADER +typedef struct _XUSER_DATA { - DWORD dwStatus; - void* hEvent; - BYTE Reserved[XINPUT_FEEDBACK_HEADER_INTERNAL_SIZE]; -} XINPUT_FEEDBACK_HEADER, *PXINPUT_FEEDBACK_HEADER; + BYTE type; -typedef struct _XINPUT_FEEDBACK + union + { + int nData; // XUSER_DATA_TYPE_INT32 + int64 i64Data; // XUSER_DATA_TYPE_INT64 + double dblData; // XUSER_DATA_TYPE_DOUBLE + struct // XUSER_DATA_TYPE_UNICODE + { + uint cbData; // Includes null-terminator + char * pwszData; + } string; + float fData; // XUSER_DATA_TYPE_FLOAT + struct // XUSER_DATA_TYPE_BINARY + { + uint cbData; + char * pbData; + } binary; + }; +} XUSER_DATA, *PXUSER_DATA; + +typedef struct _XUSER_PROPERTY { - XINPUT_FEEDBACK_HEADER Header; - union - { - XINPUT_RUMBLE Rumble; - }; -} XINPUT_FEEDBACK, *PXINPUT_FEEDBACK; + DWORD dwPropertyId; + XUSER_DATA value; +} XUSER_PROPERTY, *PXUSER_PROPERTY; -typedef struct _XINPUT_GAMEPAD +typedef struct _XUSER_CONTEXT { - WORD wButtons; - BYTE bAnalogButtons[8]; - short sThumbLX; - short sThumbLY; - short sThumbRX; - short sThumbRY; -} XINPUT_GAMEPAD, *PXINPUT_GAMEPAD; + DWORD dwContextId; + DWORD dwValue; +} XUSER_CONTEXT, *PXUSER_CONTEXT; -typedef struct _XPP_DEVICE_TYPE +typedef struct _XSESSION_SEARCHRESULT { - unsigned long Reserved[3]; -} XPP_DEVICE_TYPE, *PXPP_DEVICE_TYPE; + XSESSION_INFO info; + DWORD dwOpenPublicSlots; + DWORD dwOpenPrivateSlots; + DWORD dwFilledPublicSlots; + DWORD dwFilledPrivateSlots; + DWORD cProperties; + DWORD cContexts; + PXUSER_PROPERTY pProperties; + PXUSER_CONTEXT pContexts; +} XSESSION_SEARCHRESULT, *PXSESSION_SEARCHRESULT; -typedef struct _XDEVICE_PREALLOC_TYPE +typedef struct _XSESSION_SEARCHRESULT_HEADER { - PXPP_DEVICE_TYPE DeviceType; - DWORD dwPreallocCount; -} XDEVICE_PREALLOC_TYPE, *PXDEVICE_PREALLOC_TYPE; + DWORD dwSearchResults; + XSESSION_SEARCHRESULT *pResults; +} XSESSION_SEARCHRESULT_HEADER, *PXSESSION_SEARCHRESULT_HEADER; -typedef struct _XINPUT_STATE +typedef struct _XSESSION_REGISTRANT { - DWORD dwPacketNumber; - XINPUT_GAMEPAD Gamepad; -} XINPUT_STATE, *PXINPUT_STATE; + uint64 qwMachineID; + DWORD bTrustworthiness; + DWORD bNumUsers; + XUID *rgUsers; -typedef struct _XINPUT_POLLING_PARAMETERS +} XSESSION_REGISTRANT; + +typedef struct _XSESSION_REGISTRATION_RESULTS { - BYTE fAutoPoll:1; - BYTE fInterruptOut:1; - BYTE ReservedMBZ1:6; - BYTE bInputInterval; - BYTE bOutputInterval; - BYTE ReservedMBZ2; -} XINPUT_POLLING_PARAMETERS, *PXINPUT_POLLING_PARAMETERS; + DWORD wNumRegistrants; + XSESSION_REGISTRANT *rgRegistrants; +} XSESSION_REGISTRATION_RESULTS, *PXSESSION_REGISTRATION_RESULTS; -void XBX_DebugString(xverbose_e verbose, COLORREF color, const char* format, ...); -void XBX_ProcessEvents(void); -void XInitDevices(DWORD dwPreallocTypeCount, PXDEVICE_PREALLOC_TYPE PreallocTypes); -DWORD XGetDevices(PXPP_DEVICE_TYPE DeviceType); -bool XGetDeviceChanges(PXPP_DEVICE_TYPE DeviceType, DWORD *pdwInsertions, DWORD *pdwRemovals); -HANDLE XInputOpen(PXPP_DEVICE_TYPE DeviceType, DWORD dwPort, DWORD dwSlot, PXINPUT_POLLING_PARAMETERS pPollingParameters); -void XInputClose(HANDLE hDevice); -DWORD XInputSetState(HANDLE hDevice, PXINPUT_FEEDBACK pFeedback); -DWORD XInputGetState(HANDLE hDevice, PXINPUT_STATE pState); -DWORD XInputPoll(HANDLE hDevice); -unsigned int XBX_GetSystemTime(void); +typedef struct { + BYTE bFlags; + BYTE bReserved; + WORD cProbesXmit; + WORD cProbesRecv; + WORD cbData; + BYTE * pbData; + WORD wRttMinInMsecs; + WORD wRttMedInMsecs; + DWORD dwUpBitsPerSec; + DWORD dwDnBitsPerSec; +} XNQOSINFO; + +typedef struct { + uint cxnqos; + uint cxnqosPending; + XNQOSINFO axnqosinfo[1]; +} XNQOS; + +#define XSESSION_CREATE_HOST 0 +#define XUSER_DATA_TYPE_INT32 0 +#define XSESSION_CREATE_USES_ARBITRATION 0 +#define XNET_QOS_LISTEN_ENABLE 0 +#define XNET_QOS_LISTEN_DISABLE 0 +#define XNET_QOS_LISTEN_SET_DATA 0 + +FORCEINLINE void XBX_ProcessEvents() {} +FORCEINLINE unsigned int XBX_GetSystemTime() { return 0; } +FORCEINLINE int XBX_GetPrimaryUserId() { return 0; } +FORCEINLINE void XBX_SetPrimaryUserId( DWORD idx ) {} +FORCEINLINE int XBX_GetStorageDeviceId() { return 0; } +FORCEINLINE void XBX_SetStorageDeviceId( DWORD idx ) {} +FORCEINLINE const char *XBX_GetLanguageString() { return ""; } +FORCEINLINE bool XBX_IsLocalized() { return false; } + +#define XCONTENT_MAX_DISPLAYNAME_LENGTH 128 +#define XCONTENT_MAX_FILENAME_LENGTH 42 + +#define XBX_INVALID_STORAGE_ID ((DWORD) -1) +#define XBX_STORAGE_DECLINED ((DWORD) -2) #endif // XBOXSTUBS_H diff --git a/src/src/devtools/bin/buildshaderlist.pl b/src/src/devtools/bin/buildshaderlist.pl new file mode 100644 index 0000000..98a4051 --- /dev/null +++ b/src/src/devtools/bin/buildshaderlist.pl @@ -0,0 +1,22 @@ +use File::DosGlob; +@ARGV = map { + my @g = File::DosGlob::glob($_) if /[*?]/; + @g ? @g : $_; + } @ARGV; + +open FILE, ">__tmpshaderlist.txt"; + +foreach $arg (@ARGV) +{ + if( $arg =~ m/\.fxc$/i || $arg =~ m/\.vsh$/i || $arg =~ m/\.psh$/i ) + { + print $arg . "\n"; + print FILE $arg . "\n"; + } +} + +close FILE; + +system "buildshaders.bat __tmpshaderlist"; + +unlink "__tmpshaderlist.txt"; \ No newline at end of file diff --git a/src/src/devtools/bin/checkshaderchecksums.pl b/src/src/devtools/bin/checkshaderchecksums.pl new file mode 100644 index 0000000..26841cb --- /dev/null +++ b/src/src/devtools/bin/checkshaderchecksums.pl @@ -0,0 +1,116 @@ +use String::CRC32; +BEGIN {use File::Basename; push @INC, dirname($0); } +require "valve_perl_helpers.pl"; + +sub GetShaderType +{ + my $shadername = shift; + my $shadertype; + if( $shadername =~ m/\.vsh/i ) + { + $shadertype = "vsh"; + } + elsif( $shadername =~ m/\.psh/i ) + { + $shadertype = "psh"; + } + elsif( $shadername =~ m/\.fxc/i ) + { + $shadertype = "fxc"; + } + else + { + die; + } + return $shadertype; +} + +sub GetShaderSrc +{ + my $shadername = shift; + if ( $shadername =~ m/^(.*)-----/i ) + { + return $1; + } + else + { + return $shadername; + } +} + +sub GetShaderType +{ + my $shadername = shift; + my $shadertype; + if( $shadername =~ m/\.vsh/i ) + { + $shadertype = "vsh"; + } + elsif( $shadername =~ m/\.psh/i ) + { + $shadertype = "psh"; + } + elsif( $shadername =~ m/\.fxc/i ) + { + $shadertype = "fxc"; + } + else + { + die; + } + return $shadertype; +} + +sub GetShaderBase +{ + my $shadername = shift; + if ( $shadername =~ m/-----(.*)$/i ) + { + return $1; + } + else + { + my $shadertype = &GetShaderType( $shadername ); + $shadername =~ s/\.$shadertype//i; + return $shadername; + } +} + +$g_x360 = 0; +$g_vcsext = ".vcs"; + +while( 1 ) +{ + $inputbase = shift; + + if( $inputbase =~ m/-x360/ ) + { + $g_x360 = 1; + $g_vcsext = ".360.vcs"; + } + else + { + last; + } +} + +# rip the txt off the end if it's there. +$inputbase =~ s/\.txt//i; + +my @srcfiles = &LoadShaderListFile( $inputbase ); + +foreach $srcfile ( @srcfiles ) +{ + my $shadertype = &GetShaderType( $srcfile ); + my $shaderbase = &GetShaderBase( $srcfile ); + my $shadersrc = &GetShaderSrc( $srcfile ); + my $vcsFileName = "..\\..\\..\\game\\hl2\\shaders\\$shadertype\\$shaderbase" . $g_vcsext; +# print "shadersrc: $shadersrc vcsFileName: $vcsFileName\n"; + + if( $g_x360 && ( $shaderbase =~ m/_ps20$/i ) ) + { + next; # skip _ps20 files for 360 + } + + &CheckCRCAgainstTarget( $shadersrc, $vcsFileName, 1 ); +} diff --git a/src/src/devtools/bin/copyshaderincfiles.pl b/src/src/devtools/bin/copyshaderincfiles.pl new file mode 100644 index 0000000..c3419e6 --- /dev/null +++ b/src/src/devtools/bin/copyshaderincfiles.pl @@ -0,0 +1,75 @@ +BEGIN {use File::Basename; push @INC, dirname($0); } +require "valve_perl_helpers.pl"; +use Cwd; +use String::CRC32; + +my $txtfilename = shift; +my $arg = shift; + +my $is360 = 0; +my $platformextension = ""; +if( $arg =~ m/-x360/i ) +{ + $is360 = 1; + $platformextension = ".360"; +} + +open TXTFILE, "<$txtfilename"; + +my $src; +my $dst; +while( $src = ) +{ + # get rid of comments + $src =~ s,//.*,,g; + + # skip blank lines + if( $src =~ m/^\s*$/ ) + { + next; + } + + # Get rid of newlines. + $src =~ s/\n//g; + + # Save off the shader source filename. + my $dst = $src; + + $dst =~ s/_tmp//gi; + + # Does the dst exist? + my $dstexists = -e $dst; + my $srcexists = -e $src; + # What are the time stamps for the src and dst? + my $srcmodtime = ( stat $src )[9]; + my $dstmodtime = ( stat $dst )[9]; + + # Open for edit or add if different than what is in perforce already. + if( !$dstexists || ( $srcmodtime != $dstmodtime ) ) + { + # Make the target writable if it exists + if( $dstexists ) + { + MakeFileWritable( $dst ); + } + + my $dir = $dst; + $dir =~ s,([^/\\]*$),,; # rip the filename off the end + my $filename = $1; + + # create the target directory if it doesn't exist + if( !$dstexists ) + { + &MakeDirHier( $dir, 0777 ); + } + + # copy the file to its targets. . . we want to see STDERR here if there is an error. + my $cmd = "copy $src $dst > nul"; +# print STDERR "$cmd\n"; + system $cmd; + + MakeFileReadOnly( $dst ); + } +} + +close TXTFILE; diff --git a/src/src/devtools/bin/copyshaders.pl b/src/src/devtools/bin/copyshaders.pl new file mode 100644 index 0000000..c850687 --- /dev/null +++ b/src/src/devtools/bin/copyshaders.pl @@ -0,0 +1,161 @@ +BEGIN {use File::Basename; push @INC, dirname($0); } +require "valve_perl_helpers.pl"; +use Cwd; +use String::CRC32; + +sub ReadInputFileWithIncludes +{ + local( $filename ) = shift; + + local( *INPUT ); + local( $output ); + + open INPUT, "<$filename" || die; + + local( $line ); + local( $linenum ) = 1; + while( $line = ) + { + if( $line =~ m/\#include\s+\"(.*)\"/i ) + { + $output.= ReadInputFileWithIncludes( $1 ); + } + else + { + $output .= $line; + } + } + + close INPUT; + return $output; +} + +sub PatchCRC +{ + my $filename = shift; + my $crc = shift; +# print STDERR "PatchCRC( $filename, $crc )\n"; + local( *FP ); + open FP, "+<$filename" || die; + binmode( FP ); + seek FP, 6 * 4, 0; + my $uInt = "I"; + if( $filename =~ m/360/ ) + { + $uInt = "N"; + } + print FP pack $uInt, $crc; + close FP; +} + +my $txtfilename = shift; +my $arg = shift; + +my $is360 = 0; +my $platformextension = ""; +if( $arg =~ m/-x360/i ) +{ + $is360 = 1; + $platformextension = ".360"; +} + +open TXTFILE, "<$txtfilename"; + +my $src; +my $dst; +while( $src = ) +{ + # get rid of comments + $src =~ s,//.*,,g; + + # skip blank lines + if( $src =~ m/^\s*$/ ) + { + next; + } + + # Get rid of newlines. + $src =~ s/\n//g; + + # Save off the shader source filename. + my $shadersrcfilename = $src; + $shadersrcfilename =~ s/-----.*$//; + # use only target basename. + $src =~ s/^.*-----//; + + # where the binary vcs file is + my $spath = ""; + + if ( $shadersrcfilename =~ m@\.fxc@i ) + { + $spath = "shaders\\fxc\\"; + } + if ( $shadersrcfilename =~ m@\.vsh@i ) + { + $spath = "shaders\\vsh\\"; + } + if ( $shadersrcfilename =~ m@\.psh@i ) + { + $spath = "shaders\\psh\\"; + } + + # make the source have path and extension + $src = $spath . $src . $platformextension . ".vcs"; + + # build the dest filename. + $dst = $src; + + $dst =~ s/shaders\\/..\\..\\..\\game\\hl2\\shaders\\/i; + + # Does the dst exist? + my $dstexists = -e $dst; + my $srcexists = -e $src; + # What are the time stamps for the src and dst? + my $srcmodtime = ( stat $src )[9]; + my $dstmodtime = ( stat $dst )[9]; + + # Write $dst to a file so that we can do perforce stuff to it later. + local( *VCSLIST ); + open VCSLIST, ">>vcslist.txt" || die; + print VCSLIST $dst . "\n"; + close VCSLIST; + + # Open for edit or add if different than what is in perforce already. + if( !$dstexists || ( $srcmodtime != $dstmodtime ) ) + { + if ( $srcexists && $shadersrcfilename =~ m@\.fxc@i ) + { + # Get the CRC for the source file. + my $srccode = ReadInputFileWithIncludes( $shadersrcfilename ); + my $crc = crc32( $srccode ); + + # Patch the source VCS file with the CRC32 of the source code used to build that file. + PatchCRC( $src, $crc ); + } + + # Make the target vcs writable if it exists + if( $dstexists ) + { + MakeFileWritable( $dst ); + } + + my $dir = $dst; + $dir =~ s,([^/\\]*$),,; # rip the filename off the end + my $filename = $1; + + # create the target directory if it doesn't exist + if( !$dstexists ) + { + &MakeDirHier( $dir, 0777 ); + } + + # copy the file to its targets. . . we want to see STDERR here if there is an error. + my $cmd = "copy $src $dst > nul"; +# print STDERR "$cmd\n"; + system $cmd; + + MakeFileReadOnly( $dst ); + } +} + +close TXTFILE; diff --git a/src/src/devtools/bin/d3dx10_33.dll b/src/src/devtools/bin/d3dx10_33.dll new file mode 100644 index 0000000..05342c8 Binary files /dev/null and b/src/src/devtools/bin/d3dx10_33.dll differ diff --git a/src/src/devtools/bin/d3dx9_33.dll b/src/src/devtools/bin/d3dx9_33.dll new file mode 100644 index 0000000..a005f8f Binary files /dev/null and b/src/src/devtools/bin/d3dx9_33.dll differ diff --git a/src/src/devtools/bin/fix_particle_operator_names.pl b/src/src/devtools/bin/fix_particle_operator_names.pl new file mode 100644 index 0000000..c0f5ee0 --- /dev/null +++ b/src/src/devtools/bin/fix_particle_operator_names.pl @@ -0,0 +1,110 @@ +#!perl +use File::Find; + +&BuildRemapTable; + +find(\&convert, "." ); + + +sub convert + { + return unless (/\.pcf$/i); + return if (/^tmp\.pcf$/i); + return if (/^tmp2\.pcf$/i); + return if (/360\.pcf$/i); + print STDERR "process ", $File::Find::name," ($_) dir=",`cd`," \n"; + my $fname=$_; + print `p4 edit $fname`; + print `dmxconvert -i $_ -o tmp.pcf -oe keyvalues2`; + open(TMP, "tmp.pcf" ) || return; + open(OUT, ">tmp2.pcf" ) || die; + while() + { + s/[\n\r]//g; + if ( (/^(\s*\"functionName\"\s*\"string\"\s*\")(.*)\"(.*)$/) && + length($map{$2}) ) + { + $_=$1.$map{$2}.'"'.$3; + } + if ( (/^(\s*\"name\"\s*\"string\"\s*\")(.*)\"(.*)$/) && + length($map{$2}) ) + { + $_=$1.$map{$2}.'"'.$3; + } + print OUT "$_\n"; + } + close OUT; + close TMP; + print `dmxconvert -i tmp2.pcf -o $fname -ie keyvalues2 -oe binary`; + unlink "tmp.pcf"; + unlink "tmp2.pcf"; +} + + + + + + + + + + + + +sub BuildRemapTable +{ + $map{"alpha_fade"}= "Alpha Fade and Decay"; + $map{"alpha_fade_in_random"}= "Alpha Fade In Random"; + $map{"alpha_fade_out_random"}= "Alpha Fade Out Random"; + $map{"basic_movement"}= "Movement Basic"; + $map{"color_fade"}= "Color Fade"; + $map{"controlpoint_light"}= "Color Light From Control Point"; + $map{"Dampen Movement Relative to Control Point"}= "Movement Dampen Relative to Control Point"; + $map{"Distance Between Control Points Scale"}= "Remap Distance Between Two Control Points to Scalar"; + $map{"Distance to Control Points Scale"}= "Remap Distance to Control Point to Scalar"; + $map{"lifespan_decay"}= "Lifespan Decay"; + $map{"lock to bone"}= "Movement Lock to Bone"; + $map{"postion_lock_to_controlpoint"}= "Movement Lock to Control Point"; + $map{"maintain position along path"}= "Movement Maintain Position Along Path"; + $map{"Match Particle Velocities"}= "Movement Match Particle Velocities"; + $map{"Max Velocity"}= "Movement Max Velocity"; + $map{"noise"}= "Noise Scalar"; + $map{"vector noise"}= "Noise Vector"; + $map{"oscillate_scalar"}= "Oscillate Scalar"; + $map{"oscillate_vector"}= "Oscillate Vector"; + $map{"Orient Rotation to 2D Direction"}= "Rotation Orient to 2D Direction"; + $map{"radius_scale"}= "Radius Scale"; + $map{"Random Cull"}= "Cull Random"; + $map{"remap_scalar"}= "Remap Scalar"; + $map{"rotation_movement"}= "Rotation Basic"; + $map{"rotation_spin"}= "Rotation Spin Roll"; + $map{"rotation_spin yaw"}= "Rotation Spin Yaw"; + $map{"alpha_random"}= "Alpha Random"; + $map{"color_random"}= "Color Random"; + $map{"create from parent particles"}= "Position From Parent Particles"; + $map{"Create In Hierarchy"}= "Position In CP Hierarchy"; + $map{"random position along path"}= "Position Along Path Random"; + $map{"random position on model"}= "Position on Model Random"; + $map{"sequential position along path"}= "Position Along Path Sequential"; + $map{"position_offset_random"}= "Position Modify Offset Random"; + $map{"position_warp_random"}= "Position Modify Warp Random"; + $map{"position_within_box"}= "Position Within Box Random"; + $map{"position_within_sphere"}= "Position Within Sphere Random"; + $map{"Inherit Velocity"}= "Velocity Inherit from Control Point"; + $map{"Initial Repulsion Velocity"}= "Velocity Repulse from World"; + $map{"Initial Velocity Noise"}= "Velocity Noise"; + $map{"Initial Scalar Noise"}= "Remap Noise to Scalar"; + $map{"Lifespan from distance to world"}= "Lifetime from Time to Impact"; + $map{"Pre-Age Noise"}= "Lifetime Pre-Age Noise"; + $map{"lifetime_random"}= "Lifetime Random"; + $map{"radius_random"}= "Radius Random"; + $map{"random yaw"}= "Rotation Yaw Random"; + $map{"Randomly Flip Yaw"}= "Rotation Yaw Flip Random"; + $map{"rotation_random"}= "Rotation Random"; + $map{"rotation_speed_random"}= "Rotation Speed Random"; + $map{"sequence_random"}= "Sequence Random"; + $map{"second_sequence_random"}= "Sequence Two Random"; + $map{"trail_length_random"}= "Trail Length Random"; + $map{"velocity_random"}= "Velocity Random"; +} + diff --git a/src/src/devtools/bin/fxc_prep.pl b/src/src/devtools/bin/fxc_prep.pl index e9f6951..9f67ca5 100644 --- a/src/src/devtools/bin/fxc_prep.pl +++ b/src/src/devtools/bin/fxc_prep.pl @@ -1,4 +1,5 @@ -$dynamic_compile = defined $ENV{"dynamic_shaders"} && $ENV{"dynamic_shaders"} != 0; +BEGIN {use File::Basename; push @INC, dirname($0); } +require "valve_perl_helpers.pl"; sub ReadInputFile { @@ -34,21 +35,19 @@ sub ReadInputFile return @output; } +$dynamic_compile = defined $ENV{"dynamic_shaders"} && $ENV{"dynamic_shaders"} != 0; $generateListingFile = 0; $spewCombos = 0; @startTimes = times; $startTime = time; -$g_dx9 = 1; +$g_produceCppClasses = 1; +$g_produceCompiledVcs = 1; while( 1 ) { $fxc_filename = shift; -# if( $fxc_filename =~ m/-dx9/i ) -# { -# $g_dx9 = 1; -# } if( $fxc_filename =~ m/-source/ ) { shift; @@ -61,14 +60,18 @@ while( 1 ) { $ps2a = 1; } - elsif( $fxc_filename =~ m/-xbox/i ) + elsif( $fxc_filename =~ m/-x360/i ) { - # enable xbox - $g_xbox = 1; + # enable x360 + $g_x360 = 1; } - elsif( $fxc_filename =~ m/-shaderoutputdir/i ) + elsif( $fxc_filename =~ m/-novcs/i ) { - $shaderoutputdir = shift; + $g_produceCompiledVcs = 0; + } + elsif( $fxc_filename =~ m/-nocpp/i ) + { + $g_produceCppClasses = 0; } else { @@ -76,6 +79,10 @@ while( 1 ) } } +$argstring = $fxc_filename; +$fxc_basename = $fxc_filename; +$fxc_basename =~ s/^.*-----//; +$fxc_filename =~ s/-----.*$//; $debug = 0; $forcehalf = 0; @@ -91,7 +98,7 @@ sub CreateCCodeToSpewDynamicCombo { local( $out ) = ""; - $out .= "\t\tOutputDebugString( \"$fxc_filename dynamic index\" );\n"; + $out .= "\t\tOutputDebugString( \"src:$fxc_filename vcs:$fxc_basename dynamic index\" );\n"; $out .= "\t\tchar tmp[128];\n"; $out .= "\t\tint shaderID = "; local( $scale ) = 1; @@ -131,7 +138,7 @@ sub CreateCCodeToSpewStaticCombo { local( $out ) = ""; - $out .= "\t\tOutputDebugString( \"$fxc_filename static index\" );\n"; + $out .= "\t\tOutputDebugString( \"src:$fxc_filename vcs:$fxc_basename static index\" );\n"; $out .= "\t\tchar tmp[128];\n"; $out .= "\t\tint shaderID = "; @@ -248,8 +255,7 @@ sub WriteDynamicBoolExpression sub WriteDynamicHelperClasses { - local( $basename ) = $fxc_filename; - $basename =~ s/\.fxc//i; + local( $basename ) = $fxc_basename; $basename =~ tr/A-Z/a-z/; local( $classname ) = $basename . "_Dynamic_Index"; push @outputHeader, "class $classname\n"; @@ -338,10 +344,10 @@ sub WriteDynamicHelperClasses sub WriteStaticHelperClasses { - local( $basename ) = $fxc_filename; - $basename =~ s/\.fxc//i; + local( $basename ) = $fxc_basename; $basename =~ tr/A-Z/a-z/; local( $classname ) = $basename . "_Static_Index"; + push @outputHeader, "#include \"shaderlib/cshader.h\"\n"; push @outputHeader, "class $classname\n"; push @outputHeader, "{\n"; for( $i = 0; $i < scalar( @staticDefineNames ); $i++ ) @@ -353,17 +359,27 @@ sub WriteStaticHelperClasses } push @outputHeader, "public:\n"; # push @outputHeader, "void SetShaderIndex( IShaderShadow *pShaderShadow ) { pShaderShadow->SetPixelShaderIndex( GetIndex() ); }\n"; - push @outputHeader, "\t$classname()\n"; + push @outputHeader, "\t$classname( )\n"; push @outputHeader, "\t{\n"; for( $i = 0; $i < scalar( @staticDefineNames ); $i++ ) { local( $name ) = @staticDefineNames[$i]; local( $boolname ) = "m_b" . $name; local( $varname ) = "m_n" . $name; - push @outputHeader, "#ifdef _DEBUG\n"; - push @outputHeader, "\t\t$boolname = false;\n"; - push @outputHeader, "#endif // _DEBUG\n"; - push @outputHeader, "\t\t$varname = 0;\n"; + if ( length( $staticDefineInit{$name} ) ) + { + push @outputHeader, "#ifdef _DEBUG\n"; + push @outputHeader, "\t\t$boolname = true;\n"; + push @outputHeader, "#endif // _DEBUG\n"; + push @outputHeader, "\t\t$varname = $staticDefineInit{$name};\n"; + } + else + { + push @outputHeader, "#ifdef _DEBUG\n"; + push @outputHeader, "\t\t$boolname = false;\n"; + push @outputHeader, "#endif // _DEBUG\n"; + push @outputHeader, "\t\t$varname = 0;\n"; + } } push @outputHeader, "\t}\n"; push @outputHeader, "\tint GetIndex()\n"; @@ -423,60 +439,11 @@ sub WriteStaticHelperClasses for( $i = 0; $i < scalar( @staticDefineNames ); $i++ ) { local( $name ) = @staticDefineNames[$i]; - push @outputHeader, $prefix . "forgot_to_set_static_" . $name . " + "; + push @outputHeader, $prefix . "forgot_to_set_static_" . $name . " + " unless (length($staticDefineInit{$name} )); } push @outputHeader, "0\n"; } -sub BuildDefineOptions -{ - local( $output ); - local( $combo ) = shift; - local( $i ); - for( $i = 0; $i < scalar( @dynamicDefineNames ); $i++ ) - { - local( $val ) = ( $combo % ( $dynamicDefineMax[$i] - $dynamicDefineMin[$i] + 1 ) ) + $dynamicDefineMin[$i]; - $output .= "/D$dynamicDefineNames[$i]=$val "; - $combo = $combo / ( $dynamicDefineMax[$i] - $dynamicDefineMin[$i] + 1 ); - } - for( $i = 0; $i < scalar( @staticDefineNames ); $i++ ) - { - local( $val ) = ( $combo % ( $staticDefineMax[$i] - $staticDefineMin[$i] + 1 ) ) + $staticDefineMin[$i]; - $output .= "/D$staticDefineNames[$i]=$val "; - $combo = $combo / ( $staticDefineMax[$i] - $staticDefineMin[$i] + 1 ); - } - return $output; -} - -sub CreateFuncToSetPerlVars -{ - local( $out ) = ""; - - $out .= "sub SetPerlVarsFunc\n"; - $out .= "{\n"; - $out .= " local( \$combo ) = shift;\n"; - $out .= " local( \$i );\n"; - local( $i ); - for( $i = 0; $i < scalar( @dynamicDefineNames ); \$i++ ) - { - $out .= " \$$dynamicDefineNames[$i] = \$combo % "; - $out .= ( $dynamicDefineMax[$i] - $dynamicDefineMin[$i] + 1 ) + $dynamicDefineMin[$i]; - $out .= ";\n"; - $out .= " \$combo = \$combo / " . ( $dynamicDefineMax[$i] - $dynamicDefineMin[$i] + 1 ) . ";\n"; - } - for( $i = 0; $i < scalar( @staticDefineNames ); \$i++ ) - { - $out .= " \$$staticDefineNames[$i] = \$combo % "; - $out .= ( $staticDefineMax[$i] - $staticDefineMin[$i] + 1 ) + $staticDefineMin[$i]; - $out .= ";\n"; - $out .= " \$combo = \$combo / " . ( $staticDefineMax[$i] - $staticDefineMin[$i] + 1 ) . ";\n"; - } - $out .= "}\n"; - -# print $out; - eval $out; -} - sub GetNewMainName { local( $shadername ) = shift; @@ -504,7 +471,8 @@ sub RenameMain sub GetShaderType { - local( $shadername ) = shift; + local( $shadername ) = shift; # hack - use global variables + $shadername = $fxc_basename; if( $shadername =~ m/ps30/i ) { if( $debug ) @@ -612,7 +580,7 @@ sub CreateCFuncToCreateCompileCommandLine { local( $out ) = ""; - $out .= "\t\tOutputDebugString( \"compiling $fxc_filename \" );\n"; + $out .= "\t\tOutputDebugString( \"compiling src:$fxc_filename vcs:$fxc_basename \" );\n"; $out .= "\t\tchar tmp[128];\n"; $out .= "\t\tsprintf( tmp, \"\%d\\n\", shaderID );\n"; $out .= "\t\tOutputDebugString( tmp );\n"; @@ -752,31 +720,13 @@ sub CreateCFuncToCreateCompileCommandLine #print "--------\n"; -if ( $g_xbox ) +if ( $g_x360 ) { - $fxctmp = "fxctmp_xbox"; -} -elsif( $g_dx9 ) -{ - if( $nvidia ) - { - if( $ps2a ) - { - $fxctmp = "fxctmp9_nv3x"; - } - else - { - $fxctmp = "fxctmp9_nv3x_ps20"; - } - } - else - { - $fxctmp = "fxctmp9"; - } + $fxctmp = "fxctmp9_360_tmp"; } else { - $fxctmp = "fxctmp8"; + $fxctmp = "fxctmp9_tmp"; } if( !stat $fxctmp ) @@ -785,23 +735,49 @@ if( !stat $fxctmp ) } # suck in an input file (using includes) -print "$fxc_filename..."; +#print "$fxc_filename..."; @fxc = ReadInputFile( $fxc_filename ); # READ THE TOP OF THE FILE TO FIND SHADER COMBOS foreach $line ( @fxc ) { + $line="" if ($g_x360 && ($line=~/\[PC\]/)); # line marked as [PC] when building for x360 + $line="" if (($g_x360 == 0) && ($line=~/\[XBOX\]/)); # line marked as [XBOX] when building for pc + + if ( $fxc_basename =~ m/_ps(\d+\w?)$/i ) + { + my $psver = $1; + $line="" if (($line =~/\[ps\d+\w?\]/i) && ($line!~/\[ps$psver\]/i)); # line marked for a version of compiler and not what we build + } + if ( $fxc_basename =~ m/_vs(\d+\w?)$/i ) + { + my $vsver = $1; + $line="" if (($line =~/\[vs\d+\w?\]/i) && ($line!~/\[vs$vsver\]/i)); # line marked for a version of compiler and not what we build + } + + my $init_expr; + + $init_expr = $1 if ( $line=~/\[\=([^\]]+)\]/); # parse default init expression for combos + + $line=~s/\[[^\[\]]*\]//; # cut out all occurrences of + # square brackets and whatever is + # inside all these modifications + # to the line are seen later when + # processing skips and centroids + next if( $line =~ m/^\s*$/ ); + if( $line =~ m/^\s*\/\/\s*STATIC\s*\:\s*\"(.*)\"\s+\"(\d+)\.\.(\d+)\"/ ) { local( $name, $min, $max ); $name = $1; $min = $2; $max = $3; -# print "\"$name\" \"$min..$max\"\n"; + # print STDERR "STATIC: \"$name\" \"$min..$max\"\n"; push @staticDefineNames, $name; push @staticDefineMin, $min; push @staticDefineMax, $max; + $staticDefineInit{$name}=$init_expr; } elsif( $line =~ m/^\s*\/\/\s*DYNAMIC\s*\:\s*\"(.*)\"\s+\"(\d+)\.\.(\d+)\"/ ) { @@ -809,7 +785,7 @@ foreach $line ( @fxc ) $name = $1; $min = $2; $max = $3; -# print "\"$name\" \"$min..$max\"\n"; + # print STDERR "DYNAMIC: \"$name\" \"$min..$max\"\n"; push @dynamicDefineNames, $name; push @dynamicDefineMin, $min; push @dynamicDefineMax, $max; @@ -818,9 +794,9 @@ foreach $line ( @fxc ) # READ THE WHOLE FILE AND FIND SKIP STATEMENTS foreach $line ( @fxc ) { - if( $line =~ m/^\s*\/\/\s*SKIP\s*\:\s*(.*)$/ ) + if( $line =~ m/^\s*\/\/\s*SKIP\s*\s*\:\s*(.*)$/ ) { -# print $1 . "\n"; + # print $1 . "\n"; $perlskipcode .= "(" . $1 . ")||"; push @perlskipcodeindividual, $1; } @@ -867,144 +843,89 @@ foreach $centroidRegNum ( keys( %centroidEnable ) ) $numCombos = &CalcNumCombos(); #print "$numCombos combos\n"; -# Write out the C++ helper class for picking shader combos -&WriteStaticHelperClasses(); -&WriteDynamicHelperClasses(); -# Create a subroutine out of $perlskipcode -$perlskipfunc = "sub SkipCombo { return $perlskipcode; }\n"; -#print $perlskipfunc; - -eval $perlskipfunc; -&CreateFuncToSetPerlVars(); - -if( !$dynamic_compile ) +if( $g_produceCompiledVcs && !$dynamic_compile ) { - open OUTFILELIST, ">>filelist.txt" || die "can't open filelist.txt"; - for( $i = 0; $i < $numCombos; $i++ ) + open FOUT, ">>filelistgen.txt" || die "can't open filelistgen.txt"; + + print FOUT "**** generated by fxc_prep.pl ****\n"; + print FOUT "#BEGIN " . $fxc_basename . "\n"; + print FOUT "$fxc_filename" . "\n"; + print FOUT "#DEFINES-D:\n"; + for( $i = 0; $i < scalar( @dynamicDefineNames ); \$i++ ) { - &SetPerlVarsFunc( $i ); - - local( $compileFailed ); - # $ret = eval $perlskipcode; - $ret = &SkipCombo; - if( !defined $ret ) - { - die "$@\n"; - } - if( $ret ) - { - # skip this combo! - # print OUTFILELIST "$i/$numCombos: SKIP\n"; - $compileFailed = 1; - $numSkipped++; - } - else - { - local( $cmd ); - if( $g_xbox ) - { - $cmd = "perl fxc_xbox.pl "; - } - else - { - $cmd = "fxc.exe "; - } - $cmd .= "/DSHADERCOMBO=$i "; - $cmd .= "/DTOTALSHADERCOMBOS=$numCombos "; - $cmd .= "/DCENTROIDMASK=$centroidMask "; - $cmd .= "/DNUMDYNAMICCOMBOS=" . &CalcNumDynamicCombos() . " "; - $cmd .= "/DFLAGS=0x0 "; # Nothing here for now. - if( $g_xbox ) - { - $cmd .= "/D_XBOX=1 "; - } - $cmd .= &BuildDefineOptions( $i ); - $cmd .= &RenameMain( $fxc_filename, $i ); - $cmd .= "/T" . &GetShaderType( $fxc_filename ) . " "; - $cmd .= "/DSHADER_MODEL_" . &ToUpper( &GetShaderType( $fxc_filename ) ) . "=1 "; - if( $nvidia ) - { - $cmd .= "/DNV3X=1 "; # enable NV3X codepath - } - if( $debug ) - { - $cmd .= "/Od "; # disable optimizations - $cmd .= "/Zi "; # enable debug info - } - # $cmd .= "/Zi "; # enable debug info - $cmd .= "/nologo "; - if( $fxc_filename =~ /ps20/i && $forcehalf ) - { - $cmd .= "/Gpp "; # use half everywhere - } - else - { - if( $g_xbox ) - { - $cmd .= "/Fcshader.asm "; - } - else - { - # $cmd .= "/Fhtmpshader.h "; - $cmd .= "/Foshader.o "; - } - } - $cmd .= "$fxc_filename"; - $cmd .= ">output.txt 2>&1"; - # print $i . "/" . $numCombos . " " . $cmd . "\n"; - print OUTFILELIST $cmd . "\n"; - } + print FOUT "$dynamicDefineNames[$i]="; + print FOUT $dynamicDefineMin[$i]; + print FOUT ".."; + print FOUT $dynamicDefineMax[$i]; + print FOUT "\n"; } - close OUTFILELIST; -} - -#print "$numSkipped/$numCombos skipped\n"; - -local( $name ) = $fxc_filename; -$name =~ s/\.fxc//gi; - -#printf "writing $fxctmp/$name" . ".inc\n"; - -# open the existing inc file so that we can see if anything changed -local( *OLDINCFILE ); -my $incfilechanged = 1; -# if( open OLDINCFILE, "<$fxctmp/$name" . ".inc" ) -# { -# # print "opened old inc file $fxctmp/$name" . ".inc\n"; - -# # The inc file already exists. . let's see if it's the same as before. -# my @oldincfile; -# @oldincfile = ; -# close OLDINCFILE; + print FOUT "#DEFINES-S:\n"; + for( $i = 0; $i < scalar( @staticDefineNames ); \$i++ ) + { + print FOUT "$staticDefineNames[$i]="; + print FOUT $staticDefineMin[$i]; + print FOUT ".."; + print FOUT $staticDefineMax[$i]; + print FOUT "\n"; + } + print FOUT "#SKIP:\n"; + print FOUT "$perlskipcode\n"; + print FOUT "#COMMAND:\n"; + # first line + print FOUT "fxc.exe "; + print FOUT "/DTOTALSHADERCOMBOS=$numCombos "; + print FOUT "/DCENTROIDMASK=$centroidMask "; + print FOUT "/DNUMDYNAMICCOMBOS=" . &CalcNumDynamicCombos() . " "; + print FOUT "/DFLAGS=0x0 "; # Nothing here for now. + print FOUT "\n"; +#defines go here +# second line + print FOUT &RenameMain( $fxc_filename, $i ); + print FOUT "/T" . &GetShaderType( $fxc_filename ) . " "; + print FOUT "/DSHADER_MODEL_" . &ToUpper( &GetShaderType( $fxc_filename ) ) . "=1 "; + if( $nvidia ) + { + print FOUT "/DNV3X=1 "; # enable NV3X codepath + } + if ( $g_x360 ) + { + print FOUT "/D_X360=1 "; # shaders can identify X360 centric code + # print FOUT "/Xbe:2- "; # use the less-broken old back end + } + if( $debug ) + { + print FOUT "/Od "; # disable optimizations + print FOUT "/Zi "; # enable debug info + } +# print FOUT "/Zi "; # enable debug info + print FOUT "/nologo "; +# print FOUT "/Fhtmpshader.h "; + print FOUT "/Foshader.o "; + print FOUT "$fxc_filename"; + print FOUT ">output.txt 2>&1"; + print FOUT "\n"; + #end of command line + print FOUT "#END\n"; + print FOUT "**** end ****\n"; -# if( join( "", @oldincfile ) eq join( "", @outputHeader ) ) -# { -# # print "They are the same!\n"; -# $incfilechanged = 0; -# } -# } + close FOUT; +} -if( $incfilechanged ) +if ( $g_produceCppClasses ) { - print "writing inc\n"; - local( *FILE ); - if( !open FILE, ">$fxctmp/$name" . ".inc" ) - { - die; - } - print FILE @outputHeader; - close FILE; - undef @outputHeader; -} -else -{ - print "no inc diffs\n"; + # Write out the C++ helper class for picking shader combos + &WriteStaticHelperClasses(); + &WriteDynamicHelperClasses(); + my $incfilename = "$fxctmp\\$fxc_basename" . ".inc"; + &WriteFile( $incfilename, join( "", @outputHeader ) ); } + + if( $generateListingFile ) { - my $listFileName = "$fxctmp/$name" . ".lst"; + my $listFileName = "$fxctmp/$fxc_basename" . ".lst"; print "writing $listFileName\n"; if( !open FILE, ">$listFileName" ) { diff --git a/src/src/devtools/bin/psh_prep.pl b/src/src/devtools/bin/psh_prep.pl index de3091c..1c44c41 100644 --- a/src/src/devtools/bin/psh_prep.pl +++ b/src/src/devtools/bin/psh_prep.pl @@ -1,53 +1,6 @@ -sub BackToForwardSlash -{ - my( $path ) = shift; - $path =~ s,\\,/,g; - return $path; -} - -sub RemoveFileName -{ - my( $in ) = shift; - $in = &BackToForwardSlash( $in ); - $in =~ s,/[^/]*$,,; - return $in; -} - -sub RemovePath -{ - my( $in ) = shift; - $in = &BackToForwardSlash( $in ); - $in =~ s,^(.*)/([^/]*)$,$2,; - return $in; -} - -sub MakeDirHier -{ - my( $in ) = shift; -# print "MakeDirHier( $in )\n"; - $in = &BackToForwardSlash( $in ); - my( @path ); - while( $in =~ m,/, ) # while $in still has a slash - { - my( $end ) = &RemovePath( $in ); - push @path, $end; -# print $in . "\n"; - $in = &RemoveFileName( $in ); - } - my( $i ); - my( $numelems ) = scalar( @path ); - my( $curpath ); - for( $i = $numelems - 1; $i >= 0; $i-- ) - { - $curpath .= "/" . $path[$i]; - my( $dir ) = $in . $curpath; - if( !stat $dir ) - { - print "mkdir $dir\n"; - mkdir $dir, 0777; - } - } -} +use String::CRC32; +BEGIN {use File::Basename; push @INC, dirname($0); } +require "valve_perl_helpers.pl"; sub BuildDefineOptions { @@ -57,41 +10,13 @@ sub BuildDefineOptions for( $i = 0; $i < scalar( @dynamicDefineNames ); $i++ ) { local( $val ) = ( $combo % ( $dynamicDefineMax[$i] - $dynamicDefineMin[$i] + 1 ) ) + $dynamicDefineMin[$i]; - if ( $g_xbox ) - { - # xsasm can only support "ifdef" compilation directive form - # so symbol encodes value and shader uses "ifdef " - # xsasm mandates space for /D argument definitions - $output .= "/D $dynamicDefineNames[$i]_$val "; - } - else - { - # symbol encodes value and shader uses "ifdef " - # psa crashes without the explicit symbol=value format - # encode both flavors for backwards compatibility - $output .= "/D$dynamicDefineNames[$i]_$val=$val "; - $output .= "/D$dynamicDefineNames[$i]=$val "; - } + $output .= "/D$dynamicDefineNames[$i]=$val "; $combo = $combo / ( $dynamicDefineMax[$i] - $dynamicDefineMin[$i] + 1 ); } for( $i = 0; $i < scalar( @staticDefineNames ); $i++ ) { local( $val ) = ( $combo % ( $staticDefineMax[$i] - $staticDefineMin[$i] + 1 ) ) + $staticDefineMin[$i]; - if ( $g_xbox ) - { - # xsasm can only support "ifdef" compilation directive form - # so symbol encodes value and shader uses "ifdef " - # xsasm mandates space for /D argument definitions - $output .= "/D $staticDefineNames[$i]_$val "; - } - else - { - # symbol encodes value and shader uses "ifdef " - # psa crashes without the explicit symbol=value format - # encode both flavors for backwards compatibility - $output .= "/D$staticDefineNames[$i]_$val=$val "; - $output .= "/D$staticDefineNames[$i]=$val "; - } + $output .= "/D$staticDefineNames[$i]=$val "; $combo = $combo / ( $staticDefineMax[$i] - $staticDefineMin[$i] + 1 ); } return $output; @@ -124,7 +49,6 @@ sub CalcNumDynamicCombos } $g_dx9 = 1; -$shaderoutputdir = "shaders"; while( 1 ) { @@ -134,14 +58,9 @@ while( 1 ) { $g_SourceDir = shift; } - elsif( $psh_filename =~ m/-xbox/ ) + elsif( $psh_filename =~ m/-x360/ ) { - $g_xbox = 1; - $g_dx9 = 0; - } - elsif( $psh_filename =~ m/-shaderoutputdir/i ) - { - $shaderoutputdir = shift; + $g_x360 = 1; } else { @@ -149,6 +68,8 @@ while( 1 ) } } +$psh_filename =~ s/-----.*$//; + # Get the shader binary version number from a header file. open FILE, "<$g_SourceDir\\public\\materialsystem\\shader_vcs_version.h" || die; @@ -188,6 +109,12 @@ while( ) $min = $2; $max = $3; # print "\"STATIC: $name\" \"$min..$max\"\n"; + if (/\[(.*)\]/) + { + $platforms=$1; + next if ( ($g_x360) && (!($platforms=~/XBOX/i)) ); + next if ( (!$g_x360) && (!($platforms=~/PC/i)) ); + } push @staticDefineNames, $name; push @staticDefineMin, $min; push @staticDefineMax, $max; @@ -199,6 +126,12 @@ while( ) $min = $2; $max = $3; # print "\"DYNAMIC: $name\" \"$min..$max\"\n"; + if (/\[(.*)\]/) + { + $platforms=$1; + next if ( ($g_x360) && (!($platforms=~/XBOX/i)) ); + next if ( (!$g_x360) && (!($platforms=~/PC/i)) ); + } push @dynamicDefineNames, $name; push @dynamicDefineMin, $min; push @dynamicDefineMax, $max; @@ -212,9 +145,9 @@ print "$psh_filename\n"; #print "$numCombos combos\n"; #print "$numDynamicCombos dynamic combos\n"; -if( $g_xbox ) +if( $g_x360 ) { - $pshtmp = "pshtmp_xbox"; + $pshtmp = "pshtmp9_360"; } elsif( $g_dx9 ) { @@ -232,13 +165,13 @@ for( $shaderCombo = 0; $shaderCombo < $numCombos; $shaderCombo++ ) my $tempFilename = "shader$shaderCombo.o"; unlink $tempFilename; - if( $g_xbox ) + if( $g_x360 ) { - $cmd = "xsasm /nologo /D _XBOX=1 " . &BuildDefineOptions( $shaderCombo ) . "$psh_filename shader$shaderCombo.o > NIL 2>&1"; + $cmd = "$g_SourceDir\\x360xdk\\bin\\win32\\psa /D_X360=1 /Foshader$shaderCombo.o /nologo " . &BuildDefineOptions( $shaderCombo ) . "$psh_filename > NIL"; } else { - $cmd = "psa /Foshader$shaderCombo.o /nologo " . &BuildDefineOptions( $shaderCombo ) . "$psh_filename"; + $cmd = "$g_SourceDir\\dx9sdk\\utilities\\psa /Foshader$shaderCombo.o /nologo " . &BuildDefineOptions( $shaderCombo ) . "$psh_filename > NIL"; } if( !stat $pshtmp ) @@ -299,8 +232,19 @@ push @outputHeader, "};\n"; push @outputHeader, "static $basename" . "PixelShader_t $basename" . "_PixelShaderInstance;\n"; -&MakeDirHier( "$shaderoutputdir/psh" ); -open COMPILEDSHADER, ">$shaderoutputdir/psh/$basename.vcs"; +&MakeDirHier( "shaders/psh" ); + +my $vcsName = ""; +if( $g_x360 ) +{ + $vcsName = $basename . ".360.vcs"; +} +else +{ + $vcsName = $basename . ".vcs"; +} + +open COMPILEDSHADER, ">shaders/psh/$vcsName" || die; binmode( COMPILEDSHADER ); # @@ -309,18 +253,35 @@ binmode( COMPILEDSHADER ); #print $numCombos . "\n"; +# Pack arguments +my $sInt = "i"; +my $uInt = "I"; +if ( $g_x360 ) +{ + # Change arguments to "big endian long" + $sInt = "N"; + $uInt = "N"; +} + +open PSH, "<$psh_filename"; +my $crc = crc32( *PSH ); +close PSH; +#print STDERR "crc for $psh_filename: $crc\n"; + # version -print COMPILEDSHADER pack "i", $shaderVersion; +print COMPILEDSHADER pack $sInt, 4; # totalCombos -print COMPILEDSHADER pack "i", $numCombos; +print COMPILEDSHADER pack $sInt, $numCombos; # dynamic combos -print COMPILEDSHADER pack "i", $numDynamicCombos; +print COMPILEDSHADER pack $sInt, $numDynamicCombos; # flags -print COMPILEDSHADER pack "I", 0x0; # nothing here for now. +print COMPILEDSHADER pack $uInt, 0x0; # nothing here for now. # centroid mask -print COMPILEDSHADER pack "I", 0; +print COMPILEDSHADER pack $uInt, 0; # reference size for diffs -print COMPILEDSHADER pack "I", 0; +print COMPILEDSHADER pack $uInt, 0; +# crc32 of the source code +print COMPILEDSHADER pack $uInt, $crc; my $beginningOfDir = tell COMPILEDSHADER; @@ -328,9 +289,9 @@ my $beginningOfDir = tell COMPILEDSHADER; for( $i = 0; $i < $numCombos; $i++ ) { # offset from beginning of file. - print COMPILEDSHADER pack "i", 0; + print COMPILEDSHADER pack $sInt, 0; # size - print COMPILEDSHADER pack "i", 0; + print COMPILEDSHADER pack $sInt, 0; } my $startByteCode = tell COMPILEDSHADER; @@ -342,20 +303,12 @@ for( $shaderCombo = 0; $shaderCombo < $numCombos; $shaderCombo++ ) { my $filename = "shader$shaderCombo\.o"; my $filesize = (stat $filename)[7]; - if( $g_xbox ) - { - # ignore binary signature - $filesize = $filesize - 4; - } + $byteCodeStart[$shaderCombo] = tell COMPILEDSHADER; $byteCodeSize[$shaderCombo] = $filesize; open SHADERBYTECODE, "<$filename"; binmode SHADERBYTECODE; - if( $g_xbox ) - { - # ignore binary signature - seek SHADERBYTECODE, 4, 0; - } + my $bin; my $numread = read SHADERBYTECODE, $bin, $filesize; # print "filename: $filename numread: $numread filesize: $filesize\n"; @@ -370,9 +323,9 @@ seek COMPILEDSHADER, $beginningOfDir, 0; for( $i = 0; $i < $numCombos; $i++ ) { # offset from beginning of file. - print COMPILEDSHADER pack "i", $byteCodeStart[$i]; + print COMPILEDSHADER pack $sInt, $byteCodeStart[$i]; # size - print COMPILEDSHADER pack "i", $byteCodeSize[$i]; + print COMPILEDSHADER pack $sInt, $byteCodeSize[$i]; } close COMPILEDSHADER; diff --git a/src/src/devtools/bin/shaderinfo.pl b/src/src/devtools/bin/shaderinfo.pl new file mode 100644 index 0000000..57a8157 --- /dev/null +++ b/src/src/devtools/bin/shaderinfo.pl @@ -0,0 +1,36 @@ +#! perl + +my $fname=shift || die "format is shaderinfo blah.vcs"; + +open(SHADER, $fname) || die "can't open $fname"; +binmode SHADER; + +read(SHADER,$header,20); +($ver,$ntotal,$ndynamic,$flags,$centroidmask)=unpack("LLLLL",$header); + +#print "Version $ver total combos=$ntotal, num dynamic combos=$ndynamic,\n flags=$flags, centroid mask=$centroidmask\n"; + +read(SHADER,$refsize,4); +$refsize=unpack("L",$refsize); +#print "Size of reference shader for diffing=$refsize\n"; + +seek(SHADER,$refsize,1); + +$nskipped_combos=0; +for(1..$ntotal) + { + read(SHADER,$combodata,8); + ($ofs,$combosize)=unpack("LL",$combodata); + if ( $ofs == 0xffffffff) + { + $nskipped_combos++; + } + else + { + } + } +#print "$nskipped_combos skipped, for an actual total of ",$ntotal-$nskipped_combos,"\n"; +#print "Real to skipped ratio = ",($ntotal-$nskipped_combos)/$ntotal,"\n"; +# csv output - name, real combos, virtual combos, dynamic combos +my $real_combos=$ntotal-$nskipped_combos; +print "$fname,$real_combos,$ntotal,$ndynamic\n"; diff --git a/src/src/devtools/bin/splitdiff3.pl b/src/src/devtools/bin/splitdiff3.pl new file mode 100644 index 0000000..ccba3a9 --- /dev/null +++ b/src/src/devtools/bin/splitdiff3.pl @@ -0,0 +1,54 @@ +$infilename = shift; +$outfilename1 = shift; +$outfilename2 = shift; +open INPUT, $infilename || die; +@input = ; +close INPUT; + +open MERGEDMINE, ">$outfilename1" || die; +open MERGEDTHEIRS, ">$outfilename2" || die; + +for( $i = 0; $i < scalar( @input ); $i++ ) +{ + $line = $input[$i]; + + if( $line =~ m/^(.*)<<<<<<>>>>>>/ ) + { + $first = $second = 0; + print MERGEDTHEIRS $1; + next; + } + + if( $first ) + { + print MERGEDMINE $line; + } + elsif( $second ) + { + print MERGEDTHEIRS $line; + } + else + { + print MERGEDMINE $line; + print MERGEDTHEIRS $line; + } +} + +close MERGEDMINE; +close MERGEDTHEIRS; diff --git a/src/src/devtools/bin/uniq.pl b/src/src/devtools/bin/uniqifylist.pl similarity index 78% rename from src/src/devtools/bin/uniq.pl rename to src/src/devtools/bin/uniqifylist.pl index 9a93bea..1c3fd9c 100644 --- a/src/src/devtools/bin/uniq.pl +++ b/src/src/devtools/bin/uniqifylist.pl @@ -1,4 +1,4 @@ -while( <> ) +foreach $_ (sort <> ) { next if( defined( $prevline ) && $_ eq $prevline ); $prevline = $_; diff --git a/src/src/devtools/bin/updateshaders.pl b/src/src/devtools/bin/updateshaders.pl index c46226d..93f57ff 100644 --- a/src/src/devtools/bin/updateshaders.pl +++ b/src/src/devtools/bin/updateshaders.pl @@ -1,10 +1,14 @@ +use String::CRC32; +BEGIN {use File::Basename; push @INC, dirname($0); } +require "valve_perl_helpers.pl"; + $dynamic_compile = defined $ENV{"dynamic_shaders"} && $ENV{"dynamic_shaders"} != 0; $depnum = 0; - -$shaderoutputdir = "shaders"; $baseSourceDir = "."; +my %dep; + sub GetAsmShaderDependencies_R { local( $shadername ) = shift; @@ -15,23 +19,12 @@ sub GetAsmShaderDependencies_R { if( m/^\s*\#\s*include\s+\"(.*)\"/ ) { -# print "$shadername depends on $1\n"; -# if( !defined( $dep{$shadername} ) ) + # make sure it isn't in there already. + if( !defined( $dep{$1} ) ) { - if ( -e "$g_SourceDir\\materialsystem\\stdshaders\\$1" ) - { - $dep{$shadername} = "$g_SourceDir\\materialsystem\\stdshaders\\$1"; - } - else - { - $dep{$shadername} = ".\\$1"; - } - GetAsmShaderDependencies_R( $dep{$shadername} ); + $dep{$1} = 1; + GetAsmShaderDependencies_R( $1 ); } -# else -# { -# print "circular dependency in $shadername!\n"; -# } } } close SHADER; @@ -42,12 +35,12 @@ sub GetAsmShaderDependencies local( $shadername ) = shift; undef %dep; GetAsmShaderDependencies_R( $shadername ); - local( $i ); - foreach $i ( keys( %dep ) ) - { -# print "$i depends on $dep{$i}\n"; - } - return values( %dep ); +# local( $i ); +# foreach $i ( keys( %dep ) ) +# { +# print "$shadername depends on $i\n"; +# } + return keys( %dep ); } sub GetShaderType @@ -73,80 +66,104 @@ sub GetShaderType return $shadertype; } +sub GetShaderSrc +{ + my $shadername = shift; + if ( $shadername =~ m/^(.*)-----/i ) + { + return $1; + } + else + { + return $shadername; + } +} + sub GetShaderBase { my $shadername = shift; - my $shadertype = &GetShaderType( $shadername ); - $shadername =~ s/\.$shadertype//i; - return $shadername; + if ( $shadername =~ m/-----(.*)$/i ) + { + return $1; + } + else + { + my $shadertype = &GetShaderType( $shadername ); + $shadername =~ s/\.$shadertype//i; + return $shadername; + } } sub DoAsmShader { - local( $shadername ) = shift; - local( $shadertype ); - $shadertype = &GetShaderType( $shadername ); - @dep = &GetAsmShaderDependencies( $shadername ); - my $shaderbase = &GetShaderBase( $shadername ); + my $argstring = shift; + my $shadername = &GetShaderSrc( $argstring ); + my $shaderbase = &GetShaderBase( $argstring ); + my $shadertype = &GetShaderType( $argstring ); my $incfile = ""; if( $shadertype eq "fxc" || $shadertype eq "vsh" ) { - if( $g_xbox ) - { - $incfile = $shadertype . "tmp_xbox\\$shaderbase.inc "; - } - else - { - $incfile = $shadertype . "tmp9\\$shaderbase.inc "; - } + $incfile = $shadertype . "tmp9" . $g_tmpfolder . "\\$shaderbase.inc "; } - if( $dynamic_compile && $shadertype eq "fxc" ) + + my $vcsfile = $shaderbase . $g_vcsext; + my $bWillCompileVcs = 1; + if( ( $shadertype eq "fxc") && $dynamic_compile ) { - print MAKEFILE $incfile . ": ..\\..\\devtools\\bin\\updateshaders.pl ..\\..\\devtools\\bin\\" . $shadertype . "_prep.pl $shadername @dep\n"; + $bWillCompileVcs = 0; + } + if( $shadercrcpass{$argstring} ) + { + $bWillCompileVcs = 0; + } + + if( $bWillCompileVcs ) + { + &output_makefile_line( $incfile . "shaders\\$shadertype\\$vcsfile: $shadername @dep\n") ; } else { - print MAKEFILE $incfile . "$shaderoutputdir\\$shadertype\\$shaderbase.vcs: ..\\..\\devtools\\bin\\updateshaders.pl ..\\..\\devtools\\bin\\" . $shadertype . "_prep.pl $shadername @dep\n"; + # psh files don't need a rule at this point since they don't have inc files and we aren't compiling a vcs. + if( $shadertype eq "fxc" || $shadertype eq "vsh" ) + { + &output_makefile_line( $incfile . ": $shadername @dep\n") ; + } } - my $xboxswitch = ""; - if( $g_xbox ) + my $x360switch = ""; + my $moreswitches = ""; + if( !$bWillCompileVcs && $shadertype eq "fxc" ) { - $xboxswitch = "-xbox "; + $moreswitches .= "-novcs "; } - print MAKEFILE "\tperl $g_SourceDir\\devtools\\bin\\" . $shadertype . "_prep.pl $xboxswitch -shaderoutputdir $shaderoutputdir -source \"$g_SourceDir\" $shadername\n"; - my $filename; - if( $shadertype eq "fxc" && !$dynamic_compile ) + if( $g_x360 ) { - print MAKEFILE "\techo $shadername>> filestocopy.txt\n"; + $x360switch = "-x360"; + + if( $bWillCompileVcs && ( $shaderbase =~ m/_ps20$/i ) ) + { + $moreswitches .= "-novcs "; + $bWillCompileVcs = 0; + } + } + + # if we are psh and we are compiling the vcs, we don't need this rule. + if( !( $shadertype eq "psh" && !$bWillCompileVcs ) ) + { + &output_makefile_line( "\tperl $g_SourceDir\\devtools\\bin\\" . $shadertype . "_prep.pl $moreswitches $x360switch -source \"$g_SourceDir\" $argstring\n") ; + } + + if( $bWillCompileVcs ) + { + &output_makefile_line( "\techo $shadername>> filestocopy.txt\n") ; my $dep; foreach $dep( @dep ) { - print MAKEFILE "\techo $dep>> filestocopy.txt\n"; + &output_makefile_line( "\techo $dep>> filestocopy.txt\n") ; } } - print MAKEFILE "\n"; -} - -sub MakeSureFileExists -{ - local( $filename ) = shift; - local( $testexists ) = shift; - local( $testwrite ) = shift; - - local( @statresult ) = stat $filename; - if( !@statresult && $testexists ) - { - die "$filename doesn't exist!\n"; - } - local( $mode, $iswritable ); - $mode = oct( $statresult[2] ); - $iswritable = ( $mode & 2 ) != 0; - if( !$iswritable && $testwrite ) - { - die "$filename isn't writable!\n"; - } + &output_makefile_line( "\n") ; } if( scalar( @ARGV ) == 0 ) @@ -154,6 +171,10 @@ if( scalar( @ARGV ) == 0 ) die "Usage updateshaders.pl shaderprojectbasename\n\tie: updateshaders.pl stdshaders_dx6\n"; } +$g_x360 = 0; +$g_tmpfolder = "_tmp"; +$g_vcsext = ".vcs"; + while( 1 ) { $inputbase = shift; @@ -162,93 +183,123 @@ while( 1 ) { $g_SourceDir = shift; } - elsif( $inputbase =~ m/-xbox/ ) + elsif( $inputbase =~ m/-x360/ ) { - $g_xbox = 1; + $g_x360 = 1; + $g_tmpfolder = "_360_tmp"; + $g_vcsext = ".360.vcs"; + } + elsif( $inputbase =~ m/-execute/ ) + { + $g_execute = 1; } elsif( $inputbase =~ m/-nv3x/ ) { $nv3x = 1; } - elsif( $inputbase =~ m/-shaderoutputdir/i ) - { - $shaderoutputdir = shift; - } else { last; } } -&MakeSureFileExists( "$inputbase.txt", 1, 0 ); - -open SHADERLISTFILE, "<$inputbase.txt" || die; -while( $line = ) -{ - $line =~ s/\/\/.*$//; - $line =~ s/^\s*//; - $line =~ s/\s*$//; - next if( $line =~ m/^\s*$/ ); - if( $line =~ m/\.fxc/ || $line =~ m/\.vsh/ || $line =~ m/\.psh/ ) - { - push @srcfiles, $line; - } -} -close SHADERLISTFILE; +my @srcfiles = &LoadShaderListFile( $inputbase ); open MAKEFILE, ">makefile\.$inputbase"; +open COPYFILE, ">makefile\.$inputbase\.copy"; +open INCLIST, ">inclist.txt"; +open VCSLIST, ">vcslist.txt"; # make a default dependency that depends on all of the shaders. -print MAKEFILE "default: "; +&output_makefile_line( "default: ") ; foreach $shader ( @srcfiles ) { my $shadertype = &GetShaderType( $shader ); my $shaderbase = &GetShaderBase( $shader ); + my $shadersrc = &GetShaderSrc( $shader ); if( $shadertype eq "fxc" || $shadertype eq "vsh" ) { # We only generate inc files for fxc and vsh files. - if( $g_xbox ) + my $incFileName = "$shadertype" . "tmp9" . $g_tmpfolder . "\\" . $shaderbase . "\.inc"; + &output_makefile_line( " $incFileName" ); + &output_inclist_line( "$incFileName\n" ); + } + + my $vcsfile = $shaderbase . $g_vcsext; + + my $compilevcs = 1; + if( $shadertype eq "fxc" && $dynamic_compile ) + { + $compilevcs = 0; + } + if( $g_x360 && ( $shaderbase =~ m/_ps20$/i ) ) + { + $compilevcs = 0; + } + if( $compilevcs ) + { + my $vcsFileName = "..\\..\\..\\game\\hl2\\shaders\\$shadertype\\$shaderbase" . $g_vcsext; + # We want to check for perforce operations even if the crc matches in the event that a file has been manually reverted and needs to be checked out again. + &output_vcslist_line( "$vcsFileName\n" ); + $shadercrcpass{$shader} = &CheckCRCAgainstTarget( $shadersrc, $vcsFileName, 0 ); + if( $shadercrcpass{$shader} ) { - print MAKEFILE " $shadertype" . "tmp_xbox\\" . $shaderbase . "\.inc"; - } - else - { - print MAKEFILE " $shadertype" . "tmp9\\" . $shaderbase . "\.inc"; + $compilevcs = 0; } } - if( !$dynamic_compile || $shadertype ne "fxc" ) + if( $compilevcs ) { - print MAKEFILE " $shaderoutputdir\\$shadertype\\$shaderbase\.vcs"; + &output_makefile_line( " shaders\\$shadertype\\$vcsfile" ); + # emit a list of vcs files to copy to the target since we want to build them. + &output_copyfile_line( GetShaderSrc($shader) . "-----" . GetShaderBase($shader) . "\n" ); } } -print MAKEFILE "\n\n"; - -# make a "clean" rule -print MAKEFILE "clean:\n"; -foreach $shader ( @srcfiles ) -{ - my $shadertype = &GetShaderType( $shader ); - my $shaderbase = &GetShaderBase( $shader ); - if( $shadertype eq "fxc" || $shadertype eq "vsh" ) - { - # We only generate inc files for fxc and vsh files. - if( $g_xbox ) - { - print MAKEFILE "\tdel /f /q $shadertype" . "tmp_xbox\\" . $shaderbase . "\.inc\n"; - } - else - { - print MAKEFILE "\tdel /f /q $shadertype" . "tmp9\\" . $shaderbase . "\.inc\n"; - } - } - print MAKEFILE "\tdel /f /q \"$shaderoutputdir\\$shadertype\\$shaderbase\.vcs\"\n"; -} -print MAKEFILE "\n"; - +&output_makefile_line( "\n\n") ; # Insert all of our vertex shaders and depencencies +$lastshader = ""; foreach $shader ( @srcfiles ) { + my $currentshader = &GetShaderSrc( $shader ); + if ( $lastshader ne $currentshader ) + { + $lastshader = $currentshader; + @dep = &GetAsmShaderDependencies( $lastshader ); + } &DoAsmShader( $shader ); } +close VCSLIST; +close INCLIST; +close COPYFILE; close MAKEFILE; + +# nuke the copyfile if it is zero length +if( ( stat "makefile\.$inputbase\.copy" )[7] == 0 ) +{ + unlink "makefile\.$inputbase\.copy"; +} + +sub output_makefile_line +{ + local ($_)=@_; + print MAKEFILE $_; +} + +sub output_copyfile_line +{ + local ($_)=@_; + print COPYFILE $_; +} + +sub output_vcslist_line +{ + local ($_)=@_; + print VCSLIST $_; +} + +sub output_inclist_line +{ + local ($_)=@_; + print INCLIST $_; +} + diff --git a/src/src/devtools/bin/valve_perl_helpers.pl b/src/src/devtools/bin/valve_perl_helpers.pl new file mode 100644 index 0000000..62799a0 --- /dev/null +++ b/src/src/devtools/bin/valve_perl_helpers.pl @@ -0,0 +1,543 @@ +sub BackToForwardSlash +{ + my( $path ) = shift; + $path =~ s,\\,/,g; + return $path; +} + +sub RemoveFileName +{ + my( $in ) = shift; + $in = &BackToForwardSlash( $in ); + $in =~ s,/[^/]*$,,; + return $in; +} + +sub RemovePath +{ + my( $in ) = shift; + $in = &BackToForwardSlash( $in ); + $in =~ s,^(.*)/([^/]*)$,$2,; + return $in; +} + +sub MakeDirHier +{ + my( $in ) = shift; +# print "MakeDirHier( $in )\n"; + $in = &BackToForwardSlash( $in ); + my( @path ); + while( $in =~ m,/, ) # while $in still has a slash + { + my( $end ) = &RemovePath( $in ); + push @path, $end; +# print $in . "\n"; + $in = &RemoveFileName( $in ); + } + my( $i ); + my( $numelems ) = scalar( @path ); + my( $curpath ); + for( $i = $numelems - 1; $i >= 0; $i-- ) + { + $curpath .= "/" . $path[$i]; + my( $dir ) = $in . $curpath; + if( !stat $dir ) + { +# print "mkdir $dir\n"; + mkdir $dir, 0777; + } + } +} + +sub FileExists +{ + my $filename = shift; + my @statresult = stat $filename; + my $iswritable = @statresult != 0; + return $iswritable; +} + +sub MakeFileWritable +{ + my $filename = shift; + if ( &FileExists( $filename ) ) + { + chmod 0666, $filename || die; + } +} + +sub MakeFileReadOnly +{ + my $filename = shift; + chmod 0444, $filename || die; +} + +# Run a command and get stdout and stderr to an array +sub RunCommand +{ + my $cmd = shift; +# print STDERR "command: $cmd\n"; + system "$cmd > cmdout.txt 2>&1" || die; + local( *FILE ); + open FILE, "; +# print STDERR "command output: @output\n"; + close FILE; + unlink "cmdout.txt" || die; + return @output; +} + +sub PerforceEditOrAdd +{ + return; + my $filename = shift; + my $changelistarg = shift; + + # Is the file on the client? + my $cmd = "p4 fstat \"$filename\""; + my @p4output = &RunCommand( $cmd ); + my $p4output = join "", @p4output; + if( $p4output =~ m/no such file/ ) + { + # not on client. . add + my $cmd = "p4 add $changelistarg $filename"; + my @p4output = &RunCommand( $cmd ); + my $p4output = join "", @p4output; + if( $p4output =~ m/opened for add/ ) + { + print $p4output; + return; + } + print "ERROR: $p4output"; + return; + } + + # The file is known to be on the client at this point. + + # Is it open for edit? + if( $p4output =~ m/action edit/ ) + { + # Is is open for edit, let's see if it's still different. + # check for opened files that are not different from the revision in the depot. + my $cmd = "p4 diff -sr \"$filename\""; + my @p4output = &RunCommand( $cmd ); + my $outputstring = join "", @p4output; + # check for empty string + if( !( $outputstring =~ m/^\s*$/ ) ) + { + my $cmd = "p4 revert \"$filename\""; + my @p4output = &RunCommand( $cmd ); + my $outputstring = join "", @p4output; + print $outputstring; + return; + } + } + + # check for unopened files that are different from the revision in the depot. + my $cmd = "p4 diff -se \"$filename\""; + my @p4output = &RunCommand( $cmd ); + my $outputstring = join "", @p4output; + # check for empty string + if( $outputstring =~ m/^\s*$/ ) + { + &MakeFileReadOnly( $filename ); + return; + } + + # We need to edit the file since it is known to be different here. + my $cmd = "p4 edit $changelistarg \"$filename\""; + my @p4output = &RunCommand( $cmd ); + + my $line; + foreach $line ( @p4output ) + { + if( $line =~ m/not on client/ ) + { + #print "notonclient..."; + print "ERROR: @p4output\n"; + return; + } + if( $line =~ m/currently opened for edit/ ) + { + return; + } + if( $line =~ m/opened for edit/ ) + { + print $line; + } + } +} + +sub FileIsWritable +{ + local( $filename ) = shift; + local( @statresult ) = stat $filename; + local( $mode, $iswritable ); + $mode = oct( $statresult[2] ); + $iswritable = ( $mode & 2 ) != 0; + return $iswritable; +} + +sub TouchFile +{ + my $filename = shift; + if( !&FileExists( $filename ) ) + { + if( !open FILE, ">$filename" ) + { + die; + } + close FILE; + } + my $now = time; + local( *FILE ); + utime $now, $now, $filename; +} + +sub FileExistsInPerforce +{ + my $filename = shift; + my @output = &RunCommand( "p4 fstat $filename" ); + my $line; + foreach $line (@output) + { + if( $line =~ m/no such file/ ) + { + return 0; + } + } + return 1; +} + +sub PerforceWriteFile +{ + my $filename = shift; + my $filecontents = shift; + + # Make the target vcs writable if it exists + MakeFileWritable( $filename ); + + # Write the file. + local( *FP ); + open FP, ">$filename"; + print FP $filecontents; + close FP; +} + +sub WriteFile +{ + my $filename = shift; + my $filecontents = shift; + + # Make the target vcs writable if it exists + MakeFileWritable( $filename ); + + # Write the file. + local( *FP ); + open FP, ">$filename"; + print FP $filecontents; + close FP; +} + +sub PrintCleanPerforceOutput +{ + my $line; + while( $line = shift ) + { + if( $line =~ m/currently opened/i ) + { + next; + } + if( $line =~ m/already opened for edit/i ) + { + next; + } + if( $line =~ m/also opened/i ) + { + next; + } + if( $line =~ m/add of existing file/i ) + { + next; + } + print $line; + } +} + +# HACK!!!! Need to pass something in to do this rather than hard coding. +sub NormalizePerforceFilename +{ + my $line = shift; + + # remove newlines. + $line =~ s/\n//; + # downcase. + $line =~ tr/[A-Z]/[a-z]/; + # backslash to forwardslash + $line =~ s,\\,/,g; + + # for inc files HACK! + $line =~ s/^.*(fxctmp9.*)/$1/i; + $line =~ s/^.*(vshtmp9.*)/$1/i; + + # for vcs files. HACK! + $line =~ s,^.*game/hl2/shaders/,,i; + + return $line; +} + +sub MakeSureFileExists +{ + local( $filename ) = shift; + local( $testexists ) = shift; + local( $testwrite ) = shift; + + local( @statresult ) = stat $filename; + if( !@statresult && $testexists ) + { + die "$filename doesn't exist!\n"; + } + local( $mode, $iswritable ); + $mode = oct( $statresult[2] ); + $iswritable = ( $mode & 2 ) != 0; + if( !$iswritable && $testwrite ) + { + die "$filename isn't writable!\n"; + } +} + +sub LoadShaderListFile_GetShaderType +{ + my $shadername = shift; + my $shadertype; + if( $shadername =~ m/\.vsh/i ) + { + $shadertype = "vsh"; + } + elsif( $shadername =~ m/\.psh/i ) + { + $shadertype = "psh"; + } + elsif( $shadername =~ m/\.fxc/i ) + { + $shadertype = "fxc"; + } + else + { + die; + } + return $shadertype; +} + +sub LoadShaderListFile_GetShaderSrc +{ + my $shadername = shift; + if ( $shadername =~ m/^(.*)-----/i ) + { + return $1; + } + else + { + return $shadername; + } +} + +sub LoadShaderListFile_GetShaderBase +{ + my $shadername = shift; + if ( $shadername =~ m/-----(.*)$/i ) + { + return $1; + } + else + { + my $shadertype = &LoadShaderListFile_GetShaderType( $shadername ); + $shadername =~ s/\.$shadertype//i; + return $shadername; + } +} + +sub LoadShaderListFile +{ + my $inputbase = shift; + + my @srcfiles; + &MakeSureFileExists( "$inputbase.txt", 1, 0 ); + + open SHADERLISTFILE, "<$inputbase.txt" || die; + my $line; + while( $line = ) + { + $line =~ s/\/\/.*$//; # remove comments "//..." + $line =~ s/^\s*//; # trim leading whitespace + $line =~ s/\s*$//; # trim trailing whitespace + next if( $line =~ m/^\s*$/ ); + if( $line =~ m/\.fxc/ || $line =~ m/\.vsh/ || $line =~ m/\.psh/ ) + { + my $shaderbase = &LoadShaderListFile_GetShaderBase( $line ); + + if( $ENV{"DIRECTX_FORCE_MODEL"} =~ m/^30$/i ) # forcing all shaders to be ver. 30 + { + my $targetbase = $shaderbase; + $targetbase =~ s/_ps2x/_ps30/i; + $targetbase =~ s/_ps20b/_ps30/i; + $targetbase =~ s/_ps20/_ps30/i; + $targetbase =~ s/_vs20/_vs30/i; + $targetbase =~ s/_vsxx/_vs30/i; + push @srcfiles, ( $line . "-----" . $targetbase ); + } + else + { + if( $shaderbase =~ m/_ps2x/i ) + { + my $targetbase = $shaderbase; + $targetbase =~ s/_ps2x/_ps20/i; + push @srcfiles, ( $line . "-----" . $targetbase ); + + $targetbase = $shaderbase; + $targetbase =~ s/_ps2x/_ps20b/i; + push @srcfiles, ( $line . "-----" . $targetbase ); + } + elsif( $shaderbase =~ m/_vsxx/i ) + { + my $targetbase = $shaderbase; + $targetbase =~ s/_vsxx/_vs11/i; + push @srcfiles, ( $line . "-----" . $targetbase ); + + $targetbase = $shaderbase; + $targetbase =~ s/_vsxx/_vs20/i; + push @srcfiles, ( $line . "-----" . $targetbase ); + } + else + { + push @srcfiles, ( $line . "-----" . $shaderbase ); + } + } + } + } + close SHADERLISTFILE; + return @srcfiles; +} + +sub ReadInputFileWithIncludes +{ + local( $filename ) = shift; +# print STDERR "ReadInputFileWithIncludes: $filename\n"; + + local( *INPUT ); + local( $output ); + +# print STDERR "before open\n"; + open INPUT, "<$filename" || die; +# print STDERR "after open\n"; + + local( $line ); + while( $line = ) + { +# print STDERR $line; + if( $line =~ m/\#include\s+\"(.*)\"/i ) + { + $output.= ReadInputFileWithIncludes( $1 ); + } + else + { + $output .= $line; + } + } + + close INPUT; + return $output; +} + +sub GetCRCFromSourceFile +{ + my $filename = shift; + my $data = &ReadInputFileWithIncludes( $filename ); +# print STDERR $data; + $crc = crc32( $data ); +# print STDERR "GetCRCFromSourceFile: $crc\n"; + return $crc; +} + +sub GetCRCFromVCSFile +{ + my $filename = shift; +# print STDERR "GetCRCFromVCSFile $filename\n"; + local( *FP ); + open FP, "<$filename" || die "GetCRCFromVCSFile: can't open file $filename\n"; + binmode( FP ); + + # unpack arguments + my $sInt = "i"; + my $uInt = "I"; + if( $filename =~ m/\.360\./ ) + { + # Change arguments to "big endian long" + $sInt = "N"; + $uInt = "N"; + } + + my $header; + read FP, $header, 7 * 4 || die "updateshaders.pl:GetCRCFromVCSFile: can't read header for $filename\n"; + my $version,$numCombos,$numDynamicCombos,$flags,$centroidMask,$refSize,$crc; + ($version,$numCombos,$numDynamicCombos,$flags,$centroidMask,$refSize,$crc) = unpack "$sInt$sInt$sInt$uInt$uInt$uInt$uInt", $header; + unless( $version == 4 || $version == 5 || $version == 6 ) + { + print STDERR "ERROR: GetCRCFromVCSFile: $filename is version $version\n"; + return 0; + } +# print STDERR "version: $version\n"; +# print STDERR "numCombos: $numCombos\n"; +# print STDERR "numDynamicCombos: $numDynamicCombos\n"; +# print STDERR "flags: $flags\n"; +# print STDERR "centroidMask: $centroidMask\n"; +# print STDERR "refSize: $refSize\n"; +# print STDERR "GetCRCFromVCSFile: $crc\n"; + close( FP ); + return $crc; +} + +sub CheckCRCAgainstTarget +{ + my $srcFileName = shift; + my $vcsFileName = shift; + my $warn = shift; + + # Make sure both files exist. +# print STDERR "$srcFileName doesn't exist\n" if( !( -e $srcFileName ) ); +# print STDERR "$vcsFileName doesn't exist\n" if( !( -e $vcsFileName ) ); + if( !( -e $srcFileName ) ) + { + if( $warn ) + { + print "$srcFileName missing\n"; + } + return 0; + } + if( !( -e $vcsFileName ) ) + { + if( $warn ) + { + print "$vcsFileName missing\n"; + } + return 0; + } +# print STDERR "CheckCRCAgainstTarget( $srcFileName, $vcsFileName );\n"; +# print STDERR "vcsFileName: $vcsFileName\n"; +# print STDERR "vcsFileName: $srcFileName\n"; + my $vcsCRC = &GetCRCFromVCSFile( $vcsFileName ); + my $srcCRC = &GetCRCFromSourceFile( $srcFileName ); + if( $warn && ( $vcsCRC != $srcCRC ) ) + { + print "$vcsFileName checksum ($vcsCRC) != $srcFileName checksum: ($srcCRC)\n"; + } + +# return 0; # use this to skip crc checking. +# if( $vcsCRC == $srcCRC ) +# { +# print STDERR "CRC passed for $srcFileName $vcsFileName $vcsCRC\n"; +# } + return $vcsCRC == $srcCRC; +} + +1; diff --git a/src/src/devtools/bin/vsh_prep.pl b/src/src/devtools/bin/vsh_prep.pl index 932852b..8161c49 100644 --- a/src/src/devtools/bin/vsh_prep.pl +++ b/src/src/devtools/bin/vsh_prep.pl @@ -1,3 +1,6 @@ +use String::CRC32; +BEGIN {use File::Basename; push @INC, dirname($0); } +require "valve_perl_helpers.pl"; sub WriteHelperVar { @@ -265,57 +268,6 @@ sub CreateFuncToSetPerlVars eval $out; } -sub BackToForwardSlash -{ - my( $path ) = shift; - $path =~ s,\\,/,g; - return $path; -} - -sub RemoveFileName -{ - my( $in ) = shift; - $in = &BackToForwardSlash( $in ); - $in =~ s,/[^/]*$,,; - return $in; -} - -sub RemovePath -{ - my( $in ) = shift; - $in = &BackToForwardSlash( $in ); - $in =~ s,^(.*)/([^/]*)$,$2,; - return $in; -} - -sub MakeDirHier -{ - my( $in ) = shift; -# print "MakeDirHier( $in )\n"; - $in = &BackToForwardSlash( $in ); - my( @path ); - while( $in =~ m,/, ) # while $in still has a slash - { - my( $end ) = &RemovePath( $in ); - push @path, $end; -# print $in . "\n"; - $in = &RemoveFileName( $in ); - } - my( $i ); - my( $numelems ) = scalar( @path ); - my( $curpath ); - for( $i = $numelems - 1; $i >= 0; $i-- ) - { - $curpath .= "/" . $path[$i]; - my( $dir ) = $in . $curpath; - if( !stat $dir ) - { -# print "mkdir $dir\n"; - mkdir $dir, 0777; - } - } -} - # These sections can be interchanged to enable profiling. #$ShowTimers = 1; #use Time::HiRes; @@ -331,13 +283,13 @@ $total_start_time = SampleTime(); # NOTE: These must match the same values in macros.vsh! $vPos = "v0"; -$vBoneWeights = "v1"; -$vBoneIndices = "v2"; +$vBoneWeights = "v1"; +$vBoneIndices = "v2"; $vNormal = "v3"; -if( $g_xbox ) +if( $g_x360 ) { $vPosFlex = "v4"; - $vNormalFlex = "v13"; + $vNormalFlex = "v13"; } $vColor = "v5"; $vSpecular = "v6"; @@ -349,7 +301,50 @@ $vTangentS = "v11"; $vTangentT = "v12"; $vUserData = "v14"; -sub ReadInputFile +sub ReadInputFileWithLineInfo +{ + local( $base_filename ) = shift; + + local( *INPUT ); + local( @output ); + + # Look in the stdshaders directory, followed by the current directory. + # (This is for the SDK, since some of its files are under stdshaders). + local( $filename ) = $base_filename; + if ( !-e $filename ) + { + $filename = "$g_SourceDir\\materialsystem\\stdshaders\\$base_filename"; + if ( !-e $filename ) + { + die "\nvsh_prep.pl ERROR: missing include file: $filename.\n\n"; + } + } + + open INPUT, "<$filename" || die; + + local( $line ); + local( $linenum ) = 1; + while( $line = ) + { + $line =~ s/\n//g; + local( $postfix ) = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"; + $postfix .= "; LINEINFO($filename)($linenum)\n"; + if( $line =~ m/\#include\s+\"(.*)\"/i ) + { + push @output, &ReadInputFileWithLineInfo( $1 ); + } + else + { + push @output, $line . $postfix; + } + $linenum++; + } + + close INPUT; + return @output; +} + +sub ReadInputFileWithoutLineInfo { local( $base_filename ) = shift; @@ -371,21 +366,16 @@ sub ReadInputFile open INPUT, "<$filename" || die; local( $line ); - local( $linenum ) = 1; while( $line = ) { - $line =~ s/\n//g; - local( $postfix ) = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"; - $postfix .= "; LINEINFO($filename)($linenum)\n"; if( $line =~ m/\#include\s+\"(.*)\"/i ) { - push @output, &ReadInputFile( $1 ); + push @output, &ReadInputFileWithoutLineInfo( $1 ); } else { - push @output, $line . $postfix; + push @output, $line; } - $linenum++; } close INPUT; @@ -550,10 +540,7 @@ sub TranslateDXKeywords $line =~ s/\bENDIF\b/endif/g; $line =~ s/\bIF\b/if/g; $line =~ s/\bELSE\b/else/g; - if ( $g_xbox ) - { - $line =~ s/^\s*vs\.1\.[0-9]/xvs.1.1/i; - } + return $line; } @@ -571,7 +558,6 @@ sub GetLeadingWhiteSpace } $g_dx9 = 1; -$shaderoutputdir = "shaders"; $g_SourceDir = "..\\.."; while( 1 ) @@ -582,14 +568,9 @@ while( 1 ) { $g_SourceDir = shift; } - elsif( $filename =~ m/-xbox/i ) + elsif( $filename =~ m/-x360/i ) { - $g_xbox = 1; - $g_dx9 = 0; - } - elsif( $filename =~ m/-shaderoutputdir/i ) - { - $shaderoutputdir = shift; + $g_x360 = 1; } else { @@ -597,6 +578,8 @@ while( 1 ) } } +$filename =~ s/-----.*$//; + # # Get the shader binary version number from a header file. @@ -617,13 +600,13 @@ if( !defined $shaderVersion ) close FILE; -if( $g_xbox ) +if( $g_x360 ) { - $vshtmp = "vshtmp_xbox"; + $vshtmp = "vshtmp9_360_tmp"; } else { - $vshtmp = "vshtmp9"; + $vshtmp = "vshtmp9_tmp"; } if( !stat $vshtmp ) @@ -632,7 +615,7 @@ if( !stat $vshtmp ) } # suck in all files, including $include files. -@input = &ReadInputFile( $filename ); +@input = &ReadInputFileWithLineInfo( $filename ); sub CalcNumCombos { @@ -676,8 +659,8 @@ foreach $_ ( @input ) if (/\[(.*)\]/) { $platforms=$1; - next if ( ($g_xbox) && (!($platforms=~/XBOX/i)) ); - next if ( (!$g_xbox) && (!($platforms=~/PC/i)) ); + next if ( ($g_x360) && (!($platforms=~/XBOX/i)) ); + next if ( (!$g_x360) && (!($platforms=~/PC/i)) ); } push @staticDefineNames, $name; push @staticDefineMin, $min; @@ -692,8 +675,8 @@ foreach $_ ( @input ) if (/\[(.*)\]/) { $platforms=$1; - next if ( ($g_xbox) && (!($platforms=~/XBOX/i)) ); - next if ( (!$g_xbox) && (!($platforms=~/PC/i)) ); + next if ( ($g_x360) && (!($platforms=~/XBOX/i)) ); + next if ( (!$g_x360) && (!($platforms=~/PC/i)) ); } # print "\"$name\" \"$min..$max\"\n"; push @dynamicDefineNames, $name; @@ -723,11 +706,6 @@ else #print $perlskipcode . "\n"; -if ( $g_xbox ) -{ - # add mandatory epilogue code - push @outputProgram, "push \@output, \"" . "#pragma screenspace" . "\\n\";\n"; -} # Translate the input into a perl program that'll unroll everything and # substitute variables. @@ -756,13 +734,6 @@ while( $inputLine = shift @input ) } } -if ( $g_xbox ) -{ - # add mandatory prologue code - push @outputProgram, "push \@output, \"" . "mul oPos.xyz, r12, \$SHADER_VIEWPORT_CONST_SCALE +rcc r1.x, r12.w" . "\\n\";\n"; - push @outputProgram, "push \@output, \"" . "mad oPos.xyz, r12, r1.x, \$SHADER_VIEWPORT_CONST_OFFSET" . "\\n\";\n"; -} - $outputProgram = join "", @outputProgram; $filename_base = $filename; @@ -806,15 +777,10 @@ $perlskipfunc = "sub SkipCombo { return $perlskipcode; }\n"; eval $perlskipfunc; &CreateFuncToSetPerlVars(); +my $incfilename = "$vshtmp/$filename_base" . ".inc"; + # Write the inc file that has indexing helpers, etc. -local( *FILE ); -if( !open FILE, ">$vshtmp/$filename_base" . ".inc" ) -{ - die "\n\nUnable to open $vshtmp/$filename_base for writing\n\n"; -} -print FILE @outputHeader; -close FILE; -undef @outputHeader; +&WriteFile( $incfilename, join( "", @outputHeader ) ); # Run the output program for all the combinations of bones and lights. @@ -880,7 +846,7 @@ for( $i = 0; $i < $numCombos; $i++ ) # Have to make another pass through after we know which v registers are used. . yuck. $g_usesPos = &UsesRegister( $vPos, $strippedStr ); - if( $g_xbox ) + if( $g_x360 ) { $g_usesPosFlex = &UsesRegister( $vPosFlex, $strippedStr ); $g_usesNormalFlex = &UsesRegister( $vNormalFlex, $strippedStr ); @@ -949,18 +915,16 @@ for( $i = 0; $i < $numCombos; $i++ ) { # assemble the vertex shader unlink "shader$i.o"; - if( $g_xbox ) + if( $g_x360 ) { - $vsa = "xsasm"; - $vsadebug = "$vsa /nologo /D _XBOX=1 $outfilename shader$i.o"; - $vsanodebug = "$vsa /nologo /D _XBOX=1 $outfilename shader$i.o"; + $vsa = "..\\..\\x360xdk\\bin\\win32\\vsa"; } else { $vsa = "..\\..\\dx9sdk\\utilities\\vsa"; - $vsadebug = "$vsa /nologo /Foshader$i.o $outfilename"; - $vsanodebug = "$vsa /nologo /Foshader$i.o $outfilename"; } + $vsadebug = "$vsa /nologo /Foshader$i.o $outfilename"; + $vsanodebug = "$vsa /nologo /Foshader$i.o $outfilename"; $vsa_start_time = SampleTime(); @@ -1028,27 +992,53 @@ $finalheadername = "$vshtmp\\" . $filename_base . ".inc"; #print FINALHEADER @finalheader; #close FINALHEADER; -&MakeDirHier( "$shaderoutputdir/vsh" ); -open COMPILEDSHADER, ">$shaderoutputdir/vsh/$filename_base.vcs" || die; -binmode( COMPILEDSHADER ); +&MakeDirHier( "shaders/vsh" ); +my $vcsName = ""; +if( $g_x360 ) +{ + $vcsName = $filename_base . ".360.vcs"; +} +else +{ + $vcsName = $filename_base . ".vcs"; +} +open COMPILEDSHADER, ">shaders/vsh/$vcsName" || die; +binmode( COMPILEDSHADER ); # # Write out the part of the header that we know. . we'll write the rest after writing the object code. # +# Pack arguments +my $sInt = "i"; +my $uInt = "I"; +if ( $g_x360 ) +{ + # Change arguments to "big endian long" + $sInt = "N"; + $uInt = "N"; +} + +my $undecoratedinput = join "", &ReadInputFileWithoutLineInfo( $filename ); +#print STDERR "undecoratedinput: $undecoratedinput\n"; +my $crc = crc32( $undecoratedinput ); +#print STDERR "crc for $filename: $crc\n"; + # version -print COMPILEDSHADER pack "i", $shaderVersion; +print COMPILEDSHADER pack $sInt, 4; # totalCombos -print COMPILEDSHADER pack "i", $numCombos; +print COMPILEDSHADER pack $sInt, $numCombos; # dynamic combos -print COMPILEDSHADER pack "i", $numDynamicCombos; +print COMPILEDSHADER pack $sInt, $numDynamicCombos; # flags -print COMPILEDSHADER pack "I", $flags; +print COMPILEDSHADER pack $uInt, $flags; # centroid mask -print COMPILEDSHADER pack "I", 0; +print COMPILEDSHADER pack $uInt, 0; # reference size -print COMPILEDSHADER pack "I", 0; +print COMPILEDSHADER pack $uInt, 0; +# crc32 of the source code +print COMPILEDSHADER pack $uInt, $crc; my $beginningOfDir = tell COMPILEDSHADER; @@ -1056,9 +1046,9 @@ my $beginningOfDir = tell COMPILEDSHADER; for( $i = 0; $i < $numCombos; $i++ ) { # offset from beginning of file. - print COMPILEDSHADER pack "i", 0; + print COMPILEDSHADER pack $sInt, 0; # size - print COMPILEDSHADER pack "i", 0; + print COMPILEDSHADER pack $sInt, 0; } my $startByteCode = tell COMPILEDSHADER; @@ -1088,9 +1078,9 @@ seek COMPILEDSHADER, $beginningOfDir, 0; for( $i = 0; $i < $numCombos; $i++ ) { # offset from beginning of file. - print COMPILEDSHADER pack "i", $byteCodeStart[$i]; + print COMPILEDSHADER pack $sInt, $byteCodeStart[$i]; # size - print COMPILEDSHADER pack "i", $byteCodeSize[$i]; + print COMPILEDSHADER pack $sInt, $byteCodeSize[$i]; } close COMPILEDSHADER; diff --git a/src/src/dlls/bitstring.cpp b/src/src/dlls/bitstring.cpp deleted file mode 100644 index b0ef53c..0000000 --- a/src/src/dlls/bitstring.cpp +++ /dev/null @@ -1,321 +0,0 @@ -//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// -// -// Purpose: Arbitrary length bit string -// ** NOTE: This class does NOT override the bitwise operators -// as doing so would require overriding the operators -// to allocate memory for the returned bitstring. This method -// would be prone to memory leaks as the calling party -// would have to remember to delete the memory. Funtions -// are used instead to require the calling party to allocate -// and destroy their own memory -// -// $Workfile: $ -// $Date: $ -// $NoKeywords: $ -//=============================================================================// - -#include "cbase.h" - -#include - -#include "bitstring.h" -#include "utlbuffer.h" -#include "tier0/dbg.h" - -// memdbgon must be the last include file in a .cpp file!!! -#include "tier0/memdbgon.h" - -//----------------------------------------------------------------------------- -// Init static vars -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -// Purpose: Calculate a mask for the last int in the array -// Input : numBits - -// Output : static int -//----------------------------------------------------------------------------- - -unsigned g_BitStringEndMasks[] = -{ - 0x00000000, - 0xfffffffe, - 0xfffffffc, - 0xfffffff8, - 0xfffffff0, - 0xffffffe0, - 0xffffffc0, - 0xffffff80, - 0xffffff00, - 0xfffffe00, - 0xfffffc00, - 0xfffff800, - 0xfffff000, - 0xffffe000, - 0xffffc000, - 0xffff8000, - 0xffff0000, - 0xfffe0000, - 0xfffc0000, - 0xfff80000, - 0xfff00000, - 0xffe00000, - 0xffc00000, - 0xff800000, - 0xff000000, - 0xfe000000, - 0xfc000000, - 0xf8000000, - 0xf0000000, - 0xe0000000, - 0xc0000000, - 0x80000000, -}; - -//----------------------------------------------------------------------------- -// Purpose: Print bits for debugging purposes -// Input : -// Output : -//----------------------------------------------------------------------------- - -void DebugPrintBitStringBits( const int *pInts, int nInts ) -{ - for (int i=0;i= 0 && resizeNumBits <= USHRT_MAX ); - - int newIntCount = CalcNumIntsForBits( resizeNumBits ); - if ( newIntCount != GetNumInts() ) - { - if ( GetInts() ) - { - ReallocInts( newIntCount ); - if ( resizeNumBits >= Size() ) - { - GetInts()[GetNumInts() - 1] &= ~GetEndMask(); - memset( GetInts() + GetNumInts(), 0, (newIntCount - GetNumInts()) * sizeof(int) ); - } - } - else - { - // Figure out how many ints are needed - AllocInts( newIntCount ); - - // Initialize bitstring by clearing all bits - memset( GetInts(), 0, newIntCount * sizeof(int) ); - } - m_numInts = newIntCount; - } - else if ( resizeNumBits >= Size() && GetInts() ) - GetInts()[GetNumInts() - 1] &= ~GetEndMask(); - - // store the new size and end mask - m_numBits = resizeNumBits; -} - -//----------------------------------------------------------------------------- -// Purpose: Allocate the storage for the ints -// Input : numInts - -//----------------------------------------------------------------------------- -void CVariableBitStringBase::AllocInts( int numInts ) -{ - Assert( !m_pInt ); - - if ( numInts == 0 ) - return; - - if ( numInts == 1 ) - { - m_pInt = &m_iBitStringStorage; - return; - } - - m_pInt = (int *)malloc( numInts * sizeof(int) ); -} - - -//----------------------------------------------------------------------------- -// Purpose: Reallocate the storage for the ints -// Input : numInts - -//----------------------------------------------------------------------------- -void CVariableBitStringBase::ReallocInts( int numInts ) -{ - Assert( GetInts() ); - if ( numInts == 0) - { - FreeInts(); - return; - } - - if ( m_pInt == &m_iBitStringStorage ) - { - if ( numInts != 1 ) - { - m_pInt = ((int *)malloc( numInts * sizeof(int) )); - *m_pInt = m_iBitStringStorage; - } - - return; - } - - if ( numInts == 1 ) - { - m_iBitStringStorage = *m_pInt; - free( m_pInt ); - m_pInt = &m_iBitStringStorage; - return; - } - - m_pInt = (int *)realloc( m_pInt, numInts * sizeof(int) ); -} - - -//----------------------------------------------------------------------------- -// Purpose: Free storage allocated with AllocInts -//----------------------------------------------------------------------------- -void CVariableBitStringBase::FreeInts( void ) -{ - if ( m_numInts > 1 ) - { - free( m_pInt ); - } - m_pInt = NULL; -} - -//----------------------------------------------------------------------------- - -#ifdef DEBUG -CON_COMMAND(test_bitstring, "Tests the bit string class") -{ - // This function is only testing new features (toml 11-10-02) - - int i, j; - - // Variable sized - CBitString one, two, three; - - for ( i = 0; i < 100; i++ ) - { - one.Resize( random->RandomInt(1, USHRT_MAX ) ); - } - - one.Resize( 0 ); - - one.Resize( 2 ); - - for ( i = 0; i < 14; i++ ) - { - for ( j = 0; j < 64; j++) - { - int bit = random->RandomInt(0, one.Size() - 1 ); - Assert(!one.GetBit(bit)); - one.SetBit( bit ); - Assert(one.GetBit(bit)); - one.ClearBit( bit ); - Assert(!one.GetBit(bit)); - } - one.Resize( one.Size() * 2 ); - } - - one.Resize( 100 ); - one.SetBit( 50 ); - one.Resize( 101 ); - Assert(one.GetBit(50)); - one.Resize( 1010 ); - Assert(one.GetBit(50)); - one.Resize( 49 ); - one.Resize( 100 ); - Assert(!one.GetBit(50)); - - Assert( one.IsAllClear() ); - two.Resize( one.Size() ); - one.Not( &two ); - Assert( !two.IsAllClear() ); - Assert( two.IsAllSet() ); - - // Fixed sized - CFixedBitString<1> fbs1; Assert( fbs1.GetEndMask() == GetEndMask( fbs1.Size() ) ); - CFixedBitString<2> fbs2; Assert( fbs2.GetEndMask() == GetEndMask( fbs2.Size() ) ); - CFixedBitString<3> fbs3; Assert( fbs3.GetEndMask() == GetEndMask( fbs3.Size() ) ); - CFixedBitString<4> fbs4; Assert( fbs4.GetEndMask() == GetEndMask( fbs4.Size() ) ); - CFixedBitString<5> fbs5; Assert( fbs5.GetEndMask() == GetEndMask( fbs5.Size() ) ); - CFixedBitString<6> fbs6; Assert( fbs6.GetEndMask() == GetEndMask( fbs6.Size() ) ); - CFixedBitString<7> fbs7; Assert( fbs7.GetEndMask() == GetEndMask( fbs7.Size() ) ); - CFixedBitString<8> fbs8; Assert( fbs8.GetEndMask() == GetEndMask( fbs8.Size() ) ); - CFixedBitString<9> fbs9; Assert( fbs9.GetEndMask() == GetEndMask( fbs9.Size() ) ); - CFixedBitString<10> fbs10; Assert( fbs10.GetEndMask() == GetEndMask( fbs10.Size() ) ); - CFixedBitString<11> fbs11; Assert( fbs11.GetEndMask() == GetEndMask( fbs11.Size() ) ); - CFixedBitString<12> fbs12; Assert( fbs12.GetEndMask() == GetEndMask( fbs12.Size() ) ); - CFixedBitString<13> fbs13; Assert( fbs13.GetEndMask() == GetEndMask( fbs13.Size() ) ); - CFixedBitString<14> fbs14; Assert( fbs14.GetEndMask() == GetEndMask( fbs14.Size() ) ); - CFixedBitString<15> fbs15; Assert( fbs15.GetEndMask() == GetEndMask( fbs15.Size() ) ); - CFixedBitString<16> fbs16; Assert( fbs16.GetEndMask() == GetEndMask( fbs16.Size() ) ); - CFixedBitString<17> fbs17; Assert( fbs17.GetEndMask() == GetEndMask( fbs17.Size() ) ); - CFixedBitString<18> fbs18; Assert( fbs18.GetEndMask() == GetEndMask( fbs18.Size() ) ); - CFixedBitString<19> fbs19; Assert( fbs19.GetEndMask() == GetEndMask( fbs19.Size() ) ); - CFixedBitString<20> fbs20; Assert( fbs20.GetEndMask() == GetEndMask( fbs20.Size() ) ); - CFixedBitString<21> fbs21; Assert( fbs21.GetEndMask() == GetEndMask( fbs21.Size() ) ); - CFixedBitString<22> fbs22; Assert( fbs22.GetEndMask() == GetEndMask( fbs22.Size() ) ); - CFixedBitString<23> fbs23; Assert( fbs23.GetEndMask() == GetEndMask( fbs23.Size() ) ); - CFixedBitString<24> fbs24; Assert( fbs24.GetEndMask() == GetEndMask( fbs24.Size() ) ); - CFixedBitString<25> fbs25; Assert( fbs25.GetEndMask() == GetEndMask( fbs25.Size() ) ); - CFixedBitString<26> fbs26; Assert( fbs26.GetEndMask() == GetEndMask( fbs26.Size() ) ); - CFixedBitString<27> fbs27; Assert( fbs27.GetEndMask() == GetEndMask( fbs27.Size() ) ); - CFixedBitString<28> fbs28; Assert( fbs28.GetEndMask() == GetEndMask( fbs28.Size() ) ); - CFixedBitString<29> fbs29; Assert( fbs29.GetEndMask() == GetEndMask( fbs29.Size() ) ); - CFixedBitString<30> fbs30; Assert( fbs30.GetEndMask() == GetEndMask( fbs30.Size() ) ); - CFixedBitString<31> fbs31; Assert( fbs31.GetEndMask() == GetEndMask( fbs31.Size() ) ); - CFixedBitString<32> fbs32; Assert( fbs32.GetEndMask() == GetEndMask( fbs32.Size() ) ); - CFixedBitString<33> fbs33; Assert( fbs33.GetEndMask() == GetEndMask( fbs33.Size() ) ); - CFixedBitString<34> fbs34; Assert( fbs34.GetEndMask() == GetEndMask( fbs34.Size() ) ); - CFixedBitString<35> fbs35; Assert( fbs35.GetEndMask() == GetEndMask( fbs35.Size() ) ); -} -#endif diff --git a/src/src/dlls/bitstring.h b/src/src/dlls/bitstring.h deleted file mode 100644 index c736b1d..0000000 --- a/src/src/dlls/bitstring.h +++ /dev/null @@ -1,582 +0,0 @@ -//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// -// -// Purpose: Arbitrary length bit string -// ** NOTE: This class does NOT override the bitwise operators -// as doing so would require overriding the operators -// to allocate memory for the returned bitstring. This method -// would be prone to memory leaks as the calling party -// would have to remember to delete the memory. Funtions -// are used instead to require the calling party to allocate -// and destroy their own memory -// -// $Workfile: $ -// $Date: $ -// -//----------------------------------------------------------------------------- -// $Log: $ -// -// $NoKeywords: $ -//=============================================================================// - -#ifndef BITSTRING_H -#define BITSTRING_H -#pragma once - -class CUtlBuffer; - -//----------------------------------------------------------------------------- - -// OPTIMIZE: Removed the platform independence for speed -#define LOG2_BITS_PER_INT 5 -#define BITS_PER_INT 32 - -//------------------------------------- - -extern unsigned g_BitStringEndMasks[]; -inline unsigned GetEndMask( int numBits ) { return g_BitStringEndMasks[numBits % BITS_PER_INT]; } - -inline int CalcNumIntsForBits( int numBits ) { return (numBits + (BITS_PER_INT-1)) / BITS_PER_INT; } - -void DebugPrintBitStringBits( const int *pInts, int nInts ); -void SaveBitString(const int *pInts, int nInts, CUtlBuffer& buf); -void LoadBitString(int *pInts, int nInts, CUtlBuffer& buf); - -#define BitString_Bit( bitNum ) ( 1 << ( (bitNum) & (BITS_PER_INT-1) ) ) -#define BitString_Int( bitNum ) ( (bitNum) >> LOG2_BITS_PER_INT ) - - -//----------------------------------------------------------------------------- -// template CBitStringT -// -// Defines the operations relevant to any bit array. Simply requires a base -// class that implements Size(), GetInts(), GetNumInts() & ValidateOperand() -// -// CBitString and CFixedBitString are the actual classes generally used -// by clients -// - -template -class CBitStringT : public BASE_OPS -{ -public: - CBitStringT(); - CBitStringT(int numBits); // Must be initialized with the number of bits - - // Do NOT override bitwise operators (see note in header) - void And(const CBitStringT &andStr, CBitStringT *out) const; - void Or(const CBitStringT &orStr, CBitStringT *out) const; - void Xor(const CBitStringT &orStr, CBitStringT *out) const; - - void Not(CBitStringT *out) const; - - void Copy(CBitStringT *out) const; - - bool IsAllClear(void) const; // Are all bits zero? - bool IsAllSet(void) const; // Are all bits one? - - bool GetBit( int bitNum ) const; - void SetBit( int bitNum ); - void ClearBit(int bitNum); - - void SetAllBits(void); // Sets all bits - void ClearAllBits(void); // Clears all bits - - void DebugPrintBits(void) const; // For debugging - - void SaveBitString(CUtlBuffer& buf) const; - void LoadBitString(CUtlBuffer& buf); - -}; - -//----------------------------------------------------------------------------- -// class CVariableBitStringBase -// -// Defines the operations necessary for a variable sized bit array - -class CVariableBitStringBase -{ -public: - bool IsFixedSize() const { return false; } - int Size(void) const { return m_numBits; } - void Resize( int numBits ); // resizes bit array - - int GetNumInts() const { return m_numInts; } - int * GetInts() { return m_pInt; } - const int * GetInts() const { return m_pInt; } - -protected: - CVariableBitStringBase(); - CVariableBitStringBase(int numBits); - CVariableBitStringBase( const CVariableBitStringBase &from ); - CVariableBitStringBase &operator=( const CVariableBitStringBase &from ); - ~CVariableBitStringBase(void); - - void ValidateOperand( const CVariableBitStringBase &operand ) const; - - unsigned GetEndMask() const { return ::GetEndMask( Size() ); } - -private: - - unsigned short m_numBits; // Number of bits in the bitstring - unsigned short m_numInts; // Number of ints to needed to store bitstring - int m_iBitStringStorage; // If the bit string fits in one int, it goes here - int *m_pInt; // Array of ints containing the bitstring - - void AllocInts( int numInts ); // Free the allocated bits - void ReallocInts( int numInts ); - void FreeInts( void ); // Free the allocated bits -}; - -//----------------------------------------------------------------------------- -// class CFixedBitStringBase -// -// Defines the operations necessary for a fixed sized bit array. -// - -template struct BitCountToEndMask_t { }; -template <> struct BitCountToEndMask_t< 0> { enum { MASK = 0x00000000 }; }; -template <> struct BitCountToEndMask_t< 1> { enum { MASK = 0xfffffffe }; }; -template <> struct BitCountToEndMask_t< 2> { enum { MASK = 0xfffffffc }; }; -template <> struct BitCountToEndMask_t< 3> { enum { MASK = 0xfffffff8 }; }; -template <> struct BitCountToEndMask_t< 4> { enum { MASK = 0xfffffff0 }; }; -template <> struct BitCountToEndMask_t< 5> { enum { MASK = 0xffffffe0 }; }; -template <> struct BitCountToEndMask_t< 6> { enum { MASK = 0xffffffc0 }; }; -template <> struct BitCountToEndMask_t< 7> { enum { MASK = 0xffffff80 }; }; -template <> struct BitCountToEndMask_t< 8> { enum { MASK = 0xffffff00 }; }; -template <> struct BitCountToEndMask_t< 9> { enum { MASK = 0xfffffe00 }; }; -template <> struct BitCountToEndMask_t<10> { enum { MASK = 0xfffffc00 }; }; -template <> struct BitCountToEndMask_t<11> { enum { MASK = 0xfffff800 }; }; -template <> struct BitCountToEndMask_t<12> { enum { MASK = 0xfffff000 }; }; -template <> struct BitCountToEndMask_t<13> { enum { MASK = 0xffffe000 }; }; -template <> struct BitCountToEndMask_t<14> { enum { MASK = 0xffffc000 }; }; -template <> struct BitCountToEndMask_t<15> { enum { MASK = 0xffff8000 }; }; -template <> struct BitCountToEndMask_t<16> { enum { MASK = 0xffff0000 }; }; -template <> struct BitCountToEndMask_t<17> { enum { MASK = 0xfffe0000 }; }; -template <> struct BitCountToEndMask_t<18> { enum { MASK = 0xfffc0000 }; }; -template <> struct BitCountToEndMask_t<19> { enum { MASK = 0xfff80000 }; }; -template <> struct BitCountToEndMask_t<20> { enum { MASK = 0xfff00000 }; }; -template <> struct BitCountToEndMask_t<21> { enum { MASK = 0xffe00000 }; }; -template <> struct BitCountToEndMask_t<22> { enum { MASK = 0xffc00000 }; }; -template <> struct BitCountToEndMask_t<23> { enum { MASK = 0xff800000 }; }; -template <> struct BitCountToEndMask_t<24> { enum { MASK = 0xff000000 }; }; -template <> struct BitCountToEndMask_t<25> { enum { MASK = 0xfe000000 }; }; -template <> struct BitCountToEndMask_t<26> { enum { MASK = 0xfc000000 }; }; -template <> struct BitCountToEndMask_t<27> { enum { MASK = 0xf8000000 }; }; -template <> struct BitCountToEndMask_t<28> { enum { MASK = 0xf0000000 }; }; -template <> struct BitCountToEndMask_t<29> { enum { MASK = 0xe0000000 }; }; -template <> struct BitCountToEndMask_t<30> { enum { MASK = 0xc0000000 }; }; -template <> struct BitCountToEndMask_t<31> { enum { MASK = 0x80000000 }; }; - -//------------------------------------- - -template -class CFixedBitStringBase -{ -public: - bool IsFixedSize() const { return true; } - int Size(void) const { return NUM_BITS; } - void Resize( int numBits ) { Assert(numBits == NUM_BITS); }// for syntatic consistency (for when using templates) - - int GetNumInts() const { return NUM_INTS; } - int * GetInts() { return m_Ints; } - const int * GetInts() const { return m_Ints; } - -protected: - CFixedBitStringBase() {} - CFixedBitStringBase(int numBits) { Assert( numBits == NUM_BITS ); } // doesn't make sense, really. Supported to simplify templates & allow easy replacement of variable - - void ValidateOperand( const CFixedBitStringBase &operand ) const { } // no need, compiler does so statically - -public: // for test code - unsigned GetEndMask() const { return static_cast( BitCountToEndMask_t::MASK ); } - -private: - enum - { - NUM_INTS = (NUM_BITS + (BITS_PER_INT-1)) / BITS_PER_INT - }; - - int m_Ints[(NUM_BITS + (BITS_PER_INT-1)) / BITS_PER_INT]; -}; - -//----------------------------------------------------------------------------- -// -// The actual classes used -// - -// inheritance instead of typedef to allow forward declarations -class CBitString : public CBitStringT -{ -public: - CBitString() - { - } - - CBitString(int numBits) - : CBitStringT(numBits) - { - } -}; - -//----------------------------------------------------------------------------- - -template < int NUM_BITS > -class CFixedBitString : public CBitStringT< CFixedBitStringBase > -{ -public: - CFixedBitString() - { - } - - CFixedBitString(int numBits) - : CBitStringT< CFixedBitStringBase >(numBits) - { - } -}; - -//----------------------------------------------------------------------------- - -inline CVariableBitStringBase::CVariableBitStringBase() -{ - memset( this, 0, sizeof( *this ) ); -} - -//----------------------------------------------------------------------------- - -inline CVariableBitStringBase::CVariableBitStringBase(int numBits) -{ - Assert( numBits ); - m_numBits = numBits; - - // Figure out how many ints are needed - m_numInts = CalcNumIntsForBits( numBits ); - m_pInt = NULL; - AllocInts( m_numInts ); -} - -//----------------------------------------------------------------------------- - -inline CVariableBitStringBase::CVariableBitStringBase( const CVariableBitStringBase &from ) -{ - if ( from.m_numInts ) - { - m_numBits = from.m_numBits; - m_numInts = from.m_numInts; - m_pInt = NULL; - AllocInts( m_numInts ); - memcpy( m_pInt, from.m_pInt, m_numInts * sizeof(int) ); - } - else - memset( this, 0, sizeof( *this ) ); -} - -//----------------------------------------------------------------------------- - -inline CVariableBitStringBase &CVariableBitStringBase::operator=( const CVariableBitStringBase &from ) -{ - Resize( from.Size() ); - if ( m_pInt ) - memcpy( m_pInt, from.m_pInt, m_numInts * sizeof(int) ); - return (*this); -} - - -//----------------------------------------------------------------------------- -// Purpose: Destructor -// Input : -// Output : -//----------------------------------------------------------------------------- - -inline CVariableBitStringBase::~CVariableBitStringBase(void) -{ - FreeInts(); -} - -//----------------------------------------------------------------------------- - -template -inline CBitStringT::CBitStringT() -{ - // undef this is ints are not 4 bytes - // generate a compile error if sizeof(int) is not 4 (HACK: can't use the preprocessor so use the compiler) - - COMPILE_TIME_ASSERT( sizeof(int)==4 ); - - // Initialize bitstring by clearing all bits - ClearAllBits(); -} - -//----------------------------------------------------------------------------- -template -inline CBitStringT::CBitStringT(int numBits) - : BASE_OPS( numBits ) -{ - // undef this is ints are not 4 bytes - // generate a compile error if sizeof(int) is not 4 (HACK: can't use the preprocessor so use the compiler) - - COMPILE_TIME_ASSERT( sizeof(int)==4 ); - - // Initialize bitstring by clearing all bits - ClearAllBits(); -} - -//----------------------------------------------------------------------------- - -template -inline bool CBitStringT::GetBit( int bitNum ) const -{ - Assert( bitNum >= 0 && bitNum < Size() ); - const int *pInt = GetInts() + BitString_Int( bitNum ); - return ( ( *pInt & BitString_Bit( bitNum ) ) != 0 ); -} - -//----------------------------------------------------------------------------- - -template -inline void CBitStringT::SetBit( int bitNum ) -{ - Assert( bitNum >= 0 && bitNum < Size() ); - int *pInt = GetInts() + BitString_Int( bitNum ); - *pInt |= BitString_Bit( bitNum ); -} - -//----------------------------------------------------------------------------- - -template -inline void CBitStringT::ClearBit(int bitNum) -{ - Assert( bitNum >= 0 && bitNum < Size() ); - int *pInt = GetInts() + BitString_Int( bitNum ); - *pInt &= ~BitString_Bit( bitNum ); -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : -// Output : -//----------------------------------------------------------------------------- -template -inline void CBitStringT::And(const CBitStringT &addStr, CBitStringT *out) const -{ - ValidateOperand( addStr ); - ValidateOperand( *out ); - - int * pDest = out->GetInts(); - const int *pOperand1 = GetInts(); - const int *pOperand2 = addStr.GetInts(); - - for (int i = GetNumInts() - 1; i >= 0 ; --i) - { - pDest[i] = pOperand1[i] & pOperand2[i]; - } -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : -// Output : -//----------------------------------------------------------------------------- -template -inline void CBitStringT::Or(const CBitStringT &orStr, CBitStringT *out) const -{ - ValidateOperand( orStr ); - ValidateOperand( *out ); - - int * pDest = out->GetInts(); - const int *pOperand1 = GetInts(); - const int *pOperand2 = orStr.GetInts(); - - for (int i = GetNumInts() - 1; i >= 0; --i) - { - pDest[i] = pOperand1[i] | pOperand2[i]; - } -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : -// Output : -//----------------------------------------------------------------------------- -template -inline void CBitStringT::Xor(const CBitStringT &xorStr, CBitStringT *out) const -{ - int * pDest = out->GetInts(); - const int *pOperand1 = GetInts(); - const int *pOperand2 = xorStr.GetInts(); - - for (int i = GetNumInts() - 1; i >= 0; --i) - { - pDest[i] = pOperand1[i] ^ pOperand2[i]; - } -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : -// Output : -//----------------------------------------------------------------------------- -template -inline void CBitStringT::Not(CBitStringT *out) const -{ - ValidateOperand( *out ); - - int * pDest = out->GetInts(); - const int *pOperand = GetInts(); - - for (int i = GetNumInts() - 1; i >= 0; --i) - { - pDest[i] = ~(pOperand[i]); - } -} - -//----------------------------------------------------------------------------- -// Purpose: Copy a bit string -// Input : -// Output : -//----------------------------------------------------------------------------- -template -inline void CBitStringT::Copy(CBitStringT *out) const -{ - ValidateOperand( *out ); - Assert( out != this ); - - memcpy( out->GetInts(), GetInts(), GetNumInts() * sizeof( int ) ); -} - -//----------------------------------------------------------------------------- -// Purpose: Are all bits zero? -// Input : -// Output : -//----------------------------------------------------------------------------- -template -inline bool CBitStringT::IsAllClear(void) const -{ - // Number of available bits may be more than the number - // actually used, so make sure to mask out unused bits - // before testing for zero - (const_cast(this))->GetInts()[GetNumInts()-1] &= ~CBitStringT::GetEndMask(); // external semantics of const retained - - for (int i = GetNumInts() - 1; i >= 0; --i) - { - if ( GetInts()[i] !=0 ) - { - return false; - } - } - return true; -} - -//----------------------------------------------------------------------------- -// Purpose: Are all bits set? -// Input : -// Output : -//----------------------------------------------------------------------------- -template -inline bool CBitStringT::IsAllSet(void) const -{ - // Number of available bits may be more than the number - // actually used, so make sure to mask out unused bits - // before testing for set bits - (const_cast(this))->GetInts()[GetNumInts()-1] |= CBitStringT::GetEndMask(); // external semantics of const retained - - for (int i = GetNumInts() - 1; i >= 0; --i) - { - if ( GetInts()[i] != ~0 ) - { - return false; - } - } - return true; -} - -//----------------------------------------------------------------------------- -// Purpose: Sets all bits -// Input : -// Output : -//----------------------------------------------------------------------------- -template -inline void CBitStringT::SetAllBits(void) -{ - if ( GetInts() ) - memset( GetInts(), 0xff, GetNumInts() * sizeof(int) ); -} - -//----------------------------------------------------------------------------- -// Purpose: Clears all bits -// Input : -// Output : -//----------------------------------------------------------------------------- -template -inline void CBitStringT::ClearAllBits(void) -{ - if ( GetInts() ) - memset( GetInts(), 0, GetNumInts() * sizeof(int) ); -} - -//----------------------------------------------------------------------------- - -template -inline void CBitStringT::DebugPrintBits(void) const -{ - (const_cast(this))->GetInts()[GetNumInts()-1] &= ~CBitStringT::GetEndMask(); // external semantics of const retained - DebugPrintBitStringBits( GetInts(), GetNumInts() ); -} - -//----------------------------------------------------------------------------- - -template -inline void CBitStringT::SaveBitString(CUtlBuffer& buf) const -{ - (const_cast(this))->GetInts()[GetNumInts()-1] &= ~CBitStringT::GetEndMask(); // external semantics of const retained - ::SaveBitString( GetInts(), GetNumInts(), buf ); -} - -//----------------------------------------------------------------------------- - -template -inline void CBitStringT::LoadBitString(CUtlBuffer& buf) -{ - (const_cast(this))->GetInts()[GetNumInts()-1] &= ~CBitStringT::GetEndMask(); - ::LoadBitString( GetInts(), GetNumInts(), buf ); -} - -//----------------------------------------------------------------------------- -// @Note (toml 11-09-02): these methods are a nod to a heavy user of the -// bit string, AI conditions. This assumes MAX_CONDITIONS == 128 - -template<> -inline void CBitStringT< CFixedBitStringBase<128> >::And(const CBitStringT &addStr, CBitStringT *out) const -{ - int * pDest = out->GetInts(); - const int *pOperand1 = GetInts(); - const int *pOperand2 = addStr.GetInts(); - - pDest[0] = pOperand1[0] & pOperand2[0]; - pDest[1] = pOperand1[1] & pOperand2[1]; - pDest[2] = pOperand1[2] & pOperand2[2]; - pDest[3] = pOperand1[3] & pOperand2[3]; -} - -template<> -inline bool CBitStringT< CFixedBitStringBase<128> >::IsAllClear(void) const -{ - const int *pInts = GetInts(); - - return ( pInts[0] == 0 && pInts[1] == 0 && pInts[2] == 0 && pInts[3] == 0 ); -} - -template<> -inline void CBitStringT< CFixedBitStringBase<128> >::Copy(CBitStringT *out) const -{ - int * pDest = out->GetInts(); - const int *pInts = GetInts(); - - pDest[0] = pInts[0]; - pDest[1] = pInts[1]; - pDest[2] = pInts[2]; - pDest[3] = pInts[3]; -} - -//============================================================================= - -#endif // BITSTRING_H diff --git a/src/src/dlls/colorcorrection.cpp b/src/src/dlls/colorcorrection.cpp deleted file mode 100644 index b44bd12..0000000 --- a/src/src/dlls/colorcorrection.cpp +++ /dev/null @@ -1,144 +0,0 @@ -//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// -// -// Purpose: Color correction entity. -// -// $NoKeywords: $ -//=============================================================================// - -#include - -#include "cbase.h" - -// memdbgon must be the last include file in a .cpp file!!! -#include "tier0/memdbgon.h" - -//------------------------------------------------------------------------------ -// FIXME: This really should inherit from something more lightweight -//------------------------------------------------------------------------------ - - -//------------------------------------------------------------------------------ -// Purpose : Shadow control entity -//------------------------------------------------------------------------------ -class CColorCorrection : public CBaseEntity -{ - DECLARE_CLASS( CColorCorrection, CBaseEntity ); -public: - DECLARE_SERVERCLASS(); - DECLARE_DATADESC(); - - CColorCorrection(); - - void Spawn( void ); - int UpdateTransmitState(); - void Activate( void ); - - virtual int ObjectCaps( void ) { return BaseClass::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } - - // Inputs - void InputEnable( inputdata_t &inputdata ); - void InputDisable( inputdata_t &inputdata ); - -private: - - bool m_bStartDisabled; - CNetworkVar( bool, m_bEnabled ); - - CNetworkVar( float, m_Weight ); - CNetworkVar( float, m_MinFalloff ); - CNetworkVar( float, m_MaxFalloff ); - CNetworkVar( float, m_MaxWeight ); - CNetworkString( m_netlookupFilename, MAX_PATH ); - - string_t m_lookupFilename; -}; - -LINK_ENTITY_TO_CLASS(color_correction, CColorCorrection); - -BEGIN_DATADESC( CColorCorrection ) - - DEFINE_KEYFIELD( m_Weight, FIELD_FLOAT, "weight" ), - DEFINE_KEYFIELD( m_MinFalloff, FIELD_FLOAT, "minfalloff" ), - DEFINE_KEYFIELD( m_MaxFalloff, FIELD_FLOAT, "maxfalloff" ), - DEFINE_KEYFIELD( m_MaxWeight, FIELD_FLOAT, "maxweight" ), - DEFINE_KEYFIELD( m_lookupFilename, FIELD_STRING, "filename" ), - - DEFINE_KEYFIELD( m_bEnabled, FIELD_BOOLEAN, "enabled" ), - DEFINE_KEYFIELD( m_bStartDisabled, FIELD_BOOLEAN, "StartDisabled" ), - - DEFINE_INPUTFUNC( FIELD_VOID, "Enable", InputEnable ), - DEFINE_INPUTFUNC( FIELD_VOID, "Disable", InputDisable ), - -END_DATADESC() - -IMPLEMENT_SERVERCLASS_ST_NOBASE(CColorCorrection, DT_ColorCorrection) - SendPropVector( SENDINFO(m_vecOrigin), -1, SPROP_NOSCALE, 0.0f, HIGH_DEFAULT, SendProxy_Origin ), - SendPropFloat( SENDINFO(m_MinFalloff) ), - SendPropFloat( SENDINFO(m_MaxFalloff) ), - SendPropFloat( SENDINFO(m_MaxWeight) ), - SendPropString( SENDINFO(m_netlookupFilename) ), - SendPropBool( SENDINFO(m_bEnabled) ), -END_SEND_TABLE() - - -CColorCorrection::CColorCorrection() : BaseClass() -{ - m_bEnabled = true; - m_MinFalloff = 0.0f; - m_MaxFalloff = 1000.0f; - m_MaxWeight = 1.0f; - m_netlookupFilename.GetForModify()[0] = 0; - m_lookupFilename = NULL_STRING; -} - - -//------------------------------------------------------------------------------ -// Purpose : Send even though we don't have a model -//------------------------------------------------------------------------------ -int CColorCorrection::UpdateTransmitState() -{ - // ALWAYS transmit to all clients. - return SetTransmitState( FL_EDICT_ALWAYS ); -} - -//------------------------------------------------------------------------------ -// Purpose : -//------------------------------------------------------------------------------ -void CColorCorrection::Spawn( void ) -{ - AddEFlags( EFL_FORCE_CHECK_TRANSMIT | EFL_DIRTY_ABSTRANSFORM ); - Precache(); - SetSolid( SOLID_NONE ); - - if( m_bStartDisabled ) - { - m_bEnabled = false; - } - else - { - m_bEnabled = true; - } - - BaseClass::Spawn(); -} - -void CColorCorrection::Activate( void ) -{ - BaseClass::Activate(); - - Q_strncpy( m_netlookupFilename.GetForModify(), STRING( m_lookupFilename ), MAX_PATH ); -} - - -//------------------------------------------------------------------------------ -// Purpose : Input handlers -//------------------------------------------------------------------------------ -void CColorCorrection::InputEnable( inputdata_t &inputdata ) -{ - m_bEnabled = true; -} - -void CColorCorrection::InputDisable( inputdata_t &inputdata ) -{ - m_bEnabled = false; -} diff --git a/src/src/dlls/cterrainmorph.cpp b/src/src/dlls/cterrainmorph.cpp deleted file mode 100644 index f808fdf..0000000 --- a/src/src/dlls/cterrainmorph.cpp +++ /dev/null @@ -1,224 +0,0 @@ -//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// -// -// Purpose: -// -// $NoKeywords: $ -//=============================================================================// - -#include "cbase.h" -#if !defined(IN_XBOX_CODELINE) -#include "baseentity.h" -#include "terrainmodmgr.h" -#include "terrainmodmgr_shared.h" -#include "ndebugoverlay.h" - -// memdbgon must be the last include file in a .cpp file!!! -#include "tier0/memdbgon.h" - -#define SF_TERRAINMORPH_INSTANT 0x00000001 - -#define TERRAINMORPH_THINK_FREQUENCY 0.05 - - -//========================================================= -//========================================================= -class CTerrainMorphParams -{ -public: - Vector m_vecNormal; - - float m_flDeltaZ; - float m_flDieTime; - float m_flRadius; - float m_flDeltaRadius; - float m_flStrength; - float m_flDeltaStrength; - - float m_flDuration; - float m_flStartTime; - float m_flStartRadius; - float m_flGoalRadius; - - float m_flFraction; -}; - - -//========================================================= -//========================================================= -class CTerrainMorph : public CPointEntity -{ - DECLARE_CLASS( CTerrainMorph, CPointEntity ); -public: - void Spawn( CTerrainMorphParams ¶ms ); - void Start( void ); - void MorphThink( void ); - - // Input handlers - void InputBeginMorph( inputdata_t &inputdata ); - - DECLARE_DATADESC(); - -private: - CTerrainMorphParams m_Params; - - int m_iIterations; -}; - - -//--------------------------------------------------------- -//--------------------------------------------------------- -void CTerrainMorph::Spawn( CTerrainMorphParams ¶ms ) -{ - m_Params = params; - - SetThink( NULL ); -} - - -//--------------------------------------------------------- -//--------------------------------------------------------- -void CTerrainMorph::Start( void ) -{ -// Set up start time, die time, effect duration. - m_Params.m_flStartTime = gpGlobals->curtime; - m_Params.m_flDieTime = gpGlobals->curtime + m_Params.m_flDuration; - m_Params.m_flDuration = m_Params.m_flDuration; - -// NORMAL (direction the effect will 'pull') - GetVectors( &m_Params.m_vecNormal, NULL, NULL ); - -// RADIUS - m_Params.m_flRadius = m_Params.m_flStartRadius; - -// STRENGTH (This is the distance that the effect will pull the displacement) - trace_t tr; - - // trace backwards along the normal and find the point under myself that is going to be pulled. - UTIL_TraceLine( GetAbsOrigin(), GetAbsOrigin() + m_Params.m_vecNormal * -4096, MASK_OPAQUE, this, COLLISION_GROUP_NONE, &tr ); - - //NDebugOverlay::Line( tr.startpos, tr.endpos, 0,255,0, true, 30 ); - - // Get that distance. - float flDist; - flDist = VectorLength( tr.endpos - tr.startpos ); - - // Set the strength relative to the FRACTION specified by the designer. - m_Params.m_flStrength = flDist * m_Params.m_flFraction; - - SetThink( &CTerrainMorph::MorphThink ); - SetNextThink( gpGlobals->curtime ); - - m_iIterations = 0; - - //NDebugOverlay::Line( m_Params.m_vecLocation, m_Params.m_vecLocation + m_Params.m_vecNormal * 200, 255,0,0, true, 3 ); -} - - -//--------------------------------------------------------- -//--------------------------------------------------------- -void CTerrainMorph::MorphThink( void ) -{ - SetNextThink( gpGlobals->curtime + TERRAINMORPH_THINK_FREQUENCY ); - - - if( m_spawnflags & SF_TERRAINMORPH_INSTANT ) - { - // Do the full effect in one whack. - CTerrainModParams params; - TerrainModType type; - params.m_Flags |= CTerrainModParams::TMOD_SUCKTONORMAL; - - type = TMod_Suck; - - params.m_flRadius = m_Params.m_flRadius; - params.m_flStrength = m_Params.m_flStrength; - params.m_vCenter = GetAbsOrigin(); - params.m_vNormal = m_Params.m_vecNormal; - - params.m_flRadius = clamp(params.m_flRadius, MIN_TMOD_RADIUS, MAX_TMOD_RADIUS); - - TerrainMod_Add( type, params ); - - UTIL_Remove( this ); - - return; - } - -//---- - float flTime; - - flTime = ( (gpGlobals->curtime - m_Params.m_flStartTime) / m_Params.m_flDuration ); - flTime = 1 - clamp(flTime, 0, 1 ); -//---- - - if( flTime >= 0.0 ) - { - //Msg( "time: %f radius:%f strength: %f\n", flTime,params.m_flRadius, params.m_flStrength ); - CTerrainModParams params; - TerrainModType type; - params.m_Flags |= CTerrainModParams::TMOD_SUCKTONORMAL; - - type = TMod_Suck; - -#if 1 - float nextIteration = (1-flTime)*m_Params.m_flStrength; - - params.m_flStrength = (int)nextIteration - m_iIterations; - if ( params.m_flStrength > 0 ) - { - params.m_vCenter = GetAbsOrigin(); - params.m_vNormal = m_Params.m_vecNormal; - - params.m_flRadius = m_Params.m_flStartRadius * flTime + m_Params.m_flGoalRadius * ( 1 - flTime ); - params.m_flRadius = clamp(params.m_flRadius, MIN_TMOD_RADIUS, MAX_TMOD_RADIUS); - - //Msg( "Strength: %f - Radius: %f\n", params.m_flStrength, params.m_flRadius ); - - TerrainMod_Add( type, params ); - m_iIterations += params.m_flStrength; - } -#if 0 - NDebugOverlay::Line( m_Params.m_vecLocation, m_Params.m_vecLocation + Vector( 200, 200, 0 ), 0,255,0, true, 3 ); - NDebugOverlay::Line( m_Params.m_vecLocation + Vector( m_Params.m_flRadius, 0, 0 ), m_Params.m_vecLocation + Vector( m_Params.m_flRadius, 0 , 200 ), 0,255,0, true, 3 ); -#endif - -#endif - } - - if( gpGlobals->curtime > m_Params.m_flDieTime ) - { - SetThink( NULL ); - UTIL_Remove( this ); - } -} - -//--------------------------------------------------------- -//--------------------------------------------------------- -void CTerrainMorph::InputBeginMorph( inputdata_t &inputdata ) -{ - Start(); -} - -//--------------------------------------------------------- -//--------------------------------------------------------- -BEGIN_DATADESC( CTerrainMorph ) - - // Function Pointers - DEFINE_FUNCTION( MorphThink ), - - DEFINE_INPUTFUNC( FIELD_VOID, "BeginMorph", InputBeginMorph ), - - // quiet down classcheck - // DEFINE_FIELD( m_Params, CTerrainMorphParams ), - DEFINE_KEYFIELD( m_Params.m_flStartRadius, FIELD_FLOAT, "startradius" ), - DEFINE_KEYFIELD( m_Params.m_flGoalRadius, FIELD_FLOAT, "goalradius" ), - DEFINE_KEYFIELD( m_Params.m_flDuration, FIELD_FLOAT, "duration" ), - DEFINE_KEYFIELD( m_Params.m_flFraction, FIELD_FLOAT, "fraction" ), - - DEFINE_FIELD( m_iIterations, FIELD_INTEGER ), - -END_DATADESC() -LINK_ENTITY_TO_CLASS(tectonic, CTerrainMorph); -LINK_ENTITY_TO_CLASS(env_terrainmorph, CTerrainMorph); - -#endif diff --git a/src/src/dlls/entity_tools_server.cpp b/src/src/dlls/entity_tools_server.cpp deleted file mode 100644 index 67cdf23..0000000 --- a/src/src/dlls/entity_tools_server.cpp +++ /dev/null @@ -1,160 +0,0 @@ -//====== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======= -// -// Purpose: -// -//============================================================================= -#include "cbase.h" -#include "const.h" -#include "toolframework/itoolentity.h" -#include "entitylist.h" -#include "toolframework/itoolsystem.h" -#include "KeyValues.h" -#include "icliententity.h" -#include "iserverentity.h" -#include "sceneentity.h" - - -// Interface from engine to tools for manipulating entities -class CServerTools : public IServerTools -{ -public: - virtual IServerEntity *GetIServerEntity( IClientEntity *pClientEntity ) - { - if ( pClientEntity == NULL ) - return NULL; - - CBaseHandle ehandle = pClientEntity->GetRefEHandle(); - if ( ehandle.GetEntryIndex() >= MAX_EDICTS ) - return NULL; // the first MAX_EDICTS entities are networked, the rest are client or server only - -#if 0 - // this fails, since the server entities have extra bits in their serial numbers, - // since 20 bits are reserved for serial numbers, except for networked entities, which are restricted to 10 - - // Brian believes that everything should just restrict itself to 10 to make things simpler, - // so if/when he changes NUM_SERIAL_NUM_BITS to 10, we can switch back to this simpler code - - IServerNetworkable *pNet = gEntList.GetServerNetworkable( ehandle ); - if ( pNet == NULL ) - return NULL; - - CBaseEntity *pServerEnt = pNet->GetBaseEntity(); - return pServerEnt; -#else - IHandleEntity *pEnt = gEntList.LookupEntityByNetworkIndex( ehandle.GetEntryIndex() ); - if ( pEnt == NULL ) - return NULL; - - CBaseHandle h = gEntList.GetNetworkableHandle( ehandle.GetEntryIndex() ); - const int mask = ( 1 << NUM_NETWORKED_EHANDLE_SERIAL_NUMBER_BITS ) - 1; - if ( !h.IsValid() || ( ( h.GetSerialNumber() & mask ) != ( ehandle.GetSerialNumber() & mask ) ) ) - return NULL; - - IServerUnknown *pUnk = static_cast< IServerUnknown* >( pEnt ); - return pUnk->GetBaseEntity(); -#endif - } - - bool GetPlayerPosition( Vector &org, QAngle &ang, IClientEntity *pClientPlayer = NULL ) - { - IServerEntity *pServerPlayer = GetIServerEntity( pClientPlayer ); - CBasePlayer *pPlayer = pServerPlayer ? ( CBasePlayer* )pServerPlayer : UTIL_GetLocalPlayer(); - if ( pPlayer == NULL ) - return false; - - org = pPlayer->EyePosition(); - ang = pPlayer->EyeAngles(); - return true; - } - - bool SnapPlayerToPosition( const Vector &org, const QAngle &ang, IClientEntity *pClientPlayer = NULL ) - { - IServerEntity *pServerPlayer = GetIServerEntity( pClientPlayer ); - CBasePlayer *pPlayer = pServerPlayer ? ( CBasePlayer* )pServerPlayer : UTIL_GetLocalPlayer(); - if ( pPlayer == NULL ) - return false; - - pPlayer->SetAbsOrigin( org - pPlayer->GetViewOffset() ); - pPlayer->SnapEyeAngles( ang ); - - // Disengage from hierarchy - pPlayer->SetParent( NULL ); - - return true; - } - - int GetPlayerFOV( IClientEntity *pClientPlayer = NULL ) - { - IServerEntity *pServerPlayer = GetIServerEntity( pClientPlayer ); - CBasePlayer *pPlayer = pServerPlayer ? ( CBasePlayer* )pServerPlayer : UTIL_GetLocalPlayer(); - if ( pPlayer == NULL ) - return 0; - - return pPlayer->GetFOV(); - } - - bool SetPlayerFOV( int fov, IClientEntity *pClientPlayer = NULL ) - { - IServerEntity *pServerPlayer = GetIServerEntity( pClientPlayer ); - CBasePlayer *pPlayer = pServerPlayer ? ( CBasePlayer* )pServerPlayer : UTIL_GetLocalPlayer(); - if ( pPlayer == NULL ) - return false; - - pPlayer->SetDefaultFOV( fov ); - CBaseEntity *pFOVOwner = pPlayer->GetFOVOwner(); - return pPlayer->SetFOV( pFOVOwner ? pFOVOwner : pPlayer, fov ); - } -}; - - -static CServerTools g_ServerTools; -EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CServerTools, IServerTools, VSERVERTOOLS_INTERFACE_VERSION, g_ServerTools ); - - -// Interface from engine to tools for manipulating entities -class CServerChoreoTools : public IServerChoreoTools -{ -public: - // Iterates through ALL entities (separate list for client vs. server) - virtual EntitySearchResult NextChoreoEntity( EntitySearchResult currentEnt ) - { - CBaseEntity *ent = reinterpret_cast< CBaseEntity* >( currentEnt ); - ent = gEntList.FindEntityByClassname( ent, "logic_choreographed_scene" ); - return reinterpret_cast< EntitySearchResult >( ent ); - } - - virtual const char *GetSceneFile( EntitySearchResult sr ) - { - CBaseEntity *ent = reinterpret_cast< CBaseEntity* >( sr ); - if ( !sr ) - return ""; - - if ( Q_stricmp( ent->GetClassname(), "logic_choreographed_scene" ) ) - return ""; - - return GetSceneFilename( ent ); - } - - // For interactive editing - virtual int GetEntIndex( EntitySearchResult sr ) - { - CBaseEntity *ent = reinterpret_cast< CBaseEntity* >( sr ); - if ( !ent ) - return -1; - - return ent->entindex(); - } - - virtual void ReloadSceneFromDisk( int entindex ) - { - CBaseEntity *ent = CBaseEntity::Instance( entindex ); - if ( !ent ) - return; - - ::ReloadSceneFromDisk( ent ); - } -}; - - -static CServerChoreoTools g_ServerChoreoTools; -EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CServerChoreoTools, IServerChoreoTools, VSERVERCHOREOTOOLS_INTERFACE_VERSION, g_ServerChoreoTools ); \ No newline at end of file diff --git a/src/src/dlls/env_projectedtexture.cpp b/src/src/dlls/env_projectedtexture.cpp deleted file mode 100644 index bb96de5..0000000 --- a/src/src/dlls/env_projectedtexture.cpp +++ /dev/null @@ -1,133 +0,0 @@ -//====== Copyright © 1996-2003, Valve Corporation, All rights reserved. ======= -// -// Purpose: Entity to control screen overlays on a player -// -//============================================================================= - -#include "cbase.h" -#include "shareddefs.h" - -// memdbgon must be the last include file in a .cpp file!!! -#include "tier0/memdbgon.h" - -#define ENV_PROJECTEDTEXTURE_STARTON (1<<0) - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -class CEnvProjectedTexture : public CPointEntity -{ - DECLARE_CLASS( CEnvProjectedTexture, CPointEntity ); -public: - DECLARE_DATADESC(); - DECLARE_SERVERCLASS(); - - CEnvProjectedTexture(); - - // Always transmit to clients - virtual int UpdateTransmitState(); - virtual void Activate( void ); - - void InputTurnOn( inputdata_t &inputdata ); - void InputTurnOff( inputdata_t &inputdata ); - void InputSetFOV( inputdata_t &inputdata ); - void InitialThink( void ); - - CNetworkHandle( CBaseEntity, m_hTargetEntity ); - -private: - - CNetworkVar( bool, m_bState ); - CNetworkVar( float, m_flLightFOV ); - CNetworkVar( bool, m_bEnableShadows ); - CNetworkVar( bool, m_bLightOnlyTarget ); - CNetworkVar( bool, m_bLightWorld ); - CNetworkVar( bool, m_bCameraSpace ); - CNetworkVar( color32, m_cLightColor ); -}; - -LINK_ENTITY_TO_CLASS( env_projectedtexture, CEnvProjectedTexture ); - -BEGIN_DATADESC( CEnvProjectedTexture ) - DEFINE_FIELD( m_hTargetEntity, FIELD_EHANDLE ), - DEFINE_FIELD( m_bState, FIELD_BOOLEAN ), - DEFINE_KEYFIELD( m_flLightFOV, FIELD_FLOAT, "lightfov" ), - DEFINE_KEYFIELD( m_bEnableShadows, FIELD_BOOLEAN, "enableshadows" ), - DEFINE_KEYFIELD( m_bLightOnlyTarget, FIELD_BOOLEAN, "lightonlytarget" ), - DEFINE_KEYFIELD( m_bLightWorld, FIELD_BOOLEAN, "lightworld" ), - DEFINE_KEYFIELD( m_bCameraSpace, FIELD_BOOLEAN, "cameraspace" ), - DEFINE_KEYFIELD( m_cLightColor, FIELD_COLOR32, "lightcolor" ), - DEFINE_INPUTFUNC( FIELD_VOID, "TurnOn", InputTurnOn ), - DEFINE_INPUTFUNC( FIELD_VOID, "TurnOff", InputTurnOff ), - DEFINE_INPUTFUNC( FIELD_FLOAT, "SetFOV", InputSetFOV ), - DEFINE_THINKFUNC( InitialThink ), -END_DATADESC() - -IMPLEMENT_SERVERCLASS_ST( CEnvProjectedTexture, DT_EnvProjectedTexture ) - SendPropEHandle( SENDINFO( m_hTargetEntity ) ), - SendPropBool( SENDINFO( m_bState ) ), - SendPropFloat( SENDINFO( m_flLightFOV ) ), - SendPropBool( SENDINFO( m_bEnableShadows ) ), - SendPropBool( SENDINFO( m_bLightOnlyTarget ) ), - SendPropBool( SENDINFO( m_bLightWorld ) ), - SendPropBool( SENDINFO( m_bCameraSpace ) ), - SendPropInt( SENDINFO( m_cLightColor ), 32, SPROP_UNSIGNED ), -END_SEND_TABLE() - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -CEnvProjectedTexture::CEnvProjectedTexture( void ) -{ - m_bState = false; - m_flLightFOV = 45.0f; - m_bEnableShadows = false; - m_bLightOnlyTarget = false; - m_bLightWorld = true; - m_bCameraSpace = true; - - color32 color; - color.r = 255; - color.g = 255; - color.b = 255; - color.a = 0; - m_cLightColor.Set( color ); -} - -void CEnvProjectedTexture::InputTurnOn( inputdata_t &inputdata ) -{ - m_bState = true; -} - -void CEnvProjectedTexture::InputTurnOff( inputdata_t &inputdata ) -{ - m_bState = false; -} - -void CEnvProjectedTexture::InputSetFOV( inputdata_t &inputdata ) -{ - m_flLightFOV = inputdata.value.Float(); -} - -void CEnvProjectedTexture::Activate( void ) -{ - if ( GetSpawnFlags() & ENV_PROJECTEDTEXTURE_STARTON ) - { - m_bState = true; - } - - SetThink( &CEnvProjectedTexture::InitialThink ); - SetNextThink( gpGlobals->curtime + 0.1f ); - - BaseClass::Activate(); -} - -void CEnvProjectedTexture::InitialThink( void ) -{ - m_hTargetEntity = gEntList.FindEntityByName( NULL, m_target ); -} - -int CEnvProjectedTexture::UpdateTransmitState() -{ - return SetTransmitState( FL_EDICT_ALWAYS ); -} diff --git a/src/src/dlls/episodic/ai_behavior_passenger_companion.cpp b/src/src/dlls/episodic/ai_behavior_passenger_companion.cpp deleted file mode 100644 index ab2c4ab..0000000 --- a/src/src/dlls/episodic/ai_behavior_passenger_companion.cpp +++ /dev/null @@ -1,1481 +0,0 @@ -//====== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======= -// -// Purpose: Companion NPCs riding in cars -// -//============================================================================= - -#include "cbase.h" -#include "ai_speech.h" -#include "ai_pathfinder.h" -#include "ai_waypoint.h" -#include "ai_navigator.h" -#include "ai_navgoaltype.h" -#include "ai_memory.h" -#include "ai_behavior_passenger_companion.h" -#include "ai_squadslot.h" -#include "npc_playercompanion.h" -#include "ai_route.h" -#include "saverestore_utlvector.h" - -#define TLK_PASSENGER_WARN_COLLISION "TLK_PASSENGER_WARN_COLLISION" -#define TLK_PASSENGER_IMPACT "TLK_PASSENGER_IMPACT" -#define TLK_PASSENGER_OVERTURNED "TLK_PASSENGER_OVERTURNED" -#define TLK_PASSENGER_REQUEST_UPRIGHT "TLK_PASSENGER_REQUEST_UPRIGHT" - -#define PASSENGER_NEAR_VEHICLE_THRESHOLD 64.0f - -#define MIN_OVERTURNED_DURATION 1.0f // seconds -#define MIN_FAILED_EXIT_ATTEMPTS 2 -#define MIN_OVERTURNED_WARN_DURATION 4.0f // seconds - -ConVar passenger_impact_response_threshold( "passenger_impact_response_threshold", "-500.0" ); -ConVar passenger_collision_response_threshold( "passenger_collision_response_threshold", "500.0" ); -extern ConVar passenger_debug_transition; - -// Custom activities -Activity ACT_PASSENGER_IDLE_AIM; -Activity ACT_PASSENGER_RELOAD; -Activity ACT_PASSENGER_OVERTURNED; -Activity ACT_PASSENGER_IMPACT; -Activity ACT_PASSENGER_IMPACT_WEAPON; -Activity ACT_PASSENGER_POINT; -Activity ACT_PASSENGER_POINT_BEHIND; -Activity ACT_PASSENGER_IDLE_READY; - -BEGIN_DATADESC( CAI_PassengerBehaviorCompanion ) - - DEFINE_EMBEDDED( m_vehicleState ), - DEFINE_EMBEDDED( m_VehicleMonitor ), - - DEFINE_UTLVECTOR( m_FailedEntryPositions, FIELD_EMBEDDED ), - - DEFINE_FIELD( m_flOverturnedDuration, FIELD_FLOAT ), - DEFINE_FIELD( m_flUnseenDuration, FIELD_FLOAT ), - DEFINE_FIELD( m_nExitAttempts, FIELD_INTEGER ), - DEFINE_FIELD( m_flNextOverturnWarning, FIELD_TIME ), - -END_DATADESC(); - -BEGIN_SIMPLE_DATADESC( FailPosition_t ) - - DEFINE_FIELD( vecPosition, FIELD_VECTOR ), - DEFINE_FIELD( flTime, FIELD_TIME ), - -END_DATADESC(); - -CAI_PassengerBehaviorCompanion::CAI_PassengerBehaviorCompanion( void ) : -m_flUnseenDuration( 0.0f ), -m_flNextOverturnWarning( 0.0f ), -m_flOverturnedDuration( 0.0f ), -m_nExitAttempts( 0 ) -{ - memset( &m_vehicleState, 0, sizeof( m_vehicleState ) ); - m_VehicleMonitor.ClearMark(); -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : activity - -// Output : int -//----------------------------------------------------------------------------- -Activity CAI_PassengerBehaviorCompanion::NPC_TranslateActivity( Activity activity ) -{ - Activity newActivity = BaseClass::NPC_TranslateActivity( activity ); - - // Handle animations from inside the vehicle - if ( GetPassengerState() == PASSENGER_STATE_INSIDE ) - { - // Make sure idles are always vehicle idles - if ( newActivity == ACT_IDLE ) - { - newActivity = (Activity) ACT_PASSENGER_IDLE; - } - - // Alter idle depending on the vehicle's state - if ( newActivity == ACT_PASSENGER_IDLE ) - { - // Always play the overturned animation - if ( m_vehicleState.m_bWasOverturned ) - return ACT_PASSENGER_OVERTURNED; - - // If we have an enemy and a gun, aim - if ( GetEnemy() != NULL && HasCondition( COND_SEE_ENEMY ) && GetOuter()->GetActiveWeapon() ) - return ACT_PASSENGER_IDLE_AIM; - - CNPC_PlayerCompanion *pCompanion = dynamic_cast(GetOuter()); - if ( pCompanion != NULL && pCompanion->GetReadinessLevel() >= AIRL_STIMULATED ) - return ACT_PASSENGER_IDLE_READY; - - } - - // Override reloads - if ( newActivity == ACT_RELOAD ) - return ACT_PASSENGER_RELOAD; - - // Override range attacks - if ( newActivity == ACT_RANGE_ATTACK1 ) - return (Activity) ACT_PASSENGER_RANGE_ATTACK1; - - // FIXME: Translation is never called for scripted events - // Do special logic in points - /* - if ( newActivity == ACT_PASSENGER_POINT ) - { - // See if this is behind us - float curYaw = GetOuter()->GetPoseParameter( "aim_yaw" ); - if ( fabs( curYaw ) > 180.0f ) - return ACT_PASSENGER_POINT_BEHIND; - } - */ - } - - return newActivity; -} - -//----------------------------------------------------------------------------- -// Purpose: Returns the speed the vehicle is moving at -// Output : units per second -//----------------------------------------------------------------------------- -float CAI_PassengerBehaviorCompanion::GetVehicleSpeed( void ) -{ - if ( m_hVehicle == NULL ) - { - Assert(0); - return -1.0f; - } - - Vector vecVelocity; - m_hVehicle->GetVelocity( &vecVelocity, NULL ); - - // Get our speed - return vecVelocity.Length(); -} - -//----------------------------------------------------------------------------- -// Purpose: Detect oncoming collisions -//----------------------------------------------------------------------------- -void CAI_PassengerBehaviorCompanion::GatherVehicleCollisionConditions( const Vector &localVelocity ) -{ - // Look for walls in front of us - if ( localVelocity.y > passenger_collision_response_threshold.GetFloat() ) - { - // Detect an upcoming collision - Vector vForward; - m_hVehicle->GetVectors( &vForward, NULL, NULL ); - - // Use a smaller bounding box to make it detect mostly head-on impacts - Vector mins, maxs; - mins.Init( -16, -16, 32 ); - maxs.Init( 16, 16, 64 ); - - // Look 3/4 a second into the future - float dt = 0.75f; - float distance = localVelocity.y * dt; - - // Trace ahead of us to see what's there - trace_t tr; - UTIL_TraceHull( m_hVehicle->GetAbsOrigin(), m_hVehicle->GetAbsOrigin() + ( vForward * distance ), mins, maxs, MASK_SOLID_BRUSHONLY, m_hVehicle, COLLISION_GROUP_NONE, &tr ); - - if ( tr.DidHit() ) - { - // We need to see how "head-on" to the surface we are - float impactDot = DotProduct( tr.plane.normal, vForward ); - - // Don't warn over grazing blows or slopes - if ( impactDot < -0.9f && tr.plane.normal.z < 0.75f ) - { - // Only warn if it's not too soon to do it again - if ( m_vehicleState.m_flNextWarningTime < gpGlobals->curtime ) - { - // TODO: Turn this into a condition so that we can interrupt other schedules - GetOuter()->GetExpresser()->Speak( TLK_PASSENGER_WARN_COLLISION ); - m_vehicleState.m_flNextWarningTime = gpGlobals->curtime + 5.0f; - } - } - } - } -} - -//----------------------------------------------------------------------------- -// Purpose: Gather conditions we can comment on or react to while riding in the vehicle -//----------------------------------------------------------------------------- -void CAI_PassengerBehaviorCompanion::GatherVehicleStateConditions( void ) -{ - if ( m_hVehicle == NULL ) - return; - - // Get the vehicle's boost state - if ( m_hVehicle->m_nBoostTimeLeft < 100.0f ) - { - if ( m_vehicleState.m_bWasBoosting == false ) - { - m_vehicleState.m_bWasBoosting = true; - } - } - else - { - m_vehicleState.m_bWasBoosting = false; - } - - Vector localVelocity; - GetLocalVehicleVelocity( &localVelocity ); - - // Get our speed - float flSpeedSqr = localVelocity.LengthSqr(); - - // See if we've crossed over the threshold between movement and... stillness - if ( m_vehicleState.m_flLastSpeed > STOPPED_VELOCITY_THRESHOLD_SQR && flSpeedSqr < STOPPED_VELOCITY_THRESHOLD_SQR ) - { - SetCondition( COND_VEHICLE_STOPPED ); - } - else - { - ClearCondition( COND_VEHICLE_STOPPED ); - } - - // Store off the speed - m_vehicleState.m_flLastSpeed = flSpeedSqr; - - // Find our delta velocity from the last frame - Vector deltaVelocity = ( localVelocity - m_vehicleState.m_vecLastLocalVelocity ); - m_vehicleState.m_vecLastLocalVelocity = localVelocity; - - // Detect a sudden stop - if ( deltaVelocity.y < passenger_impact_response_threshold.GetFloat() ) - { - SetCondition( COND_VEHICLE_HARD_IMPACT ); - GetOuter()->GetExpresser()->Speak( TLK_PASSENGER_IMPACT ); - } - - // Detect being overturned - if ( m_hVehicle->IsOverturned() ) - { - if ( m_vehicleState.m_bWasOverturned == false ) - { - SetCondition( COND_VEHICLE_OVERTURNED ); - m_vehicleState.m_bWasOverturned = true; - - if ( m_vehicleState.m_flNextWarningTime < gpGlobals->curtime ) - { - // FIXME: Delay for a bit - GetOuter()->GetExpresser()->Speak( TLK_PASSENGER_OVERTURNED ); - m_vehicleState.m_flNextWarningTime = gpGlobals->curtime + 5.0f; - } - } - } - else - { - ClearCondition( COND_VEHICLE_OVERTURNED ); - m_vehicleState.m_bWasOverturned = false; - } - - // See if we're going to collide with anything soon - GatherVehicleCollisionConditions( localVelocity ); -} - -//----------------------------------------------------------------------------- -// Purpose: Handles exit failure notifications -//----------------------------------------------------------------------------- -void CAI_PassengerBehaviorCompanion::OnExitVehicleFailed( void ) -{ - m_nExitAttempts++; -} - -//----------------------------------------------------------------------------- -// Purpose: Track how long we've been overturned -//----------------------------------------------------------------------------- -void CAI_PassengerBehaviorCompanion::UpdateStuckStatus( void ) -{ - if ( m_hVehicle == NULL ) - return; - - // Always clear this to start out with - ClearCondition( COND_CAN_LEAVE_STUCK_VEHICLE ); - - // If we can't exit the vehicle, then don't bother with these checks - if ( m_hVehicle->NPC_CanExitVehicle( GetOuter(), true ) == false ) - return; - - bool bVisibleToPlayer = false; - bool bPlayerInVehicle = false; - - CBasePlayer *pPlayer = UTIL_PlayerByIndex( 1 ); - if ( pPlayer ) - { - bVisibleToPlayer = pPlayer->FInViewCone( GetOuter()->GetAbsOrigin() ); - bPlayerInVehicle = pPlayer->IsInAVehicle(); - } - - // If we're not overturned, just reset our counter - if ( m_vehicleState.m_bWasOverturned == false ) - { - m_flOverturnedDuration = 0.0f; - m_flUnseenDuration = 0.0f; - } - else - { - // Add up the time since we last checked - m_flOverturnedDuration += ( gpGlobals->curtime - GetLastThink() ); - } - - // Warn about being stuck upside-down if it's been long enough - if ( m_flOverturnedDuration > MIN_OVERTURNED_WARN_DURATION && m_flNextOverturnWarning < gpGlobals->curtime ) - { - SetCondition( COND_WARN_OVERTURNED ); - } - - // If the player can see us or is still in the vehicle, we never exit - if ( bVisibleToPlayer || bPlayerInVehicle ) - { - // Reset our timer - m_flUnseenDuration = 0.0f; - return; - } - - // Add up the time since we last checked - m_flUnseenDuration += ( gpGlobals->curtime - GetLastThink() ); - - // If we've been overturned for long enough or tried to exit one too many times - if ( m_vehicleState.m_bWasOverturned ) - { - if ( m_flUnseenDuration > MIN_OVERTURNED_DURATION ) - { - SetCondition( COND_CAN_LEAVE_STUCK_VEHICLE ); - } - } - else if ( m_nExitAttempts >= MIN_FAILED_EXIT_ATTEMPTS ) - { - // The player can't be looking at us - SetCondition( COND_CAN_LEAVE_STUCK_VEHICLE ); - } -} - -//----------------------------------------------------------------------------- -// Purpose: Gather conditions for our use in making decisions -//----------------------------------------------------------------------------- -void CAI_PassengerBehaviorCompanion::GatherConditions( void ) -{ - // Code below relies on these conditions being set first! - BaseClass::GatherConditions(); - - // In-car conditions - if ( GetPassengerState() == PASSENGER_STATE_INSIDE ) - { - // Get info on how we're driving - GatherVehicleStateConditions(); - - // See if we're upside-down - UpdateStuckStatus(); - } - - // Make sure a vehicle doesn't stray from its mark - if ( IsCurSchedule( SCHED_PASSENGER_RUN_TO_ENTER_VEHICLE ) ) - { - if ( m_VehicleMonitor.TargetMoved( m_hVehicle ) ) - { - SetCondition( COND_VEHICLE_MOVED_FROM_MARK ); - } - } -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CAI_PassengerBehaviorCompanion::AimGun( void ) -{ - // Aim at enemies we may have - if ( GetEnemy() && HasCondition( COND_SEE_ENEMY ) ) - { - Vector vecShootOrigin = GetOuter()->Weapon_ShootPosition(); - Vector vecShootDir = GetOuter()->GetShootEnemyDir( vecShootOrigin, false ); - - //NDebugOverlay::Cross3D( vecShootOrigin, 32, 255, 0, 0, true, 0.5f ); - //NDebugOverlay::Line( vecShootOrigin, vecShootOrigin + ( vecShootDir * 128 ), 255, 0, 0, true, 0.5f ); - - GetOuter()->SetAim( vecShootDir ); - } - else - { - // Stop aiming - GetOuter()->RelaxAim(); - } -} - -//----------------------------------------------------------------------------- -// Purpose: Select schedules when we're riding in the car -//----------------------------------------------------------------------------- -int CAI_PassengerBehaviorCompanion::SelectScheduleInsideVehicle( void ) -{ - // Overturned - if ( HasCondition( COND_VEHICLE_OVERTURNED ) ) - return SCHED_PASSENGER_OVERTURNED; - - if ( HasCondition( COND_VEHICLE_HARD_IMPACT ) ) - return SCHED_PASSENGER_IMPACT; - - // Look for exiting the vehicle - if ( HasCondition( COND_CAN_LEAVE_STUCK_VEHICLE ) ) - return SCHED_PASSENGER_EXIT_STUCK_VEHICLE; - - // Fire on targets - if ( GetEnemy() ) - { - // Always face - GetOuter()->AddLookTarget( GetEnemy(), 1.0f, 2.0f ); - - if ( HasCondition( COND_CAN_RANGE_ATTACK1 ) && ( GetOuter()->GetShotRegulator()->IsInRestInterval() == false ) ) - return SCHED_PASSENGER_RANGE_ATTACK1; - } - - // Say an overturned line - if ( HasCondition( COND_WARN_OVERTURNED ) ) - { - GetOuter()->GetExpresser()->Speak( TLK_PASSENGER_REQUEST_UPRIGHT ); - m_flNextOverturnWarning = gpGlobals->curtime + random->RandomFloat( 5.0f, 10.0f ); - ClearCondition( COND_WARN_OVERTURNED ); - } - - return SCHED_NONE; -} - -//----------------------------------------------------------------------------- -// Purpose: Select schedules while we're outisde the car -//----------------------------------------------------------------------------- -int CAI_PassengerBehaviorCompanion::SelectScheduleOutsideVehicle( void ) -{ - // Reset our mark - m_VehicleMonitor.SetMark( m_hVehicle, 8.0f ); - - // Wait if the vehicle is moving - if ( ( GetVehicleSpeed() > STOPPED_VELOCITY_THRESHOLD ) || m_hVehicle->IsOverturned() ) - { - GetOuter()->SetTarget( m_hVehicle ); - return SCHED_PASSENGER_RUN_TO_ENTER_VEHICLE_FAILED; - } - - // If we intend to enter, run to the vehicle - if ( m_PassengerIntent == PASSENGER_INTENT_ENTER ) - return SCHED_PASSENGER_RUN_TO_ENTER_VEHICLE; - - return SCHED_NONE; -} - -//----------------------------------------------------------------------------- -// Purpose: Overrides the schedule selection -// Output : int - Schedule to play -//----------------------------------------------------------------------------- -int CAI_PassengerBehaviorCompanion::SelectSchedule( void ) -{ - // Entering schedule - if ( HasCondition( COND_ENTERING_VEHICLE ) ) - { - ClearCondition( COND_ENTERING_VEHICLE ); - return SCHED_PASSENGER_RUN_TO_ENTER_VEHICLE; - } - - // Handle schedules based on our passenger state - if ( GetPassengerState() == PASSENGER_STATE_OUTSIDE ) - { - int nSched = SelectScheduleOutsideVehicle(); - if ( nSched != SCHED_NONE ) - return nSched; - } - else if ( GetPassengerState() == PASSENGER_STATE_INSIDE ) - { - int nSched = SelectScheduleInsideVehicle(); - if ( nSched != SCHED_NONE ) - return nSched; - } - - return BaseClass::SelectSchedule(); -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -int CAI_PassengerBehaviorCompanion::SelectFailSchedule( int failedSchedule, int failedTask, AI_TaskFailureCode_t taskFailCode ) -{ - switch( failedTask ) - { - case TASK_GET_PATH_TO_VEHICLE_ENTRY_POINT: - { - // If we're not close enough, then get nearer the target - if ( UTIL_DistApprox( m_hVehicle->GetAbsOrigin(), GetOuter()->GetAbsOrigin() ) > PASSENGER_NEAR_VEHICLE_THRESHOLD ) - return SCHED_PASSENGER_RUN_TO_ENTER_VEHICLE_FAILED; - - // Stand around and wait for something to open up - GetOuter()->SetTarget( m_hVehicle ); - - return SCHED_PASSENGER_ENTER_VEHICLE_PAUSE; - } - break; - - case TASK_GET_PATH_TO_NEAR_VEHICLE: - return SCHED_PASSENGER_ENTER_VEHICLE_PAUSE; - break; - } - - return BaseClass::SelectFailSchedule( failedSchedule, failedTask, taskFailCode ); -} - -//----------------------------------------------------------------------------- -// Purpose: Start to enter the vehicle -//----------------------------------------------------------------------------- -void CAI_PassengerBehaviorCompanion::EnterVehicle( void ) -{ - BaseClass::EnterVehicle(); - - m_nExitAttempts = 0; - m_VehicleMonitor.SetMark( m_hVehicle, 8.0f ); - - // Remove this flag because we're sitting so close we always think we're going to hit the player - // FIXME: We need to store this state so we don't incorrectly restore it later - GetOuter()->CapabilitiesRemove( bits_CAP_NO_HIT_PLAYER ); - - // Discard enemies quickly - GetOuter()->GetEnemies()->SetEnemyDiscardTime( 2.0f ); -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CAI_PassengerBehaviorCompanion::FinishEnterVehicle( void ) -{ - BaseClass::FinishEnterVehicle(); - - // We succeeded - ResetVehicleEntryFailedState(); -} - -//----------------------------------------------------------------------------- -// Purpose: Vehicle has been completely exited -//----------------------------------------------------------------------------- -void CAI_PassengerBehaviorCompanion::FinishExitVehicle( void ) -{ - BaseClass::FinishExitVehicle(); - - m_nExitAttempts = 0; - m_VehicleMonitor.ClearMark(); - - // FIXME: We need to store this state so we don't incorrectly restore it later - GetOuter()->CapabilitiesAdd( bits_CAP_NO_HIT_PLAYER ); - - // FIXME: Restore this properly - GetOuter()->GetEnemies()->SetEnemyDiscardTime( AI_DEF_ENEMY_DISCARD_TIME ); -} - -//----------------------------------------------------------------------------- -// Purpose: Tries to build a route to the entry point of the target vehicle. -// Output : Returns true on success, false on failure. -//----------------------------------------------------------------------------- -bool CAI_PassengerBehaviorCompanion::FindPathToVehicleEntryPoint( void ) -{ - // Set our custom move name - bool bFindNearest = ( GetOuter()->m_NPCState == NPC_STATE_COMBAT || GetOuter()->m_NPCState == NPC_STATE_ALERT ); - int nSequence = FindEntrySequence( bFindNearest ); - if ( nSequence == -1 ) - return false; - - // We have to do this specially because the activities are not named - SetTransitionSequence( nSequence ); - - // Get the entry position - Vector vecEntryPoint; - QAngle vecEntryAngles; - GetEntryPoint( m_nTransitionSequence, &vecEntryPoint, &vecEntryAngles ); - - // Find the actual point on the ground to base our pathfinding on - Vector vecActualPoint; - if ( FindGroundAtPosition( vecEntryPoint, 16, 64, &vecActualPoint ) == false ) - { - MarkVehicleEntryFailed( vecEntryPoint ); - return false; - } - - // If we're already close enough, just succeed - float flDistToGoal = ( GetOuter()->GetAbsOrigin() - vecActualPoint ).Length(); - if ( flDistToGoal < 8 ) - return true; - - // Setup our goal - AI_NavGoal_t goal( GOALTYPE_LOCATION ); - goal.arrivalActivity = ACT_SCRIPT_CUSTOM_MOVE; - goal.dest = vecActualPoint; - - // Try and set a direct route - if ( GetOuter()->GetNavigator()->SetGoal( goal ) ) - { - GetOuter()->GetNavigator()->SetArrivalDirection( vecEntryAngles ); - //GetOuter()->GetNavigator()->SetArrivalActivity( ACT_SCRIPT_CUSTOM_MOVE ); - //GetOuter()->GetNavigator()->SetArrivalSpeed( 64 ); - - return true; - } - - // We failed, so remember it - MarkVehicleEntryFailed( vecEntryPoint ); - return false; -} - -//----------------------------------------------------------------------------- -// Purpose: Tests the route and position to see if it's valid -// Input : &vecTestPos - position to test -// Output : Returns true on success, false on failure. -//----------------------------------------------------------------------------- -bool CAI_PassengerBehaviorCompanion::CanExitAtPosition( const Vector &vecTestPos ) -{ - CBasePlayer *pPlayer = UTIL_PlayerByIndex( 1 ); - if ( pPlayer == NULL ) - return false; - - // Can't be in our potential view - if ( pPlayer->FInViewCone( vecTestPos ) ) - return false; - - // Check to see if that path is clear and valid - return IsValidTransitionPoint( GetOuter()->WorldSpaceCenter(), vecTestPos ); -} - -#define NUM_EXIT_ITERATIONS 8 - -//----------------------------------------------------------------------------- -// Purpose: Find a position we can use to exit the vehicle via teleportation -// Input : *vecResult - safe place to exit to -// Output : Returns true on success, false on failure. -//----------------------------------------------------------------------------- -bool CAI_PassengerBehaviorCompanion::GetStuckExitPos( Vector *vecResult ) -{ - // Get our right direction - Vector vecVehicleRight; - m_hVehicle->GetVectors( NULL, &vecVehicleRight, NULL ); - - // Get the vehicle's rough horizontal bounds - float flVehicleRadius = m_hVehicle->CollisionProp()->BoundingRadius2D(); - - // Use the vehicle's center as our hub - Vector vecCenter = m_hVehicle->WorldSpaceCenter(); - - // Angle whose tan is: y/x - float flCurAngle = atan2f( vecVehicleRight.y, vecVehicleRight.x ); - float flAngleIncr = (M_PI*2.0f)/(float)NUM_EXIT_ITERATIONS; - Vector vecTestPos; - - // Test a number of discrete exit routes - for ( int i = 0; i <= NUM_EXIT_ITERATIONS-1; i++ ) - { - // Get our position - SinCos( flCurAngle, &vecTestPos.y, &vecTestPos.x ); - vecTestPos.z = 0.0f; - vecTestPos *= flVehicleRadius; - vecTestPos += vecCenter; - - // Test the position - if ( CanExitAtPosition( vecTestPos ) ) - { - // Take the result - *vecResult = vecTestPos; - return true; - } - - // Move to the next iteration - flCurAngle += flAngleIncr; - } - - // None found - return false; -} - -//----------------------------------------------------------------------------- -// Purpose: Attempt to get out of an overturned vehicle when the player isn't looking -// Output : Returns true on success, false on failure. -//----------------------------------------------------------------------------- -bool CAI_PassengerBehaviorCompanion::ExitStuckVehicle( void ) -{ - // Try and find an exit position - Vector vecExitPos; - if ( GetStuckExitPos( &vecExitPos ) == false ) - return false; - - // Detach from the parent - GetOuter()->SetParent( NULL ); - - // Do all necessary clean-up - FinishExitVehicle(); - - // Teleport to the destination - // TODO: Make sure that the player can't see this! - GetOuter()->Teleport( &vecExitPos, &vec3_angle, &vec3_origin ); - - return true; -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CAI_PassengerBehaviorCompanion::StartTask( const Task_t *pTask ) -{ - // We need to override these so we never face - if ( GetPassengerState() == PASSENGER_STATE_INSIDE ) - { - if ( pTask->iTask == TASK_FACE_TARGET || - pTask->iTask == TASK_FACE_ENEMY || - pTask->iTask == TASK_FACE_IDEAL || - pTask->iTask == TASK_FACE_HINTNODE || - pTask->iTask == TASK_FACE_LASTPOSITION || - pTask->iTask == TASK_FACE_PATH || - pTask->iTask == TASK_FACE_PLAYER || - pTask->iTask == TASK_FACE_REASONABLE || - pTask->iTask == TASK_FACE_SAVEPOSITION || - pTask->iTask == TASK_FACE_SCRIPT ) - { - return TaskComplete(); - } - } - - switch ( pTask->iTask ) - { - case TASK_GET_PATH_TO_VEHICLE_ENTRY_POINT: - { - // Reserve an entry point - if ( ReserveEntryPoint( VEHICLE_SEAT_ANY ) == false ) - { - TaskFail( "No valid entry point!\n" ); - return; - } - - // Find where we're going - if ( FindPathToVehicleEntryPoint() ) - { - TaskComplete(); - return; - } - - // We didn't find a path - TaskFail( "TASK_GET_PATH_TO_VEHICLE_ENTRY_POINT: Unable to run to entry point" ); - } - break; - - case TASK_GET_PATH_TO_TARGET: - { - GetOuter()->SetTarget( m_hVehicle ); - BaseClass::StartTask( pTask ); - } - break; - - case TASK_GET_PATH_TO_NEAR_VEHICLE: - { - // Find the passenger offset we're going for - Vector vecRight; - m_hVehicle->GetVectors( NULL, &vecRight, NULL ); - Vector vecTargetOffset = vecRight * 64.0f; - - // Try and find a path near there - AI_NavGoal_t goal( GOALTYPE_TARGETENT, vecTargetOffset, AIN_DEF_ACTIVITY, 64.0f, AIN_UPDATE_TARGET_POS, m_hVehicle ); - GetOuter()->SetTarget( m_hVehicle ); - if ( GetOuter()->GetNavigator()->SetGoal( goal ) ) - { - TaskComplete(); - return; - } - - TaskFail( "Unable to find path to get closer to vehicle!\n" ); - return; - } - - break; - - case TASK_PASSENGER_RELOAD: - { - GetOuter()->SetIdealActivity( ACT_PASSENGER_RELOAD ); - return; - } - break; - - case TASK_PASSENGER_EXIT_STUCK_VEHICLE: - { - if ( ExitStuckVehicle() ) - { - TaskComplete(); - return; - } - - TaskFail("Unable to exit overturned vehicle!\n"); - } - break; - - case TASK_PASSENGER_OVERTURNED: - { - // Go into our overturned animation - if ( GetOuter()->GetIdealActivity() != ACT_PASSENGER_OVERTURNED ) - { - GetOuter()->SetIdealActivity( ACT_PASSENGER_OVERTURNED ); - } - - TaskComplete(); - } - break; - - case TASK_PASSENGER_IMPACT: - { - // Go into our impact animation - GetOuter()->ResetIdealActivity( ACT_PASSENGER_IMPACT ); - - // Delay for twice the duration of our impact animation - int nSequence = GetOuter()->SelectWeightedSequence( ACT_PASSENGER_IMPACT ); - GetOuter()->SetNextAttack( gpGlobals->curtime + (GetOuter()->SequenceDuration( nSequence ) * 2.0f ) ); - } - break; - - default: - BaseClass::StartTask( pTask ); - break; - } -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CAI_PassengerBehaviorCompanion::RunTask( const Task_t *pTask ) -{ - switch ( pTask->iTask ) - { - case TASK_PASSENGER_RELOAD: - { - if ( GetOuter()->IsSequenceFinished() ) - { - TaskComplete(); - } - } - break; - - case TASK_PASSENGER_IMPACT: - { - if ( GetOuter()->IsSequenceFinished() ) - { - TaskComplete(); - return; - } - } - break; - - default: - BaseClass::RunTask( pTask ); - break; - } -} - -//----------------------------------------------------------------------------- -// Purpose: Add custom interrupt conditions -//----------------------------------------------------------------------------- -void CAI_PassengerBehaviorCompanion::BuildScheduleTestBits( void ) -{ - // Always break on being able to exit - if ( GetPassengerState() == PASSENGER_STATE_INSIDE ) - { - GetOuter()->SetCustomInterruptCondition( GetClassScheduleIdSpace()->ConditionLocalToGlobal( COND_CAN_LEAVE_STUCK_VEHICLE ) ); - GetOuter()->SetCustomInterruptCondition( GetClassScheduleIdSpace()->ConditionLocalToGlobal( COND_VEHICLE_HARD_IMPACT) ); - - if ( GetOuter()->IsCurSchedule( SCHED_PASSENGER_OVERTURNED ) == false ) - { - GetOuter()->SetCustomInterruptCondition( GetClassScheduleIdSpace()->ConditionLocalToGlobal( COND_VEHICLE_OVERTURNED ) ); - } - } - - BaseClass::BuildScheduleTestBits(); -} - -//----------------------------------------------------------------------------- -// Purpose: Attempt to build a local route to a goal and append it to the chain (if it exists) -// Input : &vecStart - Path's starting position -// &vecEnd - Path's ending position -// **pWaypoints - pointer to a waypoint list to append the data to -// Output : Returns true on success, false on failure. -//----------------------------------------------------------------------------- -bool CAI_PassengerBehaviorCompanion::AppendLocalPath( const Vector &vecStart, const Vector &vecEnd, AI_Waypoint_t **pWaypoints ) -{ - // Find the next waypoint to use - AI_Waypoint_t *pNextRoute = GetOuter()->GetPathfinder()->BuildLocalRoute( vecStart, vecEnd, NULL, 0, NO_NODE, bits_BUILD_GROUND, 8.0f ); - if ( pNextRoute == NULL ) - return false; - - // We cannot simply our route - pNextRoute->ModifyFlags( bits_WP_DONT_SIMPLIFY, true ); - - // Start the list - if ( (*pWaypoints) == NULL ) - { - *pWaypoints = pNextRoute; - } - else - { - // Concat the list - AddWaypointLists( (*pWaypoints), pNextRoute ); - } - - return true; -} - -//----------------------------------------------------------------------------- -// Purpose: Find the "quadrant" in which we're aligned around an entity -// Input : &vecPos - position to test -// *pCenter - Center entity (facing and origin used) -// Output : top-left = 0, bottom-left = 1, bottom-right = 2, top-right = 3 (winding counter-clockwise) -//----------------------------------------------------------------------------- -inline int FindQuadrantForPosition( const Vector &vecPos, CBaseEntity *pCenterEnt ) -{ - // Find the direction to our goal entity - Vector vecPosToGoalDir = ( pCenterEnt->GetAbsOrigin() - vecPos ); - vecPosToGoalDir.z = 0.0f; - VectorNormalize( vecPosToGoalDir ); - - // Get our goal entity's facing - Vector vecForward, vecRight; - pCenterEnt->GetVectors( &vecForward, &vecRight, NULL ); - - // Find in what "quadrant" the target is in - float flForwardDot = DotProduct( vecForward, vecPosToGoalDir ); - float flRightDot = DotProduct( vecRight, vecPosToGoalDir ); - - int nQuadrant; - if ( flForwardDot < 0.0f ) - { - // Top right / left - nQuadrant = ( flRightDot < 0.0f ) ? 3 : 0; - } - else - { - // Bottom right / left - nQuadrant = ( flRightDot < 0.0f ) ? 2 : 1; - } - - return nQuadrant; -} - -//----------------------------------------------------------------------------- -// Purpose: Get the next node (with wrapping) around a circularly wound path -// Input : nLastNode - The starting node -// nDirection - Direction we're moving -// nNumNodes - Total nodes in the chain -//----------------------------------------------------------------------------- -inline int GetNextNode( int nLastNode, int nDirection, int nNumNodes ) -{ - // FIXME: Account for non-singular steps - - int nNextNode = nLastNode + nDirection; - if ( nNextNode > (nNumNodes-1) ) - nNextNode = 0; - else if ( nNextNode < 0 ) - nNextNode = (nNumNodes-1); - - return nNextNode; -} - -//----------------------------------------------------------------------------- -// Purpose: Attempts to construct a local path given a set of nodes and criteria -// Input : *vecPositions - positions of the nodes to use -// nNumNodes - number of nodes supplied -// nDirection - direction in which to traverse the node list -// Output : Returns the path constructed, NULL if none could be made -//----------------------------------------------------------------------------- -AI_Waypoint_t *CAI_PassengerBehaviorCompanion::BuildNodeRouteAroundVehicle( const VehicleAvoidParams_t &avoidParams ) -{ - // DEBUG - /* - for ( int i = 0; i < avoidParams.nNumNodes; i++ ) - { - if ( i == avoidParams.nStartNode ) - { - NDebugOverlay::Box( avoidParams.pNodePositions[i], -Vector(14,14,14), Vector(14,14,14), 0, 255, 0, true, 1.0f ); - } - else if ( i == avoidParams.nEndNode ) - { - NDebugOverlay::Box( avoidParams.pNodePositions[i], -Vector(14,14,14), Vector(14,14,14), 0, 0, 255, true, 1.0f ); - } - else - { - NDebugOverlay::Box( avoidParams.pNodePositions[i], -Vector(14,14,14), Vector(14,14,14), 255, 0, 0, true, 1.0f ); - } - } - */ - // END DEBUG - - // Get the next node along the path - int nNextNode = GetNextNode( avoidParams.nStartNode, avoidParams.nDirection, avoidParams.nNumNodes ); - - // NDebugOverlay::Cross3D( avoidParams.pNodePositions[nNextNode], 32.0f, 255, 0, 0, true, 2.0f ); - - // If we're not moving directly to the goal, see if we're already along the path - if ( nNextNode != avoidParams.nEndNode ) - { - // Find the direction between us and our first node - Vector vecStartDir = ( GetOuter()->GetAbsOrigin() - avoidParams.pNodePositions[avoidParams.nStartNode] ); - VectorNormalize( vecStartDir ); - - // Find the direction of the next leg of the path - Vector vecPathDir = ( avoidParams.pNodePositions[avoidParams.nStartNode] - avoidParams.pNodePositions[nNextNode] ); - VectorNormalize( vecPathDir ); - - // We're closer to the next node on our path, just go there! - if ( DotProduct( vecStartDir, vecPathDir ) < 0.0f ) - { - // Validate that we have a clear shot to it - trace_t tr; - UTIL_TraceHull( GetOuter()->GetAbsOrigin(), avoidParams.pNodePositions[nNextNode], GetOuter()->GetHullMins(), GetOuter()->GetHullMaxs(), MASK_NPCSOLID, GetOuter(), COLLISION_GROUP_VEHICLE, &tr ); - if ( tr.fraction < 1.0f ) - { - // Nope, run to our start - nNextNode = avoidParams.nStartNode; - - //NDebugOverlay::HorzArrow( GetOuter()->GetAbsOrigin(), avoidParams.pNodePositions[nNextNode], 4, 255, 0, 0, 128, true, 2.0f ); - } - /*else - { - NDebugOverlay::HorzArrow( GetOuter()->GetAbsOrigin(), avoidParams.pNodePositions[nNextNode], 4, 0, 255, 0, 128, true, 2.0f ); - }*/ - } - } - - AI_Waypoint_t *pHeadRoute = NULL; - - // Attempt to path to our next node (skipping the first if possible) - if ( AppendLocalPath( avoidParams.vecStartPos, avoidParams.pNodePositions[nNextNode], &pHeadRoute ) == false ) - { - //NDebugOverlay::HorzArrow( avoidParams.vecStartPos, avoidParams.pNodePositions[nNextNode], 32, 255, 0, 0, 128, true, 2.0f ); - - // Failing that, just run to our start position - nNextNode = avoidParams.nStartNode; - if ( AppendLocalPath( avoidParams.vecStartPos, avoidParams.pNodePositions[nNextNode], &pHeadRoute ) == false ) - { - //NDebugOverlay::HorzArrow( avoidParams.vecStartPos, avoidParams.pNodePositions[nNextNode], 32, 255, 0, 0, 128, true, 2.0f ); - return false; - } - } - - // Now walk the path and keep adding point on until we're finished - int nLastNode = 0; - int nSteps = 0; - while ( nSteps < avoidParams.nNumNodes ) - { - // Move the node ahead - nLastNode = nNextNode; - nNextNode = GetNextNode( nNextNode, avoidParams.nDirection, avoidParams.nNumNodes ); - - // Try the next leg of the path - if ( AppendLocalPath( avoidParams.pNodePositions[nLastNode], avoidParams.pNodePositions[nNextNode], &pHeadRoute ) == false ) - { - //NDebugOverlay::HorzArrow( avoidParams.pNodePositions[nLastNode], avoidParams.pNodePositions[nNextNode], 16, 255, 0, 0, 128, true, 2.0f ); - return NULL; - } - - // See if we're at the final node (finished if we are) - if ( nNextNode == avoidParams.nEndNode ) - return pHeadRoute; - - //NDebugOverlay::HorzArrow( avoidParams.pNodePositions[nLastNode], avoidParams.pNodePositions[nNextNode], 16, 0, 255, 0, 128, true, 2.0f ); - - // Increment the counter - nSteps++; - } - - // No path found! - return NULL; -} - -//----------------------------------------------------------------------------- -// Purpose: Quickly walk a circular path to find the winding that's shortest -// Input : *pParams - avoid params -//----------------------------------------------------------------------------- -inline void FindShortestDirectionToNode( VehicleAvoidParams_t *pParams ) -{ - int nNextNode = GetNextNode( pParams->nStartNode, 1, pParams->nNumNodes ); - int nDistance = 1; - - // Try going counter-clockwise - for ( int i = 0; i < pParams->nNumNodes; i++ ) - { - if ( nNextNode == pParams->nEndNode ) - break; - - nNextNode = GetNextNode( nNextNode, 1, pParams->nNumNodes ); - nDistance++; - } - - nNextNode = GetNextNode( pParams->nStartNode, -1, pParams->nNumNodes ); - - // Now go the other way and see if it's shorter to do so - for ( int i = 0; i < nDistance; i++ ) - { - if ( nNextNode == pParams->nEndNode ) - { - pParams->nDirection = -1; - return; - } - - nNextNode = GetNextNode( nNextNode, -1, pParams->nNumNodes ); - } - - pParams->nDirection = 1; -} - -//----------------------------------------------------------------------------- -// Purpose: Try to build a route around a blocking vehicle (lest we bump into it dumbly) -// Output : Returns true if a path was built successfully -//----------------------------------------------------------------------------- -bool CAI_PassengerBehaviorCompanion::BuildVehicleAvoidancePath( CBaseEntity *pVehicle, const Vector &vecMoveDir ) -{ - // Get our local OBB and inflate it by our hull size - Vector vecLocalMins = pVehicle->CollisionProp()->OBBMins(); - Vector vecLocalMaxs = pVehicle->CollisionProp()->OBBMaxs(); - - // FIXME: For some reason the OBB is crazy-big! - // FIXME: Shrink the OBB for giggles - vecLocalMins[0] += GetOuter()->GetHullWidth()*0.5f; - vecLocalMins[1] += GetOuter()->GetHullWidth()*0.5f; - - vecLocalMaxs[0] -= GetOuter()->GetHullWidth()*0.5f; - vecLocalMaxs[1] -= GetOuter()->GetHullWidth()*0.5f; - - vecLocalMins[2] = 0.0f; - vecLocalMaxs[2] = 0.0f; - - // Get the four corners in worldspace as our points of circumnavigation - Vector vecNodes[4]; - Vector vecScratch; - matrix3x4_t matColToWorld = pVehicle->CollisionProp()->CollisionToWorldTransform(); - - vecScratch.z = 0.0f; - - // Top left - vecScratch.x = vecLocalMins.x; - vecScratch.y = vecLocalMaxs.y; - VectorTransform( vecScratch, matColToWorld, vecNodes[0] ); - - // Bottom left - vecScratch.x = vecLocalMins.x; - vecScratch.y = vecLocalMins.y; - VectorTransform( vecScratch, matColToWorld, vecNodes[1] ); - - // Bottom right - vecScratch.x = vecLocalMaxs.x; - vecScratch.y = vecLocalMins.y; - VectorTransform( vecScratch, matColToWorld, vecNodes[2] ); - - // Top right - vecScratch.x = vecLocalMaxs.x; - vecScratch.y = vecLocalMaxs.y; - VectorTransform( vecScratch, matColToWorld, vecNodes[3] ); - - VehicleAvoidParams_t avoidParams; - - // Get the quadrants we're moving between - avoidParams.nStartNode = FindQuadrantForPosition( GetOuter()->GetAbsOrigin(), pVehicle ); - avoidParams.nEndNode = FindQuadrantForPosition( GetOuter()->GetNavigator()->GetPath()->ActualGoalPosition(), pVehicle ); - - // If we're moving within the same quadrant, we've got no path - if ( avoidParams.nStartNode == avoidParams.nEndNode ) - return false; - - // Get the direction of traversal for the array ( 1 = counter-clockwise ) - avoidParams.pNodePositions = vecNodes; - avoidParams.nNumNodes = ARRAYSIZE( vecNodes ); - - // Specify the points in space we're coming from and going to - avoidParams.vecStartPos = GetOuter()->GetAbsOrigin(); - avoidParams.vecGoalPos = GetOuter()->GetNavigator()->GetPath()->ActualGoalPosition(); - - // Find our shortest path to the node in question - FindShortestDirectionToNode( &avoidParams ); - - // Try and build a route around the vehicle - AI_Waypoint_t *pAvoidRoute = BuildNodeRouteAroundVehicle( avoidParams ); - if ( pAvoidRoute == NULL ) - { - // Try the opposite direction - avoidParams.nDirection = -avoidParams.nDirection; - pAvoidRoute = BuildNodeRouteAroundVehicle( avoidParams ); - if ( pAvoidRoute == NULL ) - return false; - } - - // Splice this into our current node path - GetOuter()->GetNavigator()->GetPath()->PrependWaypoints( pAvoidRoute ); - GetOuter()->GetNavigator()->SimplifyPath(); - return true; -} - -//----------------------------------------------------------------------------- -// Purpose: Removes all failed points -//----------------------------------------------------------------------------- -void CAI_PassengerBehaviorCompanion::ResetVehicleEntryFailedState( void ) -{ - m_FailedEntryPositions.RemoveAll(); -} - -//----------------------------------------------------------------------------- -// Purpose: Adds a failed position to the list and marks when it occured -// Input : &vecPosition - Position that failed -//----------------------------------------------------------------------------- -void CAI_PassengerBehaviorCompanion::MarkVehicleEntryFailed( const Vector &vecPosition ) -{ - FailPosition_t failPos; - failPos.flTime = gpGlobals->curtime; - failPos.vecPosition = vecPosition; - m_FailedEntryPositions.AddToTail( failPos ); -} - -//----------------------------------------------------------------------------- -// Purpose: See if a vector is near enough to a previously failed position -// Input : &vecPosition - position to test -// Output : Returns true if the point is near enough another to be considered equivalent -//----------------------------------------------------------------------------- -bool CAI_PassengerBehaviorCompanion::PointIsWithinEntryFailureRadius( const Vector &vecPosition ) -{ - // Test this point against our known failed points and reject it if it's too near - for ( int i = 0; i < m_FailedEntryPositions.Count(); i++ ) - { - if ( ( vecPosition - m_FailedEntryPositions[i].vecPosition ).LengthSqr() < (32.0f*32.0f) ) - return true; - } - - return false; -} - -//----------------------------------------------------------------------------- -// Purpose: -// Output : Returns true on success, false on failure. -//----------------------------------------------------------------------------- -bool CAI_PassengerBehaviorCompanion::OnCalcBaseMove( AILocalMoveGoal_t *pMoveGoal, float distClear, AIMoveResult_t *pResult ) -{ - // If we've hit something we need to see what it might be - if ( pMoveGoal->bHasTraced && pMoveGoal->directTrace.pObstruction != NULL ) - { - // See if we're a buggy - CPropJeepEpisodic *pBuggy = dynamic_cast(pMoveGoal->directTrace.pObstruction); - if ( pBuggy != NULL ) - { - IServerVehicle *pServerVehicle = pBuggy->GetServerVehicle(); - if ( pServerVehicle != NULL ) - { - Vector vecGoalPos = GetNavigator()->GetPath()->ActualGoalPosition(); - float flGoalDist = ( GetAbsOrigin() - vecGoalPos ).Length(); - if ( flGoalDist > distClear ) - { - bool bSucceeded = BuildVehicleAvoidancePath( pServerVehicle->GetVehicleEnt(), pMoveGoal->target ); - if ( bSucceeded ) - { - ResetVehicleEntryFailedState(); - return true; - } - - // Mark this point as having failed, so try a new entrance when we re-tried - MarkVehicleEntryFailed( GetNavigator()->GetPath()->ActualGoalPosition() ); - return false; - } - } - } - } - - return BaseClass::OnCalcBaseMove( pMoveGoal, distClear, pResult ); -} - -//----------------------------------------------------------------------------- -// Purpose: Find the proper sequence to use (weighted by priority or distance from current position) -// to enter the vehicle. -// Input : bNearest - Use distance as the criteria for a "best" sequence. Otherwise the order of the -// seats is their priority. -// Output : int - sequence index -//----------------------------------------------------------------------------- -int CAI_PassengerBehaviorCompanion::FindEntrySequence( bool bNearest /*= false*/ ) -{ - // Get a list of all our animations - const PassengerSeatAnims_t *pEntryAnims = m_hVehicle->GetServerVehicle()->NPC_GetPassengerSeatAnims( GetOuter(), PASSENGER_SEAT_ENTRY ); - if ( pEntryAnims == NULL ) - return -1; - - // Get the ultimate position we'll end up at - Vector vecStartPos, vecEndPos; - if ( m_hVehicle->GetServerVehicle()->NPC_GetPassengerSeatPosition( GetOuter(), &vecEndPos, NULL ) == false ) - return -1; - - const CPassengerSeatTransition *pTransition; - Vector vecSeatDir; - float flNearestDist = 99999999999.9f; - float flSeatDist; - int nNearestSequence = -1; - int nSequence; - - // Test each animation (sorted by priority) for the best match - for ( int i = 0; i < pEntryAnims->Count(); i++ ) - { - // Find the activity for this animation name - pTransition = &pEntryAnims->Element(i); - nSequence = GetOuter()->LookupSequence( STRING( pTransition->GetAnimationName() ) ); - if ( nSequence == -1 ) - continue; - - // Test this entry for validity - GetEntryPoint( nSequence, &vecStartPos ); - - // See if this entry position is in our list of known unreachable places - if ( PointIsWithinEntryFailureRadius( vecStartPos ) ) - continue; - - // Check to see if we can use this - if ( IsValidTransitionPoint( vecStartPos, vecEndPos ) ) - { - // If we're just looking for the first, we're done - if ( bNearest == false ) - return nSequence; - - // Otherwise distance is the deciding factor - vecSeatDir = ( vecStartPos - GetOuter()->GetAbsOrigin() ); - flSeatDist = VectorNormalize( vecSeatDir ); - - // Closer, take it - if ( flSeatDist < flNearestDist ) - { - flNearestDist = flSeatDist; - nNearestSequence = nSequence; - } - } - - } - - return nNearestSequence; -} - -AI_BEGIN_CUSTOM_SCHEDULE_PROVIDER( CAI_PassengerBehaviorCompanion ) -{ - DECLARE_ACTIVITY( ACT_PASSENGER_IDLE_AIM ) - DECLARE_ACTIVITY( ACT_PASSENGER_RELOAD ) - DECLARE_ACTIVITY( ACT_PASSENGER_OVERTURNED ) - DECLARE_ACTIVITY( ACT_PASSENGER_IMPACT ) - DECLARE_ACTIVITY( ACT_PASSENGER_IMPACT_WEAPON ) - DECLARE_ACTIVITY( ACT_PASSENGER_POINT ) - DECLARE_ACTIVITY( ACT_PASSENGER_POINT_BEHIND ) - DECLARE_ACTIVITY( ACT_PASSENGER_IDLE_READY ) - - DECLARE_TASK( TASK_GET_PATH_TO_VEHICLE_ENTRY_POINT ) - DECLARE_TASK( TASK_GET_PATH_TO_NEAR_VEHICLE ) - DECLARE_TASK( TASK_PASSENGER_RELOAD ) - DECLARE_TASK( TASK_PASSENGER_EXIT_STUCK_VEHICLE ) - DECLARE_TASK( TASK_PASSENGER_OVERTURNED ) - DECLARE_TASK( TASK_PASSENGER_IMPACT ) - - DECLARE_CONDITION( COND_HARD_IMPACT ) - DECLARE_CONDITION( COND_VEHICLE_MOVED_FROM_MARK ) - DECLARE_CONDITION( COND_VEHICLE_STOPPED ) - DECLARE_CONDITION( COND_CAN_LEAVE_STUCK_VEHICLE ) - DECLARE_CONDITION( COND_WARN_OVERTURNED ) - - DEFINE_SCHEDULE - ( - SCHED_PASSENGER_RUN_TO_ENTER_VEHICLE, - - " Tasks" - " TASK_STOP_MOVING 0" - " TASK_SET_TOLERANCE_DISTANCE 4" - " TASK_SET_ROUTE_SEARCH_TIME 5" - " TASK_GET_PATH_TO_VEHICLE_ENTRY_POINT 0" - " TASK_RUN_PATH 0" - " TASK_WAIT_FOR_MOVEMENT 0" - " TASK_SET_SCHEDULE SCHEDULE:SCHED_PASSENGER_ENTER_VEHICLE" - "" - " Interrupts" - " COND_VEHICLE_MOVED_FROM_MARK" - ) - - DEFINE_SCHEDULE - ( - SCHED_PASSENGER_RUN_TO_ENTER_VEHICLE_FAILED, - - " Tasks" - " TASK_STOP_MOVING 0" - " TASK_SET_TOLERANCE_DISTANCE 32" - " TASK_SET_ROUTE_SEARCH_TIME 3" - " TASK_GET_PATH_TO_NEAR_VEHICLE 0" - " TASK_RUN_PATH 0" - " TASK_WAIT_FOR_MOVEMENT 0" - "" - " Interrupts" - " COND_VEHICLE_MOVED_FROM_MARK" - " COND_VEHICLE_STOPPED" - ) - - DEFINE_SCHEDULE - ( - SCHED_PASSENGER_ENTER_VEHICLE_PAUSE, - - " Tasks" - " TASK_STOP_MOVING 1" - " TASK_FACE_TARGET 0" - " TASK_WAIT 2" - "" - " Interrupts" - " COND_VEHICLE_STOPPED" - " COND_LIGHT_DAMAGE" - " COND_NEW_ENEMY" - ) - - DEFINE_SCHEDULE - ( - SCHED_PASSENGER_RANGE_ATTACK1, - - " Tasks" - " TASK_ANNOUNCE_ATTACK 1" // 1 = primary attack - " TASK_RANGE_ATTACK1 0" - "" - " Interrupts" - " COND_NEW_ENEMY" - " COND_ENEMY_DEAD" - " COND_LIGHT_DAMAGE" - " COND_HEAVY_DAMAGE" - " COND_ENEMY_OCCLUDED" - " COND_NO_PRIMARY_AMMO" - " COND_HEAR_DANGER" - " COND_WEAPON_BLOCKED_BY_FRIEND" - " COND_WEAPON_SIGHT_OCCLUDED" - ) - - DEFINE_SCHEDULE - ( - SCHED_PASSENGER_EXIT_STUCK_VEHICLE, - - " Tasks" - " TASK_PASSENGER_EXIT_STUCK_VEHICLE 0" - "" - " Interrupts" - ) - - DEFINE_SCHEDULE - ( - SCHED_PASSENGER_RELOAD, - - " Tasks" - " TASK_PASSENGER_RELOAD 0" - "" - " Interrupts" - ) - - DEFINE_SCHEDULE - ( - SCHED_PASSENGER_OVERTURNED, - - " Tasks" - " TASK_PASSENGER_OVERTURNED 0" - "" - " Interrupts" - ) - - DEFINE_SCHEDULE - ( - SCHED_PASSENGER_IMPACT, - - " Tasks" - " TASK_PASSENGER_IMPACT 0" - "" - " Interrupts" - ) - - AI_END_CUSTOM_SCHEDULE_PROVIDER() -} diff --git a/src/src/dlls/episodic/prop_stickybomb.cpp b/src/src/dlls/episodic/prop_stickybomb.cpp deleted file mode 100644 index 69f3d5e..0000000 --- a/src/src/dlls/episodic/prop_stickybomb.cpp +++ /dev/null @@ -1,274 +0,0 @@ -//====== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======= -// -// Purpose: Temp entity for testing physcannon ammo -// -//============================================================================= - -#include "cbase.h" -#include "props.h" -#include "vphysics/constraints.h" -#include "physics_saverestore.h" - -class CPropStickyBomb : public CPhysicsProp -{ - DECLARE_CLASS( CPropStickyBomb, CPhysicsProp ); - DECLARE_DATADESC(); - -public: - CPropStickyBomb( void ); - - virtual void Precache( void ); - virtual void Spawn( void ); - virtual void VPhysicsCollision( int index, gamevcollisionevent_t *pEvent ); - virtual void UpdateOnRemove( void ); - -private: - bool StickToWorld( int index, gamevcollisionevent_t *pEvent ); - bool StickToEntity( int index, gamevcollisionevent_t *pEvent ); - bool CreateConstraintToObject( CBaseEntity *pObject ); - bool CreateConstraintToNPC( CAI_BaseNPC *pNPC ); - void OnConstraintBroken( void ); - - IPhysicsConstraint *m_pConstraint; - EHANDLE m_hConstrainedEntity; -}; - -LINK_ENTITY_TO_CLASS( prop_stickybomb, CPropStickyBomb ); - -BEGIN_DATADESC( CPropStickyBomb ) - DEFINE_FIELD( m_hConstrainedEntity, FIELD_EHANDLE ), - DEFINE_PHYSPTR( m_pConstraint ), -END_DATADESC() - -CPropStickyBomb::CPropStickyBomb( void ) : m_pConstraint(NULL) -{ -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CPropStickyBomb::Precache( void ) -{ - m_iszBreakableModel = AllocPooledString( "models/props_outland/pumpkin_explosive.mdl" ); - PrecacheModel( STRING( m_iszBreakableModel ) ); - PrecacheScriptSound( "NPC_AntlionGrub.Squash" ); - - BaseClass::Precache(); -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CPropStickyBomb::Spawn( void ) -{ - BaseClass::Spawn(); -} - -//----------------------------------------------------------------------------- -// Purpose: Stick to the world -// Output : Returns true on success, false on failure. -//----------------------------------------------------------------------------- -bool CPropStickyBomb::StickToWorld( int index, gamevcollisionevent_t *pEvent ) -{ - Vector vecDir = pEvent->preVelocity[ index ]; - float speed = VectorNormalize( vecDir ); - - // Make sure the object is travelling fast enough to stick. - if( speed > 1000.0f ) - { - Vector vecPos; - QAngle angles; - VPhysicsGetObject()->GetPosition( &vecPos, &angles ); - - Vector vecVelocity = pEvent->preVelocity[0]; - VectorNormalize(vecVelocity); - - trace_t tr; - UTIL_TraceLine( vecPos, vecPos + (vecVelocity * 64), MASK_SHOT, this, COLLISION_GROUP_NONE, &tr ); - - // Finally, inhibit sticking in metal, grates, sky, or anything else that doesn't make a sound. - surfacedata_t *psurf= physprops->GetSurfaceData( pEvent->surfaceProps[!index] ); - - if ( psurf->game.material != 'X' ) - { - EmitSound( "NPC_AntlionGrub.Squash" ); - - Vector savePosition = vecPos; - - Vector vecEmbed = pEvent->preVelocity[ index ]; - VectorNormalize( vecEmbed ); - vecEmbed *= 8; - - vecPos += vecEmbed; - - Teleport( &vecPos, NULL, NULL ); - SetEnableMotionPosition( savePosition, angles ); // this uses hierarchy, so it must be set after teleport - - VPhysicsGetObject()->EnableMotion( false ); - AddSpawnFlags( SF_PHYSPROP_ENABLE_ON_PHYSCANNON ); - SetCollisionGroup( COLLISION_GROUP_DEBRIS ); - - UTIL_DecalTrace( &tr, "PaintSplatGreen" ); - - return true; - } - } - - return false; -} - -//----------------------------------------------------------------------------- -// Purpose: Create a constraint between this object and another -// Input : *pObject - Object to constrain ourselves to -// Output : Returns true on success, false on failure. -//----------------------------------------------------------------------------- -bool CPropStickyBomb::CreateConstraintToObject( CBaseEntity *pObject ) -{ - if ( m_pConstraint != NULL ) - { - // Should we destroy the constraint and make a new one at this point? - Assert( 0 ); - return false; - } - - if ( pObject == NULL ) - return false; - - IPhysicsObject *pPhysObject = pObject->VPhysicsGetObject(); - if ( pPhysObject == NULL ) - return false; - - IPhysicsObject *pMyPhysObject = VPhysicsGetObject(); - if ( pPhysObject == NULL ) - return false; - - // Create the fixed constraint - constraint_fixedparams_t fixedConstraint; - fixedConstraint.Defaults(); - fixedConstraint.InitWithCurrentObjectState( pPhysObject, pMyPhysObject ); - - IPhysicsConstraint *pConstraint = physenv->CreateFixedConstraint( pPhysObject, pMyPhysObject, NULL, fixedConstraint ); - if ( pConstraint == NULL ) - return false; - - // Hold on to us - m_pConstraint = pConstraint; - pConstraint->SetGameData( (void *)this ); - m_hConstrainedEntity = pObject; - - // Disable collisions between the two ents - PhysDisableObjectCollisions( pPhysObject, pMyPhysObject ); - - EmitSound( "NPC_AntlionGrub.Squash" ); - - return true; -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CPropStickyBomb::UpdateOnRemove( void ) -{ - OnConstraintBroken(); - - BaseClass::UpdateOnRemove(); -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CPropStickyBomb::OnConstraintBroken( void ) -{ - // Destroy the constraint - if ( m_pConstraint != NULL ) - { - physenv->DestroyConstraint( m_pConstraint ); - m_pConstraint = NULL; - } - - if ( m_hConstrainedEntity != NULL ) - { - // Re-enable the collisions between the objects - IPhysicsObject *pPhysObject = m_hConstrainedEntity->VPhysicsGetObject(); - IPhysicsObject *pMyPhysObject = VPhysicsGetObject(); - PhysEnableEntityCollisions( pPhysObject, pMyPhysObject ); - m_hConstrainedEntity = NULL; - } -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : *pNPC - -// Output : Returns true on success, false on failure. -//----------------------------------------------------------------------------- -bool CPropStickyBomb::CreateConstraintToNPC( CAI_BaseNPC *pNPC ) -{ - // Find the nearest bone to our position - return false; -} - -//----------------------------------------------------------------------------- -// Purpose: Stick to an entity (using hierarchy if we can) -// Output : Returns true on success, false on failure. -//----------------------------------------------------------------------------- -bool CPropStickyBomb::StickToEntity( int index, gamevcollisionevent_t *pEvent ) -{ - // Make sure the object is travelling fast enough to stick - float flSpeedSqr = ( pEvent->preVelocity[ index ] ).LengthSqr(); - if ( flSpeedSqr < Square( 1000.0f ) ) - return false; - - CBaseEntity *pOther = pEvent->pEntities[!index]; - - // Handle NPCs - CAI_BaseNPC *pNPC = pOther->MyNPCPointer(); - if ( pNPC != NULL ) - { - // Attach this object to the nearest bone - // TODO: How does this affect the NPC's behavior? - return CreateConstraintToNPC( pNPC ); - } - - // Handle physics props - CPhysicsProp *pProp = dynamic_cast(pOther); - if ( pProp != NULL ) - { - // Create a constraint to this object - return CreateConstraintToObject( pProp ); - } - - return false; -} - -//----------------------------------------------------------------------------- -// Purpose: Handle a collision using our special behavior -//----------------------------------------------------------------------------- -void CPropStickyBomb::VPhysicsCollision( int index, gamevcollisionevent_t *pEvent ) -{ - // Find out what we hit - CBaseEntity *pVictim = pEvent->pEntities[!index]; - if ( pVictim == NULL || m_pConstraint != NULL ) - { - BaseClass::VPhysicsCollision( index, pEvent ); - return; - } - - // Attempt to stick to the world - if ( pVictim->IsWorld() ) - { - // Done if we succeeded - if ( StickToWorld( index, pEvent ) ) - return; - - // Just bounce - BaseClass::VPhysicsCollision( index, pEvent ); - return; - } - - // Attempt to stick to an entity - if ( StickToEntity( index, pEvent ) ) - return; - - // Just bounce - BaseClass::VPhysicsCollision( index, pEvent ); -} diff --git a/src/src/dlls/episodic/vehicle_jeep_episodic.cpp b/src/src/dlls/episodic/vehicle_jeep_episodic.cpp deleted file mode 100644 index f54a685..0000000 --- a/src/src/dlls/episodic/vehicle_jeep_episodic.cpp +++ /dev/null @@ -1,222 +0,0 @@ -//====== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======= -// -// Purpose: -// -//============================================================================= - -#include "cbase.h" -#include "vehicle_jeep_episodic.h" -#include "collisionutils.h" -#include "npc_alyx_episodic.h" - -LINK_ENTITY_TO_CLASS( prop_vehicle_jeep, CPropJeepEpisodic ); - -BEGIN_DATADESC( CPropJeepEpisodic ) - - DEFINE_FIELD( m_bEntranceLocked, FIELD_BOOLEAN ), - DEFINE_FIELD( m_bExitLocked, FIELD_BOOLEAN ), - - DEFINE_OUTPUT( m_OnCompanionEnteredVehicle, "OnCompanionEnteredVehicle" ), - DEFINE_OUTPUT( m_OnCompanionExitedVehicle, "OnCompanionExitedVehicle" ), - DEFINE_OUTPUT( m_OnHostileEnteredVehicle, "OnHostileEnteredVehicle" ), - DEFINE_OUTPUT( m_OnHostileExitedVehicle, "OnHostileExitedVehicle" ), - - DEFINE_INPUTFUNC( FIELD_VOID, "LockEntrance", InputLockEntrance ), - DEFINE_INPUTFUNC( FIELD_VOID, "UnlockEntrance", InputUnlockEntrance ), - DEFINE_INPUTFUNC( FIELD_VOID, "LockExit", InputLockExit ), - DEFINE_INPUTFUNC( FIELD_VOID, "UnlockExit", InputUnlockExit ), - -END_DATADESC(); - -//============================================================================= -// Episodic jeep - -CPropJeepEpisodic::CPropJeepEpisodic( void ) : -m_bEntranceLocked( false ), -m_bExitLocked( false ) -{ - m_bHasGun = false; - m_bUnableToFire = true; -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CPropJeepEpisodic::Spawn( void ) -{ - BaseClass::Spawn(); - - SetBlocksLOS( false ); - - CBasePlayer *pPlayer = UTIL_GetLocalPlayer(); - if ( pPlayer != NULL ) - { - pPlayer->m_Local.m_iHideHUD |= HIDEHUD_VEHICLE_CROSSHAIR; - } -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CPropJeepEpisodic::NPC_FinishedEnterVehicle( CAI_BaseNPC *pPassenger, bool bCompanion ) -{ - // FIXME: This will be moved to the NPCs entering and exiting - // Fire our outputs - if ( bCompanion ) - { - m_OnCompanionEnteredVehicle.FireOutput( this, pPassenger ); - } - else - { - m_OnHostileEnteredVehicle.FireOutput( this, pPassenger ); - } -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CPropJeepEpisodic::NPC_FinishedExitVehicle( CAI_BaseNPC *pPassenger, bool bCompanion ) -{ - // FIXME: This will be moved to the NPCs entering and exiting - // Fire our outputs - if ( bCompanion ) - { - m_OnCompanionExitedVehicle.FireOutput( this, pPassenger ); - } - else - { - m_OnHostileExitedVehicle.FireOutput( this, pPassenger ); - } -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : *pPassenger - -// bCompanion - -// Output : Returns true on success, false on failure. -//----------------------------------------------------------------------------- -bool CPropJeepEpisodic::NPC_CanEnterVehicle( CAI_BaseNPC *pPassenger, bool bCompanion ) -{ - // Must be unlocked - if ( bCompanion && m_bEntranceLocked ) - return false; - - return BaseClass::NPC_CanEnterVehicle( pPassenger, bCompanion ); -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : *pPassenger - -// bCompanion - -// Output : Returns true on success, false on failure. -//----------------------------------------------------------------------------- -bool CPropJeepEpisodic::NPC_CanExitVehicle( CAI_BaseNPC *pPassenger, bool bCompanion ) -{ - // Must be unlocked - if ( bCompanion && m_bExitLocked ) - return false; - - return BaseClass::NPC_CanExitVehicle( pPassenger, bCompanion ); -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CPropJeepEpisodic::InputLockEntrance( inputdata_t &data ) -{ - m_bEntranceLocked = true; -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CPropJeepEpisodic::InputUnlockEntrance( inputdata_t &data ) -{ - m_bEntranceLocked = false; -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CPropJeepEpisodic::InputLockExit( inputdata_t &data ) -{ - m_bExitLocked = true; -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CPropJeepEpisodic::InputUnlockExit( inputdata_t &data ) -{ - m_bExitLocked = false; -} - -//----------------------------------------------------------------------------- -// Purpose: -// Output : Returns true on success, false on failure. -//----------------------------------------------------------------------------- -bool CPropJeepEpisodic::PassengerInTransition( void ) -{ - // FIXME: Big hack - we need a way to bridge this data better - // TODO: Get a list of passengers we can traverse instead - CBaseEntity *pPassenger = gEntList.FindEntityByClassname( NULL, "npc_alyx" ); - if ( pPassenger == NULL ) - return false; - - CNPC_Alyx *pAlyx = static_cast(pPassenger); - if ( pAlyx->GetPassengerState() == PASSENGER_STATE_ENTERING || - pAlyx->GetPassengerState() == PASSENGER_STATE_EXITING ) - return true; - - return false; -} - -//----------------------------------------------------------------------------- -// Purpose: Determines whether to override our normal punting behavior -// Output : Returns true on success, false on failure. -//----------------------------------------------------------------------------- -bool CPropJeepEpisodic::ShouldPuntUseLaunchForces( void ) -{ - if ( IsOverturned() || PassengerInTransition() ) - return true; - - return false; -} - -//----------------------------------------------------------------------------- -// Purpose: Override velocity if our passenger is transitioning or we're upside-down -//----------------------------------------------------------------------------- -Vector CPropJeepEpisodic::PhysGunLaunchVelocity( const Vector &forward, float flMass ) -{ - // Disallow - if ( PassengerInTransition() ) - return vec3_origin; - - return Vector( 0, 0, 500 ); -} - -//----------------------------------------------------------------------------- -// Purpose: Rolls the vehicle when its trying to upright itself from a punt -//----------------------------------------------------------------------------- -AngularImpulse CPropJeepEpisodic::PhysGunLaunchAngularImpulse( void ) -{ - // Disallow - if ( PassengerInTransition() ) - return Vector( 0, 0, 0 ); - - // Roll! - return Vector( 0, 300, 0 ); -} - -//----------------------------------------------------------------------------- -// Purpose: Get the upright strength based on what state we're in -//----------------------------------------------------------------------------- -float CPropJeepEpisodic::GetUprightStrength( void ) -{ - // Lesser if overturned - if ( IsOverturned() ) - return 16.0f; - - // Strong if upright already (prevents tipping) - return 64.0f; -} diff --git a/src/src/dlls/episodic/vehicle_jeep_episodic.h b/src/src/dlls/episodic/vehicle_jeep_episodic.h deleted file mode 100644 index 28a1cd8..0000000 --- a/src/src/dlls/episodic/vehicle_jeep_episodic.h +++ /dev/null @@ -1,59 +0,0 @@ -//====== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======= -// -// Purpose: -// -//============================================================================= - -#ifndef VEHICLE_JEEP_EPISODIC_H -#define VEHICLE_JEEP_EPISODIC_H -#ifdef _WIN32 -#pragma once -#endif - -#include "vehicle_jeep.h" -#include "ai_basenpc.h" - -//============================================================================= -// Episodic jeep - -class CPropJeepEpisodic : public CPropJeep -{ - DECLARE_CLASS( CPropJeepEpisodic, CPropJeep ); - -public: - CPropJeepEpisodic( void ); - - virtual void Spawn( void ); - virtual void NPC_FinishedEnterVehicle( CAI_BaseNPC *pPassenger, bool bCompanion ); - virtual void NPC_FinishedExitVehicle( CAI_BaseNPC *pPassenger, bool bCompanion ); - - virtual bool NPC_CanEnterVehicle( CAI_BaseNPC *pPassenger, bool bCompanion ); - virtual bool NPC_CanExitVehicle( CAI_BaseNPC *pPassenger, bool bCompanion ); - - DECLARE_DATADESC(); - -protected: - virtual float GetUprightTime( void ) { return 1.0f; } - virtual float GetUprightStrength( void ); - virtual bool ShouldPuntUseLaunchForces( void ); - virtual AngularImpulse PhysGunLaunchAngularImpulse( void ); - virtual Vector PhysGunLaunchVelocity( const Vector &forward, float flMass ); - bool PassengerInTransition( void ); - -private: - - void InputLockEntrance( inputdata_t &data ); - void InputUnlockEntrance( inputdata_t &data ); - void InputLockExit( inputdata_t &data ); - void InputUnlockExit( inputdata_t &data ); - - bool m_bEntranceLocked; - bool m_bExitLocked; - - COutputEvent m_OnCompanionEnteredVehicle; // Passenger has completed entering the vehicle - COutputEvent m_OnCompanionExitedVehicle; // Passenger has completed exited the vehicle - COutputEvent m_OnHostileEnteredVehicle; // Passenger has completed entering the vehicle - COutputEvent m_OnHostileExitedVehicle; // Passenger has completed exited the vehicle -}; - -#endif // VEHICLE_JEEP_EPISODIC_H diff --git a/src/src/dlls/fogcontroller.h b/src/src/dlls/fogcontroller.h deleted file mode 100644 index 5d115d3..0000000 --- a/src/src/dlls/fogcontroller.h +++ /dev/null @@ -1,20 +0,0 @@ -//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// -// -// Purpose: -// -//=============================================================================// - -#ifndef FOGCONTROLLER_H -#define FOGCONTROLLER_H -#ifdef _WIN32 -#pragma once -#endif - - -#include "playernet_vars.h" - - -bool GetWorldFogParams( fogparams_t &fog ); - - -#endif // FOGCONTROLLER_H diff --git a/src/src/dlls/hl2_dll/grenade_spit.cpp b/src/src/dlls/hl2_dll/grenade_spit.cpp deleted file mode 100644 index 9a0a487..0000000 --- a/src/src/dlls/hl2_dll/grenade_spit.cpp +++ /dev/null @@ -1,170 +0,0 @@ -//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// -// -// Purpose: -// -// $Workfile: $ -// $Date: $ -// $NoKeywords: $ -//=============================================================================// - -#include "cbase.h" -#include "grenade_spit.h" -#include "soundent.h" -#include "decals.h" -#include "smoke_trail.h" -#include "hl2_shareddefs.h" -#include "vstdlib/random.h" -#include "engine/IEngineSound.h" - -// memdbgon must be the last include file in a .cpp file!!! -#include "tier0/memdbgon.h" - -ConVar sk_dmg_spit_grenade ( "sk_dmg_spit_grenade","0"); -ConVar sk_spit_grenade_radius ( "sk_spit_grenade_radius","0"); - -BEGIN_DATADESC( CGrenadeSpit ) - - DEFINE_FIELD( m_nSquidSpitSprite, FIELD_INTEGER ), - DEFINE_FIELD( m_fSpitDeathTime, FIELD_FLOAT ), - - // Function pointers - DEFINE_FUNCTION( SpitThink ), - DEFINE_FUNCTION( GrenadeSpitTouch ), - -END_DATADESC() - -LINK_ENTITY_TO_CLASS( grenade_spit, CGrenadeSpit ); - -void CGrenadeSpit::Spawn( void ) -{ - Precache( ); - SetSolid( SOLID_BBOX ); - SetMoveType( MOVETYPE_FLYGRAVITY ); - - // FIXME, if these is a sprite, then we need a base class derived from CSprite rather than - // CBaseAnimating. pev->scale becomes m_flSpriteScale in that case. - SetModel( "models/spitball_large.mdl" ); - UTIL_SetSize(this, Vector(0, 0, 0), Vector(0, 0, 0)); - - m_nRenderMode = kRenderTransAdd; - SetRenderColor( 255, 255, 255, 255 ); - m_nRenderFX = kRenderFxNone; - - SetThink( SpitThink ); - SetUse( DetonateUse ); - SetTouch( GrenadeSpitTouch ); - SetNextThink( gpGlobals->curtime + 0.1f ); - - m_flDamage = sk_dmg_spit_grenade.GetFloat(); - m_DmgRadius = sk_spit_grenade_radius.GetFloat(); - m_takedamage = DAMAGE_YES; - m_iHealth = 1; - - SetGravity( UTIL_ScaleForGravity( SPIT_GRAVITY ) ); - SetFriction( 0.8 ); - SetSequence( 1 ); - - SetCollisionGroup( HL2COLLISION_GROUP_SPIT ); -} - - -void CGrenadeSpit::SetSpitSize(int nSize) -{ - switch (nSize) - { - case SPIT_LARGE: - { - SetModel( "models/spitball_large.mdl" ); - break; - } - case SPIT_MEDIUM: - { - SetModel( "models/spitball_medium.mdl" ); - break; - } - case SPIT_SMALL: - { - SetModel( "models/spitball_small.mdl" ); - break; - } - } -} - -void CGrenadeSpit::Event_Killed( const CTakeDamageInfo &info ) -{ - Detonate( ); -} - -void CGrenadeSpit::GrenadeSpitTouch( CBaseEntity *pOther ) -{ - if (m_fSpitDeathTime != 0) - { - return; - } - if ( pOther->GetCollisionGroup() == HL2COLLISION_GROUP_SPIT) - { - return; - } - if ( !pOther->m_takedamage ) - { - - // make a splat on the wall - trace_t tr; - UTIL_TraceLine( GetAbsOrigin(), GetAbsOrigin() + GetAbsVelocity() * 10, MASK_SOLID, this, COLLISION_GROUP_NONE, &tr ); - UTIL_DecalTrace(&tr, "BeerSplash" ); - - // make some flecks - // CPVSFilter filter( tr.endpos ); - //te->SpriteSpray( filter, 0.0, - // tr.endpos, tr.plane.normal, m_nSquidSpitSprite, 30, 0.8, 5 ); - } - else - { - RadiusDamage ( CTakeDamageInfo( this, GetThrower(), m_flDamage, DMG_BLAST ), GetAbsOrigin(), m_DmgRadius, CLASS_NONE, NULL ); - } - - Detonate(); -} - -void CGrenadeSpit::SpitThink( void ) -{ - if (m_fSpitDeathTime != 0 && - m_fSpitDeathTime < gpGlobals->curtime) - { - UTIL_Remove( this ); - } - SetNextThink( gpGlobals->curtime + 0.1f ); -} - -void CGrenadeSpit::Detonate(void) -{ - m_takedamage = DAMAGE_NO; - - int iPitch; - - // splat sound - iPitch = random->RandomFloat( 90, 110 ); - - EmitSound( "GrenadeSpit.Acid" ); - EmitSound( "GrenadeSpit.Hit" ); - - UTIL_Remove( this ); -} - -void CGrenadeSpit::Precache( void ) -{ - m_nSquidSpitSprite = PrecacheModel("sprites/greenglow1.vmt");// client side spittle. - - PrecacheModel("models/spitball_large.mdl"); - PrecacheModel("models/spitball_medium.mdl"); - PrecacheModel("models/spitball_small.mdl"); - - PrecacheScriptSound( "GrenadeSpit.Acid" ); - PrecacheScriptSound( "GrenadeSpit.Hit" ); - -} - - -CGrenadeSpit::CGrenadeSpit(void) -{ -} \ No newline at end of file diff --git a/src/src/dlls/hl2_dll/hl_playermove.cpp b/src/src/dlls/hl2_dll/hl_playermove.cpp deleted file mode 100644 index c5ecc25..0000000 --- a/src/src/dlls/hl2_dll/hl_playermove.cpp +++ /dev/null @@ -1,81 +0,0 @@ -//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// -// -// Purpose: -// -// $NoKeywords: $ -//=============================================================================// -#include "cbase.h" -#include "player_command.h" -#include "player.h" -#include "igamemovement.h" -#include "hl_movedata.h" -#include "ipredictionsystem.h" -#include "iservervehicle.h" -#include "hl2_player.h" - -// memdbgon must be the last include file in a .cpp file!!! -#include "tier0/memdbgon.h" - -class CHLPlayerMove : public CPlayerMove -{ - DECLARE_CLASS( CHLPlayerMove, CPlayerMove ); -public: - void SetupMove( CBasePlayer *player, CUserCmd *ucmd, IMoveHelper *pHelper, CMoveData *move ); - void FinishMove( CBasePlayer *player, CUserCmd *ucmd, CMoveData *move ); -}; - -// -// -// PlayerMove Interface -static CHLPlayerMove g_PlayerMove; - -//----------------------------------------------------------------------------- -// Singleton accessor -//----------------------------------------------------------------------------- -CPlayerMove *PlayerMove() -{ - return &g_PlayerMove; -} - -// - -static CHLMoveData g_HLMoveData; -CMoveData *g_pMoveData = &g_HLMoveData; - -IPredictionSystem *IPredictionSystem::g_pPredictionSystems = NULL; - -void CHLPlayerMove::SetupMove( CBasePlayer *player, CUserCmd *ucmd, IMoveHelper *pHelper, CMoveData *move ) -{ - // Call the default SetupMove code. - BaseClass::SetupMove( player, ucmd, pHelper, move ); - - // Convert to HL2 data. - CHL2_Player *pHLPlayer = static_cast( player ); - Assert( pHLPlayer ); - - CHLMoveData *pHLMove = static_cast( move ); - Assert( pHLMove ); - - player->m_flForwardMove = ucmd->forwardmove; - player->m_flSideMove = ucmd->sidemove; - - pHLMove->m_bIsSprinting = pHLPlayer->IsSprinting(); - - IServerVehicle *pVehicle = player->GetVehicle(); - if (pVehicle && gpGlobals->frametime != 0) - { - pVehicle->SetupMove( player, ucmd, pHelper, move ); - } -} - - -void CHLPlayerMove::FinishMove( CBasePlayer *player, CUserCmd *ucmd, CMoveData *move ) -{ - // Call the default FinishMove code. - BaseClass::FinishMove( player, ucmd, move ); - IServerVehicle *pVehicle = player->GetVehicle(); - if (pVehicle && gpGlobals->frametime != 0) - { - pVehicle->FinishMove( player, ucmd, move ); - } -} diff --git a/src/src/dlls/hl2_dll/npc_antliongrub.cpp b/src/src/dlls/hl2_dll/npc_antliongrub.cpp deleted file mode 100644 index b7ea220..0000000 --- a/src/src/dlls/hl2_dll/npc_antliongrub.cpp +++ /dev/null @@ -1,1139 +0,0 @@ -//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// -// -// Purpose: Antlion Grub - cannon fodder -// -// $NoKeywords: $ -//=============================================================================// - -#include "cbase.h" -#include "AI_Task.h" -#include "AI_Default.h" -#include "AI_Schedule.h" -#include "AI_Hull.h" -#include "AI_Navigator.h" -#include "activitylist.h" -#include "game.h" -#include "NPCEvent.h" -#include "Player.h" -#include "EntityList.h" -#include "AI_Interactions.h" -#include "soundent.h" -#include "Gib.h" -#include "soundenvelope.h" -#include "shake.h" -#include "Sprite.h" -#include "vstdlib/random.h" -#include "npc_antliongrub.h" -#include "engine/IEngineSound.h" -#include "te_effect_dispatch.h" - -// memdbgon must be the last include file in a .cpp file!!! -#include "tier0/memdbgon.h" - -ConVar sk_antliongrub_health( "sk_antliongrub_health", "0" ); - -#define ANTLIONGRUB_SQUEAL_DIST 512 -#define ANTLIONGRUB_SQUASH_TIME 1.0f -#define ANTLIONGRUB_HEAL_RANGE 256.0f -#define ANTLIONGRUB_HEAL_CONE 0.5f -#define ANTLIONGRUB_ENEMY_HOSTILE_TIME 8.0f - -#include "AI_BaseNPC.h" -#include "soundenvelope.h" -#include "bitstring.h" - -class CSprite; - -#define ANTLIONGRUB_MODEL "models/antlion_grub.mdl" -#define ANTLIONGRUB_SQUASHED_MODEL "models/antlion_grub_squashed.mdl" - -class CNPC_AntlionGrub : public CAI_BaseNPC -{ -public: - DECLARE_CLASS( CNPC_AntlionGrub, CAI_BaseNPC ); - DECLARE_DATADESC(); - - CNPC_AntlionGrub( void ); - - virtual int OnTakeDamage_Alive( const CTakeDamageInfo &info ); - virtual int SelectSchedule( void ); - virtual int TranslateSchedule( int type ); - int MeleeAttack1Conditions( float flDot, float flDist ); - - bool HandleInteraction( int interactionType, void *data, CBaseCombatCharacter *sourceEnt ); - - void Precache( void ); - void Spawn( void ); - void StartTask( const Task_t *pTask ); - void RunTask( const Task_t *pTask ); - void GrubTouch( CBaseEntity *pOther ); - void EndTouch( CBaseEntity *pOther ); - void PainSound( const CTakeDamageInfo &info ); - void PrescheduleThink( void ); - void HandleAnimEvent( animevent_t *pEvent ); - void Event_Killed( const CTakeDamageInfo &info ); - void BuildScheduleTestBits( void ); - void StopLoopingSounds(); - - float MaxYawSpeed( void ) { return 2.0f; } - float StepHeight( ) const { return 12.0f; } //NOTENOTE: We don't want them to move up too high - - Class_T Classify( void ) { return CLASS_ANTLION; } - -private: - - void AttachToSurface( void ); - void SpawnSquashedGrub( void ); - void Squash( CBaseEntity *pOther ); - void BroadcastAlert( void ); - - /* - CSoundPatch *m_pMovementSound; - CSoundPatch *m_pVoiceSound; - CSoundPatch *m_pHealSound; - */ - - CSprite *m_pGlowSprite; - - float m_flNextVoiceChange; //The next point to alter our voice - float m_flSquashTime; //Amount of time we've been stepped on - float m_flNearTime; //Amount of time the player has been near enough to be considered for healing - float m_flHealthTime; //Amount of time until the next piece of health is given - float m_flEnemyHostileTime; //Amount of time the enemy should be avoided (because they displayed aggressive behavior) - - bool m_bMoving; - bool m_bSquashed; - bool m_bSquashValid; - bool m_bHealing; - - int m_nHealthReserve; - int m_nGlowSpriteHandle; - - DEFINE_CUSTOM_AI; -}; - -//Sharp fast attack -envelopePoint_t envFastAttack[] = -{ - { 0.3f, 0.5f, //Attack - 0.5f, 1.0f, - }, - { 0.0f, 0.1f, //Decay - 0.1f, 0.2f, - }, - { -1.0f, -1.0f, //Sustain - 1.0f, 2.0f, - }, - { 0.0f, 0.0f, //Release - 0.5f, 1.0f, - } -}; - -//Slow start to fast end attack -envelopePoint_t envEndAttack[] = -{ - { 0.0f, 0.1f, - 0.5f, 1.0f, - }, - { -1.0f, -1.0f, - 0.5f, 1.0f, - }, - { 0.3f, 0.5f, - 0.2f, 0.5f, - }, - { 0.0f, 0.0f, - 0.5f, 1.0f, - }, -}; - -//rise, long sustain, release -envelopePoint_t envMidSustain[] = -{ - { 0.2f, 0.4f, - 0.1f, 0.5f, - }, - { -1.0f, -1.0f, - 0.1f, 0.5f, - }, - { 0.0f, 0.0f, - 0.5f, 1.0f, - }, -}; - -//Scared -envelopePoint_t envScared[] = -{ - { 0.8f, 1.0f, - 0.1f, 0.2f, - }, - { - -1.0f, -1.0f, - 0.25f, 0.5f - }, - { 0.0f, 0.0f, - 0.5f, 1.0f, - }, -}; - -//Grub voice envelopes -envelopeDescription_t grubVoiceEnvelopes[] = -{ - { envFastAttack, ARRAYSIZE(envFastAttack) }, - { envEndAttack, ARRAYSIZE(envEndAttack) }, - { envMidSustain, ARRAYSIZE(envMidSustain) }, -}; - -//Data description -BEGIN_DATADESC( CNPC_AntlionGrub ) - - //DEFINE_SOUNDPATCH( m_pMovementSound ), - //DEFINE_SOUNDPATCH( m_pVoiceSound ), - //DEFINE_SOUNDPATCH( m_pHealSound ), - DEFINE_FIELD( m_pGlowSprite, FIELD_CLASSPTR ), - DEFINE_FIELD( m_flNextVoiceChange, FIELD_TIME ), - DEFINE_FIELD( m_flSquashTime, FIELD_TIME ), - DEFINE_FIELD( m_flNearTime, FIELD_TIME ), - DEFINE_FIELD( m_flHealthTime, FIELD_TIME ), - DEFINE_FIELD( m_flEnemyHostileTime, FIELD_TIME ), - DEFINE_FIELD( m_bSquashed, FIELD_BOOLEAN ), - DEFINE_FIELD( m_bMoving, FIELD_BOOLEAN ), - DEFINE_FIELD( m_bSquashValid, FIELD_BOOLEAN ), - DEFINE_FIELD( m_bHealing, FIELD_BOOLEAN ), - DEFINE_FIELD( m_nHealthReserve, FIELD_INTEGER ), - DEFINE_FIELD( m_nGlowSpriteHandle, FIELD_INTEGER ), - - // Functions - DEFINE_ENTITYFUNC( GrubTouch ), - -END_DATADESC() - -//Schedules -enum AntlionGrubSchedules -{ - SCHED_ANTLIONGRUB_SQUEAL = LAST_SHARED_SCHEDULE, - SCHED_ANTLIONGRUB_SQUIRM, - SCHED_ANTLIONGRUB_STAND, - SCHED_ANTLIONGRUB_GIVE_HEALTH, - SCHED_ANTLIONGUARD_RETREAT, -}; - -//Tasks -enum AntlionGrubTasks -{ - TASK_ANTLIONGRUB_SQUIRM = LAST_SHARED_TASK, - TASK_ANTLIONGRUB_GIVE_HEALTH, - TASK_ANTLIONGRUB_MOVE_TO_TARGET, - TASK_ANTLIONGRUB_FIND_RETREAT_GOAL, -}; - -//Conditions -enum AntlionGrubConditions -{ - COND_ANTLIONGRUB_HEARD_SQUEAL = LAST_SHARED_CONDITION, - COND_ANTLIONGRUB_BEING_SQUASHED, - COND_ANTLIONGRUB_IN_HEAL_RANGE, -}; - -//Activities -int ACT_ANTLIONGRUB_SQUIRM; -int ACT_ANTLIONGRUB_HEAL; - -//Animation events -#define ANTLIONGRUB_AE_START_SQUIRM 11 //Start squirming portion of animation -#define ANTLIONGRUB_AE_END_SQUIRM 12 //End squirming portion of animation - -//Interaction IDs -int g_interactionAntlionGrubAlert = 0; - -#define REGISTER_INTERACTION( a ) { a = CBaseCombatCharacter::GetInteractionID(); } - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -CNPC_AntlionGrub::CNPC_AntlionGrub( void ) -{ -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CNPC_AntlionGrub::InitCustomSchedules( void ) -{ - INIT_CUSTOM_AI( CNPC_AntlionGrub ); - - //Schedules - ADD_CUSTOM_SCHEDULE( CNPC_AntlionGrub, SCHED_ANTLIONGRUB_SQUEAL ); - ADD_CUSTOM_SCHEDULE( CNPC_AntlionGrub, SCHED_ANTLIONGRUB_SQUIRM ); - ADD_CUSTOM_SCHEDULE( CNPC_AntlionGrub, SCHED_ANTLIONGRUB_STAND ); - ADD_CUSTOM_SCHEDULE( CNPC_AntlionGrub, SCHED_ANTLIONGRUB_GIVE_HEALTH ); - ADD_CUSTOM_SCHEDULE( CNPC_AntlionGrub, SCHED_ANTLIONGUARD_RETREAT ); - - //Tasks - ADD_CUSTOM_TASK( CNPC_AntlionGrub, TASK_ANTLIONGRUB_SQUIRM ); - ADD_CUSTOM_TASK( CNPC_AntlionGrub, TASK_ANTLIONGRUB_GIVE_HEALTH ); - ADD_CUSTOM_TASK( CNPC_AntlionGrub, TASK_ANTLIONGRUB_MOVE_TO_TARGET ); - ADD_CUSTOM_TASK( CNPC_AntlionGrub, TASK_ANTLIONGRUB_FIND_RETREAT_GOAL ); - - //Conditions - ADD_CUSTOM_CONDITION( CNPC_AntlionGrub, COND_ANTLIONGRUB_HEARD_SQUEAL ); - ADD_CUSTOM_CONDITION( CNPC_AntlionGrub, COND_ANTLIONGRUB_BEING_SQUASHED ); - ADD_CUSTOM_CONDITION( CNPC_AntlionGrub, COND_ANTLIONGRUB_IN_HEAL_RANGE ); - - //Activities - ADD_CUSTOM_ACTIVITY( CNPC_AntlionGrub, ACT_ANTLIONGRUB_SQUIRM ); - ADD_CUSTOM_ACTIVITY( CNPC_AntlionGrub, ACT_ANTLIONGRUB_HEAL ); - - AI_LOAD_SCHEDULE( CNPC_AntlionGrub, SCHED_ANTLIONGRUB_SQUEAL ); - AI_LOAD_SCHEDULE( CNPC_AntlionGrub, SCHED_ANTLIONGRUB_SQUIRM ); - AI_LOAD_SCHEDULE( CNPC_AntlionGrub, SCHED_ANTLIONGRUB_STAND ); - AI_LOAD_SCHEDULE( CNPC_AntlionGrub, SCHED_ANTLIONGRUB_GIVE_HEALTH ); - AI_LOAD_SCHEDULE( CNPC_AntlionGrub, SCHED_ANTLIONGUARD_RETREAT ); -} - -LINK_ENTITY_TO_CLASS( npc_antlion_grub, CNPC_AntlionGrub ); -IMPLEMENT_CUSTOM_AI( npc_antlion_grub, CNPC_AntlionGrub ); - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CNPC_AntlionGrub::Precache( void ) -{ - PrecacheModel( ANTLIONGRUB_MODEL ); - PrecacheModel( ANTLIONGRUB_SQUASHED_MODEL ); - - m_nGlowSpriteHandle = PrecacheModel("sprites/blueflare1.vmt"); - - /* - PrecacheScriptSound( "NPC_AntlionGrub.Scared" ); - PrecacheScriptSound( "NPC_AntlionGrub.Squash" ); - - PrecacheScriptSound( "NPC_Antlion.Movement" ); - PrecacheScriptSound( "NPC_Antlion.Voice" ); - PrecacheScriptSound( "NPC_Antlion.Heal" ); - */ - - BaseClass::Precache(); -} - -//----------------------------------------------------------------------------- -// Purpose: Attaches the grub to the surface underneath its abdomen -//----------------------------------------------------------------------------- -void CNPC_AntlionGrub::AttachToSurface( void ) -{ - // Get our downward direction - Vector vecForward, vecRight, vecDown; - GetVectors( &vecForward, &vecRight, &vecDown ); - vecDown.Negate(); - - // Trace down to find a surface - trace_t tr; - UTIL_TraceLine( WorldSpaceCenter(), WorldSpaceCenter() + (vecDown*256.0f), MASK_NPCSOLID, this, COLLISION_GROUP_NONE, &tr ); - - if ( tr.fraction < 1.0f ) - { - // Move there - UTIL_SetOrigin( this, tr.endpos, false ); - } -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CNPC_AntlionGrub::Spawn( void ) -{ - Precache(); - - SetModel( ANTLIONGRUB_MODEL ); - - m_NPCState = NPC_STATE_NONE; - m_iHealth = sk_antliongrub_health.GetFloat(); - m_iMaxHealth = m_iHealth; - m_flFieldOfView = 0.5f; - - SetSolid( SOLID_BBOX ); - SetMoveType( MOVETYPE_NONE ); - SetCollisionGroup( COLLISION_GROUP_DEBRIS ); - SetHullSizeNormal(); - SetHullType( HULL_SMALL_CENTERED ); - SetBloodColor( BLOOD_COLOR_YELLOW ); - - CapabilitiesClear(); - - m_flNextVoiceChange = gpGlobals->curtime; - m_flSquashTime = gpGlobals->curtime; - m_flNearTime = gpGlobals->curtime; - m_flHealthTime = gpGlobals->curtime; - m_flEnemyHostileTime = gpGlobals->curtime; - - m_bMoving = false; - m_bSquashed = false; - m_bSquashValid = false; - m_bHealing = false; - - m_nHealthReserve = 10; - - SetTouch( GrubTouch ); - - // Attach to the surface under our belly - AttachToSurface(); - - // Use detailed collision because we're an odd shape - CollisionProp()->SetSurroundingBoundsType( USE_HITBOXES ); - - /* - CSoundEnvelopeController &controller = CSoundEnvelopeController::GetController(); - - CPASAttenuationFilter filter( this ); - m_pMovementSound = controller.SoundCreate( filter, entindex(), CHAN_BODY, "NPC_Antlion.Movement", 3.9f ); - m_pVoiceSound = controller.SoundCreate( filter, entindex(), CHAN_VOICE, "NPC_Antlion.Voice", 3.9f ); - m_pHealSound = controller.SoundCreate( filter, entindex(), CHAN_STATIC, "NPC_Antlion.Heal", 3.9f ); - - controller.Play( m_pMovementSound, 0.0f, 100 ); - controller.Play( m_pVoiceSound, 0.0f, 100 ); - controller.Play( m_pHealSound, 0.0f, 100 ); - */ - - m_pGlowSprite = CSprite::SpriteCreate( "sprites/blueflare1.vmt", GetLocalOrigin(), false ); - - Assert( m_pGlowSprite ); - - if ( m_pGlowSprite == NULL ) - return; - - Vector vecUp; - GetVectors( NULL, NULL, &vecUp ); - - m_pGlowSprite->TurnOn(); - m_pGlowSprite->SetTransparency( kRenderWorldGlow, 156, 169, 121, 164, kRenderFxNoDissipation ); - m_pGlowSprite->SetAbsOrigin( GetAbsOrigin() + vecUp * 8.0f ); - m_pGlowSprite->SetScale( 1.0f ); - m_pGlowSprite->SetGlowProxySize( 16.0f ); - - // We don't want to teleport at this point - AddSpawnFlags( SF_NPC_FALL_TO_GROUND ); - - // We get a bogus error otherwise - NPCInit(); - AddSolidFlags( FSOLID_TRIGGER ); -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : *pEvent - -//----------------------------------------------------------------------------- -void CNPC_AntlionGrub::HandleAnimEvent( animevent_t *pEvent ) -{ - switch ( pEvent->event ) - { - case ANTLIONGRUB_AE_START_SQUIRM: - { - //float duration = random->RandomFloat( 0.1f, 0.3f ); - //CSoundEnvelopeController::GetController().SoundChangePitch( m_pMovementSound, random->RandomInt( 100, 120 ), duration ); - //CSoundEnvelopeController::GetController().SoundChangeVolume( m_pMovementSound, random->RandomFloat( 0.6f, 0.8f ), duration ); - } - break; - - case ANTLIONGRUB_AE_END_SQUIRM: - { - //float duration = random->RandomFloat( 0.1f, 0.3f ); - //CSoundEnvelopeController::GetController().SoundChangePitch( m_pMovementSound, random->RandomInt( 80, 100 ), duration ); - //CSoundEnvelopeController::GetController().SoundChangeVolume( m_pMovementSound, random->RandomFloat( 0.0f, 0.1f ), duration ); - } - break; - - default: - BaseClass::HandleAnimEvent( pEvent ); - return; - } -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -int CNPC_AntlionGrub::SelectSchedule( void ) -{ - //If we've heard someone else squeal, we should too - if ( HasCondition( COND_ANTLIONGRUB_HEARD_SQUEAL ) || HasCondition( COND_ANTLIONGRUB_BEING_SQUASHED ) ) - { - m_flEnemyHostileTime = gpGlobals->curtime + ANTLIONGRUB_ENEMY_HOSTILE_TIME; - return SCHED_SMALL_FLINCH; - } - - //See if we need to run away from our enemy - /* - if ( m_flEnemyHostileTime > gpGlobals->curtime ) - return SCHED_ANTLIONGUARD_RETREAT; - */ - - /* - if ( HasCondition( COND_ANTLIONGRUB_IN_HEAL_RANGE ) ) - { - SetTarget( GetEnemy() ); - return SCHED_ANTLIONGRUB_GIVE_HEALTH; - } - */ - - //If we've taken any damage, squirm and squeal - if ( HasCondition( COND_LIGHT_DAMAGE ) && SelectWeightedSequence( ACT_SMALL_FLINCH ) != -1 ) - return SCHED_SMALL_FLINCH; - - /* - //Randomly stand still - if ( random->RandomInt( 0, 3 ) == 0 ) - return SCHED_IDLE_STAND; - - //Otherwise just walk around a little - return SCHED_PATROL_WALK; - */ - - return SCHED_IDLE_STAND; -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : *pTask - -//----------------------------------------------------------------------------- -void CNPC_AntlionGrub::StartTask( const Task_t *pTask ) -{ - switch ( pTask->iTask ) - { - case TASK_ANTLIONGRUB_FIND_RETREAT_GOAL: - { - if ( GetEnemy() == NULL ) - { - TaskFail( FAIL_NO_ENEMY ); - return; - } - - Vector testPos, testPos2, threatDir; - trace_t tr; - - //Find the direction to our enemy - threatDir = ( GetAbsOrigin() - GetEnemy()->GetAbsOrigin() ); - VectorNormalize( threatDir ); - - //Find a position farther out away from our enemy - VectorMA( GetAbsOrigin(), random->RandomInt( 32, 128 ), threatDir, testPos ); - testPos[2] += StepHeight()*2.0f; - - testPos2 = testPos; - testPos2[2] -= StepHeight()*2.0f; - - //Check the position - AI_TraceLine( testPos, testPos2, MASK_SOLID, this, COLLISION_GROUP_NONE, &tr ); - - //Must be clear - if ( ( tr.startsolid ) || ( tr.allsolid ) || ( tr.fraction == 1.0f ) ) - { - TaskFail( FAIL_NO_ROUTE ); - return; - } - - //Save the position and go - m_vSavePosition = tr.endpos; - TaskComplete(); - } - break; - - case TASK_ANTLIONGRUB_MOVE_TO_TARGET: - - if ( GetEnemy() == NULL) - { - TaskFail( FAIL_NO_TARGET ); - } - else if ( ( GetEnemy()->GetLocalOrigin() - GetLocalOrigin()).Length() < pTask->flTaskData ) - { - TaskComplete(); - } - - break; - - case TASK_ANTLIONGRUB_GIVE_HEALTH: - - m_bHealing = true; - - SetActivity( (Activity) ACT_ANTLIONGRUB_HEAL ); - - //CSoundEnvelopeController::GetController().SoundChangeVolume( m_pHealSound, 0.5f, 2.0f ); - - //Must have a target - if ( GetEnemy() == NULL ) - { - TaskFail( FAIL_NO_ENEMY ); - return; - } - - //Must be within range - if ( (GetEnemy()->GetLocalOrigin() - GetLocalOrigin()).Length() > 92 ) - { - TaskFail( FAIL_NO_ENEMY ); - } - - break; - - case TASK_ANTLIONGRUB_SQUIRM: - { - //Pick a squirm movement to perform - Vector vecStart; - - //Move randomly around, and start a step's height above our current position - vecStart.Random( -32.0f, 32.0f ); - vecStart[2] = StepHeight(); - vecStart += GetLocalOrigin(); - - //Look straight down for the ground - Vector vecEnd = vecStart; - vecEnd[2] -= StepHeight()*2.0f; - - trace_t tr; - - //Check the position - //FIXME: Trace by the entity's hull size? - AI_TraceLine( vecStart, vecEnd, MASK_NPCSOLID, this, COLLISION_GROUP_NONE, &tr ); - - //See if we can move there - if ( ( tr.fraction == 1.0f ) || ( tr.startsolid ) || ( tr.allsolid ) ) - { - TaskFail( FAIL_NO_ROUTE ); - return; - } - - m_vSavePosition = tr.endpos; - - TaskComplete(); - } - break; - - default: - BaseClass::StartTask( pTask ); - break; - } -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : *pTask - -//----------------------------------------------------------------------------- -void CNPC_AntlionGrub::RunTask( const Task_t *pTask ) -{ - switch ( pTask->iTask ) - { - case TASK_ANTLIONGRUB_MOVE_TO_TARGET: - { - //Must have a target entity - if ( GetEnemy() == NULL ) - { - TaskFail( FAIL_NO_TARGET ); - return; - } - - float distance = ( GetNavigator()->GetGoalPos() - GetLocalOrigin() ).Length2D(); - - if ( ( GetNavigator()->GetGoalPos() - GetEnemy()->GetLocalOrigin() ).Length() > (pTask->flTaskData * 0.5f) ) - { - distance = ( GetEnemy()->GetLocalOrigin() - GetLocalOrigin() ).Length2D(); - GetNavigator()->UpdateGoalPos( GetEnemy()->GetLocalOrigin() ); - } - - //See if we've arrived - if ( distance < pTask->flTaskData ) - { - TaskComplete(); - GetNavigator()->StopMoving(); - } - } - break; - - case TASK_ANTLIONGRUB_GIVE_HEALTH: - - //Validate the enemy - if ( GetEnemy() == NULL ) - { - TaskFail( FAIL_NO_ENEMY ); - return; - } - - //Are we done giving health? - if ( ( GetEnemy()->m_iHealth == GetEnemy()->m_iMaxHealth ) || ( m_nHealthReserve <= 0 ) || ( (GetEnemy()->GetLocalOrigin() - GetLocalOrigin()).Length() > 64 ) ) - { - m_bHealing = false; - //CSoundEnvelopeController::GetController().SoundChangeVolume( m_pHealSound, 0.0f, 0.5f ); - TaskComplete(); - return; - } - - //Is it time to heal again? - if ( m_flHealthTime < gpGlobals->curtime ) - { - m_flHealthTime = gpGlobals->curtime + 0.5f; - - //Update the health - if ( GetEnemy()->m_iHealth < GetEnemy()->m_iMaxHealth ) - { - GetEnemy()->m_iHealth++; - m_nHealthReserve--; - } - } - - break; - - default: - BaseClass::RunTask( pTask ); - break; - } -} - -#define TRANSLATE_SCHEDULE( type, in, out ) { if ( type == in ) return out; } - -//----------------------------------------------------------------------------- -// Purpose: override/translate a schedule by type -// Input : Type - schedule type -// Output : int - translated type -//----------------------------------------------------------------------------- -int CNPC_AntlionGrub::TranslateSchedule( int type ) -{ - TRANSLATE_SCHEDULE( type, SCHED_IDLE_STAND, SCHED_ANTLIONGRUB_STAND ); - TRANSLATE_SCHEDULE( type, SCHED_PATROL_WALK,SCHED_ANTLIONGRUB_SQUIRM ); - - return BaseClass::TranslateSchedule( type ); -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : *pOther - -//----------------------------------------------------------------------------- -void CNPC_AntlionGrub::GrubTouch( CBaseEntity *pOther ) -{ - //Don't consider the world - if ( FClassnameIs( pOther, "worldspawn" ) ) - return; - - //Allow a crusing velocity to kill them in one go (or they're already dead) - if ( ( pOther->GetAbsVelocity().Length() > 200 ) || ( IsAlive() == false ) ) - { - //TakeDamage( CTakeDamageInfo( pOther, pOther, vec3_origin, GetAbsOrigin(), 100, DMG_CRUSH ) ); - return; - } - - //Need to know we're being squashed - SetCondition( COND_ANTLIONGRUB_BEING_SQUASHED ); -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : *pOther - -//----------------------------------------------------------------------------- -void CNPC_AntlionGrub::EndTouch( CBaseEntity *pOther ) -{ - ClearCondition( COND_ANTLIONGRUB_BEING_SQUASHED ); - - m_bSquashValid = false; - - /* - CSoundEnvelopeController::GetController().SoundChangePitch( m_pVoiceSound, 100, 0.5f ); - CSoundEnvelopeController::GetController().SoundChangeVolume( m_pVoiceSound, 0.0f, 1.0f ); - */ - - m_flPlaybackRate = 1.0f; -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CNPC_AntlionGrub::BroadcastAlert( void ) -{ - /* - CBaseEntity *pEntity = NULL; - CAI_BaseNPC *pNPC; - - //Look in a radius for potential listeners - for ( CEntitySphereQuery sphere( GetAbsOrigin(), ANTLIONGRUB_SQUEAL_DIST ); pEntity = sphere.GetCurrentEntity(); sphere.NextEntity() ) - { - if ( !( pEntity->GetFlags() & FL_NPC ) ) - continue; - - pNPC = pEntity->MyNPCPointer(); - - //Only antlions care - if ( pNPC->Classify() == CLASS_ANTLION ) - { - pNPC->DispatchInteraction( g_interactionAntlionGrubAlert, NULL, this ); - } - } - */ -} - -//----------------------------------------------------------------------------- -// Purpose: Twiddle damage based on certain criteria -//----------------------------------------------------------------------------- -int CNPC_AntlionGrub::OnTakeDamage_Alive( const CTakeDamageInfo &info ) -{ - CTakeDamageInfo newInfo = info; - - // Always squash on a crowbar hit - if ( newInfo.GetDamageType() & DMG_CLUB ) - { - newInfo.SetDamage( GetHealth() + 1.0f ); - } - - return BaseClass::OnTakeDamage_Alive( newInfo ); -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CNPC_AntlionGrub::PainSound( const CTakeDamageInfo &info ) -{ - BroadcastAlert(); -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : interactionType - -// *data - -// *sourceEnt - -// Output : Returns true on success, false on failure. -//----------------------------------------------------------------------------- -bool CNPC_AntlionGrub::HandleInteraction( int interactionType, void *data, CBaseCombatCharacter *sourceEnt ) -{ - //Handle squeals from our peers - if ( interactionType == g_interactionAntlionGrubAlert ) - { - SetCondition( COND_ANTLIONGRUB_HEARD_SQUEAL ); - - //float envDuration = PlayEnvelope( m_pVoiceSound, SOUNDCTRL_CHANGE_VOLUME, envScared, ARRAYSIZE(envScared) ); - //float envDuration = CSoundEnvelopeController::GetController().SoundPlayEnvelope( m_pVoiceSound, SOUNDCTRL_CHANGE_VOLUME, envMidSustain, ARRAYSIZE(envMidSustain) ); - //m_flNextVoiceChange = gpGlobals->curtime + envDuration + random->RandomFloat( 4.0f, 8.0f ); - - return true; - } - - return false; -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CNPC_AntlionGrub::Squash( CBaseEntity *pOther ) -{ - SpawnSquashedGrub(); - - AddEffects( EF_NODRAW ); - AddSolidFlags( FSOLID_NOT_SOLID ); - - EmitSound( "NPC_AntlionGrub.Squash" ); - - BroadcastAlert(); - - Vector vecUp; - AngleVectors( GetAbsAngles(), NULL, NULL, &vecUp ); - - trace_t tr; - - for ( int i = 0; i < 4; i++ ) - { - tr.endpos = WorldSpaceCenter(); - tr.endpos[0] += random->RandomFloat( -16.0f, 16.0f ); - tr.endpos[1] += random->RandomFloat( -16.0f, 16.0f ); - tr.endpos += vecUp * 8.0f; - - MakeDamageBloodDecal( 2, 0.8f, &tr, -vecUp ); - } - - SetTouch( NULL ); - - m_bSquashed = true; - - // Temp squash effect - CEffectData data; - data.m_fFlags = 0; - data.m_vOrigin = WorldSpaceCenter(); - data.m_vNormal = vecUp; - VectorAngles( vecUp, data.m_vAngles ); - data.m_flScale = random->RandomFloat( 5, 7 ); - data.m_fFlags |= FX_WATER_IN_SLIME; - DispatchEffect( "watersplash", data ); -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CNPC_AntlionGrub::SpawnSquashedGrub( void ) -{ - CGib *pStandin = CREATE_ENTITY( CGib, "gib" ); - - Assert( pStandin ); - - pStandin->SetModel( ANTLIONGRUB_SQUASHED_MODEL ); - pStandin->AddSolidFlags( FSOLID_NOT_SOLID ); - pStandin->SetLocalAngles( GetLocalAngles() ); - pStandin->SetLocalOrigin( GetLocalOrigin() ); -} - - -void CNPC_AntlionGrub::StopLoopingSounds() -{ - /* - CSoundEnvelopeController::GetController().SoundDestroy( m_pMovementSound ); - CSoundEnvelopeController::GetController().SoundDestroy( m_pVoiceSound ); - CSoundEnvelopeController::GetController().SoundDestroy( m_pHealSound ); - m_pMovementSound = NULL; - m_pVoiceSound = NULL; - m_pHealSound = NULL; - */ - - BaseClass::StopLoopingSounds(); -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CNPC_AntlionGrub::Event_Killed( const CTakeDamageInfo &info ) -{ - BaseClass::Event_Killed( info ); - - if ( ( m_bSquashed == false ) && ( info.GetDamageType() & DMG_CLUB ) ) - { - // Die! - Squash( info.GetAttacker() ); - } - else - { - //Restore this touch so we can still be squished - SetTouch( GrubTouch ); - } - - // Slowly fade out glow out - m_pGlowSprite->FadeAndDie( 5.0f ); -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CNPC_AntlionGrub::PrescheduleThink( void ) -{ - BaseClass::PrescheduleThink(); - - //Add a fail-safe for the glow sprite display - if ( !IsCurSchedule( SCHED_ANTLIONGRUB_GIVE_HEALTH ) ) - { - if ( m_bHealing ) - { - //CSoundEnvelopeController::GetController().SoundChangeVolume( m_pHealSound, 0.0f, 0.5f ); - } - - m_bHealing = false; - } - - //Do glowing maintenance - /* - if ( m_pGlowSprite != NULL ) - { - m_pGlowSprite->SetLocalOrigin( GetLocalOrigin() ); - - if ( m_pGlowSprite->IsEffectActive( EF_NODRAW ) == false ) - { - m_pGlowSprite->SetScale( random->RandomFloat( 0.75f, 1.0f ) ); - - float scale = random->RandomFloat( 0.25f, 0.75f ); - - m_pGlowSprite->SetTransparency( kRenderGlow, (int)(32.0f*scale), (int)(32.0f*scale), (int)(128.0f*scale), 255, kRenderFxNoDissipation ); - } - - //Deal with the healing glow - if ( m_bHealing ) - { - m_pGlowSprite->TurnOn(); - } - else - { - m_pGlowSprite->TurnOff(); - } - } - */ - - //Check for movement sounds - if ( m_flGroundSpeed > 0.0f ) - { - if ( m_bMoving == false ) - { - //CSoundEnvelopeController::GetController().SoundChangePitch( m_pMovementSound, 100, 0.1f ); - //CSoundEnvelopeController::GetController().SoundChangeVolume( m_pMovementSound, 0.4f, 1.0f ); - - m_bMoving = true; - } - } - else if ( m_bMoving ) - { - //CSoundEnvelopeController::GetController().SoundChangePitch( m_pMovementSound, 80, 0.5f ); - //CSoundEnvelopeController::GetController().SoundChangeVolume( m_pMovementSound, 0.0f, 1.0f ); - - m_bMoving = false; - } - - //Check for a voice change - if ( m_flNextVoiceChange < gpGlobals->curtime ) - { - //float envDuration = CSoundEnvelopeController::GetController().SoundPlayEnvelope( m_pVoiceSound, SOUNDCTRL_CHANGE_VOLUME, &grubVoiceEnvelopes[rand()%ARRAYSIZE(grubVoiceEnvelopes)] ); - //m_flNextVoiceChange = gpGlobals->curtime + envDuration + random->RandomFloat( 1.0f, 8.0f ); - } -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : flDot - -// flDist - -// Output : int -//----------------------------------------------------------------------------- -int CNPC_AntlionGrub::MeleeAttack1Conditions( float flDot, float flDist ) -{ - ClearCondition( COND_ANTLIONGRUB_IN_HEAL_RANGE ); - - //If we're outside the heal range, then reset our timer - if ( flDist > ANTLIONGRUB_HEAL_RANGE ) - { - m_flNearTime = gpGlobals->curtime + 2.0f; - return COND_TOO_FAR_TO_ATTACK; - } - - //Otherwise if we've been in range for long enough signal it - if ( m_flNearTime < gpGlobals->curtime ) - { - if ( ( m_nHealthReserve > 0 ) && ( GetEnemy()->m_iHealth < GetEnemy()->m_iMaxHealth ) ) - { - SetCondition( COND_ANTLIONGRUB_IN_HEAL_RANGE ); - } - } - - return COND_CAN_MELEE_ATTACK1; -} - -//----------------------------------------------------------------------------- -// Purpose: Allows for modification of the interrupt mask for the current schedule. -// In the most cases the base implementation should be called first. -//----------------------------------------------------------------------------- -void CNPC_AntlionGrub::BuildScheduleTestBits( void ) -{ - //Always squirm if we're being squashed - if ( !IsCurSchedule( SCHED_SMALL_FLINCH ) ) - { - SetCustomInterruptCondition( COND_ANTLIONGRUB_BEING_SQUASHED ); - } -} - - -//----------------------------------------------------------------------------- -// -// Schedules -// -//----------------------------------------------------------------------------- - - -//================================================== -// SCHED_ANTLIONGRUB_SQUEAL -//================================================== - -AI_DEFINE_SCHEDULE -( - SCHED_ANTLIONGRUB_SQUEAL, - - " Tasks" - " TASK_FACE_ENEMY 0" - " " - " Interrupts" - " COND_ANTLIONGRUB_BEING_SQUASHED " - " COND_NEW_ENEMY" -); - -//================================================== -// SCHED_ANTLIONGRUB_STAND -//================================================== - -AI_DEFINE_SCHEDULE -( - SCHED_ANTLIONGRUB_STAND, - - " Tasks" - " TASK_PLAY_SEQUENCE ACTIVITY:ACT_IDLE" - " " - " Interrupts" - " COND_LIGHT_DAMAGE" - " COND_ANTLIONGRUB_HEARD_SQUEAL" - " COND_ANTLIONGRUB_BEING_SQUASHED" - " COND_NEW_ENEMY" -); - -//================================================== -// SCHED_ANTLIONGRUB_SQUIRM -//================================================== - -AI_DEFINE_SCHEDULE -( - SCHED_ANTLIONGRUB_SQUIRM, - - " Tasks" - " TASK_ANTLIONGRUB_SQUIRM 0" - " TASK_SET_GOAL GOAL:SAVED_POSITION" - " TASK_GET_PATH_TO_GOAL PATH:TRAVEL" - " TASK_WALK_PATH 0" - " TASK_WAIT_FOR_MOVEMENT 0" - " " - " Interrupts" - " COND_TASK_FAILED" - " COND_LIGHT_DAMAGE" - " COND_ANTLIONGRUB_HEARD_SQUEAL" - " COND_ANTLIONGRUB_BEING_SQUASHED" - " COND_NEW_ENEMY" -); - -//================================================== -// SCHED_ANTLIONGRUB_GIVE_HEALTH -//================================================== - -AI_DEFINE_SCHEDULE -( - SCHED_ANTLIONGRUB_GIVE_HEALTH, - - " Tasks" - " TASK_SET_FAIL_SCHEDULE SCHEDULE:SCHED_ANTLIONGRUB_STAND" - " TASK_STOP_MOVING 0" - " TASK_SET_GOAL GOAL:ENEMY" - " TASK_GET_PATH_TO_GOAL PATH:TRAVEL" - " TASK_RUN_PATH 0" - " TASK_ANTLIONGRUB_MOVE_TO_TARGET 48" - " TASK_STOP_MOVING 0" - " TASK_FACE_ENEMY 0" - " TASK_ANTLIONGRUB_GIVE_HEALTH 0" - " TASK_SET_SCHEDULE SCHEDULE:SCHED_ANTLIONGRUB_SQUIRM" - " " - " Interrupts" - " COND_TASK_FAILED" - " COND_NEW_ENEMY" - " COND_ANTLIONGRUB_BEING_SQUASHED" - " COND_ANTLIONGRUB_HEARD_SQUEAL" -); - -//================================================== -// SCHED_ANTLIONGUARD_RETREAT -//================================================== - -AI_DEFINE_SCHEDULE -( - SCHED_ANTLIONGUARD_RETREAT, - - " Tasks" - " TASK_SET_FAIL_SCHEDULE SCHEDULE:SCHED_ANTLIONGRUB_STAND" - " TASK_STOP_MOVING 0" - " TASK_ANTLIONGRUB_FIND_RETREAT_GOAL 0" - " TASK_SET_GOAL GOAL:SAVED_POSITION" - " TASK_GET_PATH_TO_GOAL PATH:TRAVEL" - " TASK_RUN_PATH 0" - " TASK_WAIT_FOR_MOVEMENT 0" - " TASK_SET_SCHEDULE SCHEDULE:SCHED_ANTLIONGRUB_STAND" - " " - " Interrupts" - " COND_TASK_FAILED" - " COND_NEW_ENEMY" - " COND_ANTLIONGRUB_BEING_SQUASHED" - " COND_ANTLIONGRUB_HEARD_SQUEAL" -); diff --git a/src/src/dlls/hl2_dll/npc_combine.cpp b/src/src/dlls/hl2_dll/npc_combine.cpp deleted file mode 100644 index e7f071e..0000000 --- a/src/src/dlls/hl2_dll/npc_combine.cpp +++ /dev/null @@ -1,3654 +0,0 @@ -//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// -// -// Purpose: -// -//=============================================================================// - -#include "cbase.h" -#include "ai_hull.h" -#include "ai_navigator.h" -#include "ai_motor.h" -#include "ai_squadslot.h" -#include "ai_squad.h" -#include "ai_route.h" -#include "ai_interactions.h" -#include "ai_tacticalservices.h" -#include "soundent.h" -#include "game.h" -#include "npcevent.h" -#include "npc_combine.h" -#include "activitylist.h" -#include "player.h" -#include "basecombatweapon.h" -#include "basegrenade_shared.h" -#include "vstdlib/random.h" -#include "engine/IEngineSound.h" -#include "globals.h" -#include "grenade_frag.h" -#include "ndebugoverlay.h" -#include "weapon_physcannon.h" -#include "SoundEmitterSystem/isoundemittersystembase.h" -#include "npc_headcrab.h" - -// memdbgon must be the last include file in a .cpp file!!! -#include "tier0/memdbgon.h" - -int g_fCombineQuestion; // true if an idle grunt asked a question. Cleared when someone answers. YUCK old global from grunt code - -#define COMBINE_GRENADE_THROW_SPEED 650 -#define COMBINE_GRENADE_TIMER 3.5 -#define COMBINE_GRENADE_FLUSH_TIME 3.0 // Don't try to flush an enemy who has been out of sight for longer than this. -#define COMBINE_GRENADE_FLUSH_DIST 256.0 // Don't try to flush an enemy who has moved farther than this distance from the last place I saw him. - -#define COMBINE_LIMP_HEALTH 20 -#define COMBINE_MIN_GRENADE_CLEAR_DIST 250 - -#define COMBINE_EYE_STANDING_POSITION Vector( 0, 0, 66 ) -#define COMBINE_GUN_STANDING_POSITION Vector( 0, 0, 57 ) -#define COMBINE_EYE_CROUCHING_POSITION Vector( 0, 0, 40 ) -#define COMBINE_GUN_CROUCHING_POSITION Vector( 0, 0, 36 ) -#define COMBINE_SHOTGUN_STANDING_POSITION Vector( 0, 0, 36 ) -#define COMBINE_SHOTGUN_CROUCHING_POSITION Vector( 0, 0, 36 ) -#define COMBINE_MIN_CROUCH_DISTANCE 256.0 - -//----------------------------------------------------------------------------- -// Static stuff local to this file. -//----------------------------------------------------------------------------- -// This is the index to the name of the shotgun's classname in the string pool -// so that we can get away with an integer compare rather than a string compare. -string_t s_iszShotgunClassname; - -//----------------------------------------------------------------------------- -// Interactions -//----------------------------------------------------------------------------- -int g_interactionCombineBash = 0; // melee bash attack - -//========================================================= -// Combines's Anim Events Go Here -//========================================================= -#define COMBINE_AE_RELOAD ( 2 ) -#define COMBINE_AE_KICK ( 3 ) -#define COMBINE_AE_AIM ( 4 ) -#define COMBINE_AE_GREN_TOSS ( 7 ) -#define COMBINE_AE_GREN_LAUNCH ( 8 ) -#define COMBINE_AE_GREN_DROP ( 9 ) -#define COMBINE_AE_CAUGHT_ENEMY ( 10) // grunt established sight with an enemy (player only) that had previously eluded the squad. - -int COMBINE_AE_BEGIN_ALTFIRE; -int COMBINE_AE_ALTFIRE; - -//========================================================= -// Combine activities -//========================================================= -//Activity ACT_COMBINE_STANDING_SMG1; -//Activity ACT_COMBINE_CROUCHING_SMG1; -//Activity ACT_COMBINE_STANDING_AR2; -//Activity ACT_COMBINE_CROUCHING_AR2; -//Activity ACT_COMBINE_WALKING_AR2; -//Activity ACT_COMBINE_STANDING_SHOTGUN; -//Activity ACT_COMBINE_CROUCHING_SHOTGUN; -Activity ACT_COMBINE_THROW_GRENADE; -Activity ACT_COMBINE_LAUNCH_GRENADE; -Activity ACT_COMBINE_BUGBAIT; -Activity ACT_COMBINE_AR2_ALTFIRE; - -// ----------------------------------------------- -// > Squad slots -// ----------------------------------------------- -enum SquadSlot_T -{ - SQUAD_SLOT_GRENADE1 = LAST_SHARED_SQUADSLOT, - SQUAD_SLOT_GRENADE2, - SQUAD_SLOT_ATTACK_OCCLUDER, -}; - - -#define bits_MEMORY_PAIN_LIGHT_SOUND bits_MEMORY_CUSTOM1 -#define bits_MEMORY_PAIN_HEAVY_SOUND bits_MEMORY_CUSTOM2 -#define bits_MEMORY_PLAYER_HURT bits_MEMORY_CUSTOM3 - -LINK_ENTITY_TO_CLASS( npc_combine, CNPC_Combine ); - -//--------------------------------------------------------- -// Save/Restore -//--------------------------------------------------------- -BEGIN_DATADESC( CNPC_Combine ) - - DEFINE_FIELD( m_nKickDamage, FIELD_INTEGER ), - DEFINE_FIELD( m_vecTossVelocity, FIELD_VECTOR ), - DEFINE_FIELD( m_hForcedGrenadeTarget, FIELD_EHANDLE ), - DEFINE_FIELD( m_bShouldPatrol, FIELD_BOOLEAN ), - DEFINE_FIELD( m_bFirstEncounter, FIELD_BOOLEAN ), - DEFINE_FIELD( m_flNextPainSoundTime, FIELD_TIME ), - DEFINE_FIELD( m_flNextAlertSoundTime, FIELD_TIME ), - DEFINE_FIELD( m_flNextGrenadeCheck, FIELD_TIME ), - DEFINE_FIELD( m_flNextLostSoundTime, FIELD_TIME ), - DEFINE_FIELD( m_flAlertPatrolTime, FIELD_TIME ), - DEFINE_FIELD( m_flNextAltFireTime, FIELD_TIME ), - DEFINE_FIELD( m_nShots, FIELD_INTEGER ), - DEFINE_FIELD( m_flShotDelay, FIELD_FLOAT ), - DEFINE_KEYFIELD( m_iNumGrenades, FIELD_INTEGER, "NumGrenades" ), - DEFINE_EMBEDDED( m_Sentences ), - - // m_AssaultBehavior (auto saved by AI) - // m_StandoffBehavior (auto saved by AI) - // m_FollowBehavior (auto saved by AI) - // m_FuncTankBehavior (auto saved by AI) - // m_RappelBehavior (auto saved by AI) - // m_ActBusyBehavior (auto saved by AI) - - DEFINE_INPUTFUNC( FIELD_VOID, "LookOff", InputLookOff ), - DEFINE_INPUTFUNC( FIELD_VOID, "LookOn", InputLookOn ), - - DEFINE_INPUTFUNC( FIELD_VOID, "StartPatrolling", InputStartPatrolling ), - DEFINE_INPUTFUNC( FIELD_VOID, "StopPatrolling", InputStopPatrolling ), - - DEFINE_INPUTFUNC( FIELD_STRING, "Assault", InputAssault ), - - DEFINE_INPUTFUNC( FIELD_VOID, "HitByBugbait", InputHitByBugbait ), - - DEFINE_INPUTFUNC( FIELD_STRING, "ThrowGrenadeAtTarget", InputThrowGrenadeAtTarget ), - - DEFINE_FIELD( m_iLastAnimEventHandled, FIELD_INTEGER ), - DEFINE_FIELD( m_fIsElite, FIELD_BOOLEAN ), - DEFINE_FIELD( m_vecAltFireTarget, FIELD_VECTOR ), - - -END_DATADESC() - - -//------------------------------------------------------------------------------ -// Constructor. -//------------------------------------------------------------------------------ -CNPC_Combine::CNPC_Combine() -{ - m_vecTossVelocity = vec3_origin; -} - - -//----------------------------------------------------------------------------- -// Create components -//----------------------------------------------------------------------------- -bool CNPC_Combine::CreateComponents() -{ - if ( !BaseClass::CreateComponents() ) - return false; - - m_Sentences.Init( this, "NPC_Combine.SentenceParameters" ); - return true; -} - - -//------------------------------------------------------------------------------ -// Purpose: Don't look, only get info from squad. -//------------------------------------------------------------------------------ -void CNPC_Combine::InputLookOff( inputdata_t &inputdata ) -{ - m_spawnflags |= SF_COMBINE_NO_LOOK; -} - -//------------------------------------------------------------------------------ -// Purpose: Enable looking. -//------------------------------------------------------------------------------ -void CNPC_Combine::InputLookOn( inputdata_t &inputdata ) -{ - m_spawnflags &= ~SF_COMBINE_NO_LOOK; -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CNPC_Combine::InputStartPatrolling( inputdata_t &inputdata ) -{ - m_bShouldPatrol = true; -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CNPC_Combine::InputStopPatrolling( inputdata_t &inputdata ) -{ - m_bShouldPatrol = false; -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CNPC_Combine::InputAssault( inputdata_t &inputdata ) -{ - m_AssaultBehavior.SetParameters( AllocPooledString(inputdata.value.String()), CUE_DONT_WAIT, RALLY_POINT_SELECT_DEFAULT ); -} - -//----------------------------------------------------------------------------- -// We were hit by bugbait -//----------------------------------------------------------------------------- -void CNPC_Combine::InputHitByBugbait( inputdata_t &inputdata ) -{ - SetCondition( COND_COMBINE_HIT_BY_BUGBAIT ); -} - -//----------------------------------------------------------------------------- -// Purpose: Force the combine soldier to throw a grenade at the target -// If I'm a combine elite, fire my combine ball at the target instead. -// Input : &inputdata - -//----------------------------------------------------------------------------- -void CNPC_Combine::InputThrowGrenadeAtTarget( inputdata_t &inputdata ) -{ - CBaseEntity *pEntity = gEntList.FindEntityByName( NULL, inputdata.value.String(), NULL, inputdata.pActivator, inputdata.pCaller ); - if ( !pEntity ) - { - DevMsg("%s (%s) received ThrowGrenadeAtTarget input, but couldn't find target entity '%s'\n", GetClassname(), GetDebugName(), inputdata.value.String() ); - return; - } - - m_hForcedGrenadeTarget = pEntity; - m_flNextGrenadeCheck = 0; - - ClearSchedule(); -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CNPC_Combine::Precache() -{ - PrecacheModel("models/Weapons/w_grenade.mdl"); - UTIL_PrecacheOther( "npc_handgrenade" ); - - PrecacheScriptSound( "NPC_Combine.GrenadeLaunch" ); - PrecacheScriptSound( "NPC_Combine.WeaponBash" ); - PrecacheScriptSound( "Weapon_CombineGuard.Special1" ); - enginesound->PrecacheSentenceGroup( "COMBINE" ); - BaseClass::Precache(); -} - -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -void CNPC_Combine::Activate() -{ - s_iszShotgunClassname = FindPooledString( "weapon_shotgun" ); - BaseClass::Activate(); -} - -//----------------------------------------------------------------------------- -// Purpose: -// -// -//----------------------------------------------------------------------------- -void CNPC_Combine::Spawn( void ) -{ - SetHullType(HULL_HUMAN); - SetHullSizeNormal(); - -#ifdef _XBOX - // Always fade the corpse - AddSpawnFlags( SF_NPC_FADE_CORPSE ); -#endif // _XBOX - - SetSolid( SOLID_BBOX ); - AddSolidFlags( FSOLID_NOT_STANDABLE ); - SetMoveType( MOVETYPE_STEP ); - SetBloodColor( BLOOD_COLOR_RED ); - m_flFieldOfView = -0.2;// indicates the width of this NPC's forward view cone ( as a dotproduct result ) - m_NPCState = NPC_STATE_NONE; - m_flNextGrenadeCheck = gpGlobals->curtime + 1; - m_flNextPainSoundTime = 0; - m_flNextAlertSoundTime = 0; - m_bShouldPatrol = false; - -// CapabilitiesAdd( bits_CAP_TURN_HEAD | bits_CAP_MOVE_GROUND | bits_CAP_MOVE_JUMP | bits_CAP_MOVE_CLIMB); - // JAY: Disabled jump for now - hard to compare to HL1 - CapabilitiesAdd( bits_CAP_TURN_HEAD | bits_CAP_MOVE_GROUND ); - - CapabilitiesAdd( bits_CAP_AIM_GUN ); - - // Innate range attack for grenade - // CapabilitiesAdd(bits_CAP_INNATE_RANGE_ATTACK2 ); - - // Innate range attack for kicking - CapabilitiesAdd(bits_CAP_INNATE_MELEE_ATTACK1 ); - - // Can be in a squad - CapabilitiesAdd( bits_CAP_SQUAD); - CapabilitiesAdd( bits_CAP_USE_WEAPONS ); - - CapabilitiesAdd( bits_CAP_DUCK ); // In reloading and cover - - CapabilitiesAdd( bits_CAP_NO_HIT_SQUADMATES ); - - m_bFirstEncounter = true;// this is true when the grunt spawns, because he hasn't encountered an enemy yet. - - m_HackedGunPos = Vector ( 0, 0, 55 ); - m_MoveAndShootOverlay.SetInitialDelay( 0.75 ); - - m_flNextLostSoundTime = 0; - m_flAlertPatrolTime = 0; - - m_flNextAltFireTime = gpGlobals->curtime; - - NPCInit(); -} - -//----------------------------------------------------------------------------- -// Purpose: -// Output : Returns true on success, false on failure. -//----------------------------------------------------------------------------- -bool CNPC_Combine::CreateBehaviors() -{ - AddBehavior( &m_RappelBehavior ); - AddBehavior( &m_ActBusyBehavior ); - AddBehavior( &m_AssaultBehavior ); - AddBehavior( &m_StandoffBehavior ); - AddBehavior( &m_FollowBehavior ); - AddBehavior( &m_FuncTankBehavior ); - - return BaseClass::CreateBehaviors(); -} - -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -void CNPC_Combine::PostNPCInit() -{ - if( IsElite() ) - { - // Give a warning if a Combine Soldier is equipped with anything other than - // an AR2. - if( !GetActiveWeapon() || !FClassnameIs( GetActiveWeapon(), "weapon_ar2" ) ) - { - DevWarning("**Combine Elite Soldier MUST be equipped with AR2\n"); - } - } - - BaseClass::PostNPCInit(); -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CNPC_Combine::PrescheduleThink() -{ - BaseClass::PrescheduleThink(); - - // Speak any queued sentences - m_Sentences.UpdateSentenceQueue(); - - if ( IsOnFire() ) - { - SetCondition( COND_COMBINE_ON_FIRE ); - } - else - { - ClearCondition( COND_COMBINE_ON_FIRE ); - } - - extern ConVar ai_debug_shoot_positions; - if ( ai_debug_shoot_positions.GetBool() ) - NDebugOverlay::Cross3D( EyePosition(), 16, 0, 255, 0, false, 0.1 ); -} - - -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -void CNPC_Combine::DelayAltFireAttack( float flDelay ) -{ - float flNextAltFire = gpGlobals->curtime + flDelay; - - if( flNextAltFire > m_flNextAltFireTime ) - { - // Don't let this delay order preempt a previous request to wait longer. - m_flNextAltFireTime = flNextAltFire; - } -} - -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -void CNPC_Combine::DelaySquadAltFireAttack( float flDelay ) -{ - // Make sure to delay my own alt-fire attack. - DelayAltFireAttack( flDelay ); - - AISquadIter_t iter; - CAI_BaseNPC *pSquadmate = m_pSquad ? m_pSquad->GetFirstMember( &iter ) : NULL; - while ( pSquadmate ) - { - CNPC_Combine *pCombine = dynamic_cast(pSquadmate); - - if( pCombine && pCombine->IsElite() ) - { - pCombine->DelayAltFireAttack( flDelay ); - } - - pSquadmate = m_pSquad->GetNextMember( &iter ); - } -} - -//----------------------------------------------------------------------------- -// Purpose: degrees to turn in 0.1 seconds -//----------------------------------------------------------------------------- -float CNPC_Combine::MaxYawSpeed( void ) -{ - switch( GetActivity() ) - { - case ACT_TURN_LEFT: - case ACT_TURN_RIGHT: - return 45; - break; - case ACT_RUN: - case ACT_RUN_HURT: - return 15; - break; - case ACT_WALK: - case ACT_WALK_CROUCH: - return 25; - break; - case ACT_RANGE_ATTACK1: - case ACT_RANGE_ATTACK2: - case ACT_MELEE_ATTACK1: - case ACT_MELEE_ATTACK2: - return 35; - default: - return 35; - break; - } -} - - -//----------------------------------------------------------------------------- -// Purpose: turn in the direction of movement -// Output : -//----------------------------------------------------------------------------- -bool CNPC_Combine::OverrideMoveFacing( const AILocalMoveGoal_t &move, float flInterval ) -{ - // FIXME: this will break scripted sequences that walk when they have an enemy - if (GetEnemy() && (GetNavigator()->GetMovementActivity() == ACT_WALK_AIM || GetNavigator()->GetMovementActivity() == ACT_WALK || GetNavigator()->GetMovementActivity() == ACT_RUN_AIM)) - { - Vector vecEnemyLKP = GetEnemyLKP(); - AddFacingTarget( GetEnemy(), vecEnemyLKP, 1.0, 0.2 ); - } - - return BaseClass::OverrideMoveFacing( move, flInterval ); -} - - -//----------------------------------------------------------------------------- -// Purpose: -// -// -//----------------------------------------------------------------------------- -Class_T CNPC_Combine::Classify ( void ) -{ - return CLASS_COMBINE; -} - - -//----------------------------------------------------------------------------- -// Continuous movement tasks -//----------------------------------------------------------------------------- -bool CNPC_Combine::IsCurTaskContinuousMove() -{ - const Task_t* pTask = GetTask(); - if ( pTask && (pTask->iTask == TASK_COMBINE_CHASE_ENEMY_CONTINUOUSLY) ) - return true; - - return BaseClass::IsCurTaskContinuousMove(); -} - - -//----------------------------------------------------------------------------- -// Chase the enemy, updating the target position as the player moves -//----------------------------------------------------------------------------- -void CNPC_Combine::StartTaskChaseEnemyContinuously( const Task_t *pTask ) -{ - CBaseEntity *pEnemy = GetEnemy(); - if ( !pEnemy ) - { - TaskFail( FAIL_NO_ENEMY ); - return; - } - - // We're done once we get close enough - if ( WorldSpaceCenter().DistToSqr( pEnemy->WorldSpaceCenter() ) <= pTask->flTaskData * pTask->flTaskData ) - { - TaskComplete(); - return; - } - - // TASK_GET_PATH_TO_ENEMY - if ( IsUnreachable( pEnemy ) ) - { - TaskFail(FAIL_NO_ROUTE); - return; - } - - if ( !GetNavigator()->SetGoal( GOALTYPE_ENEMY, AIN_NO_PATH_TASK_FAIL ) ) - { - // no way to get there =( - DevWarning( 2, "GetPathToEnemy failed!!\n" ); - RememberUnreachable( pEnemy ); - TaskFail(FAIL_NO_ROUTE); - return; - } - - // NOTE: This is TaskRunPath here. - if ( TranslateActivity( ACT_RUN ) != ACT_INVALID ) - { - GetNavigator()->SetMovementActivity( ACT_RUN ); - } - else - { - GetNavigator()->SetMovementActivity(ACT_WALK); - } - - // Cover is void once I move - Forget( bits_MEMORY_INCOVER ); - - if (GetNavigator()->GetGoalType() == GOALTYPE_NONE) - { - TaskComplete(); - GetNavigator()->ClearGoal(); // Clear residual state - return; - } - - // No shooting delay when in this mode - m_MoveAndShootOverlay.SetInitialDelay( 0.0 ); - - if (!GetNavigator()->IsGoalActive()) - { - SetIdealActivity( GetStoppedActivity() ); - } - else - { - // Check validity of goal type - ValidateNavGoal(); - } - - // set that we're probably going to stop before the goal - GetNavigator()->SetArrivalDistance( pTask->flTaskData ); - m_vSavePosition = GetEnemy()->WorldSpaceCenter(); -} - -void CNPC_Combine::RunTaskChaseEnemyContinuously( const Task_t *pTask ) -{ - if (!GetNavigator()->IsGoalActive()) - { - SetIdealActivity( GetStoppedActivity() ); - } - else - { - // Check validity of goal type - ValidateNavGoal(); - } - - CBaseEntity *pEnemy = GetEnemy(); - if ( !pEnemy ) - { - TaskFail( FAIL_NO_ENEMY ); - return; - } - - // We're done once we get close enough - if ( WorldSpaceCenter().DistToSqr( pEnemy->WorldSpaceCenter() ) <= pTask->flTaskData * pTask->flTaskData ) - { - GetNavigator()->StopMoving(); - TaskComplete(); - return; - } - - // Recompute path if the enemy has moved too much - if ( m_vSavePosition.DistToSqr( pEnemy->WorldSpaceCenter() ) < (pTask->flTaskData * pTask->flTaskData) ) - return; - - if ( IsUnreachable( pEnemy ) ) - { - TaskFail(FAIL_NO_ROUTE); - return; - } - - if ( !GetNavigator()->RefindPathToGoal() ) - { - TaskFail(FAIL_NO_ROUTE); - return; - } - - m_vSavePosition = pEnemy->WorldSpaceCenter(); -} - - -//========================================================= -// start task -//========================================================= -void CNPC_Combine::StartTask( const Task_t *pTask ) -{ - // NOTE: This reset is required because we change it in TASK_COMBINE_CHASE_ENEMY_CONTINUOUSLY - m_MoveAndShootOverlay.SetInitialDelay( 0.75 ); - - switch ( pTask->iTask ) - { - case TASK_COMBINE_CHASE_ENEMY_CONTINUOUSLY: - StartTaskChaseEnemyContinuously( pTask ); - break; - - case TASK_COMBINE_PLAY_SEQUENCE_FACE_ALTFIRE_TARGET: - SetIdealActivity( (Activity)(int)pTask->flTaskData ); - GetMotor()->SetIdealYawToTargetAndUpdate( m_vecAltFireTarget, AI_KEEP_YAW_SPEED ); - break; - - case TASK_COMBINE_SIGNAL_BEST_SOUND: - if( IsInSquad() && GetSquad()->NumMembers() > 1 ) - { - CBasePlayer *pPlayer = AI_GetSinglePlayer(); - - if( pPlayer && OccupyStrategySlot( SQUAD_SLOT_EXCLUSIVE_HANDSIGN ) && pPlayer->FInViewCone( this ) ) - { - CSound *pSound; - pSound = GetBestSound(); - - Assert( pSound != NULL ); - - Vector right, tosound; - - GetVectors( NULL, &right, NULL ); - - tosound = pSound->GetSoundReactOrigin() - GetAbsOrigin(); - VectorNormalize( tosound); - - tosound.z = 0; - right.z = 0; - - if( DotProduct( right, tosound ) > 0 ) - { - // Right - SetIdealActivity( ACT_SIGNAL_RIGHT ); - } - else - { - // Left - SetIdealActivity( ACT_SIGNAL_LEFT ); - } - - break; - } - } - - // Otherwise, just skip it. - TaskComplete(); - break; - - case TASK_ANNOUNCE_ATTACK: - { - // If Primary Attack - if ((int)pTask->flTaskData == 1) - { - // ----------------------------------------------------------- - // If enemy isn't facing me and I haven't attacked in a while - // annouce my attack before I start wailing away - // ----------------------------------------------------------- - CBaseCombatCharacter *pBCC = GetEnemyCombatCharacterPointer(); - - if (pBCC && pBCC->IsPlayer() && (!pBCC->FInViewCone ( this )) && - (gpGlobals->curtime - m_flLastAttackTime > 3.0) ) - { - m_flLastAttackTime = gpGlobals->curtime; - - m_Sentences.Speak( "COMBINE_ANNOUNCE", SENTENCE_PRIORITY_HIGH ); - - // Wait two seconds - SetWait( 2.0 ); - - if ( !IsCrouching() ) - { - SetActivity(ACT_IDLE); - } - else - { - SetActivity(ACT_COWER); // This is really crouch idle - } - } - // ------------------------------------------------------------- - // Otherwise move on - // ------------------------------------------------------------- - else - { - TaskComplete(); - } - } - else - { - m_Sentences.Speak( "COMBINE_THROW_GRENADE", SENTENCE_PRIORITY_MEDIUM ); - SetActivity(ACT_IDLE); - - // Wait two seconds - SetWait( 2.0 ); - } - break; - } - - case TASK_WALK_PATH: - case TASK_RUN_PATH: - // grunt no longer assumes he is covered if he moves - Forget( bits_MEMORY_INCOVER ); - BaseClass::StartTask( pTask ); - break; - - case TASK_COMBINE_FACE_TOSS_DIR: - break; - - case TASK_COMBINE_GET_PATH_TO_FORCED_GREN_LOS: - { - if ( !m_hForcedGrenadeTarget ) - { - TaskFail(FAIL_NO_ENEMY); - return; - } - - float flMaxRange = 2000; - float flMinRange = 0; - - Vector vecEnemy = m_hForcedGrenadeTarget->GetAbsOrigin(); - Vector vecEnemyEye = vecEnemy + m_hForcedGrenadeTarget->GetViewOffset(); - - Vector posLos; - bool found = false; - - if ( GetTacticalServices()->FindLateralLos( vecEnemyEye, &posLos ) ) - { - float dist = ( posLos - vecEnemyEye ).Length(); - if ( dist < flMaxRange && dist > flMinRange ) - found = true; - } - - if ( !found && GetTacticalServices()->FindLos( vecEnemy, vecEnemyEye, flMinRange, flMaxRange, 1.0, &posLos ) ) - { - found = true; - } - - if ( !found ) - { - TaskFail( FAIL_NO_SHOOT ); - } - else - { - // else drop into run task to offer an interrupt - m_vInterruptSavePosition = posLos; - } - } - break; - - case TASK_COMBINE_IGNORE_ATTACKS: - // must be in a squad - if (m_pSquad && m_pSquad->NumMembers() > 2) - { - // the enemy must be far enough away - if (GetEnemy() && (GetEnemy()->WorldSpaceCenter() - WorldSpaceCenter()).Length() > 512.0 ) - { - m_flNextAttack = gpGlobals->curtime + pTask->flTaskData; - } - } - TaskComplete( ); - break; - - case TASK_COMBINE_DEFER_SQUAD_GRENADES: - { - if ( m_pSquad ) - { - // iterate my squad and stop everyone from throwing grenades for a little while. - AISquadIter_t iter; - - CAI_BaseNPC *pSquadmate = m_pSquad ? m_pSquad->GetFirstMember( &iter ) : NULL; - while ( pSquadmate ) - { - CNPC_Combine *pCombine = dynamic_cast(pSquadmate); - - if( pCombine ) - { - pCombine->m_flNextGrenadeCheck = gpGlobals->curtime + 5; - } - - pSquadmate = m_pSquad->GetNextMember( &iter ); - } - } - - TaskComplete(); - break; - } - - case TASK_FACE_IDEAL: - case TASK_FACE_ENEMY: - { - if( pTask->iTask == TASK_FACE_ENEMY && HasCondition( COND_CAN_RANGE_ATTACK1 ) ) - { - TaskComplete(); - return; - } - - BaseClass::StartTask( pTask ); - bool bIsFlying = (GetMoveType() == MOVETYPE_FLY) || (GetMoveType() == MOVETYPE_FLYGRAVITY); - if (bIsFlying) - { - SetIdealActivity( ACT_GLIDE ); - } - - } - break; - - case TASK_FIND_COVER_FROM_ENEMY: - { - if (GetHintGroup() == NULL_STRING) - { - CBaseEntity *pEntity = GetEnemy(); - - // FIXME: this should be generalized by the schedules that are selected, or in the definition of - // what "cover" means (i.e., trace attack vulnerability vs. physical attack vulnerability - if ( pEntity ) - { - // NOTE: This is a good time to check to see if the player is hurt. - // Have the combine notice this and call out - if ( !HasMemory(bits_MEMORY_PLAYER_HURT) && pEntity->IsPlayer() && pEntity->GetHealth() <= 20 ) - { - if ( m_pSquad ) - { - m_pSquad->SquadRemember(bits_MEMORY_PLAYER_HURT); - } - - m_Sentences.Speak( "COMBINE_PLAYERHIT", SENTENCE_PRIORITY_INVALID ); - JustMadeSound( SENTENCE_PRIORITY_HIGH ); - } - if ( pEntity->MyNPCPointer() ) - { - if ( !(pEntity->MyNPCPointer()->CapabilitiesGet( ) & bits_CAP_WEAPON_RANGE_ATTACK1) && - !(pEntity->MyNPCPointer()->CapabilitiesGet( ) & bits_CAP_INNATE_RANGE_ATTACK1) ) - { - TaskComplete(); - return; - } - } - } - } - BaseClass::StartTask( pTask ); - } - break; - case TASK_RANGE_ATTACK1: - { - m_nShots = GetActiveWeapon()->GetRandomBurst(); - m_flShotDelay = GetActiveWeapon()->GetFireRate(); - - m_flNextAttack = gpGlobals->curtime + m_flShotDelay - 0.1; - ResetIdealActivity( ACT_RANGE_ATTACK1 ); - m_flLastAttackTime = gpGlobals->curtime; - } - break; - - case TASK_COMBINE_DIE_INSTANTLY: - { - CTakeDamageInfo info; - - info.SetAttacker( this ); - info.SetInflictor( this ); - info.SetDamage( m_iHealth ); - info.SetDamageType( pTask->flTaskData ); - info.SetDamageForce( Vector( 0.1, 0.1, 0.1 ) ); - - TakeDamage( info ); - - TaskComplete(); - } - break; - - default: - BaseClass:: StartTask( pTask ); - break; - } -} - -//========================================================= -// RunTask -//========================================================= -void CNPC_Combine::RunTask( const Task_t *pTask ) -{ - /* - { - CBaseEntity *pEnemy = GetEnemy(); - if (pEnemy) - { - NDebugOverlay::Line(Center(), pEnemy->Center(), 0,255,255, false, 0.1); - } - - } - */ - - /* - if (m_iMySquadSlot != SQUAD_SLOT_NONE) - { - char text[64]; - Q_snprintf( text, strlen( text ), "%d", m_iMySquadSlot ); - - NDebugOverlay::Text( Center() + Vector( 0, 0, 72 ), text, false, 0.1 ); - } - */ - - switch ( pTask->iTask ) - { - case TASK_COMBINE_CHASE_ENEMY_CONTINUOUSLY: - RunTaskChaseEnemyContinuously( pTask ); - break; - - case TASK_COMBINE_SIGNAL_BEST_SOUND: - AutoMovement( ); - if ( IsActivityFinished() ) - { - TaskComplete(); - } - break; - - case TASK_ANNOUNCE_ATTACK: - { - // Stop waiting if enemy facing me or lost enemy - CBaseCombatCharacter* pBCC = GetEnemyCombatCharacterPointer(); - if (!pBCC || pBCC->FInViewCone( this )) - { - TaskComplete(); - } - - if ( IsWaitFinished() ) - { - TaskComplete(); - } - } - break; - - case TASK_COMBINE_PLAY_SEQUENCE_FACE_ALTFIRE_TARGET: - GetMotor()->SetIdealYawToTargetAndUpdate( m_vecAltFireTarget, AI_KEEP_YAW_SPEED ); - - if ( IsActivityFinished() ) - { - TaskComplete(); - } - break; - - case TASK_COMBINE_FACE_TOSS_DIR: - { - // project a point along the toss vector and turn to face that point. - GetMotor()->SetIdealYawToTargetAndUpdate( GetLocalOrigin() + m_vecTossVelocity * 64, AI_KEEP_YAW_SPEED ); - - if ( FacingIdeal() ) - { - TaskComplete( true ); - } - break; - } - - case TASK_COMBINE_GET_PATH_TO_FORCED_GREN_LOS: - { - if ( !m_hForcedGrenadeTarget ) - { - TaskFail(FAIL_NO_ENEMY); - return; - } - - if ( GetTaskInterrupt() > 0 ) - { - ClearTaskInterrupt(); - - Vector vecEnemy = m_hForcedGrenadeTarget->GetAbsOrigin(); - AI_NavGoal_t goal( m_vInterruptSavePosition, ACT_RUN, AIN_HULL_TOLERANCE ); - - GetNavigator()->SetGoal( goal, AIN_CLEAR_TARGET ); - GetNavigator()->SetArrivalDirection( vecEnemy - goal.dest ); - } - else - { - TaskInterrupt(); - } - } - break; - - case TASK_RANGE_ATTACK1: - { - AutoMovement( ); - - Vector vecEnemyLKP = GetEnemyLKP(); - if (!FInAimCone( vecEnemyLKP )) - { - GetMotor()->SetIdealYawToTargetAndUpdate( vecEnemyLKP, AI_KEEP_YAW_SPEED ); - } - else - { - GetMotor()->SetIdealYawAndUpdate( GetMotor()->GetIdealYaw(), AI_KEEP_YAW_SPEED ); - } - - if ( gpGlobals->curtime >= m_flNextAttack ) - { - if ( IsActivityFinished() ) - { - if (--m_nShots > 0) - { - // DevMsg("ACT_RANGE_ATTACK1\n"); - ResetIdealActivity( ACT_RANGE_ATTACK1 ); - m_flLastAttackTime = gpGlobals->curtime; - m_flNextAttack = gpGlobals->curtime + m_flShotDelay - 0.1; - } - else - { - // DevMsg("TASK_RANGE_ATTACK1 complete\n"); - TaskComplete(); - } - } - } - else - { - // DevMsg("Wait\n"); - } - } - break; - - default: - { - BaseClass::RunTask( pTask ); - break; - } - } -} - -//------------------------------------------------------------------------------ -// Purpose : Override to always shoot at eyes (for ducking behind things) -// Input : -// Output : -//------------------------------------------------------------------------------ -Vector CNPC_Combine::BodyTarget( const Vector &posSrc, bool bNoisy ) -{ - Vector result = BaseClass::BodyTarget( posSrc, bNoisy ); - - // @TODO (toml 02-02-04): this seems wrong. Isn't this already be accounted for - // with the eye position used in the base BodyTarget() - if ( GetFlags() & FL_DUCKING ) - result -= Vector(0,0,16); - - return result; -} - -//------------------------------------------------------------------------------ -// Purpose: -//------------------------------------------------------------------------------ -bool CNPC_Combine::FVisible( CBaseEntity *pEntity, int traceMask, CBaseEntity **ppBlocker ) -{ - if( m_spawnflags & SF_COMBINE_NO_LOOK ) - { - // When no look is set, if enemy has eluded the squad, - // he's always invisble to me - if (GetEnemies()->HasEludedMe(pEntity)) - { - return false; - } - } - return BaseClass::FVisible(pEntity, traceMask, ppBlocker); -} - -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -void CNPC_Combine::Event_Killed( const CTakeDamageInfo &info ) -{ - // if I was killed before I could finish throwing my grenade, drop - // a grenade item that the player can retrieve. - if( GetActivity() == ACT_RANGE_ATTACK2 ) - { - if( m_iLastAnimEventHandled != COMBINE_AE_GREN_TOSS ) - { - // Drop the grenade as an item. - Vector vecStart; - GetAttachment( "lefthand", vecStart ); - - CBaseEntity *pItem = DropItem( "weapon_frag", vecStart, RandomAngle(0,360) ); - - if ( pItem ) - { - IPhysicsObject *pObj = pItem->VPhysicsGetObject(); - - if ( pObj ) - { - Vector vel; - vel.x = random->RandomFloat( -100.0f, 100.0f ); - vel.y = random->RandomFloat( -100.0f, 100.0f ); - vel.z = random->RandomFloat( 800.0f, 1200.0f ); - AngularImpulse angImp = RandomAngularImpulse( -300.0f, 300.0f ); - - vel[2] = 0.0f; - pObj->AddVelocity( &vel, &angImp ); - } - - // In the Citadel we need to dissolve this - if ( PlayerHasMegaPhysCannon() ) - { - CBaseCombatWeapon *pWeapon = static_cast(pItem); - - pWeapon->Dissolve( NULL, gpGlobals->curtime, false, ENTITY_DISSOLVE_NORMAL ); - } - } - } - } - - BaseClass::Event_Killed( info ); -} - -//----------------------------------------------------------------------------- -// Purpose: Override. Don't update if I'm not looking -// Input : -// Output : Returns true is new enemy, false is known enemy -//----------------------------------------------------------------------------- -bool CNPC_Combine::UpdateEnemyMemory( CBaseEntity *pEnemy, const Vector &position, CBaseEntity *pInformer ) -{ - if( m_spawnflags & SF_COMBINE_NO_LOOK ) - { - return false; - } - - return BaseClass::UpdateEnemyMemory( pEnemy, position, pInformer ); -} - - -//----------------------------------------------------------------------------- -// Purpose: Allows for modification of the interrupt mask for the current schedule. -// In the most cases the base implementation should be called first. -//----------------------------------------------------------------------------- -void CNPC_Combine::BuildScheduleTestBits( void ) -{ - BaseClass::BuildScheduleTestBits(); - - if (gpGlobals->curtime < m_flNextAttack) - { - ClearCustomInterruptCondition( COND_CAN_RANGE_ATTACK1 ); - ClearCustomInterruptCondition( COND_CAN_RANGE_ATTACK2 ); - } - - SetCustomInterruptCondition( COND_COMBINE_HIT_BY_BUGBAIT ); - - if ( !IsCurSchedule( SCHED_COMBINE_BURNING_STAND ) ) - { - SetCustomInterruptCondition( COND_COMBINE_ON_FIRE ); - } -} - - -//----------------------------------------------------------------------------- -// Purpose: Translate base class activities into combot activites -//----------------------------------------------------------------------------- -Activity CNPC_Combine::NPC_TranslateActivity( Activity eNewActivity ) -{ - //Slaming this back to ACT_COMBINE_BUGBAIT since we don't want ANYTHING to change our activity while we burn. - if ( HasCondition( COND_COMBINE_ON_FIRE ) ) - return BaseClass::NPC_TranslateActivity( ACT_COMBINE_BUGBAIT ); - - if (eNewActivity == ACT_RANGE_ATTACK2) - { - // grunt is going to a secondary long range attack. This may be a thrown - // grenade or fired grenade, we must determine which and pick proper sequence - if (Weapon_OwnsThisType( "weapon_grenadelauncher" ) ) - { - return ( Activity )ACT_COMBINE_LAUNCH_GRENADE; - } - else - { - return ( Activity )ACT_COMBINE_THROW_GRENADE; - } - } - else if (eNewActivity == ACT_IDLE) - { - if ( !IsCrouching() && ( m_NPCState == NPC_STATE_COMBAT || m_NPCState == NPC_STATE_ALERT ) ) - { - eNewActivity = ACT_IDLE_ANGRY; - } - } - - if ( m_AssaultBehavior.IsRunning() ) - { - switch ( eNewActivity ) - { - case ACT_IDLE: - eNewActivity = ACT_IDLE_ANGRY; - break; - - case ACT_WALK: - eNewActivity = ACT_WALK_AIM; - break; - - case ACT_RUN: - eNewActivity = ACT_RUN_AIM; - break; - } - } - - return BaseClass::NPC_TranslateActivity( eNewActivity ); -} - - -//----------------------------------------------------------------------------- -// Purpose: Overidden for human grunts because they hear the DANGER sound -// Input : -// Output : -//----------------------------------------------------------------------------- -int CNPC_Combine::GetSoundInterests( void ) -{ - return SOUND_WORLD | SOUND_COMBAT | SOUND_PLAYER | SOUND_DANGER | SOUND_PHYSICS_DANGER | SOUND_BULLET_IMPACT | SOUND_MOVE_AWAY; -} - -//----------------------------------------------------------------------------- -// Purpose: Return true if this NPC can hear the specified sound -//----------------------------------------------------------------------------- -bool CNPC_Combine::QueryHearSound( CSound *pSound ) -{ - if ( pSound->SoundContext() & SOUND_CONTEXT_COMBINE_ONLY ) - return true; - - if ( pSound->SoundContext() & SOUND_CONTEXT_EXCLUDE_COMBINE ) - return false; - - return BaseClass::QueryHearSound( pSound ); -} - - -//----------------------------------------------------------------------------- -// Purpose: Announce an assault if the enemy can see me and we are pretty -// close to him/her -// Input : -// Output : -//----------------------------------------------------------------------------- -void CNPC_Combine::AnnounceAssault(void) -{ - if (random->RandomInt(0,5) > 1) - return; - - // If enemy can see me make assualt sound - CBaseCombatCharacter* pBCC = GetEnemyCombatCharacterPointer(); - - if (!pBCC) - return; - - if (!FOkToMakeSound()) - return; - - // Make sure we are pretty close - if ( WorldSpaceCenter().DistToSqr( pBCC->WorldSpaceCenter() ) > (2000 * 2000)) - return; - - // Make sure we are in view cone of player - if (!pBCC->FInViewCone ( this )) - return; - - // Make sure player can see me - if ( FVisible( pBCC ) ) - { - m_Sentences.Speak( "COMBINE_ASSAULT" ); - } -} - - -void CNPC_Combine::AnnounceEnemyType( CBaseEntity *pEnemy ) -{ - const char *pSentenceName = "COMBINE_MONST"; - switch ( pEnemy->Classify() ) - { - case CLASS_PLAYER: - pSentenceName = "COMBINE_ALERT"; - break; - - case CLASS_PLAYER_ALLY: - case CLASS_CITIZEN_REBEL: - case CLASS_CITIZEN_PASSIVE: - case CLASS_VORTIGAUNT: - pSentenceName = "COMBINE_MONST_CITIZENS"; - break; - - case CLASS_PLAYER_ALLY_VITAL: - pSentenceName = "COMBINE_MONST_CHARACTER"; - break; - - case CLASS_ANTLION: - pSentenceName = "COMBINE_MONST_BUGS"; - break; - - case CLASS_ZOMBIE: - pSentenceName = "COMBINE_MONST_ZOMBIES"; - break; - - case CLASS_HEADCRAB: - case CLASS_BARNACLE: - pSentenceName = "COMBINE_MONST_PARASITES"; - break; - } - - m_Sentences.Speak( pSentenceName, SENTENCE_PRIORITY_HIGH ); -} - -void CNPC_Combine::AnnounceEnemyKill( CBaseEntity *pEnemy ) -{ - if (!pEnemy ) - return; - - const char *pSentenceName = "COMBINE_KILL_MONST"; - switch ( pEnemy->Classify() ) - { - case CLASS_PLAYER: - pSentenceName = "COMBINE_PLAYER_DEAD"; - break; - - // no sentences for these guys yet - case CLASS_PLAYER_ALLY: - case CLASS_CITIZEN_REBEL: - case CLASS_CITIZEN_PASSIVE: - case CLASS_VORTIGAUNT: - break; - - case CLASS_PLAYER_ALLY_VITAL: - break; - - case CLASS_ANTLION: - break; - - case CLASS_ZOMBIE: - break; - - case CLASS_HEADCRAB: - case CLASS_BARNACLE: - break; - } - - m_Sentences.Speak( pSentenceName, SENTENCE_PRIORITY_HIGH ); -} - -//----------------------------------------------------------------------------- -// Select the combat schedule -//----------------------------------------------------------------------------- -int CNPC_Combine::SelectCombatSchedule() -{ - // ----------- - // dead enemy - // ----------- - if ( HasCondition( COND_ENEMY_DEAD ) ) - { - // call base class, all code to handle dead enemies is centralized there. - return SCHED_NONE; - } - - // ----------- - // new enemy - // ----------- - if ( HasCondition( COND_NEW_ENEMY ) ) - { - CBaseEntity *pEnemy = GetEnemy(); - if ( m_pSquad && pEnemy ) - { - if ( m_pSquad->IsLeader( this ) || ( m_pSquad->GetLeader() && m_pSquad->GetLeader()->GetEnemy() != pEnemy ) ) - { - // First contact, and I'm the squad leader. - AnnounceEnemyType( pEnemy ); - - if ( HasCondition( COND_CAN_RANGE_ATTACK1 ) && OccupyStrategySlotRange( SQUAD_SLOT_ATTACK1, SQUAD_SLOT_ATTACK2 ) ) - { - return SCHED_COMBINE_SUPPRESS; - } - else - { - return SCHED_COMBINE_ASSAULT; - } - } - else - { - if ( m_pSquad->GetLeader() && FOkToMakeSound( SENTENCE_PRIORITY_MEDIUM ) ) - { - JustMadeSound( SENTENCE_PRIORITY_MEDIUM ); // squelch anything that isn't high priority so the leader can speak - } - - // First contact, and I'm solo, or not the squad leader. - if( HasCondition( COND_SEE_ENEMY ) && CanGrenadeEnemy() ) - { - if( OccupyStrategySlot( SQUAD_SLOT_GRENADE1 ) ) - { - return SCHED_RANGE_ATTACK2; - } - } - - return SCHED_TAKE_COVER_FROM_ENEMY; - } - } - } - - // --------------------- - // no ammo - // --------------------- - if ( ( HasCondition ( COND_NO_PRIMARY_AMMO ) || HasCondition ( COND_LOW_PRIMARY_AMMO ) ) && !HasCondition( COND_CAN_MELEE_ATTACK1) ) - { - return SCHED_HIDE_AND_RELOAD; - } - -#if 0 //WEDGE - if (!HasCondition(COND_CAN_RANGE_ATTACK1) && HasCondition( COND_NO_SECONDARY_AMMO )) - { - return SCHED_HIDE_AND_RELOAD; - } -#endif - - // ---------------------- - // LIGHT DAMAGE - // ---------------------- - if ( HasCondition( COND_LIGHT_DAMAGE ) ) - { - // if hurt: - // 90% chance of taking cover - // 10% chance of flinch. - int iPercent = random->RandomInt(0,99); - - if ( iPercent <= 90 && GetEnemy() != NULL ) - { - // only try to take cover if we actually have an enemy! - - // FIXME: need to take cover for enemy dealing the damage - - //!!!KELLY - this grunt was hit and is going to run to cover. - // m_Sentences.Speak( "COMBINE_COVER" ); - - return SCHED_TAKE_COVER_FROM_ENEMY; - } - else - { - // taking damage should have entered a "null" enemy position into memory - return SCHED_FEAR_FACE; - } - } - - int attackSchedule = SelectScheduleAttack(); - if ( attackSchedule != SCHED_NONE ) - return attackSchedule; - - if (HasCondition(COND_ENEMY_OCCLUDED)) - { - // stand up, just in case - Stand(); - DesireStand(); - - if( GetEnemy() && !(GetEnemy()->GetFlags() & FL_NOTARGET) && OccupyStrategySlotRange( SQUAD_SLOT_ATTACK1, SQUAD_SLOT_ATTACK2 ) ) - { - // Charge in and break the enemy's cover! - return SCHED_COMBINE_ESTABLISH_LINE_OF_FIRE; - } - - // If I'm a long, long way away, establish a LOF anyway. Once I get there I'll - // start respecting the squad slots again. - float flDistSq = GetEnemy()->WorldSpaceCenter().DistToSqr( WorldSpaceCenter() ); - if ( flDistSq > (3000*3000) ) - return SCHED_COMBINE_ESTABLISH_LINE_OF_FIRE; - - return SCHED_STANDOFF; - } - - // -------------------------------------------------------------- - // Enemy not occluded but isn't open to attack - // -------------------------------------------------------------- - if ( HasCondition( COND_SEE_ENEMY ) && !HasCondition( COND_CAN_RANGE_ATTACK1 ) ) - { - if (HasCondition( COND_TOO_FAR_TO_ATTACK ) && OccupyStrategySlotRange( SQUAD_SLOT_ATTACK1, SQUAD_SLOT_ATTACK2 )) - { - return SCHED_COMBINE_PRESS_ATTACK; - } - - AnnounceAssault(); - return SCHED_COMBINE_ASSAULT; - } - - return SCHED_NONE; -} - - -//----------------------------------------------------------------------------- -// Purpose: -// Input : -// Output : -//----------------------------------------------------------------------------- -int CNPC_Combine::SelectSchedule( void ) -{ - if ( HasCondition(COND_COMBINE_ON_FIRE) ) - return SCHED_COMBINE_BURNING_STAND; - - int nSched = SelectFlinchSchedule(); - if ( nSched != SCHED_NONE ) - return nSched; - - if ( m_hForcedGrenadeTarget ) - { - if ( m_flNextGrenadeCheck < gpGlobals->curtime ) - { - Vector vecTarget = m_hForcedGrenadeTarget->WorldSpaceCenter(); - - if ( IsElite() ) - { - if ( BaseClass::FVisible( vecTarget ) ) - { - m_vecAltFireTarget = vecTarget; - m_hForcedGrenadeTarget = NULL; - return SCHED_COMBINE_AR2_ALTFIRE; - } - } - else - { - // If we can, throw a grenade at the target. - // Ignore grenade count / distance / etc - if ( CheckCanThrowGrenade( vecTarget ) ) - { - m_hForcedGrenadeTarget = NULL; - return SCHED_COMBINE_FORCED_GRENADE_THROW; - } - } - } - - // Can't throw at the target, so lets try moving to somewhere where I can see it - if ( !FVisible( m_hForcedGrenadeTarget ) ) - return SCHED_COMBINE_MOVE_TO_FORCED_GREN_LOS; - } - - if ( m_NPCState != NPC_STATE_SCRIPT) - { - // If we're hit by bugbait, thrash around - if ( HasCondition( COND_COMBINE_HIT_BY_BUGBAIT ) ) - { - // Don't do this if we're mounting a func_tank - if ( m_FuncTankBehavior.IsMounted() == true ) - { - m_FuncTankBehavior.Dismount(); - } - - ClearCondition( COND_COMBINE_HIT_BY_BUGBAIT ); - return SCHED_COMBINE_BUGBAIT_DISTRACTION; - } - - // We've been told to move away from a target to make room for a grenade to be thrown at it - if ( HasCondition( COND_HEAR_MOVE_AWAY ) ) - { - return SCHED_MOVE_AWAY; - } - - // These things are done in any state but dead and prone - if (m_NPCState != NPC_STATE_DEAD && m_NPCState != NPC_STATE_PRONE ) - { - // Cower when physics objects are thrown at me - if ( HasCondition( COND_HEAR_PHYSICS_DANGER ) ) - return SCHED_FLINCH_PHYSICS; - - // grunts place HIGH priority on running away from danger sounds. - if ( HasCondition(COND_HEAR_DANGER) ) - { - CSound *pSound; - pSound = GetBestSound(); - - Assert( pSound != NULL ); - if ( pSound) - { - if (pSound->m_iType & SOUND_DANGER) - { - // I hear something dangerous, probably need to take cover. - // dangerous sound nearby!, call it out - const char *pSentenceName = "COMBINE_DANGER"; - - CBaseEntity *pSoundOwner = pSound->m_hOwner; - if ( pSoundOwner ) - { - CBaseGrenade *pGrenade = dynamic_cast(pSoundOwner); - if ( pGrenade && pGrenade->GetThrower() ) - { - if ( IRelationType( pGrenade->GetThrower() ) != D_LI ) - { - // special case call out for enemy grenades - pSentenceName = "COMBINE_GREN"; - } - } - } - - m_Sentences.Speak( pSentenceName, SENTENCE_PRIORITY_NORMAL, SENTENCE_CRITERIA_NORMAL ); - - // If the sound is approaching danger, I have no enemy, and I don't see it, turn to face. - if( !GetEnemy() && pSound->IsSoundType(SOUND_CONTEXT_DANGER_APPROACH) && pSound->m_hOwner && !FInViewCone(pSound->GetSoundReactOrigin()) ) - { - GetMotor()->SetIdealYawToTarget( pSound->GetSoundReactOrigin() ); - return SCHED_COMBINE_FACE_IDEAL_YAW; - } - - return SCHED_TAKE_COVER_FROM_BEST_SOUND; - } - - // JAY: This was disabled in HL1. Test? - if (!HasCondition( COND_SEE_ENEMY ) && ( pSound->m_iType & (SOUND_PLAYER | SOUND_COMBAT) )) - { - GetMotor()->SetIdealYawToTarget( pSound->GetSoundReactOrigin() ); - } - } - } - } - - if( BehaviorSelectSchedule() ) - { - return BaseClass::SelectSchedule(); - } - } - - switch ( m_NPCState ) - { - case NPC_STATE_IDLE: - { - if ( m_bShouldPatrol ) - return SCHED_COMBINE_PATROL; - } - // NOTE: Fall through! - - case NPC_STATE_ALERT: - { - if( HasCondition(COND_LIGHT_DAMAGE) || HasCondition(COND_HEAVY_DAMAGE) ) - { - AI_EnemyInfo_t *pDanger = GetEnemies()->GetDangerMemory(); - if( pDanger && FInViewCone(pDanger->vLastKnownLocation) && !BaseClass::FVisible(pDanger->vLastKnownLocation) ) - { - // I've been hurt, I'm facing the danger, but I don't see it, so move from this position. - return SCHED_TAKE_COVER_FROM_ORIGIN; - } - } - - if( HasCondition( COND_HEAR_COMBAT ) ) - { - if( m_pSquad && OccupyStrategySlot( SQUAD_SLOT_INVESTIGATE_SOUND ) ) - return SCHED_INVESTIGATE_SOUND; - } - - // Don't patrol if I'm in the middle of an assault, because I'll never return to the assault. - if ( !m_AssaultBehavior.HasAssaultCue() ) - { - if( m_bShouldPatrol || HasCondition( COND_COMBINE_SHOULD_PATROL ) ) - return SCHED_COMBINE_PATROL; - } - } - break; - - case NPC_STATE_COMBAT: - { - int nSched = SelectCombatSchedule(); - if ( nSched != SCHED_NONE ) - return nSched; - } - break; - } - - // no special cases here, call the base class - return BaseClass::SelectSchedule(); -} - - -//----------------------------------------------------------------------------- -// Should we charge the player? -//----------------------------------------------------------------------------- -bool CNPC_Combine::ShouldChargePlayer() -{ - return GetEnemy() && GetEnemy()->IsPlayer() && PlayerHasMegaPhysCannon() && !IsLimitingHintGroups(); -} - - -//----------------------------------------------------------------------------- -// Select attack schedules -//----------------------------------------------------------------------------- -#define COMBINE_MEGA_PHYSCANNON_ATTACK_DISTANCE 192 -#define COMBINE_MEGA_PHYSCANNON_ATTACK_DISTANCE_SQ (COMBINE_MEGA_PHYSCANNON_ATTACK_DISTANCE*COMBINE_MEGA_PHYSCANNON_ATTACK_DISTANCE) - -int CNPC_Combine::SelectScheduleAttack() -{ - // Drop a grenade? - if ( HasCondition( COND_COMBINE_DROP_GRENADE ) ) - return SCHED_COMBINE_DROP_GRENADE; - - // Kick attack? - if ( HasCondition( COND_CAN_MELEE_ATTACK1 ) ) - { - return SCHED_MELEE_ATTACK1; - } - - // If I'm fighting a combine turret (it's been hacked to attack me), I can't really - // hurt it with bullets, so become grenade happy. - if ( GetEnemy() && GetEnemy()->Classify() == CLASS_COMBINE && FClassnameIs(GetEnemy(), "npc_turret_floor") ) - { - // Don't do this until I've been fighting the turret for a few seconds - float flTimeAtFirstHand = GetEnemies()->TimeAtFirstHand(GetEnemy()); - if ( flTimeAtFirstHand != AI_INVALID_TIME ) - { - float flTimeEnemySeen = gpGlobals->curtime - flTimeAtFirstHand; - if ( flTimeEnemySeen > 4.0 ) - { - if ( CanGrenadeEnemy() && OccupyStrategySlot( SQUAD_SLOT_GRENADE1 ) ) - return SCHED_RANGE_ATTACK2; - } - } - - // If we're not in the viewcone of the turret, run up and hit it. Do this a bit later to - // give other squadmembers a chance to throw a grenade before I run in. - if ( !GetEnemy()->MyNPCPointer()->FInViewCone( this ) && OccupyStrategySlot( SQUAD_SLOT_GRENADE1 ) ) - return SCHED_COMBINE_CHARGE_TURRET; - } - - // When fighting against the player who's wielding a mega-physcannon, - // always close the distance if possible - // But don't do it if you're in a nav-limited hint group - if ( ShouldChargePlayer() ) - { - float flDistSq = GetEnemy()->WorldSpaceCenter().DistToSqr( WorldSpaceCenter() ); - if ( flDistSq <= COMBINE_MEGA_PHYSCANNON_ATTACK_DISTANCE_SQ ) - { - if ( HasCondition( COND_CAN_RANGE_ATTACK1 ) && OccupyStrategySlotRange( SQUAD_SLOT_ATTACK1, SQUAD_SLOT_ATTACK2 ) ) - return SCHED_RANGE_ATTACK1; - } - - if ( HasCondition(COND_SEE_ENEMY) && !IsUnreachable( GetEnemy() ) ) - { - return SCHED_COMBINE_CHARGE_PLAYER; - } - } - - // Can I shoot? - if ( HasCondition(COND_CAN_RANGE_ATTACK1) ) - { - -// JAY: HL1 behavior missing? -#if 0 - if ( m_pSquad ) - { - // if the enemy has eluded the squad and a squad member has just located the enemy - // and the enemy does not see the squad member, issue a call to the squad to waste a - // little time and give the player a chance to turn. - if ( MySquadLeader()->m_fEnemyEluded && !HasConditions ( bits_COND_ENEMY_FACING_ME ) ) - { - MySquadLeader()->m_fEnemyEluded = FALSE; - return SCHED_GRUNT_FOUND_ENEMY; - } - } -#endif - - // Engage if allowed - if ( OccupyStrategySlotRange( SQUAD_SLOT_ATTACK1, SQUAD_SLOT_ATTACK2 ) ) - { - return SCHED_RANGE_ATTACK1; - } - - // Throw a grenade if not allowed to engage with weapon. - if ( CanGrenadeEnemy() ) - { - if ( OccupyStrategySlot( SQUAD_SLOT_GRENADE1 ) ) - { - return SCHED_RANGE_ATTACK2; - } - } - - DesireCrouch(); - return SCHED_TAKE_COVER_FROM_ENEMY; - } - - if ( GetEnemy() && !HasCondition(COND_SEE_ENEMY) ) - { - // We don't see our enemy. If it hasn't been long since I last saw him, - // and he's pretty close to the last place I saw him, throw a grenade in - // to flush him out. A wee bit of cheating here... - - float flTime; - float flDist; - - flTime = gpGlobals->curtime - GetEnemies()->LastTimeSeen( GetEnemy() ); - flDist = ( GetEnemy()->GetAbsOrigin() - GetEnemies()->LastSeenPosition( GetEnemy() ) ).Length(); - - //Msg("Time: %f Dist: %f\n", flTime, flDist ); - if ( flTime <= COMBINE_GRENADE_FLUSH_TIME && flDist <= COMBINE_GRENADE_FLUSH_DIST && CanGrenadeEnemy( false ) && OccupyStrategySlot( SQUAD_SLOT_GRENADE1 ) ) - { - return SCHED_RANGE_ATTACK2; - } - } - - if (HasCondition(COND_WEAPON_SIGHT_OCCLUDED)) - { - // If they are hiding behind something that we can destroy, start shooting at it. - CBaseEntity *pBlocker = GetEnemyOccluder(); - if ( pBlocker && pBlocker->GetHealth() > 0 && OccupyStrategySlot( SQUAD_SLOT_ATTACK_OCCLUDER ) ) - { - return SCHED_SHOOT_ENEMY_COVER; - } - } - - return SCHED_NONE; -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : -// Output : -//----------------------------------------------------------------------------- -int CNPC_Combine::TranslateSchedule( int scheduleType ) -{ - switch( scheduleType ) - { - case SCHED_TAKE_COVER_FROM_ENEMY: - { - if ( m_pSquad ) - { - // Have to explicitly check innate range attack condition as may have weapon with range attack 2 - if ( g_pGameRules->IsSkillLevel( SKILL_HARD ) && - HasCondition(COND_CAN_RANGE_ATTACK2) && - OccupyStrategySlot( SQUAD_SLOT_GRENADE1 ) ) - { - m_Sentences.Speak( "COMBINE_THROW_GRENADE" ); - return SCHED_COMBINE_TOSS_GRENADE_COVER1; - } - else - { - if ( ShouldChargePlayer() && !IsUnreachable( GetEnemy() ) ) - return SCHED_COMBINE_CHARGE_PLAYER; - - return SCHED_COMBINE_TAKE_COVER1; - } - } - else - { - // Have to explicitly check innate range attack condition as may have weapon with range attack 2 - if ( random->RandomInt(0,1) && HasCondition(COND_CAN_RANGE_ATTACK2) ) - { - return SCHED_COMBINE_GRENADE_COVER1; - } - else - { - if ( ShouldChargePlayer() && !IsUnreachable( GetEnemy() ) ) - return SCHED_COMBINE_CHARGE_PLAYER; - - return SCHED_COMBINE_TAKE_COVER1; - } - } - } - case SCHED_TAKE_COVER_FROM_BEST_SOUND: - { - return SCHED_COMBINE_TAKE_COVER_FROM_BEST_SOUND; - } - break; - case SCHED_COMBINE_TAKECOVER_FAILED: - { - if ( HasCondition( COND_CAN_RANGE_ATTACK1 ) && OccupyStrategySlotRange( SQUAD_SLOT_ATTACK1, SQUAD_SLOT_ATTACK2 ) ) - { - return TranslateSchedule( SCHED_RANGE_ATTACK1 ); - } - - // Run somewhere randomly - return TranslateSchedule( SCHED_FAIL ); - break; - } - break; - case SCHED_FAIL_ESTABLISH_LINE_OF_FIRE: - { - if( HasCondition( COND_SEE_ENEMY ) ) - { - return TranslateSchedule( SCHED_TAKE_COVER_FROM_ENEMY ); - } - else if ( !m_AssaultBehavior.HasAssaultCue() ) - { - // Don't patrol if I'm in the middle of an assault, because - // I'll never return to the assault. - if ( GetEnemy() ) - RememberUnreachable( GetEnemy() ); - - return TranslateSchedule( SCHED_COMBINE_PATROL ); - } - } - break; - case SCHED_COMBINE_ASSAULT: - { - CBaseEntity *pEntity = GetEnemy(); - - // FIXME: this should be generalized by the schedules that are selected, or in the definition of - // what "cover" means (i.e., trace attack vulnerability vs. physical attack vulnerability - if (pEntity && pEntity->MyNPCPointer()) - { - if ( !(pEntity->MyNPCPointer()->CapabilitiesGet( ) & bits_CAP_WEAPON_RANGE_ATTACK1)) - { - return TranslateSchedule( SCHED_ESTABLISH_LINE_OF_FIRE ); - } - } - // don't charge forward if there's a hint group - if (GetHintGroup() != NULL_STRING) - { - return TranslateSchedule( SCHED_ESTABLISH_LINE_OF_FIRE ); - } - return SCHED_COMBINE_ASSAULT; - } - case SCHED_ESTABLISH_LINE_OF_FIRE: - { - // always assume standing - Stand(); - - if( CanAltFireEnemy(true) && OccupyStrategySlot(SQUAD_SLOT_SPECIAL_ATTACK) ) - { - // If an elite in the squad could fire a combine ball at the player's last known position, - // do so! - return SCHED_COMBINE_AR2_ALTFIRE; - } - - return SCHED_COMBINE_ESTABLISH_LINE_OF_FIRE; - } - break; - case SCHED_HIDE_AND_RELOAD: - { - // stand up, just in case - // Stand(); - // DesireCrouch(); - if( CanGrenadeEnemy() && OccupyStrategySlot( SQUAD_SLOT_GRENADE1 ) && random->RandomInt( 0, 100 ) < 20 ) - { - // If I COULD throw a grenade and I need to reload, 20% chance I'll throw a grenade before I hide to reload. - return SCHED_COMBINE_GRENADE_AND_RELOAD; - } - - // No running away in the citadel! - if ( ShouldChargePlayer() ) - return SCHED_RELOAD; - - return SCHED_COMBINE_HIDE_AND_RELOAD; - } - break; - case SCHED_RANGE_ATTACK1: - { - if ( HasCondition( COND_NO_PRIMARY_AMMO ) || HasCondition( COND_LOW_PRIMARY_AMMO ) ) - { - return TranslateSchedule( SCHED_HIDE_AND_RELOAD ); - } - - if( CanAltFireEnemy(true) && OccupyStrategySlot(SQUAD_SLOT_SPECIAL_ATTACK) ) - { - // Since I'm holding this squadslot, no one else can try right now. If I die before the shot - // goes off, I won't have affected anyone else's ability to use this attack at their nearest - // convenience. - return SCHED_COMBINE_AR2_ALTFIRE; - } - - if ( CrouchIsDesired() && !HasCondition( COND_HEAVY_DAMAGE )) - { - // See if we can crouch and shoot - if (GetEnemy() != NULL) - { - float dist = (GetLocalOrigin() - GetEnemy()->GetLocalOrigin()).Length(); - - // only crouch if they are relativly far away - if (dist > COMBINE_MIN_CROUCH_DISTANCE) - { - // try crouching - Crouch(); - - Vector targetPos = GetEnemy()->BodyTarget(GetActiveWeapon()->GetLocalOrigin()); - - // if we can't see it crouched, stand up - if (!WeaponLOSCondition(GetLocalOrigin(),targetPos,false)) - { - Stand(); - } - } - } - } - else - { - // always assume standing - Stand(); - } - - return SCHED_COMBINE_RANGE_ATTACK1; - } - case SCHED_RANGE_ATTACK2: - { - // If my weapon can range attack 2 use the weapon - if (GetActiveWeapon() && GetActiveWeapon()->CapabilitiesGet() & bits_CAP_WEAPON_RANGE_ATTACK2) - { - return SCHED_RANGE_ATTACK2; - } - // Otherwise use innate attack - else - { - return SCHED_COMBINE_RANGE_ATTACK2; - } - } - // SCHED_COMBAT_FACE: - // SCHED_COMBINE_WAIT_FACE_ENEMY: - // SCHED_COMBINE_SWEEP: - // SCHED_COMBINE_COVER_AND_RELOAD: - // SCHED_COMBINE_FOUND_ENEMY: - - case SCHED_VICTORY_DANCE: - { - return SCHED_COMBINE_VICTORY_DANCE; - } - case SCHED_COMBINE_SUPPRESS: - { -#define MIN_SIGNAL_DIST 256 - if ( GetEnemy() != NULL && GetEnemy()->IsPlayer() && m_bFirstEncounter ) - { - float flDistToEnemy = ( GetEnemy()->GetAbsOrigin() - GetAbsOrigin() ).Length(); - - if( flDistToEnemy >= MIN_SIGNAL_DIST ) - { - m_bFirstEncounter = false;// after first encounter, leader won't issue handsigns anymore when he has a new enemy - return SCHED_COMBINE_SIGNAL_SUPPRESS; - } - } - - return SCHED_COMBINE_SUPPRESS; - } - case SCHED_FAIL: - { - if ( GetEnemy() != NULL ) - { - return SCHED_COMBINE_COMBAT_FAIL; - } - return SCHED_FAIL; - } - - case SCHED_COMBINE_PATROL: - { - // If I have an enemy, don't go off into random patrol mode. - if ( GetEnemy() && GetEnemy()->IsAlive() ) - return SCHED_COMBINE_PATROL_ENEMY; - - return SCHED_COMBINE_PATROL; - } - } - - return BaseClass::TranslateSchedule( scheduleType ); -} - -//========================================================= -//========================================================= -void CNPC_Combine::OnStartSchedule( int scheduleType ) -{ -} - -//========================================================= -// HandleAnimEvent - catches the monster-specific messages -// that occur when tagged animation frames are played. -//========================================================= -void CNPC_Combine::HandleAnimEvent( animevent_t *pEvent ) -{ - Vector vecShootDir; - Vector vecShootOrigin; - bool handledEvent = false; - - if (pEvent->type & AE_TYPE_NEWEVENTSYSTEM) - { - if ( pEvent->event == COMBINE_AE_BEGIN_ALTFIRE ) - { - EmitSound( "Weapon_CombineGuard.Special1" ); - handledEvent = true; - } - else if ( pEvent->event == COMBINE_AE_ALTFIRE ) - { - if( IsElite() ) - { - animevent_t fakeEvent; - - fakeEvent.pSource = this; - fakeEvent.event = EVENT_WEAPON_AR2_ALTFIRE; - GetActiveWeapon()->Operator_HandleAnimEvent( &fakeEvent, this ); - - // Stop other squad members from combine balling for a while. - DelaySquadAltFireAttack( 10.0f ); - - m_iNumGrenades--; - } - - handledEvent = true; - } - else - { - BaseClass::HandleAnimEvent( pEvent ); - } - } - else - { - switch( pEvent->event ) - { - case COMBINE_AE_AIM: - { - handledEvent = true; - break; - } - case COMBINE_AE_RELOAD: - - // We never actually run out of ammo, just need to refill the clip - if (GetActiveWeapon()) - { - GetActiveWeapon()->WeaponSound( RELOAD_NPC ); - GetActiveWeapon()->m_iClip1 = GetActiveWeapon()->GetMaxClip1(); - GetActiveWeapon()->m_iClip2 = GetActiveWeapon()->GetMaxClip2(); - } - ClearCondition(COND_LOW_PRIMARY_AMMO); - ClearCondition(COND_NO_PRIMARY_AMMO); - ClearCondition(COND_NO_SECONDARY_AMMO); - handledEvent = true; - break; - - case COMBINE_AE_GREN_TOSS: - { - Vector vecSpin; - vecSpin.x = random->RandomFloat( -1000.0, 1000.0 ); - vecSpin.y = random->RandomFloat( -1000.0, 1000.0 ); - vecSpin.z = random->RandomFloat( -1000.0, 1000.0 ); - - Vector vecStart; - GetAttachment( "lefthand", vecStart ); - - if( m_NPCState == NPC_STATE_SCRIPT ) - { - // Use a fixed velocity for grenades thrown in scripted state. - // Grenades thrown from a script do not count against grenades remaining for the AI to use. - Vector forward, up, vecThrow; - - GetVectors( &forward, NULL, &up ); - vecThrow = forward * 750 + up * 175; - Fraggrenade_Create( vecStart, vec3_angle, vecThrow, vecSpin, this, COMBINE_GRENADE_TIMER, true ); - } - else - { - // Use the Velocity that AI gave us. - Fraggrenade_Create( vecStart, vec3_angle, m_vecTossVelocity, vecSpin, this, COMBINE_GRENADE_TIMER, true ); - m_iNumGrenades--; - } - - // wait six seconds before even looking again to see if a grenade can be thrown. - m_flNextGrenadeCheck = gpGlobals->curtime + 6; - } - handledEvent = true; - break; - - case COMBINE_AE_GREN_LAUNCH: - { - EmitSound( "NPC_Combine.GrenadeLaunch" ); - - CBaseEntity *pGrenade = CreateNoSpawn( "npc_contactgrenade", Weapon_ShootPosition(), vec3_angle, this ); - pGrenade->KeyValue( "velocity", m_vecTossVelocity ); - pGrenade->Spawn( ); - - if ( g_pGameRules->IsSkillLevel(SKILL_HARD) ) - m_flNextGrenadeCheck = gpGlobals->curtime + random->RandomFloat( 2, 5 );// wait a random amount of time before shooting again - else - m_flNextGrenadeCheck = gpGlobals->curtime + 6;// wait six seconds before even looking again to see if a grenade can be thrown. - } - handledEvent = true; - break; - - case COMBINE_AE_GREN_DROP: - { - Vector vecStart; - GetAttachment( "lefthand", vecStart ); - - Fraggrenade_Create( vecStart, vec3_angle, m_vecTossVelocity, vec3_origin, this, COMBINE_GRENADE_TIMER, true ); - m_iNumGrenades--; - } - handledEvent = true; - break; - - case COMBINE_AE_KICK: - { - // Does no damage, because damage is applied based upon whether the target can handle the interaction - CBaseEntity *pHurt = CheckTraceHullAttack( 70, -Vector(16,16,18), Vector(16,16,18), 0, DMG_CLUB ); - CBaseCombatCharacter* pBCC = ToBaseCombatCharacter( pHurt ); - if (pBCC) - { - Vector forward, up; - AngleVectors( GetLocalAngles(), &forward, NULL, &up ); - - if ( !pBCC->DispatchInteraction( g_interactionCombineBash, NULL, this ) ) - { - if ( pBCC->IsPlayer() ) - { - pBCC->ViewPunch( QAngle(-12,-7,0) ); - pHurt->ApplyAbsVelocityImpulse( forward * 100 + up * 50 ); - } - - CTakeDamageInfo info( this, this, m_nKickDamage, DMG_CLUB ); - CalculateMeleeDamageForce( &info, forward, pBCC->GetAbsOrigin() ); - pBCC->TakeDamage( info ); - - EmitSound( "NPC_Combine.WeaponBash" ); - } - } - - m_Sentences.Speak( "COMBINE_KICK" ); - handledEvent = true; - break; - } - - case COMBINE_AE_CAUGHT_ENEMY: - m_Sentences.Speak( "COMBINE_ALERT" ); - handledEvent = true; - break; - - default: - BaseClass::HandleAnimEvent( pEvent ); - break; - } - } - - if( handledEvent ) - { - m_iLastAnimEventHandled = pEvent->event; - } -} - -//----------------------------------------------------------------------------- -// Purpose: Get shoot position of BCC at an arbitrary position -// Input : -// Output : -//----------------------------------------------------------------------------- -Vector CNPC_Combine::Weapon_ShootPosition( ) -{ - bool bStanding = !IsCrouching(); - Vector right; - GetVectors( NULL, &right, NULL ); - - if ((CapabilitiesGet() & bits_CAP_DUCK) ) - { - if ( IsCrouchedActivity( GetActivity() ) ) - bStanding = false; - } - - // FIXME: rename this "estimated" since it's not based on animation - // FIXME: the orientation won't be correct when testing from arbitary positions for arbitary angles - - if ( bStanding ) - { - if( HasShotgun() ) - { - return GetAbsOrigin() + COMBINE_SHOTGUN_STANDING_POSITION + right * 8; - } - else - { - return GetAbsOrigin() + COMBINE_GUN_STANDING_POSITION + right * 8; - } - } - else - { - if( HasShotgun() ) - { - return GetAbsOrigin() + COMBINE_SHOTGUN_CROUCHING_POSITION + right * 8; - } - else - { - return GetAbsOrigin() + COMBINE_GUN_CROUCHING_POSITION + right * 8; - } - } -} - - -//========================================================= -// Speak Sentence - say your cued up sentence. -// -// Some grunt sentences (take cover and charge) rely on actually -// being able to execute the intended action. It's really lame -// when a grunt says 'COVER ME' and then doesn't move. The problem -// is that the sentences were played when the decision to TRY -// to move to cover was made. Now the sentence is played after -// we know for sure that there is a valid path. The schedule -// may still fail but in most cases, well after the grunt has -// started moving. -//========================================================= -void CNPC_Combine::SpeakSentence( int sentenceType ) -{ - switch( sentenceType ) - { - case 0: // assault - AnnounceAssault(); - break; - - case 1: // Flanking the player - // If I'm moving more than 20ft, I need to talk about it - if ( GetNavigator()->GetPath()->GetPathLength() > 20 * 12.0f ) - { - m_Sentences.Speak( "COMBINE_FLANK" ); - } - break; - } -} - -//========================================================= -// PainSound -//========================================================= -void CNPC_Combine::PainSound( const CTakeDamageInfo &info ) -{ - // NOTE: The response system deals with this at the moment - if ( GetFlags() & FL_DISSOLVING ) - return; - - if ( gpGlobals->curtime > m_flNextPainSoundTime ) - { - const char *pSentenceName = "COMBINE_PAIN"; - float healthRatio = (float)GetHealth() / (float)GetMaxHealth(); - if ( !HasMemory(bits_MEMORY_PAIN_LIGHT_SOUND) && healthRatio > 0.9 ) - { - Remember( bits_MEMORY_PAIN_LIGHT_SOUND ); - pSentenceName = "COMBINE_TAUNT"; - } - else if ( !HasMemory(bits_MEMORY_PAIN_HEAVY_SOUND) && healthRatio < 0.25 ) - { - Remember( bits_MEMORY_PAIN_HEAVY_SOUND ); - pSentenceName = "COMBINE_COVER"; - } - - m_Sentences.Speak( pSentenceName, SENTENCE_PRIORITY_INVALID, SENTENCE_CRITERIA_ALWAYS ); - m_flNextPainSoundTime = gpGlobals->curtime + 1; - } -} - -//----------------------------------------------------------------------------- -// Purpose: implemented by subclasses to give them an opportunity to make -// a sound when they lose their enemy -// Input : -// Output : -//----------------------------------------------------------------------------- -void CNPC_Combine::LostEnemySound( void) -{ - if ( gpGlobals->curtime <= m_flNextLostSoundTime ) - return; - - const char *pSentence; - if (!(CBaseEntity*)GetEnemy() || gpGlobals->curtime - GetEnemyLastTimeSeen() > 10) - { - pSentence = "COMBINE_LOST_LONG"; - } - else - { - pSentence = "COMBINE_LOST_SHORT"; - } - - if ( m_Sentences.Speak( pSentence ) >= 0 ) - { - m_flNextLostSoundTime = gpGlobals->curtime + random->RandomFloat(5.0,15.0); - } -} - -//----------------------------------------------------------------------------- -// Purpose: implemented by subclasses to give them an opportunity to make -// a sound when they lose their enemy -// Input : -// Output : -//----------------------------------------------------------------------------- -void CNPC_Combine::FoundEnemySound( void) -{ - m_Sentences.Speak( "COMBINE_REFIND_ENEMY", SENTENCE_PRIORITY_HIGH ); -} - -//----------------------------------------------------------------------------- -// Purpose: Implemented by subclasses to give them an opportunity to make -// a sound before they attack -// Input : -// Output : -//----------------------------------------------------------------------------- - -// BUGBUG: It looks like this is never played because combine don't do SCHED_WAKE_ANGRY or anything else that does a TASK_SOUND_WAKE -void CNPC_Combine::AlertSound( void) -{ - if ( gpGlobals->curtime > m_flNextAlertSoundTime ) - { - m_Sentences.Speak( "COMBINE_GO_ALERT", SENTENCE_PRIORITY_HIGH ); - m_flNextAlertSoundTime = gpGlobals->curtime + 10.0f; - } -} - -//========================================================= -// NotifyDeadFriend -//========================================================= -void CNPC_Combine::NotifyDeadFriend ( CBaseEntity* pFriend ) -{ - if ( GetSquad()->NumMembers() < 2 ) - { - m_Sentences.Speak( "COMBINE_LAST_OF_SQUAD", SENTENCE_PRIORITY_INVALID, SENTENCE_CRITERIA_NORMAL ); - JustMadeSound(); - return; - } - // relaxed visibility test so that guys say this more often - //if( FInViewCone( pFriend ) && FVisible( pFriend ) ) - { - m_Sentences.Speak( "COMBINE_MAN_DOWN" ); - } - BaseClass::NotifyDeadFriend(pFriend); -} - -//========================================================= -// DeathSound -//========================================================= -void CNPC_Combine::DeathSound( const CTakeDamageInfo &info ) -{ - // NOTE: The response system deals with this at the moment - if ( GetFlags() & FL_DISSOLVING ) - return; - - m_Sentences.Speak( "COMBINE_DIE", SENTENCE_PRIORITY_INVALID, SENTENCE_CRITERIA_ALWAYS ); -} - -//========================================================= -// IdleSound -//========================================================= -void CNPC_Combine::IdleSound( void ) -{ - if (g_fCombineQuestion || random->RandomInt(0,1)) - { - if (!g_fCombineQuestion) - { - // ask question or make statement - switch (random->RandomInt(0,2)) - { - case 0: // check in - if ( m_Sentences.Speak( "COMBINE_CHECK" ) >= 0 ) - { - g_fCombineQuestion = 1; - } - break; - - case 1: // question - if ( m_Sentences.Speak( "COMBINE_QUEST" ) >= 0 ) - { - g_fCombineQuestion = 2; - } - break; - - case 2: // statement - m_Sentences.Speak( "COMBINE_IDLE" ); - break; - } - } - else - { - switch (g_fCombineQuestion) - { - case 1: // check in - if ( m_Sentences.Speak( "COMBINE_CLEAR" ) >= 0 ) - { - g_fCombineQuestion = 0; - } - break; - case 2: // question - if ( m_Sentences.Speak( "COMBINE_ANSWER" ) >= 0 ) - { - g_fCombineQuestion = 0; - } - break; - } - } - } -} - -//----------------------------------------------------------------------------- -// Purpose: -// -// This is for Grenade attacks. As the test for grenade attacks -// is expensive we don't want to do it every frame. Return true -// if we meet minimum set of requirements and then test for actual -// throw later if we actually decide to do a grenade attack. -// Input : -// Output : -//----------------------------------------------------------------------------- -int CNPC_Combine::RangeAttack2Conditions( float flDot, float flDist ) -{ - return COND_NONE; -} - -//----------------------------------------------------------------------------- -// Purpose: Return true if the combine has grenades, hasn't checked lately, and -// can throw a grenade at the target point. -// Input : &vecTarget - -// Output : Returns true on success, false on failure. -//----------------------------------------------------------------------------- -bool CNPC_Combine::CanThrowGrenade( const Vector &vecTarget ) -{ - if( m_iNumGrenades < 1 ) - { - // Out of grenades! - return false; - } - - if (gpGlobals->curtime < m_flNextGrenadeCheck ) - { - // Not allowed to throw another grenade right now. - return false; - } - - float flDist; - flDist = ( vecTarget - GetAbsOrigin() ).Length(); - - if( flDist > 1024 || flDist < 128 ) - { - // Too close or too far! - m_flNextGrenadeCheck = gpGlobals->curtime + 1; // one full second. - return false; - } - - // ----------------------- - // If moving, don't check. - // ----------------------- - if ( m_flGroundSpeed != 0 ) - return false; - -#if 0 - Vector vecEnemyLKP = GetEnemyLKP(); - if ( !( GetEnemy()->GetFlags() & FL_ONGROUND ) && GetEnemy()->GetWaterLevel() == 0 && vecEnemyLKP.z > (GetAbsOrigin().z + WorldAlignMaxs().z) ) - { - //!!!BUGBUG - we should make this check movetype and make sure it isn't FLY? Players who jump a lot are unlikely to - // be grenaded. - // don't throw grenades at anything that isn't on the ground! - return COND_NONE; - } -#endif - - // --------------------------------------------------------------------- - // Are any of my squad members near the intended grenade impact area? - // --------------------------------------------------------------------- - if ( m_pSquad ) - { - if (m_pSquad->SquadMemberInRange( vecTarget, COMBINE_MIN_GRENADE_CLEAR_DIST )) - { - // crap, I might blow my own guy up. Don't throw a grenade and don't check again for a while. - m_flNextGrenadeCheck = gpGlobals->curtime + 1; // one full second. - - // Tell my squad members to clear out so I can get a grenade in - CSoundEnt::InsertSound( SOUND_MOVE_AWAY | SOUND_CONTEXT_COMBINE_ONLY, vecTarget, COMBINE_MIN_GRENADE_CLEAR_DIST, 0.1 ); - return false; - } - } - - return CheckCanThrowGrenade( vecTarget ); -} - -//----------------------------------------------------------------------------- -// Purpose: Returns true if the combine can throw a grenade at the specified target point -// Input : &vecTarget - -// Output : Returns true on success, false on failure. -//----------------------------------------------------------------------------- -bool CNPC_Combine::CheckCanThrowGrenade( const Vector &vecTarget ) -{ - //NDebugOverlay::Line( EyePosition(), vecTarget, 0, 255, 0, false, 5 ); - - // --------------------------------------------------------------------- - // Check that throw is legal and clear - // --------------------------------------------------------------------- - // FIXME: this is only valid for hand grenades, not RPG's - Vector vecToss; - Vector vecMins = -Vector(4,4,4); - Vector vecMaxs = Vector(4,4,4); - if( FInViewCone( vecTarget ) && CBaseEntity::FVisible( vecTarget ) ) - { - vecToss = VecCheckThrow( this, EyePosition(), vecTarget, COMBINE_GRENADE_THROW_SPEED, 1.0, &vecMins, &vecMaxs ); - } - else - { - // Have to try a high toss. Do I have enough room? - trace_t tr; - AI_TraceLine( EyePosition(), EyePosition() + Vector( 0, 0, 64 ), MASK_SHOT, this, COLLISION_GROUP_NONE, &tr ); - if( tr.fraction != 1.0 ) - { - return false; - } - - vecToss = VecCheckToss( this, EyePosition(), vecTarget, -1, 1.0, true, &vecMins, &vecMaxs ); - } - - if ( vecToss != vec3_origin ) - { - m_vecTossVelocity = vecToss; - - // don't check again for a while. - m_flNextGrenadeCheck = gpGlobals->curtime + 1; // 1/3 second. - return true; - } - else - { - // don't check again for a while. - m_flNextGrenadeCheck = gpGlobals->curtime + 1; // one full second. - return false; - } -} - -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -bool CNPC_Combine::CanAltFireEnemy( bool bUseFreeKnowledge ) -{ - if (!IsElite() ) - return false; - - if (IsCrouching()) - return false; - - if( gpGlobals->curtime < m_flNextAltFireTime ) - return false; - - if( !GetEnemy() ) - return false; - - if (gpGlobals->curtime < m_flNextGrenadeCheck ) - return false; - - //if (m_iNumGrenades < 1) - // return false; - - CBaseEntity *pEnemy = GetEnemy(); - - if( !pEnemy->IsPlayer() && (!pEnemy->IsNPC() || !pEnemy->MyNPCPointer()->IsPlayerAlly()) ) - return false; - - Vector vecTarget; - - // Determine what point we're shooting at - if( bUseFreeKnowledge ) - { - vecTarget = GetEnemies()->LastKnownPosition( pEnemy ) + (pEnemy->GetViewOffset()*0.75);// approximates the chest - } - else - { - vecTarget = GetEnemies()->LastSeenPosition( pEnemy ) + (pEnemy->GetViewOffset()*0.75);// approximates the chest - } - - // Trace a hull about the size of the combine ball (don't shoot through grates!) - trace_t tr; - - Vector mins( -12, -12, -12 ); - Vector maxs( 12, 12, 12 ); - - Vector vShootPosition = EyePosition(); - - if ( GetActiveWeapon() ) - { - GetActiveWeapon()->GetAttachment( "muzzle", vShootPosition ); - } - - // Trace a hull about the size of the combine ball. - UTIL_TraceHull( vShootPosition, vecTarget, mins, maxs, MASK_SHOT, this, COLLISION_GROUP_NONE, &tr ); - - float flLength = (vShootPosition - vecTarget).Length(); - - flLength *= tr.fraction; - - //If the ball can travel at least 65% of the distance to the player then let the NPC shoot it. - if( tr.fraction >= 0.65 && flLength > 128.0f ) - { - // Target is valid - m_vecAltFireTarget = vecTarget; - return true; - } - - - // Check again later - m_vecAltFireTarget = vec3_origin; - m_flNextGrenadeCheck = gpGlobals->curtime + 1.0f; - return false; -} - -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -bool CNPC_Combine::CanGrenadeEnemy( bool bUseFreeKnowledge ) -{ - if( IsElite() ) - return false; - - CBaseEntity *pEnemy = GetEnemy(); - - Assert( pEnemy != NULL ); - - if( pEnemy ) - { - // I'm not allowed to throw grenades during dustoff - if ( IsCurSchedule(SCHED_DROPSHIP_DUSTOFF) ) - return false; - - if( bUseFreeKnowledge ) - { - // throw to where we think they are. - return CanThrowGrenade( GetEnemies()->LastKnownPosition( pEnemy ) ); - } - else - { - // hafta throw to where we last saw them. - return CanThrowGrenade( GetEnemies()->LastSeenPosition( pEnemy ) ); - } - } - - return false; -} - -//----------------------------------------------------------------------------- -// Purpose: For combine melee attack (kick/hit) -// Input : -// Output : -//----------------------------------------------------------------------------- -int CNPC_Combine::MeleeAttack1Conditions ( float flDot, float flDist ) -{ - if (flDist > 64) - { - return COND_NONE; // COND_TOO_FAR_TO_ATTACK; - } - else if (flDot < 0.7) - { - return COND_NONE; // COND_NOT_FACING_ATTACK; - } - - // Check Z - if ( GetEnemy() && fabs(GetEnemy()->GetAbsOrigin().z - GetAbsOrigin().z) > 64 ) - return COND_NONE; - - if ( dynamic_cast(GetEnemy()) != NULL ) - { - return COND_NONE; - } - - // Make sure not trying to kick through a window or something. - trace_t tr; - Vector vecSrc, vecEnd; - - vecSrc = WorldSpaceCenter(); - vecEnd = GetEnemy()->WorldSpaceCenter(); - - AI_TraceLine(vecSrc, vecEnd, MASK_SHOT, this, COLLISION_GROUP_NONE, &tr); - if( tr.m_pEnt != GetEnemy() ) - { - return COND_NONE; - } - - return COND_CAN_MELEE_ATTACK1; -} - -//----------------------------------------------------------------------------- -// Purpose: -// Output : Vector -//----------------------------------------------------------------------------- -Vector CNPC_Combine::EyePosition( void ) -{ - if ( !IsCrouching() ) - { - return GetAbsOrigin() + COMBINE_EYE_STANDING_POSITION; - } - else - { - return GetAbsOrigin() + COMBINE_EYE_CROUCHING_POSITION; - } - - /* - Vector m_EyePos; - GetAttachment( "eyes", m_EyePos ); - return m_EyePos; - */ -} - -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -Vector CNPC_Combine::GetAltFireTarget() -{ - Assert( IsElite() ); - - return m_vecAltFireTarget; -} - -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -bool CNPC_Combine::IsCrouchedActivity( Activity activity ) -{ - Activity realActivity = TranslateActivity(activity); - - switch ( realActivity ) - { - case ACT_RELOAD_LOW: - case ACT_COVER_LOW: - case ACT_COVER_PISTOL_LOW: - case ACT_COVER_SMG1_LOW: - case ACT_RELOAD_SMG1_LOW: - - // Aren't these supposed to be a little higher than the above? - case ACT_RANGE_ATTACK1_LOW: - case ACT_RANGE_ATTACK2_LOW: - case ACT_RANGE_ATTACK_AR2_LOW: - case ACT_RANGE_ATTACK_SMG1_LOW: - case ACT_RANGE_ATTACK_SHOTGUN_LOW: - case ACT_RANGE_ATTACK_PISTOL_LOW: - case ACT_RANGE_AIM_LOW: - case ACT_RANGE_AIM_SMG1_LOW: - case ACT_RANGE_AIM_PISTOL_LOW: - case ACT_RANGE_AIM_AR2_LOW: - return true; - } - return false; -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : nActivity - -// Output : Vector -//----------------------------------------------------------------------------- -Vector CNPC_Combine::EyeOffset( Activity nActivity ) -{ - if (CapabilitiesGet() & bits_CAP_DUCK) - { - if ( IsCrouchedActivity( nActivity ) ) - return COMBINE_EYE_CROUCHING_POSITION; - - } - // if the hint doesn't tell anything, assume current state - if ( !IsCrouching() ) - { - return COMBINE_EYE_STANDING_POSITION; - } - else - { - return COMBINE_EYE_CROUCHING_POSITION; - } -} - -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -void CNPC_Combine::SetActivity( Activity NewActivity ) -{ - BaseClass::SetActivity( NewActivity ); - - m_iLastAnimEventHandled = -1; -} - -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -NPC_STATE CNPC_Combine::SelectIdealState( void ) -{ - switch ( m_NPCState ) - { - case NPC_STATE_COMBAT: - { - if ( GetEnemy() == NULL ) - { - if ( !HasCondition( COND_ENEMY_DEAD ) ) - { - // Lost track of my enemy. Patrol. - SetCondition( COND_COMBINE_SHOULD_PATROL ); - } - return NPC_STATE_ALERT; - } - else if ( HasCondition( COND_ENEMY_DEAD ) ) - { - AnnounceEnemyKill(GetEnemy()); - } - } - - default: - { - return BaseClass::SelectIdealState(); - } - } - - return GetIdealState(); -} - - -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -bool CNPC_Combine::OnBeginMoveAndShoot() -{ - if ( BaseClass::OnBeginMoveAndShoot() ) - { - if( HasStrategySlotRange( SQUAD_SLOT_ATTACK1, SQUAD_SLOT_ATTACK2 ) ) - return true; // already have the slot I need - - if( !HasStrategySlotRange( SQUAD_SLOT_GRENADE1, SQUAD_SLOT_ATTACK_OCCLUDER ) && OccupyStrategySlotRange( SQUAD_SLOT_ATTACK1, SQUAD_SLOT_ATTACK2 ) ) - return true; - } - return false; -} - -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -void CNPC_Combine::OnEndMoveAndShoot() -{ - VacateStrategySlot(); -} - -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -WeaponProficiency_t CNPC_Combine::CalcWeaponProficiency( CBaseCombatWeapon *pWeapon ) -{ - if( FClassnameIs( pWeapon, "weapon_ar2" ) ) - { - return WEAPON_PROFICIENCY_GOOD; - } - else if( FClassnameIs( pWeapon, "weapon_shotgun" ) ) - { - return WEAPON_PROFICIENCY_PERFECT; - } - else if( FClassnameIs( pWeapon, "weapon_smg1" ) ) - { - return WEAPON_PROFICIENCY_GOOD; - } - - return BaseClass::CalcWeaponProficiency( pWeapon ); -} - -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -bool CNPC_Combine::HasShotgun() -{ - if( GetActiveWeapon() && GetActiveWeapon()->m_iClassname == s_iszShotgunClassname ) - { - return true; - } - - return false; -} - -//----------------------------------------------------------------------------- -// Purpose: This is a generic function (to be implemented by sub-classes) to -// handle specific interactions between different types of characters -// (For example the barnacle grabbing an NPC) -// Input : The type of interaction, extra info pointer, and who started it -// Output : true - if sub-class has a response for the interaction -// false - if sub-class has no response -//----------------------------------------------------------------------------- -bool CNPC_Combine::HandleInteraction(int interactionType, void *data, CBaseCombatCharacter *sourceEnt) -{ - if ( interactionType == g_interactionTurretStillStanding ) - { - // A turret that I've kicked recently is still standing 5 seconds later. - if ( sourceEnt == GetEnemy() ) - { - // It's still my enemy. Time to grenade it. - Vector forward, up; - AngleVectors( GetLocalAngles(), &forward, NULL, &up ); - m_vecTossVelocity = forward * 10; - SetCondition( COND_COMBINE_DROP_GRENADE ); - ClearSchedule(); - } - return true; - } - - return BaseClass::HandleInteraction( interactionType, data, sourceEnt ); -} - -//----------------------------------------------------------------------------- -// -// Schedules -// -//----------------------------------------------------------------------------- - -AI_BEGIN_CUSTOM_NPC( npc_combine, CNPC_Combine ) - - //Tasks - DECLARE_TASK( TASK_COMBINE_FACE_TOSS_DIR ) - DECLARE_TASK( TASK_COMBINE_IGNORE_ATTACKS ) - DECLARE_TASK( TASK_COMBINE_SIGNAL_BEST_SOUND ) - DECLARE_TASK( TASK_COMBINE_DEFER_SQUAD_GRENADES ) - DECLARE_TASK( TASK_COMBINE_CHASE_ENEMY_CONTINUOUSLY ) - DECLARE_TASK( TASK_COMBINE_DIE_INSTANTLY ) - DECLARE_TASK( TASK_COMBINE_PLAY_SEQUENCE_FACE_ALTFIRE_TARGET ) - DECLARE_TASK( TASK_COMBINE_GET_PATH_TO_FORCED_GREN_LOS ) - - //Activities - DECLARE_ACTIVITY( ACT_COMBINE_THROW_GRENADE ) - DECLARE_ACTIVITY( ACT_COMBINE_LAUNCH_GRENADE ) - DECLARE_ACTIVITY( ACT_COMBINE_BUGBAIT ) - DECLARE_ACTIVITY( ACT_COMBINE_AR2_ALTFIRE ) - - DECLARE_ANIMEVENT( COMBINE_AE_BEGIN_ALTFIRE ) - DECLARE_ANIMEVENT( COMBINE_AE_ALTFIRE ) - - DECLARE_SQUADSLOT( SQUAD_SLOT_GRENADE1 ) - DECLARE_SQUADSLOT( SQUAD_SLOT_GRENADE2 ) - - DECLARE_CONDITION( COND_COMBINE_NO_FIRE ) - DECLARE_CONDITION( COND_COMBINE_DEAD_FRIEND ) - DECLARE_CONDITION( COND_COMBINE_SHOULD_PATROL ) - DECLARE_CONDITION( COND_COMBINE_HIT_BY_BUGBAIT ) - DECLARE_CONDITION( COND_COMBINE_DROP_GRENADE ) - DECLARE_CONDITION( COND_COMBINE_ON_FIRE ) - - DECLARE_INTERACTION( g_interactionCombineBash ); - - //========================================================= - // SCHED_COMBINE_TAKE_COVER_FROM_BEST_SOUND - // - // hide from the loudest sound source (to run from grenade) - //========================================================= - DEFINE_SCHEDULE - ( - SCHED_COMBINE_TAKE_COVER_FROM_BEST_SOUND, - - " Tasks" - " TASK_SET_FAIL_SCHEDULE SCHEDULE:SCHED_COMBINE_RUN_AWAY_FROM_BEST_SOUND" - " TASK_STOP_MOVING 0" - " TASK_COMBINE_SIGNAL_BEST_SOUND 0" - " TASK_FIND_COVER_FROM_BEST_SOUND 0" - " TASK_RUN_PATH 0" - " TASK_WAIT_FOR_MOVEMENT 0" - " TASK_REMEMBER MEMORY:INCOVER" - " TASK_FACE_REASONABLE 0" - "" - " Interrupts" - ) - - DEFINE_SCHEDULE - ( - SCHED_COMBINE_RUN_AWAY_FROM_BEST_SOUND, - - " Tasks" - " TASK_SET_FAIL_SCHEDULE SCHEDULE:SCHED_COWER" - " TASK_GET_PATH_AWAY_FROM_BEST_SOUND 600" - " TASK_RUN_PATH_TIMED 2" - " TASK_STOP_MOVING 0" - "" - " Interrupts" - ) - //========================================================= - // SCHED_COMBINE_COMBAT_FAIL - //========================================================= - DEFINE_SCHEDULE - ( - SCHED_COMBINE_COMBAT_FAIL, - - " Tasks" - " TASK_STOP_MOVING 0" - " TASK_SET_ACTIVITY ACTIVITY:ACT_IDLE " - " TASK_WAIT_FACE_ENEMY 2" - " TASK_WAIT_PVS 0" - "" - " Interrupts" - " COND_CAN_RANGE_ATTACK1" - " COND_CAN_RANGE_ATTACK2" - " COND_CAN_MELEE_ATTACK1" - " COND_CAN_MELEE_ATTACK2" - ) - - //========================================================= - // SCHED_COMBINE_VICTORY_DANCE - //========================================================= - DEFINE_SCHEDULE - ( - SCHED_COMBINE_VICTORY_DANCE, - - " Tasks" - " TASK_STOP_MOVING 0" - " TASK_FACE_ENEMY 0" - " TASK_WAIT 1.5" - " TASK_GET_PATH_TO_ENEMY_CORPSE 0" - " TASK_WALK_PATH 0" - " TASK_WAIT_FOR_MOVEMENT 0" - " TASK_FACE_ENEMY 0" - " TASK_PLAY_SEQUENCE ACTIVITY:ACT_VICTORY_DANCE" - "" - " Interrupts" - " COND_NEW_ENEMY" - " COND_LIGHT_DAMAGE" - " COND_HEAVY_DAMAGE" - ) - - //========================================================= - // SCHED_COMBINE_ASSAULT - //========================================================= - DEFINE_SCHEDULE - ( - SCHED_COMBINE_ASSAULT, - - " Tasks " - " TASK_SET_FAIL_SCHEDULE SCHEDULE:SCHED_COMBINE_ESTABLISH_LINE_OF_FIRE" - " TASK_SET_TOLERANCE_DISTANCE 48" - " TASK_GET_PATH_TO_ENEMY_LKP 0" - " TASK_COMBINE_IGNORE_ATTACKS 0.2" - " TASK_SPEAK_SENTENCE 0" - " TASK_RUN_PATH 0" -// " TASK_COMBINE_MOVE_AND_AIM 0" - " TASK_WAIT_FOR_MOVEMENT 0" - " TASK_COMBINE_IGNORE_ATTACKS 0.0" - "" - " Interrupts " - " COND_NEW_ENEMY" - " COND_ENEMY_DEAD" - " COND_ENEMY_UNREACHABLE" - " COND_CAN_RANGE_ATTACK1" - " COND_CAN_MELEE_ATTACK1" - " COND_CAN_RANGE_ATTACK2" - " COND_CAN_MELEE_ATTACK2" - " COND_TOO_FAR_TO_ATTACK" - " COND_HEAR_DANGER" - " COND_HEAR_MOVE_AWAY" - ) - - DEFINE_SCHEDULE - ( - SCHED_COMBINE_ESTABLISH_LINE_OF_FIRE, - - " Tasks " - " TASK_SET_FAIL_SCHEDULE SCHEDULE:SCHED_FAIL_ESTABLISH_LINE_OF_FIRE" - " TASK_SET_TOLERANCE_DISTANCE 48" - " TASK_GET_PATH_TO_ENEMY_LKP_LOS 0" - " TASK_SPEAK_SENTENCE 1" - " TASK_RUN_PATH 0" - " TASK_WAIT_FOR_MOVEMENT 0" - " TASK_COMBINE_IGNORE_ATTACKS 0.0" - " TASK_SET_SCHEDULE SCHEDULE:SCHED_COMBAT_FACE" - " " - " Interrupts " - " COND_NEW_ENEMY" - " COND_ENEMY_DEAD" - //" COND_CAN_RANGE_ATTACK1" - //" COND_CAN_RANGE_ATTACK2" - " COND_CAN_MELEE_ATTACK1" - " COND_CAN_MELEE_ATTACK2" - " COND_HEAR_DANGER" - " COND_HEAR_MOVE_AWAY" - " COND_HEAVY_DAMAGE" - ) - - //========================================================= - // SCHED_COMBINE_PRESS_ATTACK - //========================================================= - DEFINE_SCHEDULE - ( - SCHED_COMBINE_PRESS_ATTACK, - - " Tasks " - " TASK_SET_FAIL_SCHEDULE SCHEDULE:SCHED_COMBINE_ESTABLISH_LINE_OF_FIRE" - " TASK_SET_TOLERANCE_DISTANCE 48" - " TASK_GET_PATH_TO_ENEMY_LKP 0" - " TASK_RUN_PATH 0" - " TASK_WAIT_FOR_MOVEMENT 0" - "" - " Interrupts " - " COND_NEW_ENEMY" - " COND_ENEMY_DEAD" - " COND_ENEMY_UNREACHABLE" - " COND_NO_PRIMARY_AMMO" - " COND_LOW_PRIMARY_AMMO" - " COND_TOO_CLOSE_TO_ATTACK" - " COND_ENEMY_OCCLUDED" - " COND_CAN_MELEE_ATTACK1" - " COND_CAN_MELEE_ATTACK2" - " COND_HEAR_DANGER" - " COND_HEAR_MOVE_AWAY" - ) - - //========================================================= - // SCHED_COMBINE_COMBAT_FACE - //========================================================= - DEFINE_SCHEDULE - ( - SCHED_COMBINE_COMBAT_FACE, - - " Tasks" - " TASK_STOP_MOVING 0" - " TASK_SET_ACTIVITY ACTIVITY:ACT_IDLE" - " TASK_FACE_ENEMY 0" - " TASK_WAIT 1.5" - //" TASK_SET_SCHEDULE SCHEDULE:SCHED_COMBINE_SWEEP" - "" - " Interrupts" - " COND_NEW_ENEMY" - " COND_ENEMY_DEAD" - " COND_CAN_RANGE_ATTACK1" - " COND_CAN_RANGE_ATTACK2" - ) - - //========================================================= - // SCHED_HIDE_AND_RELOAD - //========================================================= - DEFINE_SCHEDULE - ( - SCHED_COMBINE_HIDE_AND_RELOAD, - - " Tasks" - " TASK_SET_FAIL_SCHEDULE SCHEDULE:SCHED_RELOAD" - " TASK_FIND_COVER_FROM_ENEMY 0" - " TASK_RUN_PATH 0" - " TASK_WAIT_FOR_MOVEMENT 0" - " TASK_REMEMBER MEMORY:INCOVER" - " TASK_FACE_ENEMY 0" - " TASK_RELOAD 0" - "" - " Interrupts" - " COND_CAN_MELEE_ATTACK1" - " COND_CAN_MELEE_ATTACK2" - " COND_HEAVY_DAMAGE" - " COND_HEAR_DANGER" - " COND_HEAR_MOVE_AWAY" - ) - - //========================================================= - // SCHED_COMBINE_SIGNAL_SUPPRESS - // don't stop shooting until the clip is - // empty or combine gets hurt. - //========================================================= - DEFINE_SCHEDULE - ( - SCHED_COMBINE_SIGNAL_SUPPRESS, - - " Tasks" - " TASK_STOP_MOVING 0" - " TASK_FACE_IDEAL 0" - " TASK_PLAY_SEQUENCE_FACE_ENEMY ACTIVITY:ACT_SIGNAL_GROUP" - " TASK_WAIT 0.5" - " TASK_RANGE_ATTACK1 0" - "" - " Interrupts" - " COND_ENEMY_DEAD" - " COND_LIGHT_DAMAGE" - " COND_HEAVY_DAMAGE" - " COND_NO_PRIMARY_AMMO" - " COND_WEAPON_BLOCKED_BY_FRIEND" - " COND_WEAPON_SIGHT_OCCLUDED" - " COND_HEAR_DANGER" - " COND_HEAR_MOVE_AWAY" - " COND_COMBINE_NO_FIRE" - ) - - //========================================================= - // SCHED_COMBINE_SUPPRESS - //========================================================= - DEFINE_SCHEDULE - ( - SCHED_COMBINE_SUPPRESS, - - " Tasks" - " TASK_STOP_MOVING 0" - " TASK_FACE_ENEMY 0" - " TASK_WAIT 0.5" - " TASK_RANGE_ATTACK1 0" - "" - " Interrupts" - " COND_ENEMY_DEAD" - " COND_LIGHT_DAMAGE" - " COND_HEAVY_DAMAGE" - " COND_NO_PRIMARY_AMMO" - " COND_HEAR_DANGER" - " COND_HEAR_MOVE_AWAY" - " COND_COMBINE_NO_FIRE" - " COND_WEAPON_BLOCKED_BY_FRIEND" - ) - - //========================================================= - // SCHED_COMBINE_WAIT_IN_COVER - // we don't allow danger or the ability - // to attack to break a combine's run to cover schedule but - // when a combine is in cover we do want them to attack if they can. - //========================================================= - DEFINE_SCHEDULE - ( - SCHED_COMBINE_WAIT_IN_COVER, - - " Tasks" - " TASK_STOP_MOVING 0" - " TASK_SET_ACTIVITY ACTIVITY:ACT_IDLE" // Translated to cover - " TASK_WAIT_FACE_ENEMY 1" - "" - " Interrupts" - " COND_NEW_ENEMY" - " COND_CAN_RANGE_ATTACK1" - " COND_CAN_RANGE_ATTACK2" - " COND_CAN_MELEE_ATTACK1" - " COND_CAN_MELEE_ATTACK2" - " COND_HEAR_DANGER" - " COND_HEAR_MOVE_AWAY" - ) - - //========================================================= - // SCHED_COMBINE_TAKE_COVER1 - //========================================================= - DEFINE_SCHEDULE - ( - SCHED_COMBINE_TAKE_COVER1 , - - " Tasks" - " TASK_SET_FAIL_SCHEDULE SCHEDULE:SCHED_COMBINE_TAKECOVER_FAILED" - " TASK_STOP_MOVING 0" - " TASK_WAIT 0.2" - " TASK_FIND_COVER_FROM_ENEMY 0" - " TASK_RUN_PATH 0" - " TASK_WAIT_FOR_MOVEMENT 0" - " TASK_REMEMBER MEMORY:INCOVER" - " TASK_SET_SCHEDULE SCHEDULE:SCHED_COMBINE_WAIT_IN_COVER" - "" - " Interrupts" - ) - - DEFINE_SCHEDULE - ( - SCHED_COMBINE_TAKECOVER_FAILED, - - " Tasks" - " TASK_STOP_MOVING 0" - "" - " Interrupts" - ) - - //========================================================= - // SCHED_COMBINE_GRENADE_COVER1 - //========================================================= - DEFINE_SCHEDULE - ( - SCHED_COMBINE_GRENADE_COVER1, - - " Tasks" - " TASK_STOP_MOVING 0" - " TASK_FIND_COVER_FROM_ENEMY 99" - " TASK_FIND_FAR_NODE_COVER_FROM_ENEMY 384" - " TASK_PLAY_SEQUENCE ACTIVITY:ACT_SPECIAL_ATTACK2" - " TASK_CLEAR_MOVE_WAIT 0" - " TASK_RUN_PATH 0" - " TASK_WAIT_FOR_MOVEMENT 0" - " TASK_SET_SCHEDULE SCHEDULE:SCHED_COMBINE_WAIT_IN_COVER" - "" - " Interrupts" - ) - - //========================================================= - // SCHED_COMBINE_TOSS_GRENADE_COVER1 - // - // drop grenade then run to cover. - //========================================================= - DEFINE_SCHEDULE - ( - SCHED_COMBINE_TOSS_GRENADE_COVER1, - - " Tasks" - " TASK_FACE_ENEMY 0" - " TASK_RANGE_ATTACK2 0" - " TASK_SET_SCHEDULE SCHEDULE:SCHED_TAKE_COVER_FROM_ENEMY" - "" - " Interrupts" - ) - - //========================================================= - // SCHED_COMBINE_RANGE_ATTACK1 - //========================================================= - DEFINE_SCHEDULE - ( - SCHED_COMBINE_RANGE_ATTACK1, - - " Tasks" - " TASK_STOP_MOVING 0" - " TASK_FACE_ENEMY 0" - " TASK_ANNOUNCE_ATTACK 1" // 1 = primary attack - " TASK_WAIT_RANDOM 0.3" - " TASK_RANGE_ATTACK1 0" - " TASK_COMBINE_IGNORE_ATTACKS 0.5" - "" - " Interrupts" - " COND_NEW_ENEMY" - " COND_ENEMY_DEAD" - " COND_HEAVY_DAMAGE" - " COND_LOW_PRIMARY_AMMO" - " COND_NO_PRIMARY_AMMO" - " COND_WEAPON_BLOCKED_BY_FRIEND" - " COND_TOO_CLOSE_TO_ATTACK" - " COND_GIVE_WAY" - " COND_HEAR_DANGER" - " COND_HEAR_MOVE_AWAY" - " COND_COMBINE_NO_FIRE" - "" - // Enemy_Occluded Don't interrupt on this. Means - // comibine will fire where player was after - // he has moved for a little while. Good effect!! - // WEAPON_SIGHT_OCCLUDED Don't block on this! Looks better for railings, etc. - ) - - //========================================================= - // AR2 Alt Fire Attack - //========================================================= - DEFINE_SCHEDULE - ( - SCHED_COMBINE_AR2_ALTFIRE, - - " Tasks" - " TASK_STOP_MOVING 0" - " TASK_ANNOUNCE_ATTACK 1" - " TASK_COMBINE_PLAY_SEQUENCE_FACE_ALTFIRE_TARGET ACTIVITY:ACT_COMBINE_AR2_ALTFIRE" - "" - " Interrupts" - ) - - //========================================================= - // Mapmaker forced grenade throw - //========================================================= - DEFINE_SCHEDULE - ( - SCHED_COMBINE_FORCED_GRENADE_THROW, - - " Tasks" - " TASK_STOP_MOVING 0" - " TASK_COMBINE_FACE_TOSS_DIR 0" - " TASK_ANNOUNCE_ATTACK 2" // 2 = grenade - " TASK_PLAY_SEQUENCE ACTIVITY:ACT_RANGE_ATTACK2" - " TASK_COMBINE_DEFER_SQUAD_GRENADES 0" - "" - " Interrupts" - ) - - //========================================================= - // Move to LOS of the mapmaker's forced grenade throw target - //========================================================= - DEFINE_SCHEDULE - ( - SCHED_COMBINE_MOVE_TO_FORCED_GREN_LOS, - - " Tasks " - " TASK_SET_TOLERANCE_DISTANCE 48" - " TASK_COMBINE_GET_PATH_TO_FORCED_GREN_LOS 0" - " TASK_SPEAK_SENTENCE 1" - " TASK_RUN_PATH 0" - " TASK_WAIT_FOR_MOVEMENT 0" - " " - " Interrupts " - " COND_NEW_ENEMY" - " COND_ENEMY_DEAD" - " COND_CAN_MELEE_ATTACK1" - " COND_CAN_MELEE_ATTACK2" - " COND_HEAR_DANGER" - " COND_HEAR_MOVE_AWAY" - " COND_HEAVY_DAMAGE" - ) - - //========================================================= - // SCHED_COMBINE_RANGE_ATTACK2 - // - // secondary range attack. Overriden because base class stops attacking when the enemy is occluded. - // combines's grenade toss requires the enemy be occluded. - //========================================================= - DEFINE_SCHEDULE - ( - SCHED_COMBINE_RANGE_ATTACK2, - - " Tasks" - " TASK_STOP_MOVING 0" - " TASK_COMBINE_FACE_TOSS_DIR 0" - " TASK_ANNOUNCE_ATTACK 2" // 2 = grenade - " TASK_PLAY_SEQUENCE ACTIVITY:ACT_RANGE_ATTACK2" - " TASK_COMBINE_DEFER_SQUAD_GRENADES 0" - " TASK_SET_SCHEDULE SCHEDULE:SCHED_COMBINE_WAIT_IN_COVER" // don't run immediately after throwing grenade. - "" - " Interrupts" - ) - - - //========================================================= - // Throw a grenade, then run off and reload. - //========================================================= - DEFINE_SCHEDULE - ( - SCHED_COMBINE_GRENADE_AND_RELOAD, - - " Tasks" - " TASK_STOP_MOVING 0" - " TASK_COMBINE_FACE_TOSS_DIR 0" - " TASK_ANNOUNCE_ATTACK 2" // 2 = grenade - " TASK_PLAY_SEQUENCE ACTIVITY:ACT_RANGE_ATTACK2" - " TASK_COMBINE_DEFER_SQUAD_GRENADES 0" - " TASK_SET_SCHEDULE SCHEDULE:SCHED_HIDE_AND_RELOAD" // don't run immediately after throwing grenade. - "" - " Interrupts" - ) - - DEFINE_SCHEDULE - ( - SCHED_COMBINE_PATROL, - - " Tasks" - " TASK_STOP_MOVING 0" - " TASK_WANDER 900540" - " TASK_WALK_PATH 0" - " TASK_WAIT_FOR_MOVEMENT 0" - " TASK_STOP_MOVING 0" - " TASK_FACE_REASONABLE 0" - " TASK_WAIT 3" - " TASK_WAIT_RANDOM 3" - " TASK_SET_SCHEDULE SCHEDULE:SCHED_COMBINE_PATROL" // keep doing it - "" - " Interrupts" - " COND_ENEMY_DEAD" - " COND_LIGHT_DAMAGE" - " COND_HEAVY_DAMAGE" - " COND_HEAR_DANGER" - " COND_HEAR_MOVE_AWAY" - " COND_NEW_ENEMY" - " COND_SEE_ENEMY" - " COND_CAN_RANGE_ATTACK1" - " COND_CAN_RANGE_ATTACK2" - ) - - DEFINE_SCHEDULE - ( - SCHED_COMBINE_BUGBAIT_DISTRACTION, - - " Tasks" - " TASK_STOP_MOVING 0" - " TASK_RESET_ACTIVITY 0" - " TASK_PLAY_SEQUENCE ACTIVITY:ACT_COMBINE_BUGBAIT" - "" - " Interrupts" - "" - ) - - //========================================================= - // SCHED_COMBINE_CHARGE_TURRET - // - // Used to run straight at enemy turrets to knock them over. - // Prevents squadmates from throwing grenades during. - //========================================================= - DEFINE_SCHEDULE - ( - SCHED_COMBINE_CHARGE_TURRET, - - " Tasks" - " TASK_COMBINE_DEFER_SQUAD_GRENADES 0" - " TASK_STOP_MOVING 0" - " TASK_SET_FAIL_SCHEDULE SCHEDULE:SCHED_CHASE_ENEMY_FAILED" - " TASK_GET_CHASE_PATH_TO_ENEMY 300" - " TASK_RUN_PATH 0" - " TASK_WAIT_FOR_MOVEMENT 0" - " TASK_FACE_ENEMY 0" - "" - " Interrupts" - " COND_NEW_ENEMY" - " COND_ENEMY_DEAD" - " COND_ENEMY_UNREACHABLE" - " COND_CAN_MELEE_ATTACK1" - " COND_CAN_MELEE_ATTACK2" - " COND_TOO_CLOSE_TO_ATTACK" - " COND_TASK_FAILED" - " COND_LOST_ENEMY" - " COND_BETTER_WEAPON_AVAILABLE" - " COND_HEAR_DANGER" - ) - - //========================================================= - // SCHED_COMBINE_CHARGE_PLAYER - // - // Used to run straight at enemy player since physgun combat - // is more fun when the enemies are close - //========================================================= - DEFINE_SCHEDULE - ( - SCHED_COMBINE_CHARGE_PLAYER, - - " Tasks" - " TASK_STOP_MOVING 0" - " TASK_SET_FAIL_SCHEDULE SCHEDULE:SCHED_CHASE_ENEMY_FAILED" - " TASK_COMBINE_CHASE_ENEMY_CONTINUOUSLY 192" - " TASK_FACE_ENEMY 0" - "" - " Interrupts" - " COND_NEW_ENEMY" - " COND_ENEMY_DEAD" - " COND_ENEMY_UNREACHABLE" - " COND_CAN_MELEE_ATTACK1" - " COND_CAN_MELEE_ATTACK2" - " COND_TASK_FAILED" - " COND_LOST_ENEMY" - " COND_HEAR_DANGER" - ) - - //========================================================= - // SCHED_COMBINE_DROP_GRENADE - // - // Place a grenade at my feet - //========================================================= - DEFINE_SCHEDULE - ( - SCHED_COMBINE_DROP_GRENADE, - - " Tasks" - " TASK_STOP_MOVING 0" - " TASK_PLAY_SEQUENCE ACTIVITY:ACT_SPECIAL_ATTACK2" - " TASK_FIND_COVER_FROM_ENEMY 99" - " TASK_FIND_FAR_NODE_COVER_FROM_ENEMY 384" - " TASK_CLEAR_MOVE_WAIT 0" - " TASK_RUN_PATH 0" - " TASK_WAIT_FOR_MOVEMENT 0" - "" - " Interrupts" - ) - - //========================================================= - // SCHED_COMBINE_PATROL_ENEMY - // - // Used instead if SCHED_COMBINE_PATROL if I have an enemy. - // Wait for the enemy a bit in the hopes of ambushing him. - //========================================================= - DEFINE_SCHEDULE - ( - SCHED_COMBINE_PATROL_ENEMY, - - " Tasks" - " TASK_STOP_MOVING 0" - " TASK_WAIT_FACE_ENEMY 1" - " TASK_WAIT_FACE_ENEMY_RANDOM 3" - "" - " Interrupts" - " COND_ENEMY_DEAD" - " COND_LIGHT_DAMAGE" - " COND_HEAVY_DAMAGE" - " COND_HEAR_DANGER" - " COND_HEAR_MOVE_AWAY" - " COND_NEW_ENEMY" - " COND_SEE_ENEMY" - " COND_CAN_RANGE_ATTACK1" - " COND_CAN_RANGE_ATTACK2" - ) - - DEFINE_SCHEDULE - ( - SCHED_COMBINE_BURNING_STAND, - - " Tasks" - " TASK_SET_ACTIVITY ACTIVITY:ACT_COMBINE_BUGBAIT" - " TASK_RANDOMIZE_FRAMERATE 20" - " TASK_WAIT 2" - " TASK_WAIT_RANDOM 3" - " TASK_COMBINE_DIE_INSTANTLY DMG_BURN" - " TASK_WAIT 1.0" - " " - " Interrupts" - ) - - DEFINE_SCHEDULE - ( - SCHED_COMBINE_FACE_IDEAL_YAW, - - " Tasks" - " TASK_FACE_IDEAL 0" - " " - " Interrupts" - ) - -AI_END_CUSTOM_NPC() diff --git a/src/src/dlls/hl2_dll/npc_combine_episodic.h b/src/src/dlls/hl2_dll/npc_combine_episodic.h deleted file mode 100644 index 1773a65..0000000 --- a/src/src/dlls/hl2_dll/npc_combine_episodic.h +++ /dev/null @@ -1,295 +0,0 @@ -//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// -// -// Purpose: -// -//=============================================================================// - -#ifndef NPC_COMBINE_H -#define NPC_COMBINE_H -#ifdef _WIN32 -#pragma once -#endif - -#include "ai_basenpc.h" -#include "ai_basehumanoid.h" -#include "ai_behavior.h" -#include "ai_behavior_assault.h" -#include "ai_behavior_standoff.h" -#include "ai_behavior_follow.h" -#include "ai_behavior_functank.h" -#include "ai_behavior_rappel.h" -#include "ai_behavior_actbusy.h" -#include "ai_sentence.h" -#include "ai_baseactor.h" - -// Used when only what combine to react to what the spotlight sees -#define SF_COMBINE_NO_LOOK (1 << 16) -#define SF_COMBINE_NO_GRENADEDROP ( 1 << 17 ) -#define SF_COMBINE_NO_AR2DROP ( 1 << 18 ) - -//========================================================= -// >> CNPC_Combine -//========================================================= -class CNPC_Combine : public CAI_BaseActor -{ - DECLARE_DATADESC(); - DEFINE_CUSTOM_AI; - DECLARE_CLASS( CNPC_Combine, CAI_BaseActor ); - -public: - CNPC_Combine(); - - // Create components - virtual bool CreateComponents(); - - bool CanThrowGrenade( const Vector &vecTarget ); - bool CheckCanThrowGrenade( const Vector &vecTarget ); - virtual bool CanGrenadeEnemy( bool bUseFreeKnowledge = true ); - virtual bool CanAltFireEnemy( bool bUseFreeKnowledge ); - int GetGrenadeConditions( float flDot, float flDist ); - int RangeAttack2Conditions( float flDot, float flDist ); // For innate grenade attack - int MeleeAttack1Conditions( float flDot, float flDist ); // For kick/punch - bool FVisible( CBaseEntity *pEntity, int traceMask = MASK_OPAQUE, CBaseEntity **ppBlocker = NULL ); - virtual bool IsCurTaskContinuousMove(); - - virtual float GetJumpGravity() const { return 1.8f; } - - virtual Vector GetCrouchEyeOffset( void ); - - void Event_Killed( const CTakeDamageInfo &info ); - - - void SetActivity( Activity NewActivity ); - NPC_STATE SelectIdealState ( void ); - - // Input handlers. - void InputLookOn( inputdata_t &inputdata ); - void InputLookOff( inputdata_t &inputdata ); - void InputStartPatrolling( inputdata_t &inputdata ); - void InputStopPatrolling( inputdata_t &inputdata ); - void InputAssault( inputdata_t &inputdata ); - void InputHitByBugbait( inputdata_t &inputdata ); - void InputThrowGrenadeAtTarget( inputdata_t &inputdata ); - - bool UpdateEnemyMemory( CBaseEntity *pEnemy, const Vector &position, CBaseEntity *pInformer = NULL ); - - void Spawn( void ); - void Precache( void ); - void Activate(); - - Class_T Classify( void ); - bool IsElite() { return m_fIsElite; } - void DelayAltFireAttack( float flDelay ); - void DelaySquadAltFireAttack( float flDelay ); - float MaxYawSpeed( void ); - bool ShouldMoveAndShoot(); - bool OverrideMoveFacing( const AILocalMoveGoal_t &move, float flInterval );; - void HandleAnimEvent( animevent_t *pEvent ); - Vector Weapon_ShootPosition( ); - - Vector EyeOffset( Activity nActivity ); - Vector EyePosition( void ); - Vector BodyTarget( const Vector &posSrc, bool bNoisy = true ); - Vector GetAltFireTarget(); - - void StartTask( const Task_t *pTask ); - void RunTask( const Task_t *pTask ); - void PostNPCInit(); - void GatherConditions(); - virtual void PrescheduleThink(); - - Activity NPC_TranslateActivity( Activity eNewActivity ); - void BuildScheduleTestBits( void ); - virtual int SelectSchedule( void ); - int SelectScheduleAttack(); - - bool CreateBehaviors(); - - bool OnBeginMoveAndShoot(); - void OnEndMoveAndShoot(); - - // Combat - WeaponProficiency_t CalcWeaponProficiency( CBaseCombatWeapon *pWeapon ); - bool HasShotgun(); - bool ActiveWeaponIsFullyLoaded(); - - bool HandleInteraction(int interactionType, void *data, CBaseCombatCharacter *sourceEnt); - const char* GetSquadSlotDebugName( int iSquadSlot ); - - bool IsUsingTacticalVariant( int variant ) { return m_iTacticalVariant == variant; } - bool IsUsingPathfindingVariant( int variant ) { return m_iPathfindingVariant == variant; } - - bool IsRunningApproachEnemySchedule(); - - // ------------- - // Sounds - // ------------- - void DeathSound( void ); - void PainSound( void ); - void IdleSound( void ); - void AlertSound( void ); - void LostEnemySound( void ); - void FoundEnemySound( void ); - void AnnounceAssault( void ); - void AnnounceEnemyType( CBaseEntity *pEnemy ); - void AnnounceEnemyKill( CBaseEntity *pEnemy ); - - void NotifyDeadFriend( CBaseEntity* pFriend ); - - virtual float HearingSensitivity( void ) { return 1.0; }; - int GetSoundInterests( void ); - virtual bool QueryHearSound( CSound *pSound ); - - // Speaking - void SpeakSentence( int sentType ); - - virtual int TranslateSchedule( int scheduleType ); - void OnStartSchedule( int scheduleType ); - - virtual bool ShouldPickADeathPose( void ); - -protected: - void SetKickDamage( int nDamage ) { m_nKickDamage = nDamage; } - CAI_Sentence< CNPC_Combine > *GetSentences() { return &m_Sentences; } - -private: - //========================================================= - // Combine S schedules - //========================================================= - enum - { - SCHED_COMBINE_SUPPRESS = BaseClass::NEXT_SCHEDULE, - SCHED_COMBINE_COMBAT_FAIL, - SCHED_COMBINE_VICTORY_DANCE, - SCHED_COMBINE_COMBAT_FACE, - SCHED_COMBINE_HIDE_AND_RELOAD, - SCHED_COMBINE_SIGNAL_SUPPRESS, - SCHED_COMBINE_ENTER_OVERWATCH, - SCHED_COMBINE_OVERWATCH, - SCHED_COMBINE_ASSAULT, - SCHED_COMBINE_ESTABLISH_LINE_OF_FIRE, - SCHED_COMBINE_PRESS_ATTACK, - SCHED_COMBINE_WAIT_IN_COVER, - SCHED_COMBINE_RANGE_ATTACK1, - SCHED_COMBINE_RANGE_ATTACK2, - SCHED_COMBINE_TAKE_COVER1, - SCHED_COMBINE_TAKE_COVER_FROM_BEST_SOUND, - SCHED_COMBINE_RUN_AWAY_FROM_BEST_SOUND, - SCHED_COMBINE_GRENADE_COVER1, - SCHED_COMBINE_TOSS_GRENADE_COVER1, - SCHED_COMBINE_TAKECOVER_FAILED, - SCHED_COMBINE_GRENADE_AND_RELOAD, - SCHED_COMBINE_PATROL, - SCHED_COMBINE_BUGBAIT_DISTRACTION, - SCHED_COMBINE_CHARGE_TURRET, - SCHED_COMBINE_DROP_GRENADE, - SCHED_COMBINE_CHARGE_PLAYER, - SCHED_COMBINE_PATROL_ENEMY, - SCHED_COMBINE_BURNING_STAND, - SCHED_COMBINE_AR2_ALTFIRE, - SCHED_COMBINE_FORCED_GRENADE_THROW, - SCHED_COMBINE_MOVE_TO_FORCED_GREN_LOS, - SCHED_COMBINE_FACE_IDEAL_YAW, - NEXT_SCHEDULE, - }; - - //========================================================= - // Combine Tasks - //========================================================= - enum - { - TASK_COMBINE_FACE_TOSS_DIR = BaseClass::NEXT_TASK, - TASK_COMBINE_IGNORE_ATTACKS, - TASK_COMBINE_SIGNAL_BEST_SOUND, - TASK_COMBINE_DEFER_SQUAD_GRENADES, - TASK_COMBINE_CHASE_ENEMY_CONTINUOUSLY, - TASK_COMBINE_DIE_INSTANTLY, - TASK_COMBINE_PLAY_SEQUENCE_FACE_ALTFIRE_TARGET, - TASK_COMBINE_GET_PATH_TO_FORCED_GREN_LOS, - TASK_COMBINE_SET_STANDING, - NEXT_TASK - }; - - //========================================================= - // Combine Conditions - //========================================================= - enum Combine_Conds - { - COND_COMBINE_NO_FIRE = BaseClass::NEXT_CONDITION, - COND_COMBINE_DEAD_FRIEND, - COND_COMBINE_SHOULD_PATROL, - COND_COMBINE_HIT_BY_BUGBAIT, - COND_COMBINE_DROP_GRENADE, - COND_COMBINE_ON_FIRE, - COND_COMBINE_ATTACK_SLOT_AVAILABLE, - NEXT_CONDITION - }; - -private: - // Select the combat schedule - int SelectCombatSchedule(); - - // Should we charge the player? - bool ShouldChargePlayer(); - - // Chase the enemy, updating the target position as the player moves - void StartTaskChaseEnemyContinuously( const Task_t *pTask ); - void RunTaskChaseEnemyContinuously( const Task_t *pTask ); - - class CCombineStandoffBehavior : public CAI_ComponentWithOuter - { - typedef CAI_ComponentWithOuter BaseClass; - - virtual int SelectScheduleAttack() - { - int result = GetOuter()->SelectScheduleAttack(); - if ( result == SCHED_NONE ) - result = BaseClass::SelectScheduleAttack(); - return result; - } - }; - - // Rappel - virtual bool IsWaitingToRappel( void ) { return m_RappelBehavior.IsWaitingToRappel(); } - void BeginRappel() { m_RappelBehavior.BeginRappel(); } - -private: - int m_nKickDamage; - Vector m_vecTossVelocity; - EHANDLE m_hForcedGrenadeTarget; - bool m_bShouldPatrol; - bool m_bFirstEncounter;// only put on the handsign show in the squad's first encounter. - - // Time Variables - float m_flNextPainSoundTime; - float m_flNextAlertSoundTime; - float m_flNextGrenadeCheck; - float m_flNextLostSoundTime; - float m_flAlertPatrolTime; // When to stop doing alert patrol - float m_flNextAltFireTime; // Elites only. Next time to begin considering alt-fire attack. - - int m_nShots; - float m_flShotDelay; - float m_flStopMoveShootTime; - - CAI_Sentence< CNPC_Combine > m_Sentences; - - int m_iNumGrenades; - CAI_AssaultBehavior m_AssaultBehavior; - CCombineStandoffBehavior m_StandoffBehavior; - CAI_FollowBehavior m_FollowBehavior; - CAI_FuncTankBehavior m_FuncTankBehavior; - CAI_RappelBehavior m_RappelBehavior; - CAI_ActBusyBehavior m_ActBusyBehavior; - -public: - int m_iLastAnimEventHandled; - bool m_fIsElite; - Vector m_vecAltFireTarget; - - int m_iTacticalVariant; - int m_iPathfindingVariant; -}; - - -#endif // NPC_COMBINE_H diff --git a/src/src/dlls/hl2_dll/npc_vortigaunt.cpp b/src/src/dlls/hl2_dll/npc_vortigaunt.cpp deleted file mode 100644 index 19f449d..0000000 --- a/src/src/dlls/hl2_dll/npc_vortigaunt.cpp +++ /dev/null @@ -1,2670 +0,0 @@ -//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// -// -// Purpose: -// -// $NoKeywords: $ -//=============================================================================// - -#include "cbase.h" -#include "beam_shared.h" -#include "game.h" // For skill levels -#include "globalstate.h" -#include "npc_talker.h" -#include "ai_motor.h" -#include "ai_schedule.h" -#include "scripted.h" -#include "basecombatweapon.h" -#include "soundent.h" -#include "npcevent.h" -#include "ai_hull.h" -#include "animation.h" -#include "ammodef.h" // For DMG_CLUB -#include "Sprite.h" -#include "npc_vortigaunt.h" -#include "activitylist.h" -#include "player.h" -#include "items.h" -#include "basegrenade_shared.h" -#include "ai_interactions.h" -#include "IEffects.h" -#include "vstdlib/random.h" -#include "engine/IEngineSound.h" -#include "globals.h" -#include "effect_dispatch_data.h" -#include "te_effect_dispatch.h" -#include "SoundEmitterSystem/isoundemittersystembase.h" -#include "physics_prop_ragdoll.h" -#include "RagdollBoogie.h" - -// memdbgon must be the last include file in a .cpp file!!! -#include "tier0/memdbgon.h" - -#define VORTIGAUNT_LIMP_HEALTH 20 -#define VORTIGAUNT_SENTENCE_VOLUME (float)0.35 // volume of vortigaunt sentences -#define VORTIGAUNT_VOL 0.35 // volume of vortigaunt sounds -#define VORTIGAUNT_ATTN ATTN_NORM // attenutation of vortigaunt sentences -#define VORTIGAUNT_HEAL_RECHARGE 15.0 // How long to rest between heals -#define VORTIGAUNT_ZAP_GLOWGROW_TIME 0.5 // How long does glow last -#define VORTIGAUNT_HEAL_GLOWGROW_TIME 1.4 // How long does glow last -#define VORTIGAUNT_GLOWFADE_TIME 0.5 // How long does it fade -#define VORTIGAUNT_STOMP_DIST 40 -#define VORTIGAUNT_BEAM_HURT 0 -#define VORTIGAUNT_BEAM_HEAL 1 -#define VORTIGAUNT_STOMP_TURN_OFFSET 20 - -#define VORTIGAUNT_LEFT_CLAW "leftclaw" -#define VORTIGAUNT_RIGHT_CLAW "rightclaw" - -#define VORT_CURE "VORT_CURE" -#define VORT_CURESTOP "VORT_CURESTOP" -#define VORT_CURE_INTERRUPT "VORT_CURE_INTERRUPT" -#define VORT_ATTACK "VORT_ATTACK" -#define VORT_MAD "VORT_MAD" -#define VORT_SHOT "VORT_SHOT" -#define VORT_PAIN "VORT_PAIN" -#define VORT_DIE "VORT_DIE" -#define VORT_KILL "VORT_KILL" -#define VORT_LINE_FIRE "VORT_LINE_FIRE" -#define VORT_POK "VORT_POK" -#define VORT_EXTRACT_START "VORT_EXTRACT_START" -#define VORT_EXTRACT_FINISH "VORT_EXTRACT_FINISH" - -// Target must be within this range to heal -#define HEAL_RANGE 256 - -ConVar sk_vortigaunt_health( "sk_vortigaunt_health","0"); -ConVar sk_vortigaunt_armor_charge( "sk_vortigaunt_armor_charge","30"); -ConVar sk_vortigaunt_dmg_claw( "sk_vortigaunt_dmg_claw","0"); -ConVar sk_vortigaunt_dmg_rake( "sk_vortigaunt_dmg_rake","0"); -ConVar sk_vortigaunt_dmg_zap( "sk_vortigaunt_dmg_zap","0"); - -//========================================================= -// Vortigaunt activities -//========================================================= -int ACT_VORTIGAUNT_AIM; -int ACT_VORTIGAUNT_START_HEAL; -int ACT_VORTIGAUNT_HEAL_LOOP; -int ACT_VORTIGAUNT_END_HEAL; -int ACT_VORTIGAUNT_TO_ACTION; -int ACT_VORTIGAUNT_TO_IDLE; -int ACT_VORTIGAUNT_STOMP; -int ACT_VORTIGAUNT_DEFEND; -int ACT_VORTIGAUNT_TO_DEFEND; -int ACT_VORTIGAUNT_FROM_DEFEND; - -//========================================================= -// Monster's Anim Events Go Here -//========================================================= -int AE_VORTIGAUNT_CLAW_LEFT; -int AE_VORTIGAUNT_CLAW_RIGHT; -int AE_VORTIGAUNT_ZAP_POWERUP; -int AE_VORTIGAUNT_ZAP_SHOOT; -int AE_VORTIGAUNT_ZAP_DONE; -int AE_VORTIGAUNT_HEAL_STARTGLOW; -int AE_VORTIGAUNT_HEAL_STARTBEAMS; -int AE_VORTIGAUNT_KICK; -int AE_VORTIGAUNT_STOMP; -int AE_VORTIGAUNT_HEAL_STARTSOUND; -int AE_VORTIGAUNT_SWING_SOUND; -int AE_VORTIGAUNT_SHOOT_SOUNDSTART; -int AE_VORTIGAUNT_DEFEND_BEAMS; - - -//----------------------------------------------------------------------------- -// Interactions -//----------------------------------------------------------------------------- -int g_interactionVortigauntStomp = 0; -int g_interactionVortigauntStompFail = 0; -int g_interactionVortigauntStompHit = 0; -int g_interactionVortigauntKick = 0; -int g_interactionVortigauntClaw = 0; - -//--------------------------------------------------------- -// Save/Restore -//--------------------------------------------------------- -BEGIN_DATADESC( CNPC_Vortigaunt ) - - DEFINE_FIELD( m_flNextNPCThink, FIELD_TIME), - DEFINE_ARRAY( m_pBeam, FIELD_EHANDLE, VORTIGAUNT_MAX_BEAMS ), - DEFINE_FIELD( m_iBeams, FIELD_INTEGER), - DEFINE_FIELD( m_nLightningSprite, FIELD_INTEGER), - DEFINE_FIELD( m_fGlowAge, FIELD_FLOAT), - DEFINE_FIELD( m_fGlowScale, FIELD_FLOAT), - DEFINE_FIELD( m_fGlowChangeTime, FIELD_FLOAT), - DEFINE_FIELD( m_bGlowTurningOn, FIELD_BOOLEAN), - DEFINE_FIELD( m_nCurGlowIndex, FIELD_INTEGER), - DEFINE_FIELD( m_pLeftHandGlow, FIELD_EHANDLE), - DEFINE_FIELD( m_pRightHandGlow, FIELD_EHANDLE), - DEFINE_FIELD( m_flNextHealTime, FIELD_TIME), - DEFINE_FIELD( m_nCurrentHealAmt, FIELD_INTEGER), - DEFINE_FIELD( m_nLastArmorAmt, FIELD_INTEGER), - DEFINE_FIELD( m_iSuitSound, FIELD_INTEGER), - DEFINE_FIELD( m_flSuitSoundTime, FIELD_TIME), - DEFINE_FIELD( m_painTime, FIELD_TIME), - DEFINE_FIELD( m_nextLineFireTime, FIELD_TIME), - DEFINE_FIELD( m_bInBarnacleMouth, FIELD_BOOLEAN), - DEFINE_KEYFIELD( m_bArmorRechargeEnabled, FIELD_BOOLEAN, "ArmorRechargeEnabled" ), - DEFINE_FIELD( m_bForceArmorRecharge, FIELD_BOOLEAN), - DEFINE_FIELD( m_iCurrentRechargeGoal, FIELD_INTEGER ), - DEFINE_FIELD( m_hVictim, FIELD_EHANDLE ), - DEFINE_FIELD( m_bExtractingBugbait, FIELD_BOOLEAN), - DEFINE_FIELD( m_iLeftHandAttachment, FIELD_INTEGER ), - DEFINE_FIELD( m_iRightHandAttachment, FIELD_INTEGER ), - DEFINE_FIELD( m_hHealTarget, FIELD_EHANDLE ), - - // m_AssaultBehavior (auto saved by AI) - // m_LeadBehavior (auto saved by AI) - // DEFINE_FIELD( m_bStopLoopingSounds, FIELD_BOOLEAN ), - - // Function Pointers - DEFINE_USEFUNC( Use ), - - DEFINE_INPUTFUNC( FIELD_VOID, "EnableArmorRecharge", InputEnableArmorRecharge ), - DEFINE_INPUTFUNC( FIELD_VOID, "DisableArmorRecharge", InputDisableArmorRecharge ), - DEFINE_INPUTFUNC( FIELD_STRING, "ChargeTarget", InputChargeTarget ), - DEFINE_INPUTFUNC( FIELD_STRING, "ExtractBugbait", InputExtractBugbait ), - - // Outputs - DEFINE_OUTPUT(m_OnFinishedExtractingBugbait, "OnFinishedExtractingBugbait"), - DEFINE_OUTPUT(m_OnFinishedChargingTarget, "OnFinishedChargingTarget"), - DEFINE_OUTPUT(m_OnPlayerUse, "OnPlayerUse" ), - -END_DATADESC() -LINK_ENTITY_TO_CLASS( npc_vortigaunt, CNPC_Vortigaunt ); - -// for special behavior with rollermines -static bool IsRoller( CBaseEntity *pRoller ) -{ - return FClassnameIs( pRoller, "npc_rollermine" ); -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : -// Output : -//----------------------------------------------------------------------------- -bool CNPC_Vortigaunt::IsHealPositionValid(void) -{ - CBasePlayer *pPlayer = AI_GetSinglePlayer(); - if ( !pPlayer ) - return false; - - Vector vecToPlayer = ( pPlayer->EyePosition() - EyePosition() ); - // Make sure he's still within heal range - if ( vecToPlayer.LengthSqr() > (HEAL_RANGE*HEAL_RANGE) ) - return false; - - // Make sure the player stays in front of me. - // Don't do a straight viewcone check, because my head turns to follow the player, and - // that will allow the player to move too far around me. Instead, do a viewcone check - // from my base facing. - vecToPlayer.z = 0; - VectorNormalize( vecToPlayer ); - Vector facingDir = BodyDirection2D(); - float flDot = DotProduct( vecToPlayer, facingDir ); - if ( flDot < VIEW_FIELD_NARROW ) - return false; - - // Now ensure he's still visible - return ( FVisible( pPlayer ) ); -} - -//----------------------------------------------------------------------------- -// Purpose: Check the heal position. If it's bad, break out current schedule -// and setup for healing at a later time. -//----------------------------------------------------------------------------- -bool CNPC_Vortigaunt::CheckHealPosition( void ) -{ - if ( IsHealPositionValid() ) - return true; - - // Heal position isn't valid. Abort heal. - Speak( VORT_CURE_INTERRUPT ); - ClearBeams(); - EndHandGlow(); - m_flNextHealTime = gpGlobals->curtime + 5.0; - TaskFail(FAIL_BAD_POSITION); - return false; -} - -//------------------------------------------------------------------------------ -// Purpose : -// Input : -// Output : -//------------------------------------------------------------------------------ -#define VORT_HEAL_SENTENCE 0 -#define VORT_DONE_HEAL_SENTENCE 1 -#define VORT_START_EXTRACT_SENTENCE 2 -#define VORT_FINISH_EXTRACT_SENTENCE 3 - -void CNPC_Vortigaunt::SpeakSentence( int sentenceType ) -{ - if (sentenceType == VORT_HEAL_SENTENCE) - { - if ( IsHealPositionValid() ) - { - Speak( VORT_CURE ); - } - } - else if (sentenceType == VORT_DONE_HEAL_SENTENCE) - { - Speak( VORT_CURESTOP ); - } - else if (sentenceType == VORT_START_EXTRACT_SENTENCE) - { - Speak( VORT_EXTRACT_START ); - } - else if (sentenceType == VORT_FINISH_EXTRACT_SENTENCE) - { - Speak( VORT_EXTRACT_FINISH ); - } -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : -// Output : -//----------------------------------------------------------------------------- -void CNPC_Vortigaunt::StartTask( const Task_t *pTask ) -{ - switch ( pTask->iTask) - { - - case TASK_VORTIGAUNT_GET_HEAL_TARGET: - { - // Sets our target to the entity that we cached earlier. - if ( !m_hHealTarget ) - { - TaskFail( FAIL_NO_TARGET ); - } - else - { - SetTarget( m_hHealTarget ); - TaskComplete(); - } - - break; - } - - case TASK_VORTIGAUNT_EXTRACT_WARMUP: - { - ResetIdealActivity( (Activity) ACT_VORTIGAUNT_TO_ACTION ); - break; - } - - case TASK_VORTIGAUNT_EXTRACT: - { - SetActivity( (Activity) ACT_RANGE_ATTACK1 ); - break; - } - - case TASK_VORTIGAUNT_EXTRACT_COOLDOWN: - { - ResetIdealActivity( (Activity)ACT_VORTIGAUNT_TO_IDLE ); - break; - } - - case TASK_VORTIGAUNT_FIRE_EXTRACT_OUTPUT: - { - // Cheat, and fire both outputs - m_OnFinishedExtractingBugbait.FireOutput( this, this ); - TaskComplete(); - break; - } - - case TASK_VORTIGAUNT_HEAL_WARMUP: - { - ResetIdealActivity( (Activity)ACT_VORTIGAUNT_START_HEAL ); - break; - } - case TASK_VORTIGAUNT_HEAL: - { - ResetIdealActivity( (Activity)ACT_VORTIGAUNT_HEAL_LOOP ); - break; - } - case TASK_VORTIGAUNT_FACE_STOMP: - { - if (GetEnemy()!=NULL) - { - GetMotor()->SetIdealYaw( CalcIdealYaw ( GetEnemy()->GetLocalOrigin() ) + VORTIGAUNT_STOMP_TURN_OFFSET ); - SetTurnActivity(); - } - else - { - TaskFail(FAIL_NO_ENEMY); - } - break; - } - case TASK_VORTIGAUNT_STOMP_ATTACK: - { - m_flLastAttackTime = gpGlobals->curtime; - ResetIdealActivity( (Activity)ACT_VORTIGAUNT_STOMP ); - break; - } - case TASK_VORTIGAUNT_GRENADE_KILL: - { - if (GetTarget() == NULL) - { - TaskComplete(); - } - // Used to set delay between beam shot and damage - ClearWait(); - - break; - } - case TASK_VORTIGAUNT_ZAP_GRENADE_OWNER: - { - if (GetEnemy() == NULL) - { - TaskComplete(); - } - // Used to set delay between beam shot and damage - ClearWait(); - - break; - } - case TASK_VORTIGAUNT_WAIT_FOR_PLAYER: - { - // Wait for the player to get near (before starting the bugbait sequence) - break; - } - default: - { - BaseClass::StartTask( pTask ); - break; - } - } -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : -// Output : -//----------------------------------------------------------------------------- -void CNPC_Vortigaunt::RunTask( const Task_t *pTask ) -{ - switch ( pTask->iTask ) - { - case TASK_RANGE_ATTACK1: - { - if (GetEnemy() != NULL) - { - if (GetEnemy()->IsPlayer()) - { - m_flPlaybackRate = 1.5; - } - if (!GetEnemy()->IsAlive()) - { - if( IsActivityFinished() ) - { - TaskComplete(); - break; - } - } - // This is along attack sequence so if the enemy - // becomes occluded bail - if (HasCondition( COND_ENEMY_OCCLUDED )) - { - TaskComplete(); - break; - } - } - BaseClass::RunTask( pTask ); - break; - } - case TASK_MELEE_ATTACK1: - { - if (GetEnemy() == NULL) - { - if ( IsActivityFinished() ) - { - TaskComplete(); - } - } - else - { - BaseClass::RunTask( pTask ); - } - break; - } - case TASK_MELEE_ATTACK2: - { - if ( IsActivityFinished() ) - { - TaskComplete(); - } - break; - } - case TASK_VORTIGAUNT_STOMP_ATTACK: - { - // Face enemy slightly off center - if (GetEnemy() != NULL) - { - GetMotor()->SetIdealYawAndUpdate( CalcIdealYaw ( GetEnemy()->GetLocalOrigin() ) + VORTIGAUNT_STOMP_TURN_OFFSET, AI_KEEP_YAW_SPEED ); - } - - if ( IsActivityFinished() ) - { - TaskComplete(); - } - break; - } - case TASK_VORTIGAUNT_FACE_STOMP: - { - if (GetEnemy()!=NULL) - { - GetMotor()->SetIdealYawAndUpdate( CalcIdealYaw( GetEnemy()->GetLocalOrigin() ) + VORTIGAUNT_STOMP_TURN_OFFSET ); - - if ( FacingIdeal() ) - { - TaskComplete(); - } - } - else - { - TaskFail(FAIL_NO_ENEMY); - } - break; - } - - case TASK_VORTIGAUNT_EXTRACT_WARMUP: - { - if ( IsActivityFinished() ) - { - TaskComplete(); - } - break; - } - - case TASK_VORTIGAUNT_EXTRACT: - { - if ( IsActivityFinished() ) - { - TaskComplete(); - } - break; - } - - case TASK_VORTIGAUNT_EXTRACT_COOLDOWN: - { - if ( IsActivityFinished() ) - { - m_bExtractingBugbait = false; - TaskComplete(); - } - break; - } - - case TASK_VORTIGAUNT_HEAL_WARMUP: - { - if ( IsActivityFinished() ) - { - TaskComplete(); - } - - if ( !CheckHealPosition() ) - return; - break; - } - case TASK_VORTIGAUNT_GRENADE_KILL: - { - if (GetTarget() == NULL) - { - TaskComplete(); - break; - } - - // Face the grenade - GetMotor()->SetIdealYawToTargetAndUpdate( GetTarget()->GetLocalOrigin() ); - - // Shoot beam when grenade is close - float flDist = (GetTarget()->GetLocalOrigin() - GetLocalOrigin()).Length(); - - if (flDist < 225) - { - ClawBeam(GetTarget(),16, m_iLeftHandAttachment ); - ClawBeam(GetTarget(),16, m_iRightHandAttachment ); - } - if (flDist < 150) - { - CBaseGrenade* pGrenade = dynamic_cast((CBaseEntity*)GetTarget()); - if (!pGrenade) - { - TaskComplete(); - } - pGrenade->Detonate(); - TaskComplete(); - } - break; - } - case TASK_VORTIGAUNT_ZAP_GRENADE_OWNER: - { - if (GetEnemy() == NULL) - { - TaskComplete(); - break; - } - - // Face the grenade owner - GetMotor()->SetIdealYawToTargetAndUpdate( GetEnemy()->GetLocalOrigin() ); - - // Shoot beam only if enemy is close enough - float flDist = (GetEnemy()->GetLocalOrigin() - GetLocalOrigin()).Length(); - if (flDist < 350) - { - if (!IsWaitSet() || - IsWaitFinished() ) - { - ClawBeam(GetEnemy(),5, m_iLeftHandAttachment ); - ClawBeam(GetEnemy(),5, m_iRightHandAttachment ); - - // Set a delay and then we do damage. Store in - // m_hVictim in case we are interrupted - if (!IsWaitSet()) - { - SetWait( 0.2 ); - m_hVictim = GetEnemy(); - } - } - else - { - if (m_hVictim != NULL) - { - CTakeDamageInfo info( this, this, 15, DMG_SHOCK ); - CalculateMeleeDamageForce( &info, (GetEnemy()->GetAbsOrigin() - GetAbsOrigin()), GetEnemy()->GetAbsOrigin() ); - m_hVictim->MyNPCPointer()->TakeDamage( info ); - } - TaskComplete(); - } - } - else - { - // To far away to shoot - TaskComplete(); - } - break; - } - case TASK_VORTIGAUNT_HEAL: - { - CBasePlayer *pPlayer = AI_GetSinglePlayer(); - if (pPlayer) - { - if (!CheckHealPosition()) - return; - - // Charge the suit's armor - pPlayer->IncrementArmorValue( 1, m_iCurrentRechargeGoal ); - - // Stop healing once we've hit the maximum level we'll ever charge the player to. - if ( pPlayer->ArmorValue() >= m_iCurrentRechargeGoal ) - { - m_bForceArmorRecharge = false; - m_flNextHealTime = gpGlobals->curtime + VORTIGAUNT_HEAL_RECHARGE; - ClearBeams(); - EndHandGlow(); - TaskComplete(); - m_OnFinishedChargingTarget.FireOutput( this, this ); - return; - } - - // ------------------------------------------ - // Suit sound - // ------------------------------------------ - // Play the on sound or the looping charging sound - if (!m_iSuitSound) - { - m_iSuitSound++; - EmitSound( "NPC_Vortigaunt.SuitOn" ); - m_flSuitSoundTime = 0.56 + gpGlobals->curtime; - } - if ((m_iSuitSound == 1) && (m_flSuitSoundTime <= gpGlobals->curtime)) - { - m_iSuitSound++; - - CPASAttenuationFilter filter( this, "NPC_Vortigaunt.SuitCharge" ); - filter.MakeReliable(); - - EmitSound( filter, entindex(), "NPC_Vortigaunt.SuitCharge" ); - - m_bStopLoopingSounds = true; - } - } - - break; - } - - case TASK_VORTIGAUNT_WAIT_FOR_PLAYER: - { - // Wait for the player to get near (before starting the bugbait sequence) - // Get edict for one player - CBasePlayer *pPlayer = AI_GetSinglePlayer(); - if ( pPlayer ) - { - GetMotor()->SetIdealYawToTargetAndUpdate( pPlayer->GetAbsOrigin(), AI_KEEP_YAW_SPEED ); - SetTurnActivity(); - if ( GetMotor()->DeltaIdealYaw() < 10 ) - { - // Wait for the player to get close enough - if ( UTIL_DistApprox( GetAbsOrigin(), pPlayer->GetAbsOrigin() ) < 384 ) - { - TaskComplete(); - } - } - } - else - { - TaskFail(FAIL_NO_PLAYER); - } - } - break; - - - default: - { - BaseClass::RunTask( pTask ); - break; - } - } -} - - - - -//========================================================= -// GetSoundInterests - returns a bit mask indicating which types -// of sounds this monster regards. -//========================================================= -int CNPC_Vortigaunt::GetSoundInterests ( void) -{ - return SOUND_WORLD | - SOUND_COMBAT | - SOUND_CARCASS | - SOUND_MEAT | - SOUND_GARBAGE | - SOUND_DANGER | - SOUND_PLAYER; -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : -// Output : -//----------------------------------------------------------------------------- -Class_T CNPC_Vortigaunt::Classify ( void ) -{ - return CLASS_VORTIGAUNT; -} - -//========================================================= -// ALertSound - barney says "Freeze!" -//========================================================= -void CNPC_Vortigaunt::AlertSound( void ) -{ - if ( GetEnemy() != NULL ) - { - if ( IsOkToCombatSpeak() ) - { - Speak( VORT_ATTACK ); - } - } - -} -//========================================================= -// MaxYawSpeed - allows each sequence to have a different -// turn rate associated with it. -//========================================================= -float CNPC_Vortigaunt::MaxYawSpeed ( void ) -{ - switch ( GetActivity() ) - { - case ACT_IDLE: - return 35; - break; - case ACT_WALK: - return 35; - break; - case ACT_RUN: - return 45; - break; - default: - return 35; - break; - } -} - -//------------------------------------------------------------------------------ -// Purpose : For innate range attack -// Input : -// Output : -//------------------------------------------------------------------------------ -int CNPC_Vortigaunt::RangeAttack1Conditions( float flDot, float flDist ) -{ - if (GetEnemy() == NULL) - { - return( COND_NONE ); - } - - if ( gpGlobals->curtime < m_flNextAttack ) - { - return( COND_NONE ); - } - - // Range attack is ineffective on manhack so never use it - // Melee attack looks a lot better anyway - if (GetEnemy()->Classify() == CLASS_MANHACK) - { - return( COND_NONE ); - } - - // dvs: Allow up-close range attacks for episodic as the vort's melee - // attack is rather ineffective. - #ifndef HL2_EPISODIC - if ( flDist <= 70 ) - { - return( COND_TOO_CLOSE_TO_ATTACK ); - } - else - #endif // HL2_EPISODIC - if ( flDist > 1500 * 12 ) // 1500ft max - { - return( COND_TOO_FAR_TO_ATTACK ); - } - else if ( flDot < 0.65 ) - { - return( COND_NOT_FACING_ATTACK ); - } - - return( COND_CAN_RANGE_ATTACK1 ); -} - -//----------------------------------------------------------------------------- -// Purpose: For innate melee attack -// Input : -// Output : -//----------------------------------------------------------------------------- -int CNPC_Vortigaunt::MeleeAttack1Conditions ( float flDot, float flDist ) -{ - if (flDist > 70) - { - return COND_TOO_FAR_TO_ATTACK; - } - else if (flDot < 0.7) - { - // If I'm not facing attack clear TOOFAR which may have been set by range attack - // Otherwise we may try to back away even when melee attack is valid - ClearCondition(COND_TOO_FAR_TO_ATTACK); - return COND_NOT_FACING_ATTACK; - } - - // no melee attacks against rollermins - if ( IsRoller(GetEnemy()) ) - return COND_NONE; - - return COND_CAN_MELEE_ATTACK1; -} - -//------------------------------------------------------------------------------ -// Purpose : Returns who I hit on a kick (or NULL) -// Input : -// Output : -//------------------------------------------------------------------------------ -CBaseEntity* CNPC_Vortigaunt::Kick( void ) -{ - trace_t tr; - - Vector forward; - AngleVectors( GetAbsAngles(), &forward ); - Vector vecStart = WorldSpaceCenter(); - Vector vecEnd = vecStart + (forward * 70); - - AI_TraceHull( vecStart, vecEnd, Vector(-16,-16,-18), Vector(16,16,18), - MASK_SHOT_HULL, this, COLLISION_GROUP_NONE, &tr ); - - return tr.m_pEnt; -} - -//------------------------------------------------------------------------------ -// Purpose : Vortigaunt claws at his enemy -// Input : -// Output : -//------------------------------------------------------------------------------ -void CNPC_Vortigaunt::Claw( int iAttachment) -{ - CBaseEntity *pHurt = CheckTraceHullAttack( 40, Vector(-10,-10,-10), Vector(10,10,10),sk_vortigaunt_dmg_claw.GetFloat(), DMG_SLASH ); - if ( pHurt ) - { - pHurt->ViewPunch( QAngle(5,0,-18) ); - // If hit manhack make temp glow - if (pHurt->Classify() == CLASS_MANHACK) - { - ClawBeam( pHurt, 16, iAttachment ); - } - // Play a random attack hit sound - EmitSound( "NPC_Vortigaunt.Claw" ); - } -} - -//========================================================= -// HandleAnimEvent - catches the monster-specific messages -// that occur when tagged animation frames are played. -// -// Returns number of events handled, 0 if none. -//========================================================= -void CNPC_Vortigaunt::HandleAnimEvent( animevent_t *pEvent ) -{ - if ( pEvent->event == AE_VORTIGAUNT_CLAW_LEFT ) - { - Claw( m_iLeftHandAttachment ); - return; - } - - if ( pEvent->event == AE_VORTIGAUNT_CLAW_RIGHT ) - { - Claw( m_iRightHandAttachment ); - return; - } - - if ( pEvent->event == AE_VORTIGAUNT_ZAP_POWERUP ) - { - // speed up attack when on hard - if ( g_iSkillLevel == SKILL_HARD ) - m_flPlaybackRate = 1.5; - - ArmBeam( -1 ,VORTIGAUNT_BEAM_HURT ); - ArmBeam( 1 ,VORTIGAUNT_BEAM_HURT ); - BeamGlow(); - - // Make hands glow if not already glowing - if ( m_fGlowAge == 0 ) - { - StartHandGlow( VORTIGAUNT_BEAM_HURT ); - } - - CPASAttenuationFilter filter( this ); - - CSoundParameters params; - if ( GetParametersForSound( "NPC_Vortigaunt.ZapPowerup", params, NULL ) ) - { - EmitSound_t ep( params ); - ep.m_nPitch = 100 + m_iBeams * 10; - - EmitSound( filter, entindex(), ep ); - - m_bStopLoopingSounds = true; - } - //m_nSkin = m_iBeams / 2; - return; - } - - if ( pEvent->event == AE_VORTIGAUNT_ZAP_SHOOT ) - { - ClearBeams(); - - ClearMultiDamage(); - - ZapBeam( -1 ); - ZapBeam( 1 ); - EndHandGlow(); - - EmitSound( "NPC_Vortigaunt.Shoot" ); - m_bStopLoopingSounds = true; - ApplyMultiDamage(); - - if ( m_bExtractingBugbait == true ) - { - // Spawn bugbait! - CBaseCombatWeapon *pWeapon = Weapon_Create( "weapon_bugbait" ); - if ( pWeapon ) - { - // Starting above the body, spawn closer and closer to the vort until it's clear - Vector vecSpawnOrigin = GetTarget()->WorldSpaceCenter() + Vector(0, 0, 32); - int iNumAttempts = 4; - Vector vecToVort = (WorldSpaceCenter() - vecSpawnOrigin); - float flDistance = VectorNormalize( vecToVort ) / (iNumAttempts-1); - int i = 0; - for (; i < iNumAttempts; i++ ) - { - trace_t tr; - CTraceFilterSkipTwoEntities traceFilter( GetTarget(), this, COLLISION_GROUP_NONE ); - AI_TraceLine( vecSpawnOrigin, vecSpawnOrigin, MASK_SHOT, &traceFilter, &tr ); - - if ( tr.fraction == 1.0 && !tr.m_pEnt ) - { - // Make sure it can fit there - AI_TraceHull( vecSpawnOrigin, vecSpawnOrigin, -Vector(16,16,16), Vector(16,16,48), MASK_SHOT, &traceFilter, &tr ); - if ( tr.fraction == 1.0 && !tr.m_pEnt ) - break; - } - - //NDebugOverlay::Box( vecSpawnOrigin, pWeapon->WorldAlignMins(), pWeapon->WorldAlignMins(), 255,0,0, 64, 100 ); - - // Move towards the vort - vecSpawnOrigin = vecSpawnOrigin + (vecToVort * flDistance); - } - - // HACK: If we've still failed, just spawn it on the player - if ( i == iNumAttempts ) - { - CBasePlayer *pPlayer = AI_GetSinglePlayer(); - if ( pPlayer ) - { - vecSpawnOrigin = pPlayer->WorldSpaceCenter(); - } - } - - //NDebugOverlay::Box( vecSpawnOrigin, -Vector(20,20,20), Vector(20,20,20), 0,255,0, 64, 100 ); - - pWeapon->SetAbsOrigin( vecSpawnOrigin ); - pWeapon->Drop( Vector(0,0,1) ); - } - - CEffectData data; - - data.m_vOrigin = GetTarget()->WorldSpaceCenter(); - data.m_vNormal = WorldSpaceCenter() - GetTarget()->WorldSpaceCenter(); - VectorNormalize( data.m_vNormal ); - - data.m_flScale = 4; - - DispatchEffect( "AntlionGib", data ); - } - - m_flNextAttack = gpGlobals->curtime + random->RandomFloat( 0.5, 4.0 ); - return; - } - - if ( pEvent->event == AE_VORTIGAUNT_ZAP_DONE ) - { - ClearBeams( ); - return; - } - - if ( pEvent->event == AE_VORTIGAUNT_HEAL_STARTGLOW ) - { - // Make hands glow - StartHandGlow(VORTIGAUNT_BEAM_HEAL); - return; - } - - if ( pEvent->event == AE_VORTIGAUNT_HEAL_STARTBEAMS ) - { - if ( !CheckHealPosition()) - return; - - HealBeam(-1); - return; - - //m_nSkin = m_iBeams / 2; - } - - if( pEvent->event == AE_VORTIGAUNT_KICK ) - { - CBaseEntity *pHurt = Kick(); - CBaseCombatCharacter* pBCC = ToBaseCombatCharacter( pHurt ); - - if (pBCC) - { - Vector forward, up; - AngleVectors( GetLocalAngles(), &forward, NULL, &up ); - - if ( pBCC->DispatchInteraction( g_interactionVortigauntKick, NULL, this ) ) - { - pBCC->ApplyAbsVelocityImpulse( forward * 300 + up * 250 ); - - CTakeDamageInfo info( this, this, pBCC->m_iHealth+1, DMG_CLUB ); - CalculateMeleeDamageForce( &info, forward, pHurt->GetAbsOrigin() ); - pBCC->TakeDamage( info ); - } - else - { - pBCC->ViewPunch( QAngle(15,0,0) ); - - CTakeDamageInfo info( this, this, sk_vortigaunt_dmg_claw.GetFloat(), DMG_CLUB ); - CalculateMeleeDamageForce( &info, forward, pHurt->GetAbsOrigin() ); - pBCC->TakeDamage( info ); - } - EmitSound( "NPC_Vortigaunt.Kick" ); - } - - return; - } - - if ( pEvent->event == AE_VORTIGAUNT_STOMP ) - { - CBaseCombatCharacter* pBCC = GetEnemyCombatCharacterPointer(); - - if ( pBCC ) - { - float fDist = (pBCC->GetLocalOrigin() - GetLocalOrigin()).Length(); - if (fDist > VORTIGAUNT_STOMP_DIST) - { - pBCC->DispatchInteraction( g_interactionVortigauntStompFail, NULL, this ); - return; - } - else - { - pBCC->DispatchInteraction( g_interactionVortigauntStompHit, NULL, this ); - } - EmitSound( "NPC_Vortigaunt.Kick" ); - } - - return; - } - - if ( pEvent->event == AE_VORTIGAUNT_HEAL_STARTSOUND ) - { - CPASAttenuationFilter filter( this ); - - CSoundParameters params; - if ( GetParametersForSound( "NPC_Vortigaunt.StartHealLoop", params, NULL ) ) - { - EmitSound_t ep( params ); - ep.m_nPitch = 100 + m_iBeams * 10; - - EmitSound( filter, entindex(), ep ); - - m_bStopLoopingSounds = true; - } - return; - } - - if ( pEvent->event == AE_VORTIGAUNT_SWING_SOUND ) - { - EmitSound( "NPC_Vortigaunt.Swing" ); - return; - } - - if ( pEvent->event == AE_VORTIGAUNT_SHOOT_SOUNDSTART ) - { - CPASAttenuationFilter filter( this ); - CSoundParameters params; - if ( GetParametersForSound( "NPC_Vortigaunt.StartShootLoop", params, NULL ) ) - { - EmitSound_t ep( params ); - ep.m_nPitch = 100 + m_iBeams * 10; - - EmitSound( filter, entindex(), ep ); - m_bStopLoopingSounds = true; - } - return; - } - - if ( pEvent->event == AE_VORTIGAUNT_DEFEND_BEAMS ) - { - DefendBeams(); - return; - } - - if ( pEvent->event == AE_NPC_LEFTFOOT ) - { - EmitSound( "NPC_Vortigaunt.FootstepLeft", pEvent->eventtime ); - return; - } - - if ( pEvent->event == AE_NPC_RIGHTFOOT ) - { - EmitSound( "NPC_Vortigaunt.FootstepRight", pEvent->eventtime ); - return; - } - - BaseClass::HandleAnimEvent( pEvent ); -} - -//------------------------------------------------------------------------------ -// Purpose : Returnst true if entity is stompable -// Input : -// Output : -//------------------------------------------------------------------------------ -bool CNPC_Vortigaunt::IsStompable(CBaseEntity *pEntity) -{ - if (!pEntity) - return false; - - float fDist = (pEntity->GetLocalOrigin() - GetLocalOrigin()).Length(); - if (fDist > VORTIGAUNT_STOMP_DIST) - return false; - - CBaseCombatCharacter* pBCC = (CBaseCombatCharacter *)pEntity; - - if ( pBCC && pBCC->DispatchInteraction( g_interactionVortigauntStomp, NULL, this ) ) - return true; - - return false; -} - -//------------------------------------------------------------------------------ -// Purpose : Translate some activites for the Vortigaunt -// Input : -// Output : -//------------------------------------------------------------------------------ -Activity CNPC_Vortigaunt::NPC_TranslateActivity( Activity eNewActivity ) -{ - if ((eNewActivity == ACT_SIGNAL3) && - (SelectWeightedSequence ( ACT_SIGNAL3 ) == ACTIVITY_NOT_AVAILABLE) ) - { - eNewActivity = ACT_IDLE; - } - - if (eNewActivity == ACT_IDLE) - { - if ( m_NPCState == NPC_STATE_COMBAT || m_NPCState == NPC_STATE_ALERT) - { - return ACT_IDLE_ANGRY; - } - } - else if (eNewActivity == ACT_MELEE_ATTACK1) - { - // If enemy is low pick ATTACK2 (kick) - if (GetEnemy() != NULL && (GetEnemy()->EyePosition().z - GetLocalOrigin().z) < 20) - { - return ACT_MELEE_ATTACK2; - } - } - return BaseClass::NPC_TranslateActivity( eNewActivity ); -} - -//------------------------------------------------------------------------------ -// Purpose : If I've been in alert for a while and nothing's happened, -// go back to idle -// Input : -// Output : -//------------------------------------------------------------------------------ -bool CNPC_Vortigaunt::ShouldGoToIdleState( void ) -{ - if (m_flLastStateChangeTime + 10 < gpGlobals->curtime) - { - return true; - } - return false; -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CNPC_Vortigaunt::UpdateOnRemove( void) -{ - ClearBeams(); - ClearHandGlow(); - - // Chain at end to mimic destructor unwind order - BaseClass::UpdateOnRemove(); -} - -//------------------------------------------------------------------------------ -// Purpose : -// Input : -// Output : -//------------------------------------------------------------------------------ -void CNPC_Vortigaunt::Event_Killed( const CTakeDamageInfo &info ) -{ - ClearBeams(); - ClearHandGlow(); - - BaseClass::Event_Killed( info ); -} - -bool CNPC_Vortigaunt::CreateBehaviors() -{ - AddBehavior( &m_AssaultBehavior ); - AddBehavior( &m_LeadBehavior ); - //AddBehavior( &m_FollowBehavior ); - - return BaseClass::CreateBehaviors(); -} -//========================================================= -// Spawn -//========================================================= -void CNPC_Vortigaunt::Spawn() -{ - // Allow multiple models (for slaves), but default to vortigaunt.mdl - char *szModel = (char *)STRING( GetModelName() ); - if (!szModel || !*szModel) - { - szModel = "models/vortigaunt.mdl"; - SetModelName( AllocPooledString(szModel) ); - } - - Precache(); - SetModel( szModel ); - - SetHullType(HULL_WIDE_HUMAN); - SetHullSizeNormal(); - - SetSolid( SOLID_BBOX ); - AddSolidFlags( FSOLID_NOT_STANDABLE ); - SetMoveType( MOVETYPE_STEP ); - m_bloodColor = BLOOD_COLOR_GREEN; - m_iHealth = sk_vortigaunt_health.GetFloat(); - SetViewOffset( Vector ( 0, 0, 64 ) );// position of the eyes relative to monster's origin. - m_flFieldOfView = VIEW_FIELD_WIDE; // NOTE: we need a wide field of view so npc will notice player and say hello - m_NPCState = NPC_STATE_NONE; - - GetExpresser()->SetVoicePitch( random->RandomInt( 85, 110 ) ); - - CapabilitiesAdd( bits_CAP_ANIMATEDFACE | bits_CAP_TURN_HEAD | bits_CAP_MOVE_GROUND | bits_CAP_NO_HIT_PLAYER ); - CapabilitiesAdd ( bits_CAP_INNATE_RANGE_ATTACK1 ); - CapabilitiesAdd ( bits_CAP_INNATE_MELEE_ATTACK1 ); - CapabilitiesAdd ( bits_CAP_DOORS_GROUP ); - CapabilitiesAdd( bits_CAP_FRIENDLY_DMG_IMMUNE ); - - m_flNextHealTime = 0; // Next time allowed to heal player - m_flEyeIntegRate = 0.6; // Got a big eyeball so turn it slower - m_hVictim = NULL; - m_bForceArmorRecharge = false; - - m_nCurGlowIndex = 0; - m_pLeftHandGlow = NULL; - m_pRightHandGlow = NULL; - - m_bStopLoopingSounds = false; - - m_iLeftHandAttachment = LookupAttachment( VORTIGAUNT_LEFT_CLAW ); - m_iRightHandAttachment = LookupAttachment( VORTIGAUNT_RIGHT_CLAW ); - - NPCInit(); - - SetUse( &CNPC_Vortigaunt::Use ); -} - -//========================================================= -// Precache - precaches all resources this monster needs -//========================================================= -void CNPC_Vortigaunt::Precache() -{ - PrecacheModel( STRING( GetModelName() ) ); - - m_nLightningSprite = PrecacheModel("sprites/lgtning.vmt"); - - PrecacheModel("sprites/blueglow1.vmt"); - PrecacheModel("sprites/greenglow1.vmt"); - - // every new barney must call this, otherwise - // when a level is loaded, nobody will talk (time is reset to 0) - TalkInit(); - - PrecacheScriptSound( "NPC_Vortigaunt.SuitOn" ); - PrecacheScriptSound( "NPC_Vortigaunt.SuitCharge" ); - PrecacheScriptSound( "NPC_Vortigaunt.Claw" ); - PrecacheScriptSound( "NPC_Vortigaunt.ZapPowerup" ); - PrecacheScriptSound( "NPC_Vortigaunt.Shoot" ); - PrecacheScriptSound( "NPC_Vortigaunt.Kick" ); - PrecacheScriptSound( "NPC_Vortigaunt.StartHealLoop" ); - PrecacheScriptSound( "NPC_Vortigaunt.Swing" ); - PrecacheScriptSound( "NPC_Vortigaunt.StartShootLoop" ); - PrecacheScriptSound( "NPC_Vortigaunt.FootstepLeft" ); - PrecacheScriptSound( "NPC_Vortigaunt.FootstepRight" ); - PrecacheScriptSound( "NPC_Vortigaunt.ClawBeam" ); - - BaseClass::Precache(); -} - -// Init talk data -void CNPC_Vortigaunt::TalkInit() -{ - BaseClass::TalkInit(); - - // vortigaunt will try to talk to friends in this order: - m_szFriends[0] = "npc_vortigaunt"; - m_szFriends[1] = "npc_citizen"; - - // get voice for head - just one barney voice for now - GetExpresser()->SetVoicePitch( 100 ); -} - - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CNPC_Vortigaunt::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - m_OnPlayerUse.FireOutput( pActivator, pCaller ); - - if ( !IsInAScript() && m_NPCState != NPC_STATE_SCRIPT ) - { - // First, try to speak the +USE concept - if ( IsOkToSpeakInResponseToPlayer() ) - { - if ( !Speak( TLK_USE ) ) - { - // If we haven't said hi, say that first - if ( !SpokeConcept( TLK_HELLO ) ) - { - Speak( TLK_HELLO ); - } - else - { - Speak( TLK_IDLE ); - } - } - else - { - // Don't say hi after you've said your +USE speech - SetSpokeConcept( TLK_HELLO, NULL ); - } - } - } -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : -// Output : -//----------------------------------------------------------------------------- -int CNPC_Vortigaunt::OnTakeDamage_Alive( const CTakeDamageInfo &info ) -{ - // make sure friends talk about it if player hurts talkmonsters... - int ret = BaseClass::OnTakeDamage_Alive( info ); - if (!IsAlive()) - { - return ret; - } - - if ( m_NPCState != NPC_STATE_PRONE && (info.GetAttacker()->GetFlags() & FL_CLIENT) ) - { - - // This is a heurstic to determine if the player intended to harm me - // If I have an enemy, we can't establish intent (may just be crossfire) - if ( GetEnemy() == NULL ) - { - // If I'm already suspicious, get mad - if (m_afMemory & bits_MEMORY_SUSPICIOUS) - { - // Alright, now I'm pissed! - Speak( VORT_MAD ); - - Remember( bits_MEMORY_PROVOKED ); - - // Allowed to hit the player now! - CapabilitiesRemove(bits_CAP_NO_HIT_PLAYER); - - StopFollowing(); - } - else - { - // Hey, be careful with that - Speak( VORT_SHOT ); - Remember( bits_MEMORY_SUSPICIOUS ); - } - } - else if ( !(GetEnemy()->IsPlayer()) && (m_lifeState != LIFE_DEAD )) - { - Speak( VORT_SHOT ); - } - } - return ret; -} - - -//========================================================= -// PainSound -//========================================================= -void CNPC_Vortigaunt::PainSound( const CTakeDamageInfo &info ) -{ - if (gpGlobals->curtime < m_painTime) - return; - - m_painTime = gpGlobals->curtime + random->RandomFloat(0.5, 0.75); - - Speak( VORT_PAIN ); -} - -//========================================================= -// DeathSound -//========================================================= -void CNPC_Vortigaunt::DeathSound( const CTakeDamageInfo &info ) -{ - Speak( VORT_DIE ); -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : -// Output : -//----------------------------------------------------------------------------- -void CNPC_Vortigaunt::TraceAttack( const CTakeDamageInfo &inputInfo, const Vector &vecDir, trace_t *ptr ) -{ - CTakeDamageInfo info = inputInfo; - - if ( (info.GetDamageType() & DMG_SHOCK) && FClassnameIs( info.GetAttacker(), GetClassname() ) ) - { - // mask off damage from other vorts for now - info.SetDamage( 0.01 ); - } - - switch( ptr->hitgroup) - { - case HITGROUP_CHEST: - case HITGROUP_STOMACH: - if (info.GetDamageType() & (DMG_BULLET | DMG_SLASH | DMG_BLAST)) - { - info.ScaleDamage( 0.5f ); - } - break; - case 10: - if (info.GetDamageType() & (DMG_BULLET | DMG_SLASH | DMG_CLUB)) - { - info.SetDamage( info.GetDamage() - 20 ); - if (info.GetDamage() <= 0) - { - g_pEffects->Ricochet( ptr->endpos, (vecDir*-1.0f) ); - info.SetDamage( 0.01 ); - } - } - // always a head shot - ptr->hitgroup = HITGROUP_HEAD; - break; - } - - BaseClass::TraceAttack( info, vecDir, ptr ); -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : -// Output : -//----------------------------------------------------------------------------- -int CNPC_Vortigaunt::TranslateSchedule( int scheduleType ) -{ - int baseType; - - switch( scheduleType ) - { - case SCHED_RANGE_ATTACK1: - return SCHED_VORTIGAUNT_RANGE_ATTACK; - break; - - case SCHED_MELEE_ATTACK1: - if (IsStompable(GetEnemy())) - { - return SCHED_VORTIGAUNT_STOMP_ATTACK; - } - else - { - // Tell my enemy I'm about to punch them so they can do something - // special if they want to - if ((GetEnemy() != NULL) && (GetEnemy()->MyNPCPointer() != NULL)) - { - Vector vFacingDir = BodyDirection2D( ); - Vector vClawPos = EyePosition() + vFacingDir*30; - GetEnemy()->MyNPCPointer()->DispatchInteraction( g_interactionVortigauntClaw, &vClawPos, this ); - } - return SCHED_VORTIGAUNT_MELEE_ATTACK; - } - break; - - case SCHED_IDLE_STAND: - { - // call base class default so that scientist will talk - // when standing during idle - baseType = BaseClass::TranslateSchedule(scheduleType); - - if (baseType == SCHED_IDLE_STAND) - { - // just look straight ahead - return SCHED_VORTIGAUNT_STAND; - } - else - return baseType; - break; - - } - case SCHED_FAIL_ESTABLISH_LINE_OF_FIRE: - { - // Fail schedule doesn't go through SelectSchedule() - // So we have to clear beams and glow here - ClearBeams(); - EndHandGlow(); - - return SCHED_COMBAT_FACE; - break; - } - case SCHED_CHASE_ENEMY_FAILED: - { - baseType = BaseClass::TranslateSchedule(scheduleType); - if ( baseType != SCHED_CHASE_ENEMY_FAILED ) - return baseType; - - if (HasMemory(bits_MEMORY_INCOVER)) - { - // Occasionally run somewhere so I don't just - // stand around forever if my enemy is stationary - if (random->RandomInt(0,5) == 5) - { - return SCHED_PATROL_RUN; - } - else - { - return SCHED_VORTIGAUNT_STAND; - } - } - break; - } - case SCHED_FAIL_TAKE_COVER: - { - // Fail schedule doesn't go through SelectSchedule() - // So we have to clear beams and glow here - ClearBeams(); - EndHandGlow(); - - return SCHED_RUN_RANDOM; - break; - } - } - - return BaseClass::TranslateSchedule( scheduleType ); -} - -//----------------------------------------------------------------------------- -// Purpose: -// Output : Returns true on success, false on failure. -//----------------------------------------------------------------------------- -bool CNPC_Vortigaunt::ShouldHealTarget( void ) -{ - if ( IsInAScript() ) - return false; - - // Must be allowed to do this - if ( m_bArmorRechargeEnabled == false ) - return false; - - // Can't be too soon - if ( m_flNextHealTime > gpGlobals->curtime ) - return false; - - // Don't heal when fighting - if ( m_NPCState == NPC_STATE_COMBAT ) - return false; - - if ( GetEnemy() ) - return false; - - if ( IsCurSchedule( SCHED_VORTIGAUNT_EXTRACT_BUGBAIT ) ) - return false; - - // Can't heal if we're leading the player - if ( IsLeading() ) - return false; - - // Need to be looking at the player - if ( !HasCondition( COND_SEE_PLAYER ) ) - return false; - - // Can't be saying something -// if ( GetExpresser()->IsSpeaking() ) -// return false; - - // Find a likely target in range - CBaseEntity *pEntity = PlayerInRange( GetLocalOrigin(), HEAL_RANGE ); - - if ( pEntity != NULL ) - { - CBasePlayer *pPlayer = ToBasePlayer( pEntity ); - - // Make sure the player's got a suit - if ( !pPlayer->IsSuitEquipped() ) - return false; - - if ( pPlayer->GetFlags() & FL_NOTARGET ) - return false; - - // See if the player needs armor, or tau-cannon ammo - if ( pPlayer->ArmorValue() < sk_vortigaunt_armor_charge.GetInt() ) - { - m_iCurrentRechargeGoal = pPlayer->ArmorValue() + sk_vortigaunt_armor_charge.GetInt(); - if ( m_iCurrentRechargeGoal > 100 ) - m_iCurrentRechargeGoal = 100; - - m_hHealTarget = pEntity; - return true; - } - } - - return false; -} - -//----------------------------------------------------------------------------- -// Purpose: -// Output : int -//----------------------------------------------------------------------------- -int CNPC_Vortigaunt::SelectHealSchedule( void ) -{ - // If our lead behavior has a goal, don't wait around to heal anyone - if ( m_LeadBehavior.HasGoal() ) - return SCHED_NONE; - - // See if we should heal the player - if ( ShouldHealTarget() ) - return SCHED_VORTIGAUNT_HEAL; - - return SCHED_NONE; -} - -//------------------------------------------------------------------------------ -// Purpose : -// Input : -// Output : -//------------------------------------------------------------------------------ -int CNPC_Vortigaunt::SelectSchedule( void ) -{ - ClearBeams(); - EndHandGlow(); - - // If we're currently supposed to be doing something scripted, do it immediately. - if ( m_bExtractingBugbait ) - return SCHED_VORTIGAUNT_EXTRACT_BUGBAIT; - - if ( m_bForceArmorRecharge ) - { - m_flNextHealTime = 0; - return SCHED_VORTIGAUNT_HEAL; - } - - int schedule = SelectHealSchedule(); - if ( schedule != SCHED_NONE ) - return schedule; - - if ( HasCondition( COND_PLAYER_PUSHING ) && GlobalEntity_GetState("gordon_precriminal") != GLOBAL_ON ) - { - return SCHED_MOVE_AWAY; - } - - if ( BehaviorSelectSchedule() ) - return BaseClass::SelectSchedule(); - - switch( m_NPCState ) - { - case NPC_STATE_PRONE: - { - if (m_bInBarnacleMouth) - { - return SCHED_VORTIGAUNT_BARNACLE_CHOMP; - } - else - { - return SCHED_VORTIGAUNT_BARNACLE_HIT; - } - } - case NPC_STATE_COMBAT: - { - // dead enemy - if ( HasCondition( COND_ENEMY_DEAD ) ) - { - // call base class, all code to handle dead enemies is centralized there. - return BaseClass::SelectSchedule(); - } - - if ( HasCondition( COND_HEAVY_DAMAGE ) ) - { - return SCHED_TAKE_COVER_FROM_ENEMY; - } - - if ( HasCondition( COND_HEAR_DANGER ) ) - { - return SCHED_TAKE_COVER_FROM_BEST_SOUND; - } - - if ( HasCondition( COND_ENEMY_DEAD ) && IsOkToCombatSpeak() ) - { - Speak( VORT_KILL ); - } - - // If I might hit the player shooting... - else if ( HasCondition( COND_WEAPON_PLAYER_IN_SPREAD )) - { - if ( IsOkToCombatSpeak() && m_nextLineFireTime < gpGlobals->curtime) - { - Speak( VORT_LINE_FIRE ); - m_nextLineFireTime = gpGlobals->curtime + 3.0f; - } - - // Run to a new location or stand and aim - if (random->RandomInt(0,2) == 0) - { - return SCHED_ESTABLISH_LINE_OF_FIRE; - } - else - { - return SCHED_COMBAT_FACE; - } - } - } - break; - - case NPC_STATE_ALERT: - case NPC_STATE_IDLE: - - if ( HasCondition( COND_HEAR_DANGER ) ) - { - return SCHED_TAKE_COVER_FROM_BEST_SOUND; - } - - if ( HasCondition( COND_ENEMY_DEAD ) && IsOkToCombatSpeak() ) - { - Speak( VORT_KILL ); - } - - break; - } - - return BaseClass::SelectSchedule(); -} - -//----------------------------------------------------------------------------- -// Purpose: This is a generic function (to be implemented by sub-classes) to -// handle specific interactions between different types of characters -// (For example the barnacle grabbing an NPC) -// Input : Constant for the type of interaction -// Output : true - if sub-class has a response for the interaction -// false - if sub-class has no response -//----------------------------------------------------------------------------- -bool CNPC_Vortigaunt::HandleInteraction(int interactionType, void *data, CBaseCombatCharacter* sourceEnt) -{ - if (interactionType == g_interactionBarnacleVictimDangle) - { - // Force choosing of a new schedule - ClearSchedule(); - m_bInBarnacleMouth = true; - return true; - } - else if ( interactionType == g_interactionBarnacleVictimReleased ) - { - SetIdealState( NPC_STATE_IDLE ); - - m_bInBarnacleMouth = false; - SetAbsVelocity( vec3_origin ); - SetMoveType( MOVETYPE_STEP ); - return true; - } - else if ( interactionType == g_interactionBarnacleVictimGrab ) - { - if ( GetFlags() & FL_ONGROUND ) - { - SetGroundEntity( NULL ); - } - SetIdealState( NPC_STATE_PRONE ); - - CTakeDamageInfo info; - PainSound( info ); - return true; - } - return false; -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CNPC_Vortigaunt::DeclineFollowing( void ) -{ - Speak( VORT_POK ); -} - -//----------------------------------------------------------------------------- -// Purpose: Return true if you're willing to be idly talked to by other friends. -//----------------------------------------------------------------------------- -bool CNPC_Vortigaunt::CanBeUsedAsAFriend( void ) -{ - // We don't want to be used if we're busy - if ( IsCurSchedule( SCHED_VORTIGAUNT_HEAL ) ) - return false; - if ( IsCurSchedule( SCHED_VORTIGAUNT_EXTRACT_BUGBAIT ) ) - return false; - - return BaseClass::CanBeUsedAsAFriend(); -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CNPC_Vortigaunt::PrescheduleThink( void ) -{ - if ( m_bGlowTurningOn ) - { - m_bGlowTurningOn = false; - - if ( m_pLeftHandGlow != NULL ) - { - m_pLeftHandGlow->SetScale( 0.5f, 2.0f ); - m_pLeftHandGlow->SetBrightness( 200, 2.0f ); - } - - if ( m_pRightHandGlow != NULL ) - { - m_pRightHandGlow->SetScale( 0.5f, 2.0f ); - m_pRightHandGlow->SetBrightness( 200, 2.0f ); - } - } - - // See if we're able to heal now - if ( ShouldHealTarget() ) - { - SetCondition( COND_VORTIGAUNT_CAN_HEAL ); - } - else - { - ClearCondition( COND_VORTIGAUNT_CAN_HEAL ); - } -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CNPC_Vortigaunt::BuildScheduleTestBits( void ) -{ - BaseClass::BuildScheduleTestBits(); - - if ( IsCurSchedule( SCHED_IDLE_STAND ) || IsCurSchedule( SCHED_ALERT_STAND ) ) - { - SetCustomInterruptCondition( COND_VORTIGAUNT_CAN_HEAL ); - } - - if ( ( ConditionInterruptsCurSchedule( COND_GIVE_WAY ) || - IsCurSchedule(SCHED_HIDE_AND_RELOAD ) || - IsCurSchedule(SCHED_RELOAD ) || - IsCurSchedule(SCHED_STANDOFF ) || - IsCurSchedule(SCHED_TAKE_COVER_FROM_ENEMY ) || - IsCurSchedule(SCHED_COMBAT_FACE ) || - IsCurSchedule(SCHED_ALERT_FACE ) || - IsCurSchedule(SCHED_COMBAT_STAND ) || - IsCurSchedule(SCHED_ALERT_FACE_BESTSOUND) || - IsCurSchedule(SCHED_ALERT_STAND) ) ) - { - SetCustomInterruptCondition( COND_PLAYER_PUSHING ); - } -} - -//========================================================= -// ArmBeam - small beam from arm to nearby geometry -//========================================================= -void CNPC_Vortigaunt::ArmBeam( int side, int beamType ) -{ - trace_t tr; - float flDist = 1.0; - - if (m_iBeams >= VORTIGAUNT_MAX_BEAMS) - return; - - Vector forward, right, up; - AngleVectors( GetLocalAngles(), &forward, &right, &up ); - Vector vecSrc = GetLocalOrigin() + up * 36 + right * side * 16 + forward * 32; - - for (int i = 0; i < 3; i++) - { - Vector vecAim = forward * random->RandomFloat( -1, 1 ) + right * side * random->RandomFloat( 0, 1 ) + up * random->RandomFloat( -1, 1 ); - trace_t tr1; - AI_TraceLine ( vecSrc, vecSrc + vecAim * 512, MASK_SOLID, this, COLLISION_GROUP_NONE, &tr1); - if (flDist > tr1.fraction) - { - tr = tr1; - flDist = tr.fraction; - } - } - - // Couldn't find anything close enough - if ( flDist == 1.0 ) - return; - - UTIL_ImpactTrace( &tr, DMG_CLUB ); - - m_pBeam[m_iBeams] = CBeam::BeamCreate( "sprites/lgtning.vmt", 3.0 ); - if (!m_pBeam[m_iBeams]) - return; - - m_pBeam[m_iBeams]->PointEntInit( tr.endpos, this ); - m_pBeam[m_iBeams]->SetEndAttachment( side < 0 ? m_iLeftHandAttachment : m_iRightHandAttachment ); - - if (beamType == VORTIGAUNT_BEAM_HEAL) - { - m_pBeam[m_iBeams]->SetColor( 0, 0, 255 ); - } - else - { - m_pBeam[m_iBeams]->SetColor( 96, 128, 16 ); - } - m_pBeam[m_iBeams]->SetBrightness( 64 ); - m_pBeam[m_iBeams]->SetNoise( 12.5 ); - m_iBeams++; -} - -//------------------------------------------------------------------------------ -// Purpose : Short beam on had in grenade defend mode -// Input : -// Output : -//------------------------------------------------------------------------------ -void CNPC_Vortigaunt::DefendBeams( void ) -{ - Vector vBeamStart; - - // ----------- - // Left hand - // ----------- - int i; - GetAttachment( 1, vBeamStart ); - for (i=0;i<4;i++) - { - Vector vBeamPos = vBeamStart; - vBeamPos.x += random->RandomFloat(-8,8); - vBeamPos.y += random->RandomFloat(-8,8); - vBeamPos.z += random->RandomFloat(-8,8); - - CBeam *pBeam = CBeam::BeamCreate( "sprites/lgtning.vmt", 3.0 ); - pBeam->PointEntInit( vBeamPos, this ); - pBeam->SetEndAttachment( 1 ); - pBeam->SetBrightness( 255 ); - pBeam->SetNoise( 2 ); - pBeam->SetColor( 96, 128, 16 ); - pBeam->LiveForTime( 0.1 ); - } - - // ----------- - // Right hand - // ----------- - GetAttachment( 2, vBeamStart ); - for (i=4;iRandomFloat(-8,8); - vBeamPos.y += random->RandomFloat(-8,8); - vBeamPos.z += random->RandomFloat(-8,8); - - CBeam *pBeam = CBeam::BeamCreate( "sprites/lgtning.vmt", 3.0 ); - pBeam->PointEntInit( vBeamPos, this ); - pBeam->SetEndAttachment( 2 ); - pBeam->SetBrightness( 255 ); - pBeam->SetNoise( 2 ); - pBeam->SetColor( 96, 128, 16 ); - pBeam->LiveForTime( 0.1 ); - } -} - -//------------------------------------------------------------------------------ -// Purpose : Glow for when vortigaunt punches manhack -// Input : -// Output : -//------------------------------------------------------------------------------ -void CNPC_Vortigaunt::ClawBeam( CBaseEntity *pHurt, int nNoise, int iAttachment ) -{ - for (int i=0;i<2;i++) - { - CBeam* pBeam = CBeam::BeamCreate( "sprites/lgtning.vmt", 3.0 ); - pBeam->EntsInit( this, pHurt ); - pBeam->SetStartAttachment( iAttachment); - pBeam->SetBrightness( 255 ); - pBeam->SetNoise( nNoise ); - pBeam->SetColor( 96, 128, 16 ); - pBeam->LiveForTime( 0.2 ); - } - EmitSound( "NPC_Vortigaunt.ClawBeam" ); -} - -//------------------------------------------------------------------------------ -// Purpose : Put glowing sprites on hands -// Input : -// Output : -//------------------------------------------------------------------------------ -void CNPC_Vortigaunt::StartHandGlow( int beamType ) -{ - m_bGlowTurningOn = true; - m_fGlowAge = 0; - - if (beamType == VORTIGAUNT_BEAM_HEAL) - { - m_fGlowChangeTime = VORTIGAUNT_HEAL_GLOWGROW_TIME; - m_fGlowScale = 0.6f; - } - else - { - m_fGlowChangeTime = VORTIGAUNT_ZAP_GLOWGROW_TIME; - m_fGlowScale = 0.8f; - } - - if ( m_pLeftHandGlow == NULL ) - { - - if ( beamType == VORTIGAUNT_BEAM_HEAL ) - { - m_pLeftHandGlow = CSprite::SpriteCreate( "sprites/blueglow1.vmt", GetLocalOrigin(), FALSE ); - m_pLeftHandGlow->SetAttachment( this, 3 ); - } - else - { - m_pLeftHandGlow = CSprite::SpriteCreate( "sprites/greenglow1.vmt", GetLocalOrigin(), FALSE ); - m_pLeftHandGlow->SetAttachment( this, 3 ); - } - - m_pLeftHandGlow->SetTransparency( kRenderGlow, 255, 200, 200, 0, kRenderFxNoDissipation ); - m_pLeftHandGlow->SetBrightness( 0 ); - m_pLeftHandGlow->SetScale( 0 ); - } - - if ( beamType != VORTIGAUNT_BEAM_HEAL ) - { - if ( m_pRightHandGlow == NULL ) - { - m_pRightHandGlow = CSprite::SpriteCreate( "sprites/greenglow1.vmt", GetLocalOrigin(), FALSE ); - m_pRightHandGlow->SetAttachment( this, 4 ); - - m_pRightHandGlow->SetTransparency( kRenderGlow, 255, 200, 200, 0, kRenderFxNoDissipation ); - m_pRightHandGlow->SetBrightness( 0 ); - m_pRightHandGlow->SetScale( 0 ); - } - } -} - - -//------------------------------------------------------------------------------ -// Purpose : Fade glow from hands -// Input : -// Output : -//------------------------------------------------------------------------------ -void CNPC_Vortigaunt::EndHandGlow( void ) -{ - m_bGlowTurningOn = false; - m_fGlowChangeTime = VORTIGAUNT_GLOWFADE_TIME; - - if ( m_pLeftHandGlow ) - { - m_pLeftHandGlow->SetScale( 0, 0.5f ); - m_pLeftHandGlow->FadeAndDie( 0.5f ); - } - - if ( m_pRightHandGlow ) - { - m_pRightHandGlow->SetScale( 0, 0.5f ); - m_pRightHandGlow->FadeAndDie( 0.5f ); - } -} - -//----------------------------------------------------------------------------- -// Purpose: vortigaunt shoots at noisy body target (fixes problems in cover, etc) -// NOTE: His weapon doesn't have any error -// Input : -// Output : -//----------------------------------------------------------------------------- -Vector CNPC_Vortigaunt::GetShootEnemyDir( const Vector &shootOrigin, bool bNoisy ) -{ - CBaseEntity *pEnemy = GetEnemy(); - - if ( pEnemy ) - { - return (pEnemy->BodyTarget(shootOrigin, bNoisy)-shootOrigin); - } - else - { - Vector forward; - AngleVectors( GetLocalAngles(), &forward ); - return forward; - } -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -bool CNPC_Vortigaunt::IsValidEnemy( CBaseEntity *pEnemy ) -{ - if ( IsRoller( pEnemy ) ) - { - CAI_BaseNPC *pNPC = pEnemy->MyNPCPointer(); - if ( pNPC && pNPC->GetEnemy() != NULL ) - return true; - return false; - } - - return BaseClass::IsValidEnemy( pEnemy ); -} - -//========================================================= -// BeamGlow - brighten all beams -//========================================================= -void CNPC_Vortigaunt::BeamGlow( ) -{ - int b = m_iBeams * 32; - if (b > 255) - b = 255; - - for (int i = 0; i < m_iBeams; i++) - { - if (m_pBeam[i]->GetBrightness() != 255) - { - m_pBeam[i]->SetBrightness( b ); - } - } -} - - -//========================================================= -// WackBeam - regenerate dead colleagues -//========================================================= -void CNPC_Vortigaunt::WackBeam( int side, CBaseEntity *pEntity ) -{ - Vector vecDest; - - if (m_iBeams >= VORTIGAUNT_MAX_BEAMS) - return; - - if (pEntity == NULL) - return; - - m_pBeam[m_iBeams] = CBeam::BeamCreate( "sprites/lgtning.vmt", 3.0 ); - if (!m_pBeam[m_iBeams]) - return; - - m_pBeam[m_iBeams]->PointEntInit( pEntity->WorldSpaceCenter(), this ); - m_pBeam[m_iBeams]->SetEndAttachment( side < 0 ? m_iLeftHandAttachment : m_iRightHandAttachment ); - m_pBeam[m_iBeams]->SetColor( 180, 255, 96 ); - m_pBeam[m_iBeams]->SetBrightness( 255 ); - m_pBeam[m_iBeams]->SetNoise( 12 ); - m_iBeams++; -} - -//========================================================= -// ZapBeam - heavy damage directly forward -//========================================================= -void CNPC_Vortigaunt::ZapBeam( int side ) -{ - Vector vecSrc, vecAim; - trace_t tr; - CBaseEntity *pEntity; - - if (m_iBeams >= VORTIGAUNT_MAX_BEAMS) - return; - - Vector forward, right, up; - AngleVectors( GetLocalAngles(), &forward, &right, &up ); - - vecSrc = GetLocalOrigin() + up * 36; - vecAim = GetShootEnemyDir( vecSrc ); - float deflection = 0.01; - vecAim = vecAim + side * right * random->RandomFloat( 0, deflection ) + up * random->RandomFloat( -deflection, deflection ); - - if ( m_bExtractingBugbait == true ) - { - CRagdollProp *pTest = dynamic_cast< CRagdollProp *>( GetTarget() ); - - if ( pTest ) - { - ragdoll_t *m_ragdoll = pTest->GetRagdoll(); - - if ( m_ragdoll ) - { - Vector vOrigin; - m_ragdoll->list[0].pObject->GetPosition( &vOrigin, 0 ); - - AI_TraceLine ( vecSrc, vOrigin, MASK_SOLID, this, COLLISION_GROUP_NONE, &tr); - } - - CRagdollBoogie::Create( pTest, 200, gpGlobals->curtime, 1.0f ); - } - } - else - { - AI_TraceLine ( vecSrc, vecSrc + vecAim * 1024, MASK_SOLID, this, COLLISION_GROUP_NONE, &tr); - } - - m_pBeam[m_iBeams] = CBeam::BeamCreate( "sprites/lgtning.vmt", 5.0 ); - if (!m_pBeam[m_iBeams]) - return; - - m_pBeam[m_iBeams]->PointEntInit( tr.endpos, this ); - m_pBeam[m_iBeams]->SetEndAttachment( side < 0 ? m_iLeftHandAttachment : m_iRightHandAttachment ); - m_pBeam[m_iBeams]->SetColor( 180, 255, 96 ); - m_pBeam[m_iBeams]->SetBrightness( 255 ); - m_pBeam[m_iBeams]->SetNoise( 3 ); - m_iBeams++; - - pEntity = tr.m_pEnt; - if (pEntity != NULL && m_takedamage) - { - CTakeDamageInfo dmgInfo( this, this, sk_vortigaunt_dmg_zap.GetFloat(), DMG_SHOCK ); - dmgInfo.SetDamagePosition( tr.endpos ); - VectorNormalize( vecAim );// not a unit vec yet - // hit like a 5kg object flying 400 ft/s - dmgInfo.SetDamageForce( 5 * 400 * 12 * vecAim ); - pEntity->DispatchTraceAttack( dmgInfo, vecAim, &tr ); - } -} - -//------------------------------------------------------------------------------ -// Purpose : -// Input : -// Output : -//------------------------------------------------------------------------------ -void CNPC_Vortigaunt::HealBeam( int side ) -{ - if (m_iBeams >= VORTIGAUNT_MAX_BEAMS) - return; - - Vector forward, right, up; - AngleVectors( GetLocalAngles(), &forward, &right, &up ); - - trace_t tr; - Vector vecSrc = GetLocalOrigin() + up * 36; - - m_pBeam[m_iBeams] = CBeam::BeamCreate( "sprites/lgtning.vmt", 5.0 ); - if (!m_pBeam[m_iBeams]) - return; - - m_pBeam[m_iBeams]->EntsInit( GetTarget(), this ); - m_pBeam[m_iBeams]->SetEndAttachment( side < 0 ? m_iLeftHandAttachment : m_iRightHandAttachment ); - m_pBeam[m_iBeams]->SetColor( 0, 0, 255 ); - - m_pBeam[m_iBeams]->SetBrightness( 255 ); - m_pBeam[m_iBeams]->SetNoise( 6.5 ); - m_iBeams++; -} - -//------------------------------------------------------------------------------ -// Purpose : Clear Glow -// Input : -// Output : -//------------------------------------------------------------------------------ -void CNPC_Vortigaunt::ClearHandGlow( ) -{ - if (m_pLeftHandGlow) - { - UTIL_Remove( m_pLeftHandGlow ); - m_pLeftHandGlow = NULL; - } - if (m_pRightHandGlow) - { - UTIL_Remove( m_pRightHandGlow ); - m_pRightHandGlow = NULL; - } -} - -//========================================================= -// ClearBeams - remove all beams -//========================================================= -void CNPC_Vortigaunt::ClearBeams( ) -{ - for (int i = 0; i < VORTIGAUNT_MAX_BEAMS; i++) - { - if (m_pBeam[i]) - { - UTIL_Remove( m_pBeam[i] ); - m_pBeam[i] = NULL; - } - } - - m_iBeams = 0; - m_nSkin = 0; - - // Stop looping suit charge sound. - if (m_iSuitSound > 1) - { - StopSound( "NPC_Vortigaunt.SuitCharge" ); - m_iSuitSound = 0; - } - - - if ( m_bStopLoopingSounds ) - { - StopSound( "NPC_Vortigaunt.StartHealLoop" ); - StopSound( "NPC_Vortigaunt.StartShootLoop" ); - StopSound( "NPC_Vortigaunt.SuitCharge" ); - StopSound( "NPC_Vortigaunt.Shoot" ); - StopSound( "NPC_Vortigaunt.ZapPowerup" ); - m_bStopLoopingSounds = false; - } -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : &data - -//----------------------------------------------------------------------------- -void CNPC_Vortigaunt::InputEnableArmorRecharge( inputdata_t &data ) -{ - m_bArmorRechargeEnabled = true; -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : &data - -//----------------------------------------------------------------------------- -void CNPC_Vortigaunt::InputDisableArmorRecharge( inputdata_t &data ) -{ - m_bArmorRechargeEnabled = false; -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : &data - -//----------------------------------------------------------------------------- -void CNPC_Vortigaunt::InputChargeTarget( inputdata_t &data ) -{ - CBaseEntity *pTarget = gEntList.FindEntityByName( NULL, data.value.String(), NULL, data.pActivator, data.pCaller ); - - // Must be valid - if ( pTarget == NULL ) - { - DevMsg( 1, "Unable to charge from unknown entity: %s!\n", data.value.String() ); - return; - } - - int playerArmor = (pTarget->IsPlayer()) ? ((CBasePlayer *)pTarget)->ArmorValue() : 0; - - if ( playerArmor >= 100 || ( pTarget->GetFlags() & FL_NOTARGET ) ) - { - m_OnFinishedChargingTarget.FireOutput( this, this ); - return; - } - - m_hHealTarget = pTarget; - - m_iCurrentRechargeGoal = playerArmor + sk_vortigaunt_armor_charge.GetInt(); - if ( m_iCurrentRechargeGoal > 100 ) - m_iCurrentRechargeGoal = 100; - m_bForceArmorRecharge = true; - - SetCondition( COND_PROVOKED ); -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : &data - -//----------------------------------------------------------------------------- -void CNPC_Vortigaunt::InputExtractBugbait( inputdata_t &data ) -{ - CBaseEntity *pTarget = gEntList.FindEntityByName( NULL, data.value.String(), NULL, data.pActivator, data.pCaller ); - - // Must be valid - if ( pTarget == NULL ) - { - DevMsg( 1, "Unable to extract bugbait from unknown entity %s!\n", data.value.String() ); - return; - } - - // Keep this as our target - SetTarget( pTarget ); - - // Start to extract - m_bExtractingBugbait = true; - SetSchedule( SCHED_VORTIGAUNT_EXTRACT_BUGBAIT ); -} - - -//----------------------------------------------------------------------------- -// The vort overloads the CNPC_PlayerCompanion version because he uses different -// rules. The player companion rules looked too sensitive to muck with. -//----------------------------------------------------------------------------- -bool CNPC_Vortigaunt::OnObstructionPreSteer( AILocalMoveGoal_t *pMoveGoal, float distClear, AIMoveResult_t *pResult ) -{ - if ( pMoveGoal->directTrace.flTotalDist - pMoveGoal->directTrace.flDistObstructed < GetHullWidth() * 1.5 ) - { - CAI_BaseNPC *pBlocker = pMoveGoal->directTrace.pObstruction->MyNPCPointer(); - if ( pBlocker && pBlocker->IsPlayerAlly() && !pBlocker->IsMoving() && !pBlocker->IsInAScript() ) - { - if ( pBlocker->ConditionInterruptsCurSchedule( COND_GIVE_WAY ) || - pBlocker->ConditionInterruptsCurSchedule( COND_PLAYER_PUSHING ) ) - { - // HACKHACK - pBlocker->GetMotor()->SetIdealYawToTarget( WorldSpaceCenter() ); - pBlocker->SetSchedule( SCHED_MOVE_AWAY ); - } - - } - } - - return BaseClass::OnObstructionPreSteer( pMoveGoal, distClear, pResult ); -} - - -//------------------------------------------------------------------------------ -// -// Schedules -// -//------------------------------------------------------------------------------ - -AI_BEGIN_CUSTOM_NPC( npc_vortigaunt, CNPC_Vortigaunt ) - - DECLARE_USES_SCHEDULE_PROVIDER( CAI_LeadBehavior ) - - DECLARE_TASK(TASK_VORTIGAUNT_HEAL_WARMUP) - DECLARE_TASK(TASK_VORTIGAUNT_HEAL) - DECLARE_TASK(TASK_VORTIGAUNT_FACE_STOMP) - DECLARE_TASK(TASK_VORTIGAUNT_STOMP_ATTACK) - DECLARE_TASK(TASK_VORTIGAUNT_GRENADE_KILL) - DECLARE_TASK(TASK_VORTIGAUNT_ZAP_GRENADE_OWNER) - DECLARE_TASK(TASK_VORTIGAUNT_EXTRACT) - DECLARE_TASK(TASK_VORTIGAUNT_FIRE_EXTRACT_OUTPUT) - DECLARE_TASK(TASK_VORTIGAUNT_WAIT_FOR_PLAYER) - - DECLARE_TASK( TASK_VORTIGAUNT_EXTRACT_WARMUP ) - DECLARE_TASK( TASK_VORTIGAUNT_EXTRACT_COOLDOWN ) - DECLARE_TASK( TASK_VORTIGAUNT_GET_HEAL_TARGET ) - - DECLARE_ACTIVITY(ACT_VORTIGAUNT_AIM) - DECLARE_ACTIVITY(ACT_VORTIGAUNT_START_HEAL) - DECLARE_ACTIVITY(ACT_VORTIGAUNT_HEAL_LOOP) - DECLARE_ACTIVITY(ACT_VORTIGAUNT_END_HEAL) - DECLARE_ACTIVITY(ACT_VORTIGAUNT_TO_ACTION) - DECLARE_ACTIVITY(ACT_VORTIGAUNT_TO_IDLE) - DECLARE_ACTIVITY(ACT_VORTIGAUNT_STOMP) - DECLARE_ACTIVITY(ACT_VORTIGAUNT_DEFEND) - DECLARE_ACTIVITY(ACT_VORTIGAUNT_TO_DEFEND) - DECLARE_ACTIVITY(ACT_VORTIGAUNT_FROM_DEFEND) - - DECLARE_CONDITION(COND_VORTIGAUNT_CAN_HEAL) - - DECLARE_INTERACTION( g_interactionVortigauntStomp ) - DECLARE_INTERACTION( g_interactionVortigauntStompFail ) - DECLARE_INTERACTION( g_interactionVortigauntStompHit ) - DECLARE_INTERACTION( g_interactionVortigauntKick ) - DECLARE_INTERACTION( g_interactionVortigauntClaw ) - - DECLARE_ANIMEVENT( AE_VORTIGAUNT_CLAW_LEFT ) - DECLARE_ANIMEVENT( AE_VORTIGAUNT_CLAW_RIGHT ) - DECLARE_ANIMEVENT( AE_VORTIGAUNT_ZAP_POWERUP ) - DECLARE_ANIMEVENT( AE_VORTIGAUNT_ZAP_SHOOT ) - DECLARE_ANIMEVENT( AE_VORTIGAUNT_ZAP_DONE ) - DECLARE_ANIMEVENT( AE_VORTIGAUNT_HEAL_STARTGLOW ) - DECLARE_ANIMEVENT( AE_VORTIGAUNT_HEAL_STARTBEAMS ) - DECLARE_ANIMEVENT( AE_VORTIGAUNT_KICK ) - DECLARE_ANIMEVENT( AE_VORTIGAUNT_STOMP ) - DECLARE_ANIMEVENT( AE_VORTIGAUNT_HEAL_STARTSOUND ) - DECLARE_ANIMEVENT( AE_VORTIGAUNT_SWING_SOUND ) - DECLARE_ANIMEVENT( AE_VORTIGAUNT_SHOOT_SOUNDSTART ) - DECLARE_ANIMEVENT( AE_VORTIGAUNT_DEFEND_BEAMS ) - - //========================================================= - // > SCHED_VORTIGAUNT_RANGE_ATTACK - //========================================================= - DEFINE_SCHEDULE - ( - SCHED_VORTIGAUNT_RANGE_ATTACK, - - " Tasks" - " TASK_STOP_MOVING 0" - " TASK_FACE_IDEAL 0" - " TASK_RANGE_ATTACK1 0" - " TASK_WAIT 0.2" // Wait a sec before killing beams - "" - " Interrupts" - ); - - //========================================================= - // > SCHED_VORTIGAUNT_MELEE_ATTACK - //========================================================= - DEFINE_SCHEDULE - ( - SCHED_VORTIGAUNT_MELEE_ATTACK, - - " Tasks" - " TASK_STOP_MOVING 0" - " TASK_SET_ACTIVITY ACTIVITY:ACT_IDLE" - " TASK_FACE_ENEMY 0" - " TASK_MELEE_ATTACK1 0" - "" - " Interrupts" - " COND_ENEMY_DEAD" - " COND_HEAVY_DAMAGE" - " COND_ENEMY_OCCLUDED" - ); - - //========================================================= - // > SCHED_VORTIGAUNT_STOMP_ATTACK - //========================================================= - DEFINE_SCHEDULE - ( - SCHED_VORTIGAUNT_STOMP_ATTACK, - - " Tasks" - " TASK_STOP_MOVING 0" - " TASK_SET_ACTIVITY ACTIVITY:ACT_IDLE" - " TASK_VORTIGAUNT_FACE_STOMP 0" - " TASK_VORTIGAUNT_STOMP_ATTACK 0" - "" - " Interrupts" - // New_Enemy Don't interrupt, finish current attack first - " COND_ENEMY_DEAD" - " COND_HEAVY_DAMAGE" - " COND_ENEMY_OCCLUDED" - ); - - //========================================================= - // > SCHED_VORTIGAUNT_GRENADE_KILL - // - // Zap an incoming grenade (GetTarget()) - //========================================================= - DEFINE_SCHEDULE - ( - SCHED_VORTIGAUNT_GRENADE_KILL, - - " Tasks" - " TASK_VORTIGAUNT_GRENADE_KILL 0" - " TASK_WAIT 0.3" - " TASK_VORTIGAUNT_ZAP_GRENADE_OWNER 0" - "" - " Interrupts" - " COND_LIGHT_DAMAGE" - ); - //========================================================= - // > SCHED_VORTIGAUNT_HEAL - //========================================================= - DEFINE_SCHEDULE - ( - SCHED_VORTIGAUNT_HEAL, - - " Tasks" - " TASK_VORTIGAUNT_GET_HEAL_TARGET 0" - " TASK_STOP_MOVING 0" - " TASK_SET_FAIL_SCHEDULE SCHEDULE:SCHED_VORTIGAUNT_STAND" - " TASK_GET_PATH_TO_TARGET 0" - " TASK_MOVE_TO_TARGET_RANGE 128" // Move within 128 of target ent (client) - " TASK_STOP_MOVING 0" - " TASK_FACE_PLAYER 0" - " TASK_SPEAK_SENTENCE 0" // VORT_HEAL_SENTENCE - " TASK_VORTIGAUNT_HEAL_WARMUP 0" - " TASK_VORTIGAUNT_HEAL 0" - " TASK_SPEAK_SENTENCE 1" // VORT_DONE_HEAL_SENTENCE - "" - " Interrupts" - " COND_LIGHT_DAMAGE" - " COND_HEAVY_DAMAGE" - ); - - //========================================================= - // > SCHED_VORTIGAUNT_STAND - //========================================================= - DEFINE_SCHEDULE - ( - SCHED_VORTIGAUNT_STAND, - - " Tasks" - " TASK_STOP_MOVING 0" - " TASK_SET_ACTIVITY ACTIVITY:ACT_IDLE" - " TASK_WAIT 2" // repick IDLESTAND every two seconds." - " TASK_TALKER_HEADRESET 0" // reset head position" - "" - " Interrupts" - " COND_NEW_ENEMY" - " COND_LIGHT_DAMAGE" - " COND_HEAVY_DAMAGE" - " COND_SMELL" - " COND_PROVOKED" - " COND_HEAR_COMBAT" - " COND_HEAR_DANGER" - ); - - //========================================================= - // > SCHED_VORTIGAUNT_BARNACLE_HIT - //========================================================= - DEFINE_SCHEDULE - ( - SCHED_VORTIGAUNT_BARNACLE_HIT, - - " Tasks" - " TASK_STOP_MOVING 0" - " TASK_PLAY_SEQUENCE ACTIVITY:ACT_BARNACLE_HIT" - " TASK_SET_SCHEDULE SCHEDULE:SCHED_VORTIGAUNT_BARNACLE_PULL" - "" - " Interrupts" - ); - - //========================================================= - // > SCHED_VORTIGAUNT_BARNACLE_PULL - //========================================================= - DEFINE_SCHEDULE - ( - SCHED_VORTIGAUNT_BARNACLE_PULL, - - " Tasks" - " TASK_PLAY_SEQUENCE ACTIVITY:ACT_BARNACLE_PULL" - "" - " Interrupts" - ); - - //========================================================= - // > SCHED_VORTIGAUNT_BARNACLE_CHOMP - //========================================================= - DEFINE_SCHEDULE - ( - SCHED_VORTIGAUNT_BARNACLE_CHOMP, - - " Tasks" - " TASK_PLAY_SEQUENCE ACTIVITY:ACT_BARNACLE_CHOMP" - " TASK_SET_SCHEDULE SCHEDULE:SCHED_VORTIGAUNT_BARNACLE_CHEW" - "" - " Interrupts" - ); - - //========================================================= - // > SCHED_VORTIGAUNT_BARNACLE_CHEW - //========================================================= - DEFINE_SCHEDULE - ( - SCHED_VORTIGAUNT_BARNACLE_CHEW, - - " Tasks" - " TASK_PLAY_SEQUENCE ACTIVITY:ACT_BARNACLE_CHEW" - ) - - //========================================================= - // > SCHED_VORTIGAUNT_EXTRACT_BUGBAIT - //========================================================= - DEFINE_SCHEDULE - ( - SCHED_VORTIGAUNT_EXTRACT_BUGBAIT, - - " Tasks" - " TASK_SET_FAIL_SCHEDULE SCHEDULE:SCHED_VORTIGAUNT_STAND" - " TASK_STOP_MOVING 0" - " TASK_GET_PATH_TO_TARGET 0" - " TASK_MOVE_TO_TARGET_RANGE 128" // Move within 128 of target ent (client) - " TASK_STOP_MOVING 0" - " TASK_VORTIGAUNT_WAIT_FOR_PLAYER 0" - " TASK_SPEAK_SENTENCE 2" // Start extracting sentence - " TASK_WAIT_FOR_SPEAK_FINISH 1" - " TASK_FACE_TARGET 0" - " TASK_WAIT_FOR_SPEAK_FINISH 1" - " TASK_VORTIGAUNT_EXTRACT_WARMUP 0" - " TASK_VORTIGAUNT_EXTRACT 0" - " TASK_VORTIGAUNT_EXTRACT_COOLDOWN 0" - " TASK_VORTIGAUNT_FIRE_EXTRACT_OUTPUT 0" - " TASK_SPEAK_SENTENCE 3" // Finish extracting sentence - " TASK_WAIT_FOR_SPEAK_FINISH 1" - " TASK_WAIT 2" - "" - " Interrupts" - ) - -AI_END_CUSTOM_NPC() diff --git a/src/src/dlls/hl2_dll/npc_vortigaunt.h b/src/src/dlls/hl2_dll/npc_vortigaunt.h deleted file mode 100644 index 83cd16f..0000000 --- a/src/src/dlls/hl2_dll/npc_vortigaunt.h +++ /dev/null @@ -1,221 +0,0 @@ -//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// -// -// Purpose: This is the base version of the vortigaunt -// -// $NoKeywords: $ -//=============================================================================// - -#ifndef NPC_VORTIGAUNT_H -#define NPC_VORTIGAUNT_H -#ifdef _WIN32 -#pragma once -#endif - -#include "ai_basenpc.h" -#include "ai_behavior.h" -#include "ai_behavior_lead.h" -#include "ai_behavior_standoff.h" -#include "ai_behavior_assault.h" - -#define VORTIGAUNT_MAX_BEAMS 8 - -class CBeam; -class CSprite; - - -//========================================================= -// >> CNPC_Vortigaunt -//========================================================= -class CNPC_Vortigaunt : public CNPCSimpleTalker -{ - DECLARE_CLASS( CNPC_Vortigaunt, CNPCSimpleTalker ); - -public: - void Spawn( void ); - void Precache( void ); - float MaxYawSpeed( void ); - int GetSoundInterests( void ); - - void PrescheduleThink( void ); - void BuildScheduleTestBits( void ); - - int RangeAttack1Conditions( float flDot, float flDist ); - int MeleeAttack1Conditions( float flDot, float flDist ); - CBaseEntity* Kick( void ); - void Claw( int iAttachment ); - Vector GetShootEnemyDir( const Vector &shootOrigin, bool bNoisy = true ); - - virtual void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void AlertSound( void ); - Class_T Classify ( void ); - void HandleAnimEvent( animevent_t *pEvent ); - bool HandleInteraction(int interactionType, void *data, CBaseCombatCharacter* sourceEnt); - Activity NPC_TranslateActivity( Activity eNewActivity ); - - void UpdateOnRemove( void ); - void Event_Killed( const CTakeDamageInfo &info ); - - bool ShouldGoToIdleState( void ); - void RunTask( const Task_t *pTask ); - void StartTask( const Task_t *pTask ); - int ObjectCaps( void ) { return UsableNPCObjectCaps( BaseClass::ObjectCaps() ); } - int OnTakeDamage_Alive( const CTakeDamageInfo &info ); - - // Navigation/Locomotion - bool OnObstructionPreSteer( AILocalMoveGoal_t *pMoveGoal, float distClear, AIMoveResult_t *pResult ); - - void DeclineFollowing( void ); - bool CanBeUsedAsAFriend( void ); - bool IsPlayerAlly( void ) { return true; } - - // Override these to set behavior - virtual int TranslateSchedule( int scheduleType ); - virtual int SelectSchedule( void ); - bool IsValidEnemy( CBaseEntity *pEnemy ); - bool IsLeading( void ) { return ( GetRunningBehavior() == &m_LeadBehavior && m_LeadBehavior.HasGoal() ); } - - void DeathSound( const CTakeDamageInfo &info ); - void PainSound( const CTakeDamageInfo &info ); - - void TalkInit( void ); - - void TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr ); - void SpeakSentence( int sentType ); - - void VortigauntThink( void ); - bool CreateBehaviors( void ); - bool ShouldHealTarget( void ); - int SelectHealSchedule( void ); - - void InputEnableArmorRecharge( inputdata_t &data ); - void InputDisableArmorRecharge( inputdata_t &data ); - void InputExtractBugbait( inputdata_t &data ); - void InputChargeTarget( inputdata_t &data ); - -private: - //========================================================= - // Vortigaunt schedules - //========================================================= - enum - { - SCHED_VORTIGAUNT_STAND = BaseClass::NEXT_SCHEDULE, - SCHED_VORTIGAUNT_RANGE_ATTACK, - SCHED_VORTIGAUNT_MELEE_ATTACK, - SCHED_VORTIGAUNT_STOMP_ATTACK, - SCHED_VORTIGAUNT_HEAL, - SCHED_VORTIGAUNT_BARNACLE_HIT, - SCHED_VORTIGAUNT_BARNACLE_PULL, - SCHED_VORTIGAUNT_BARNACLE_CHOMP, - SCHED_VORTIGAUNT_BARNACLE_CHEW, - SCHED_VORTIGAUNT_GRENADE_KILL, - SCHED_VORTIGAUNT_EXTRACT_BUGBAIT, - }; - - - //========================================================= - // Vortigaunt Tasks - //========================================================= - enum - { - TASK_VORTIGAUNT_HEAL_WARMUP = BaseClass::NEXT_TASK, - TASK_VORTIGAUNT_HEAL, - TASK_VORTIGAUNT_FACE_STOMP, - TASK_VORTIGAUNT_STOMP_ATTACK, - TASK_VORTIGAUNT_GRENADE_KILL, - TASK_VORTIGAUNT_ZAP_GRENADE_OWNER, - TASK_VORTIGAUNT_EXTRACT_WARMUP, - TASK_VORTIGAUNT_EXTRACT, - TASK_VORTIGAUNT_EXTRACT_COOLDOWN, - TASK_VORTIGAUNT_FIRE_EXTRACT_OUTPUT, - TASK_VORTIGAUNT_WAIT_FOR_PLAYER, - TASK_VORTIGAUNT_GET_HEAL_TARGET, - }; - - //========================================================= - // Vortigaunt Conditions - //========================================================= - enum - { - COND_VORTIGAUNT_CAN_HEAL = BaseClass::NEXT_CONDITION, - }; - - float m_flNextNPCThink; - - // ------------ - // Beams - // ------------ - void ClearBeams( ); - void ArmBeam( int side , int beamType); - void WackBeam( int side, CBaseEntity *pEntity ); - void ZapBeam( int side ); - void BeamGlow( void ); - void ClawBeam( CBaseEntity* pHurt, int nNoise, int iAttachment ); - void DefendBeams( void ); - CHandle m_pBeam[VORTIGAUNT_MAX_BEAMS]; - int m_iBeams; - int m_nLightningSprite; - - // --------------- - // Glow - // ---------------- - void ClearHandGlow( ); - float m_fGlowAge; - float m_fGlowScale; - float m_fGlowChangeTime; - bool m_bGlowTurningOn; - int m_nCurGlowIndex; - - CHandle m_pLeftHandGlow; - CHandle m_pRightHandGlow; - - void StartHandGlow( int beamType ); - void EndHandGlow( void ); - - // ---------------- - // Healing - // ---------------- - float m_flNextHealTime; // Next time allowed to heal player - int m_nCurrentHealAmt; // How much healed this session - int m_nLastArmorAmt; // Player armor at end of last heal - int m_iSuitSound; // 0 = off, 1 = startup, 2 = going - float m_flSuitSoundTime; - EHANDLE m_hHealTarget; // The person that I'm going to heal. - - void HealBeam( int side ); - bool IsHealPositionValid( void ); - bool CheckHealPosition( void ); - - // ----------------- - // Stomping - // ----------------- - bool IsStompable(CBaseEntity *pEntity); - - float m_painTime; - float m_nextLineFireTime; - bool m_bInBarnacleMouth; - bool m_bArmorRechargeEnabled; - bool m_bForceArmorRecharge; - int m_iCurrentRechargeGoal; - - EHANDLE m_hVictim; // Who I'm actively attacking (as opposed to enemy that I'm not necessarily attacking) - - bool m_bExtractingBugbait; - - COutputEvent m_OnFinishedExtractingBugbait; - COutputEvent m_OnFinishedChargingTarget; - COutputEvent m_OnPlayerUse; - - CAI_AssaultBehavior m_AssaultBehavior; - CAI_LeadBehavior m_LeadBehavior; - - //Adrian: Let's do it the right way! - int m_iLeftHandAttachment; - int m_iRightHandAttachment; - bool m_bStopLoopingSounds; - -public: - DECLARE_DATADESC(); - DEFINE_CUSTOM_AI; -}; - -#endif // NPC_VORTIGAUNT_H diff --git a/src/src/dlls/hl2_dll/npc_vortigaunt_episodic.cpp b/src/src/dlls/hl2_dll/npc_vortigaunt_episodic.cpp deleted file mode 100644 index 39d94a5..0000000 --- a/src/src/dlls/hl2_dll/npc_vortigaunt_episodic.cpp +++ /dev/null @@ -1,2138 +0,0 @@ -//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ==== -// -// Purpose: Vortigaunt - now much friendlier! -// -//============================================================================= - -#include "cbase.h" -#include "beam_shared.h" -#include "globalstate.h" -#include "npcevent.h" -#include "Sprite.h" -#include "IEffects.h" -#include "te_effect_dispatch.h" -#include "SoundEmitterSystem/isoundemittersystembase.h" -#include "physics_prop_ragdoll.h" -#include "RagdollBoogie.h" -#include "ai_squadslot.h" - -#include "npc_vortigaunt_episodic.h" - -// memdbgon must be the last include file in a .cpp file!!! -#include "tier0/memdbgon.h" - -#define VORTIGAUNT_LIMP_HEALTH 20 -#define VORTIGAUNT_SENTENCE_VOLUME (float)0.35 // volume of vortigaunt sentences -#define VORTIGAUNT_VOL 0.35 // volume of vortigaunt sounds -#define VORTIGAUNT_ATTN ATTN_NORM // attenutation of vortigaunt sentences -#define VORTIGAUNT_HEAL_RECHARGE 15.0 // How long to rest between heals -#define VORTIGAUNT_ZAP_GLOWGROW_TIME 0.5 // How long does glow last -#define VORTIGAUNT_HEAL_GLOWGROW_TIME 1.4 // How long does glow last -#define VORTIGAUNT_GLOWFADE_TIME 0.5 // How long does it fade -#define VORTIGAUNT_BEAM_HURT 0 -#define VORTIGAUNT_BEAM_HEAL 1 - -#define PLAYER_CRITICAL_HEALTH_PERC 0.3f - -static const char *VORTIGAUNT_LEFT_CLAW = "leftclaw"; -static const char *VORTIGAUNT_RIGHT_CLAW = "rightclaw"; - -static const char *VORT_CURE = "VORT_CURE"; -static const char *VORT_CURESTOP = "VORT_CURESTOP"; -static const char *VORT_CURE_INTERRUPT = "VORT_CURE_INTERRUPT"; -static const char *VORT_ATTACK = "VORT_ATTACK"; -static const char *VORT_MAD = "VORT_MAD"; -static const char *VORT_SHOT = "VORT_SHOT"; -static const char *VORT_PAIN = "VORT_PAIN"; -static const char *VORT_DIE = "VORT_DIE"; -static const char *VORT_KILL = "VORT_KILL"; -static const char *VORT_LINE_FIRE = "VORT_LINE_FIRE"; -static const char *VORT_POK = "VORT_POK"; -static const char *VORT_EXTRACT_START = "VORT_EXTRACT_START"; -static const char *VORT_EXTRACT_FINISH = "VORT_EXTRACT_FINISH"; - -// Target must be within this range to heal -#define HEAL_RANGE (15*12) //ft -#define HEAL_SEARCH_RANGE (40*12) //ft - -ConVar sk_vortigaunt_health( "sk_vortigaunt_health","0"); -ConVar sk_vortigaunt_armor_charge( "sk_vortigaunt_armor_charge","30"); -ConVar sk_vortigaunt_dmg_claw( "sk_vortigaunt_dmg_claw","0"); -ConVar sk_vortigaunt_dmg_rake( "sk_vortigaunt_dmg_rake","0"); -ConVar sk_vortigaunt_dmg_zap( "sk_vortigaunt_dmg_zap","0"); - -//----------------------------------------------------------------------------- -// Interactions -//----------------------------------------------------------------------------- -int g_interactionVortigauntStomp = 0; -int g_interactionVortigauntStompFail = 0; -int g_interactionVortigauntStompHit = 0; -int g_interactionVortigauntKick = 0; -int g_interactionVortigauntClaw = 0; - -//========================================================= -// Vortigaunt activities -//========================================================= -int ACT_VORTIGAUNT_AIM; -int ACT_VORTIGAUNT_START_HEAL; -int ACT_VORTIGAUNT_HEAL_LOOP; -int ACT_VORTIGAUNT_END_HEAL; -int ACT_VORTIGAUNT_TO_ACTION; -int ACT_VORTIGAUNT_TO_IDLE; -int ACT_VORTIGAUNT_HEAL; // Heal gesture - -//========================================================= -// Monster's Anim Events Go Here -//========================================================= -int AE_VORTIGAUNT_CLAW_LEFT; -int AE_VORTIGAUNT_CLAW_RIGHT; -int AE_VORTIGAUNT_ZAP_POWERUP; -int AE_VORTIGAUNT_ZAP_SHOOT; -int AE_VORTIGAUNT_ZAP_DONE; -int AE_VORTIGAUNT_HEAL_STARTGLOW; -int AE_VORTIGAUNT_HEAL_STARTBEAMS; -int AE_VORTIGAUNT_HEAL_STARTSOUND; -int AE_VORTIGAUNT_SWING_SOUND; -int AE_VORTIGAUNT_SHOOT_SOUNDSTART; -int AE_VORTIGAUNT_HEAL_PAUSE; - -//----------------------------------------------------------------------------- -// Squad slots -//----------------------------------------------------------------------------- -enum SquadSlot_T -{ - SQUAD_SLOT_HEAL_PLAYER = LAST_SHARED_SQUADSLOT, -}; - -//--------------------------------------------------------- -// Save/Restore -//--------------------------------------------------------- -BEGIN_DATADESC( CNPC_Vortigaunt ) - - DEFINE_FIELD( m_flHealHinderedTime, FIELD_FLOAT ), - DEFINE_FIELD( m_bHealBeamActive, FIELD_BOOLEAN ), - DEFINE_ARRAY( m_pBeam, FIELD_EHANDLE, VORTIGAUNT_MAX_BEAMS ), - DEFINE_FIELD( m_iBeams, FIELD_INTEGER), - DEFINE_FIELD( m_nLightningSprite, FIELD_INTEGER), - DEFINE_FIELD( m_fGlowAge, FIELD_FLOAT), - DEFINE_FIELD( m_fGlowScale, FIELD_FLOAT), - DEFINE_FIELD( m_fGlowChangeTime, FIELD_FLOAT), - DEFINE_FIELD( m_bGlowTurningOn, FIELD_BOOLEAN), - DEFINE_FIELD( m_nCurGlowIndex, FIELD_INTEGER), - DEFINE_FIELD( m_pLeftHandGlow, FIELD_EHANDLE), - DEFINE_FIELD( m_pRightHandGlow, FIELD_EHANDLE), - DEFINE_FIELD( m_flNextHealTime, FIELD_TIME), - DEFINE_FIELD( m_nCurrentHealAmt, FIELD_INTEGER), - DEFINE_FIELD( m_nLastArmorAmt, FIELD_INTEGER), - DEFINE_FIELD( m_iSuitSound, FIELD_INTEGER), - DEFINE_FIELD( m_flSuitSoundTime, FIELD_TIME), - DEFINE_FIELD( m_flPainTime, FIELD_TIME), - DEFINE_FIELD( m_nextLineFireTime, FIELD_TIME), - DEFINE_KEYFIELD( m_bArmorRechargeEnabled,FIELD_BOOLEAN, "ArmorRechargeEnabled" ), - DEFINE_FIELD( m_bForceArmorRecharge, FIELD_BOOLEAN), - DEFINE_FIELD( m_iCurrentRechargeGoal, FIELD_INTEGER ), - DEFINE_FIELD( m_bExtractingBugbait, FIELD_BOOLEAN), - DEFINE_FIELD( m_iLeftHandAttachment, FIELD_INTEGER ), - DEFINE_FIELD( m_iRightHandAttachment, FIELD_INTEGER ), - DEFINE_FIELD( m_hHealTarget, FIELD_EHANDLE ), - DEFINE_KEYFIELD( m_bRegenerateHealth, FIELD_BOOLEAN, "HealthRegenerateEnabled" ), - // m_AssaultBehavior (auto saved by AI) - // m_LeadBehavior - // DEFINE_FIELD( m_bStopLoopingSounds, FIELD_BOOLEAN ), - - // Function Pointers - DEFINE_USEFUNC( Use ), - - DEFINE_INPUTFUNC( FIELD_VOID, "EnableArmorRecharge", InputEnableArmorRecharge ), - DEFINE_INPUTFUNC( FIELD_VOID, "DisableArmorRecharge", InputDisableArmorRecharge ), - DEFINE_INPUTFUNC( FIELD_STRING, "ChargeTarget", InputChargeTarget ), - DEFINE_INPUTFUNC( FIELD_STRING, "ExtractBugbait", InputExtractBugbait ), - DEFINE_INPUTFUNC( FIELD_VOID, "EnableHealthRegeneration", InputEnableHealthRegeneration ), - DEFINE_INPUTFUNC( FIELD_VOID, "DisableHealthRegeneration",InputDisableHealthRegeneration ), - - // Outputs - DEFINE_OUTPUT(m_OnFinishedExtractingBugbait, "OnFinishedExtractingBugbait"), - DEFINE_OUTPUT(m_OnFinishedChargingTarget, "OnFinishedChargingTarget"), - DEFINE_OUTPUT(m_OnPlayerUse, "OnPlayerUse" ), - -END_DATADESC() - -LINK_ENTITY_TO_CLASS( npc_vortigaunt, CNPC_Vortigaunt ); - -// for special behavior with rollermines -static bool IsRoller( CBaseEntity *pRoller ) -{ - return FClassnameIs( pRoller, "npc_rollermine" ); -} - -//----------------------------------------------------------------------------- -// Purpose: Determines whether or not the player is below a certain percentage -// of their maximum health -// Input : flPerc - Percentage to test against -// Output : Returns true if less than supplied parameter -//----------------------------------------------------------------------------- -bool CNPC_Vortigaunt::PlayerBelowHealthPercentage( float flPerc ) -{ - CBasePlayer *pPlayer = AI_GetSinglePlayer(); - if ( pPlayer == NULL ) - return false; - - if ( pPlayer->GetMaxHealth() == 0.0f ) - return false; - - float flHealthPerc = (float) pPlayer->GetHealth() / (float) pPlayer->GetMaxHealth(); - return ( flHealthPerc <= flPerc ); -} - -#define VORT_START_EXTRACT_SENTENCE 500 -#define VORT_FINISH_EXTRACT_SENTENCE 501 - -//------------------------------------------------------------------------------ -// Purpose: Make the vort speak a line -//------------------------------------------------------------------------------ -void CNPC_Vortigaunt::SpeakSentence( int sentenceType ) -{ - if (sentenceType == VORT_START_EXTRACT_SENTENCE) - { - Speak( VORT_EXTRACT_START ); - } - else if (sentenceType == VORT_FINISH_EXTRACT_SENTENCE) - { - Speak( VORT_EXTRACT_FINISH ); - } -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CNPC_Vortigaunt::StartTask( const Task_t *pTask ) -{ - switch ( pTask->iTask) - { - - // Sets our target to the entity that we cached earlier. - case TASK_VORTIGAUNT_GET_HEAL_TARGET: - { - if ( m_hHealTarget == NULL ) - { - TaskFail( FAIL_NO_TARGET ); - } - else - { - SetTarget( m_hHealTarget ); - TaskComplete(); - } - - break; - } - - case TASK_VORTIGAUNT_EXTRACT_WARMUP: - { - ResetIdealActivity( (Activity) ACT_VORTIGAUNT_TO_ACTION ); - break; - } - - case TASK_VORTIGAUNT_EXTRACT: - { - SetActivity( (Activity) ACT_RANGE_ATTACK1 ); - break; - } - - case TASK_VORTIGAUNT_EXTRACT_COOLDOWN: - { - ResetIdealActivity( (Activity)ACT_VORTIGAUNT_TO_IDLE ); - break; - } - - case TASK_VORTIGAUNT_FIRE_EXTRACT_OUTPUT: - { - // Cheat, and fire both outputs - m_OnFinishedExtractingBugbait.FireOutput( this, this ); - TaskComplete(); - break; - } - - case TASK_VORTIGAUNT_HEAL: - { - AddGesture( (Activity) ACT_VORTIGAUNT_HEAL ); - m_eHealState = HEAL_STATE_WARMUP; - TaskComplete(); - break; - } - - case TASK_VORTIGAUNT_WAIT_FOR_PLAYER: - { - // Wait for the player to get near (before starting the bugbait sequence) - break; - } - - default: - { - BaseClass::StartTask( pTask ); - break; - } - } -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CNPC_Vortigaunt::RunTask( const Task_t *pTask ) -{ - switch ( pTask->iTask ) - { - case TASK_RANGE_ATTACK1: - { - // If our enemy is gone, dead or out of sight, pick a new one - if ( HasCondition( COND_ENEMY_OCCLUDED ) || - GetEnemy() == NULL || - GetEnemy()->IsAlive() == false ) - { - CBaseEntity *pNewEnemy = BestEnemy(); - if ( pNewEnemy != NULL ) - { - SetEnemy( pNewEnemy ); - SetState( NPC_STATE_COMBAT ); - } - } - - BaseClass::RunTask( pTask ); - break; - } - - case TASK_VORTIGAUNT_EXTRACT_WARMUP: - { - if ( IsActivityFinished() ) - { - TaskComplete(); - } - break; - } - - case TASK_VORTIGAUNT_EXTRACT: - { - if ( IsActivityFinished() ) - { - TaskComplete(); - } - break; - } - - case TASK_VORTIGAUNT_EXTRACT_COOLDOWN: - { - if ( IsActivityFinished() ) - { - m_bExtractingBugbait = false; - TaskComplete(); - } - break; - } - - case TASK_VORTIGAUNT_WAIT_FOR_PLAYER: - { - // Wait for the player to get near (before starting the bugbait sequence) - CBasePlayer *pPlayer = AI_GetSinglePlayer(); - if ( pPlayer != NULL ) - { - GetMotor()->SetIdealYawToTargetAndUpdate( pPlayer->GetAbsOrigin(), AI_KEEP_YAW_SPEED ); - SetTurnActivity(); - if ( GetMotor()->DeltaIdealYaw() < 10 ) - { - // Wait for the player to get close enough - if ( UTIL_DistApprox( GetAbsOrigin(), pPlayer->GetAbsOrigin() ) < 384 ) - { - TaskComplete(); - } - } - } - else - { - TaskFail( FAIL_NO_PLAYER ); - } - break; - } - - default: - { - BaseClass::RunTask( pTask ); - break; - } - } -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CNPC_Vortigaunt::AlertSound( void ) -{ - if ( GetEnemy() != NULL && IsOkToCombatSpeak() ) - { - Speak( VORT_ATTACK ); - } -} - -//----------------------------------------------------------------------------- -// Purpose: Allows each sequence to have a different turn rate associated with it. -// Output : float CNPC_Vortigaunt::MaxYawSpeed -//----------------------------------------------------------------------------- -float CNPC_Vortigaunt::MaxYawSpeed ( void ) -{ - switch ( GetActivity() ) - { - case ACT_IDLE: - return 35; - break; - case ACT_WALK: - return 35; - break; - case ACT_RUN: - return 45; - break; - default: - return 35; - break; - } -} - -//------------------------------------------------------------------------------ -// Purpose : For innate range attack -//------------------------------------------------------------------------------ -int CNPC_Vortigaunt::RangeAttack1Conditions( float flDot, float flDist ) -{ - if ( GetEnemy() == NULL ) - return( COND_NONE ); - - if ( gpGlobals->curtime < m_flNextAttack ) - return( COND_NONE ); - - // dvs: Allow up-close range attacks for episodic as the vort's melee - // attack is rather ineffective. -#ifndef HL2_EPISODIC - if ( flDist <= 70 ) - { - return( COND_TOO_CLOSE_TO_ATTACK ); - } - else -#endif // HL2_EPISODIC - if ( flDist > 1500 * 12 ) // 1500ft max - { - return( COND_TOO_FAR_TO_ATTACK ); - } - else if ( flDot < 0.65 ) - { - return( COND_NOT_FACING_ATTACK ); - } - - return( COND_CAN_RANGE_ATTACK1 ); -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CNPC_Vortigaunt::HandleAnimEvent( animevent_t *pEvent ) -{ - // Start of our heal loop - if ( pEvent->event == AE_VORTIGAUNT_HEAL_PAUSE ) - { - StartHealing(); - return; - } - - if ( pEvent->event == AE_VORTIGAUNT_ZAP_POWERUP ) - { - // speed up attack when on hard - if ( g_iSkillLevel == SKILL_HARD ) - m_flPlaybackRate = 1.5; - - ArmBeam( -1 ,VORTIGAUNT_BEAM_HURT ); - ArmBeam( 1 ,VORTIGAUNT_BEAM_HURT ); - BeamGlow(); - - // Make hands glow if not already glowing - if ( m_fGlowAge == 0 ) - { - StartHandGlow( VORTIGAUNT_BEAM_HURT ); - } - - CPASAttenuationFilter filter( this ); - - CSoundParameters params; - if ( GetParametersForSound( "NPC_Vortigaunt.ZapPowerup", params, NULL ) ) - { - EmitSound_t ep( params ); - ep.m_nPitch = 100 + m_iBeams * 10; - - EmitSound( filter, entindex(), ep ); - - m_bStopLoopingSounds = true; - } - return; - } - - if ( pEvent->event == AE_VORTIGAUNT_ZAP_SHOOT ) - { - ClearBeams(); - - ClearMultiDamage(); - - ZapBeam( -1 ); - ZapBeam( 1 ); - EndHandGlow(); - - EmitSound( "NPC_Vortigaunt.Shoot" ); - m_bStopLoopingSounds = true; - ApplyMultiDamage(); - - if ( m_bExtractingBugbait == true ) - { - // Spawn bugbait! - CBaseCombatWeapon *pWeapon = Weapon_Create( "weapon_bugbait" ); - if ( pWeapon ) - { - // Starting above the body, spawn closer and closer to the vort until it's clear - Vector vecSpawnOrigin = GetTarget()->WorldSpaceCenter() + Vector(0, 0, 32); - int iNumAttempts = 4; - Vector vecToVort = (WorldSpaceCenter() - vecSpawnOrigin); - float flDistance = VectorNormalize( vecToVort ) / (iNumAttempts-1); - int i = 0; - for (; i < iNumAttempts; i++ ) - { - trace_t tr; - CTraceFilterSkipTwoEntities traceFilter( GetTarget(), this, COLLISION_GROUP_NONE ); - AI_TraceLine( vecSpawnOrigin, vecSpawnOrigin, MASK_SHOT, &traceFilter, &tr ); - - if ( tr.fraction == 1.0 && !tr.m_pEnt ) - { - // Make sure it can fit there - AI_TraceHull( vecSpawnOrigin, vecSpawnOrigin, -Vector(16,16,16), Vector(16,16,48), MASK_SHOT, &traceFilter, &tr ); - if ( tr.fraction == 1.0 && !tr.m_pEnt ) - break; - } - - //NDebugOverlay::Box( vecSpawnOrigin, pWeapon->WorldAlignMins(), pWeapon->WorldAlignMins(), 255,0,0, 64, 100 ); - - // Move towards the vort - vecSpawnOrigin = vecSpawnOrigin + (vecToVort * flDistance); - } - - // HACK: If we've still failed, just spawn it on the player - if ( i == iNumAttempts ) - { - CBasePlayer *pPlayer = AI_GetSinglePlayer(); - if ( pPlayer ) - { - vecSpawnOrigin = pPlayer->WorldSpaceCenter(); - } - } - - //NDebugOverlay::Box( vecSpawnOrigin, -Vector(20,20,20), Vector(20,20,20), 0,255,0, 64, 100 ); - - pWeapon->SetAbsOrigin( vecSpawnOrigin ); - pWeapon->Drop( Vector(0,0,1) ); - } - - CEffectData data; - - data.m_vOrigin = GetTarget()->WorldSpaceCenter(); - data.m_vNormal = WorldSpaceCenter() - GetTarget()->WorldSpaceCenter(); - VectorNormalize( data.m_vNormal ); - - data.m_flScale = 4; - - DispatchEffect( "AntlionGib", data ); - } - - m_flNextAttack = gpGlobals->curtime + random->RandomFloat( 1.0, 2.0 ); - return; - } - - if ( pEvent->event == AE_VORTIGAUNT_ZAP_DONE ) - { - ClearBeams(); - return; - } - - if ( pEvent->event == AE_VORTIGAUNT_HEAL_STARTGLOW ) - { - // Make hands glow - StartHandGlow( VORTIGAUNT_BEAM_HEAL ); - m_eHealState = HEAL_STATE_WARMUP; - return; - } - - if ( pEvent->event == AE_VORTIGAUNT_HEAL_STARTBEAMS ) - { - HealBeam(1); - m_eHealState = HEAL_STATE_HEALING; - return; - } - - if ( pEvent->event == AE_VORTIGAUNT_HEAL_STARTSOUND ) - { - CPASAttenuationFilter filter( this ); - - CSoundParameters params; - if ( GetParametersForSound( "NPC_Vortigaunt.StartHealLoop", params, NULL ) ) - { - EmitSound_t ep( params ); - ep.m_nPitch = 100 + m_iBeams * 10; - - EmitSound( filter, entindex(), ep ); - m_bStopLoopingSounds = true; - } - return; - } - - if ( pEvent->event == AE_VORTIGAUNT_SWING_SOUND ) - { - EmitSound( "NPC_Vortigaunt.Swing" ); - return; - } - - if ( pEvent->event == AE_VORTIGAUNT_SHOOT_SOUNDSTART ) - { - CPASAttenuationFilter filter( this ); - CSoundParameters params; - if ( GetParametersForSound( "NPC_Vortigaunt.StartShootLoop", params, NULL ) ) - { - EmitSound_t ep( params ); - ep.m_nPitch = 100 + m_iBeams * 10; - - EmitSound( filter, entindex(), ep ); - m_bStopLoopingSounds = true; - } - return; - } - - if ( pEvent->event == AE_NPC_LEFTFOOT ) - { - EmitSound( "NPC_Vortigaunt.FootstepLeft", pEvent->eventtime ); - return; - } - - if ( pEvent->event == AE_NPC_RIGHTFOOT ) - { - EmitSound( "NPC_Vortigaunt.FootstepRight", pEvent->eventtime ); - return; - } - - BaseClass::HandleAnimEvent( pEvent ); -} - -//------------------------------------------------------------------------------ -// Purpose : Translate some activites for the Vortigaunt -//------------------------------------------------------------------------------ -Activity CNPC_Vortigaunt::NPC_TranslateActivity( Activity eNewActivity ) -{ - // NOTE: This is a stand-in until the readiness system can handle non-weapon holding NPC's - if ( eNewActivity == ACT_IDLE ) - { - // More than relaxed means we're stimulated - if ( GetReadinessLevel() >= AIRL_STIMULATED ) - return ACT_IDLE_STIMULATED; - } - - return BaseClass::NPC_TranslateActivity( eNewActivity ); -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CNPC_Vortigaunt::UpdateOnRemove( void) -{ - ClearBeams(); - ClearHandGlow(); - - // Chain at end to mimic destructor unwind order - BaseClass::UpdateOnRemove(); -} - -//------------------------------------------------------------------------------ -// Purpose : -//------------------------------------------------------------------------------ -void CNPC_Vortigaunt::Event_Killed( const CTakeDamageInfo &info ) -{ - ClearBeams(); - ClearHandGlow(); - - BaseClass::Event_Killed( info ); -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CNPC_Vortigaunt::Spawn( void ) -{ - // Allow multiple models (for slaves), but default to vortigaunt.mdl - char *szModel = (char *)STRING( GetModelName() ); - if (!szModel || !*szModel) - { - szModel = "models/vortigaunt.mdl"; - SetModelName( AllocPooledString(szModel) ); - } - - Precache(); - SetModel( szModel ); - - SetHullType( HULL_WIDE_HUMAN ); - SetHullSizeNormal(); - - SetSolid( SOLID_BBOX ); - AddSolidFlags( FSOLID_NOT_STANDABLE ); - SetMoveType( MOVETYPE_STEP ); - m_bloodColor = BLOOD_COLOR_GREEN; - m_iHealth = sk_vortigaunt_health.GetFloat(); - SetViewOffset( Vector ( 0, 0, 64 ) );// position of the eyes relative to monster's origin. - m_flFieldOfView = VIEW_FIELD_WIDE; // NOTE: we need a wide field of view so npc will notice player and say hello - m_NPCState = NPC_STATE_NONE; - - CapabilitiesClear(); - CapabilitiesAdd( bits_CAP_ANIMATEDFACE | bits_CAP_TURN_HEAD | bits_CAP_DOORS_GROUP ); - CapabilitiesAdd( bits_CAP_INNATE_RANGE_ATTACK1 | bits_CAP_SQUAD ); - CapabilitiesAdd( bits_CAP_NO_HIT_PLAYER | bits_CAP_NO_HIT_SQUADMATES | bits_CAP_FRIENDLY_DMG_IMMUNE ); - CapabilitiesAdd( bits_CAP_MOVE_GROUND | bits_CAP_MOVE_SHOOT ); - - m_flNextHealTime = 0; // Next time allowed to heal player - m_flEyeIntegRate = 0.6; // Got a big eyeball so turn it slower - m_bForceArmorRecharge = false; - m_flHealHinderedTime = 0.0f; - - m_nCurGlowIndex = 0; - m_pLeftHandGlow = NULL; - m_pRightHandGlow = NULL; - - m_bStopLoopingSounds = false; - - m_iLeftHandAttachment = LookupAttachment( VORTIGAUNT_LEFT_CLAW ); - m_iRightHandAttachment = LookupAttachment( VORTIGAUNT_RIGHT_CLAW ); - - NPCInit(); - - SetUse( &CNPC_Vortigaunt::Use ); - - // Hold-over until spawn collisions are worked out - m_bReadinessCapable = IsReadinessCapable(); - SetReadinessValue( 0.0f ); - SetReadinessSensitivity( random->RandomFloat( 0.7, 1.3 ) ); - - // Default to off - m_bHealBeamActive = false; -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CNPC_Vortigaunt::Precache() -{ - PrecacheModel( STRING( GetModelName() ) ); - - m_nLightningSprite = PrecacheModel("sprites/lgtning.vmt"); - - PrecacheModel("sprites/physbeam.vmt"); - PrecacheModel("sprites/physring1.vmt"); - PrecacheModel("sprites/vortring1.vmt"); - - PrecacheScriptSound( "NPC_Vortigaunt.SuitOn" ); - PrecacheScriptSound( "NPC_Vortigaunt.SuitCharge" ); - PrecacheScriptSound( "NPC_Vortigaunt.ZapPowerup" ); - PrecacheScriptSound( "NPC_Vortigaunt.Shoot" ); - PrecacheScriptSound( "NPC_Vortigaunt.StartHealLoop" ); - PrecacheScriptSound( "NPC_Vortigaunt.Swing" ); - PrecacheScriptSound( "NPC_Vortigaunt.StartShootLoop" ); - PrecacheScriptSound( "NPC_Vortigaunt.FootstepLeft" ); - PrecacheScriptSound( "NPC_Vortigaunt.FootstepRight" ); - - BaseClass::Precache(); -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CNPC_Vortigaunt::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - m_OnPlayerUse.FireOutput( pActivator, pCaller ); - - if ( !IsInAScript() && m_NPCState != NPC_STATE_SCRIPT ) - { - if ( ShouldHealTarget( pActivator, true ) ) - { - // We should heal the player. Don't say idle stuff. - } - else - { - // First, try to speak the +USE concept - if ( IsOkToSpeakInResponseToPlayer() ) - { - if ( !Speak( TLK_USE ) ) - { - // If we haven't said hi, say that first - if ( !SpokeConcept( TLK_HELLO ) ) - { - Speak( TLK_HELLO ); - } - else - { - Speak( TLK_IDLE ); - } - } - else - { - // Don't say hi after you've said your +USE speech - SetSpokeConcept( TLK_HELLO, NULL ); - } - } - } - } -} - -//========================================================= -// PainSound -//========================================================= -void CNPC_Vortigaunt::PainSound( const CTakeDamageInfo &info ) -{ - if ( gpGlobals->curtime < m_flPainTime ) - return; - - m_flPainTime = gpGlobals->curtime + random->RandomFloat(0.5, 0.75); - - Speak( VORT_PAIN ); -} - -//========================================================= -// DeathSound -//========================================================= -void CNPC_Vortigaunt::DeathSound( const CTakeDamageInfo &info ) -{ - Speak( VORT_DIE ); -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CNPC_Vortigaunt::TraceAttack( const CTakeDamageInfo &inputInfo, const Vector &vecDir, trace_t *ptr ) -{ - CTakeDamageInfo info = inputInfo; - - if ( (info.GetDamageType() & DMG_SHOCK) && FClassnameIs( info.GetAttacker(), GetClassname() ) ) - { - // mask off damage from other vorts for now - info.SetDamage( 0.01 ); - } - - switch( ptr->hitgroup) - { - case HITGROUP_CHEST: - case HITGROUP_STOMACH: - if (info.GetDamageType() & (DMG_BULLET | DMG_SLASH | DMG_BLAST)) - { - info.ScaleDamage( 0.5f ); - } - break; - case 10: - if (info.GetDamageType() & (DMG_BULLET | DMG_SLASH | DMG_CLUB)) - { - info.SetDamage( info.GetDamage() - 20 ); - if (info.GetDamage() <= 0) - { - g_pEffects->Ricochet( ptr->endpos, (vecDir*-1.0f) ); - info.SetDamage( 0.01 ); - } - } - // always a head shot - ptr->hitgroup = HITGROUP_HEAD; - break; - } - - BaseClass::TraceAttack( info, vecDir, ptr ); -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -int CNPC_Vortigaunt::TranslateSchedule( int scheduleType ) -{ - int baseType; - - switch( scheduleType ) - { - case SCHED_RANGE_ATTACK1: - return SCHED_VORTIGAUNT_RANGE_ATTACK; - break; - - case SCHED_FAIL_ESTABLISH_LINE_OF_FIRE: - { - // Fail schedule doesn't go through SelectSchedule() - // So we have to clear beams and glow here - ClearBeams(); - EndHandGlow(); - - return SCHED_COMBAT_FACE; - break; - } - case SCHED_CHASE_ENEMY_FAILED: - { - baseType = BaseClass::TranslateSchedule(scheduleType); - if ( baseType != SCHED_CHASE_ENEMY_FAILED ) - return baseType; - - if (HasMemory(bits_MEMORY_INCOVER)) - { - // Occasionally run somewhere so I don't just - // stand around forever if my enemy is stationary - if (random->RandomInt(0,5) == 5) - { - return SCHED_PATROL_RUN; - } - else - { - return SCHED_VORTIGAUNT_STAND; - } - } - break; - } - case SCHED_FAIL_TAKE_COVER: - { - // Fail schedule doesn't go through SelectSchedule() - // So we have to clear beams and glow here - ClearBeams(); - EndHandGlow(); - - return SCHED_RUN_RANDOM; - break; - } - } - - return BaseClass::TranslateSchedule( scheduleType ); -} - -//----------------------------------------------------------------------------- -// Purpose: -// Output : Returns true on success, false on failure. -//----------------------------------------------------------------------------- -bool CNPC_Vortigaunt::ShouldHealTarget( CBaseEntity *pTarget, bool bResetTimer ) -{ - // Don't bother if we're already healing - if ( m_eHealState != HEAL_STATE_NONE ) - return false; - - // Must be allowed to do this - if ( m_bArmorRechargeEnabled == false ) - return false; - - // Don't interrupt a script - if ( IsInAScript() ) - return false; - - if ( bResetTimer ) - { - m_flNextHealTime = gpGlobals->curtime; - } - else if ( m_flNextHealTime > gpGlobals->curtime ) - { - return false; - } - - if ( IsCurSchedule( SCHED_VORTIGAUNT_EXTRACT_BUGBAIT ) ) - return false; - - // Can't heal if we're leading the player - if ( IsLeading() ) - return false; - - // Must be a valid squad activity to do - if ( IsStrategySlotRangeOccupied( SQUAD_SLOT_HEAL_PLAYER, SQUAD_SLOT_HEAL_PLAYER ) ) - return false; - - // Only consider things in here if the player is NOT at critical health - if ( PlayerBelowHealthPercentage( PLAYER_CRITICAL_HEALTH_PERC ) == false ) - { - // Don't heal when fighting - if ( m_NPCState == NPC_STATE_COMBAT ) - return false; - - // No enemies - if ( GetEnemy() ) - return false; - - // No recent damage - if ( HasCondition( COND_LIGHT_DAMAGE ) || HasCondition( COND_HEAVY_DAMAGE ) ) - return false; - } - - CBaseEntity *pEntity; - if ( pTarget != NULL ) - { - pEntity = pTarget; - } - else - { - // Need to be looking at the player to decide to heal them. - if ( HasCondition( COND_SEE_PLAYER ) == false ) - return false; - - // Find a likely target in range - pEntity = PlayerInRange( GetLocalOrigin(), HEAL_SEARCH_RANGE ); - } - - if ( pEntity != NULL ) - { - CBasePlayer *pPlayer = ToBasePlayer( pEntity ); - - // Make sure the player's got a suit - if ( pPlayer->IsSuitEquipped() == false ) - return false; - - // FIXME: Huh? - if ( pPlayer->GetFlags() & FL_NOTARGET ) - return false; - - // See if the player needs armor, or tau-cannon ammo - if ( pPlayer->ArmorValue() < sk_vortigaunt_armor_charge.GetInt() ) - { - OccupyStrategySlot( SQUAD_SLOT_HEAL_PLAYER ); - m_hHealTarget = pEntity; - return true; - } - } - - return false; -} - -//----------------------------------------------------------------------------- -// Purpose: -// Output : int -//----------------------------------------------------------------------------- -int CNPC_Vortigaunt::SelectHealSchedule( void ) -{ - // If our lead behavior has a goal, don't wait around to heal anyone - if ( m_LeadBehavior.HasGoal() ) - return SCHED_NONE; - - // Cannot already be healing the player - if ( m_eHealState != HEAL_STATE_NONE ) - { - // Check for an interruption occuring - if ( PlayerBelowHealthPercentage( PLAYER_CRITICAL_HEALTH_PERC ) == false && - ( HasCondition( COND_HEAVY_DAMAGE ) || - HasCondition( COND_LIGHT_DAMAGE ) || - HasCondition( COND_NEW_ENEMY ) ) ) - { - StopHealing( true ); - return SCHED_NONE; - } - - // Decide if the player is at a valid range. If so, stand and face - if ( HasCondition( COND_VORTIGAUNT_HEAL_VALID ) ) - return SCHED_IDLE_STAND; - - // If the player is too far away or blocked, give chase - if ( HasCondition( COND_VORTIGAUNT_HEAL_TARGET_TOO_FAR ) || - HasCondition( COND_VORTIGAUNT_HEAL_TARGET_BLOCKED ) ) - { - return SCHED_VORTIGAUNT_RUN_TO_PLAYER; - } - - // If the player is behind us, turn to face him - if ( HasCondition( COND_VORTIGAUNT_HEAL_TARGET_BEHIND_US ) ) - return SCHED_VORTIGAUNT_FACE_PLAYER; - - return SCHED_NONE; - } - - // See if we should heal the player - if ( ShouldHealTarget( NULL, false ) ) - return SCHED_VORTIGAUNT_HEAL; - - return SCHED_NONE; -} - -//------------------------------------------------------------------------------ -// Purpose: Select a schedule -//------------------------------------------------------------------------------ -int CNPC_Vortigaunt::SelectSchedule( void ) -{ - // If we're currently supposed to be doing something scripted, do it immediately. - if ( m_bExtractingBugbait ) - return SCHED_VORTIGAUNT_EXTRACT_BUGBAIT; - - if ( m_bForceArmorRecharge ) - { - m_flNextHealTime = 0; - return SCHED_VORTIGAUNT_HEAL; - } - - int schedule = SelectHealSchedule(); - if ( schedule != SCHED_NONE ) - return schedule; - - if ( HasCondition( COND_PLAYER_PUSHING ) && GlobalEntity_GetState("gordon_precriminal") != GLOBAL_ON ) - return SCHED_MOVE_AWAY; - - if ( BehaviorSelectSchedule() ) - return BaseClass::SelectSchedule(); - - switch( m_NPCState ) - { - case NPC_STATE_COMBAT: - { - // dead enemy - if ( HasCondition( COND_ENEMY_DEAD ) ) - { - // call base class, all code to handle dead enemies is centralized there. - return BaseClass::SelectSchedule(); - } - - if ( HasCondition( COND_HEAVY_DAMAGE ) ) - return SCHED_TAKE_COVER_FROM_ENEMY; - - if ( HasCondition( COND_HEAR_DANGER ) ) - return SCHED_TAKE_COVER_FROM_BEST_SOUND; - - if ( HasCondition( COND_ENEMY_DEAD ) && IsOkToCombatSpeak() ) - { - Speak( VORT_KILL ); - } - - // If I might hit the player shooting... - else if ( HasCondition( COND_WEAPON_PLAYER_IN_SPREAD )) - { - if ( IsOkToCombatSpeak() && m_nextLineFireTime < gpGlobals->curtime) - { - Speak( VORT_LINE_FIRE ); - m_nextLineFireTime = gpGlobals->curtime + 3.0f; - } - - // Run to a new location or stand and aim - if ( random->RandomInt( 0, 2 ) == 0 ) - return SCHED_ESTABLISH_LINE_OF_FIRE; - - return SCHED_COMBAT_FACE; - } - } - break; - - case NPC_STATE_ALERT: - case NPC_STATE_IDLE: - - // Run from danger - if ( HasCondition( COND_HEAR_DANGER ) ) - return SCHED_TAKE_COVER_FROM_BEST_SOUND; - - // Heal a player if they can be - if ( HasCondition( COND_VORTIGAUNT_CAN_HEAL ) ) - return SCHED_VORTIGAUNT_HEAL; - - if ( HasCondition( COND_ENEMY_DEAD ) && IsOkToCombatSpeak() ) - { - Speak( VORT_KILL ); - } - - break; - } - - return BaseClass::SelectSchedule(); -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CNPC_Vortigaunt::DeclineFollowing( void ) -{ - Speak( VORT_POK ); -} - -//----------------------------------------------------------------------------- -// Purpose: Return true if you're willing to be idly talked to by other friends. -//----------------------------------------------------------------------------- -bool CNPC_Vortigaunt::CanBeUsedAsAFriend( void ) -{ - // We don't want to be used if we're busy - if ( IsCurSchedule( SCHED_VORTIGAUNT_HEAL ) ) - return false; - - if ( IsCurSchedule( SCHED_VORTIGAUNT_EXTRACT_BUGBAIT ) ) - return false; - - return BaseClass::CanBeUsedAsAFriend(); -} - -//----------------------------------------------------------------------------- -// Purpose: Start our heal loop -//----------------------------------------------------------------------------- -void CNPC_Vortigaunt::StartHealing( void ) -{ - // Find the layer and stop it from moving forward in the cycle - int nLayer = FindGestureLayer( (Activity) ACT_VORTIGAUNT_HEAL ); - SetLayerPlaybackRate( nLayer, 0.0f ); - - // We're now in the healing loop - m_eHealState = HEAL_STATE_HEALING; -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CNPC_Vortigaunt::StopHealing( bool bInterrupt ) -{ - m_eHealState = HEAL_STATE_NONE; - m_bForceArmorRecharge = false; - - ClearBeams(); - EndHandGlow(); - VacateStrategySlot(); - - // See if we're completely interrupting the heal or just ending normally - if ( bInterrupt ) - { - RemoveGesture( (Activity) ACT_VORTIGAUNT_HEAL ); - m_flNextHealTime = gpGlobals->curtime + 2.0f; - } - else - { - // Start our animation back up again - int nLayer = FindGestureLayer( (Activity) ACT_VORTIGAUNT_HEAL ); - SetLayerPlaybackRate( nLayer, 1.0f ); - - m_flNextHealTime = gpGlobals->curtime + VORTIGAUNT_HEAL_RECHARGE; - m_OnFinishedChargingTarget.FireOutput( this, this ); - } -} - -//----------------------------------------------------------------------------- -// Purpose: Update our heal schedule and gestures if we're currently healing -//----------------------------------------------------------------------------- -void CNPC_Vortigaunt::MaintainHealSchedule( void ) -{ - // Need to be healing - if ( m_eHealState == HEAL_STATE_NONE ) - return; - - // For now, we only heal the player - CBasePlayer *pPlayer = AI_GetSinglePlayer(); - if ( pPlayer == NULL ) - return; - - // FIXME: Implement this in the animation - // SetAimTarget( pPlayer ); - - // If we're in the healing phase, heal our target (if able) - if ( m_eHealState == HEAL_STATE_HEALING ) - { - // FIXME: We need to have better logic controlling this - if ( HasCondition( COND_VORTIGAUNT_HEAL_VALID ) ) - { - // Clear our timer - m_flHealHinderedTime = 0.0f; - - // Turn the heal beam back on if it's not already - HealBeam( 1 ); - - // Charge the suit's armor - pPlayer->IncrementArmorValue( 1, sk_vortigaunt_armor_charge.GetInt() ); - - // Stop healing once we've hit the maximum level we'll ever charge the player to. - if ( pPlayer->ArmorValue() >= sk_vortigaunt_armor_charge.GetInt() ) - { - SpeakIfAllowed( VORT_CURESTOP ); - StopHealing(); - return; - } - - // Play the on sound or the looping charging sound - if ( m_iSuitSound == 0 ) - { - m_iSuitSound++; - EmitSound( "NPC_Vortigaunt.SuitOn" ); - m_flSuitSoundTime = 0.56 + gpGlobals->curtime; - } - else if ( m_iSuitSound == 1 && m_flSuitSoundTime <= gpGlobals->curtime ) - { - m_iSuitSound++; - - CPASAttenuationFilter filter( this, "NPC_Vortigaunt.SuitCharge" ); - filter.MakeReliable(); - EmitSound( filter, entindex(), "NPC_Vortigaunt.SuitCharge" ); - - m_bStopLoopingSounds = true; - } - } - else - { - // Turn off the main beam but leave the hand glow active - ClearBeams(); - - // Increment a counter to let us know how long we've failed - m_flHealHinderedTime += gpGlobals->curtime - GetLastThink(); - - if ( m_flHealHinderedTime > 2.0f ) - { - // If too long, stop trying - StopHealing(); - } - } - } -} - -//----------------------------------------------------------------------------- -// Purpose: Do various non-schedule specific maintainence -//----------------------------------------------------------------------------- -void CNPC_Vortigaunt::PrescheduleThink( void ) -{ - // Update glows - if ( m_bGlowTurningOn ) - { - m_bGlowTurningOn = false; - - if ( m_pLeftHandGlow != NULL ) - { - m_pLeftHandGlow->SetScale( 0.5f, 1.0f ); - m_pLeftHandGlow->SetBrightness( 200, 1.0f ); - m_pLeftHandGlow->AnimateForTime( random->RandomFloat( 50.0f, 60.0f ), 10.0f ); - } - - if ( m_pRightHandGlow != NULL ) - { - m_pRightHandGlow->SetScale( 0.75f, 1.0f ); - m_pRightHandGlow->SetBrightness( 200, 1.0f ); - m_pRightHandGlow->AnimateForTime( random->RandomFloat( 50.0f, 60.0f ), 10.0f ); - } - } - - // Update our healing (if active) - MaintainHealSchedule(); - - // Let the base class have a go - BaseClass::PrescheduleThink(); -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CNPC_Vortigaunt::BuildScheduleTestBits( void ) -{ - // Call to base - BaseClass::BuildScheduleTestBits(); - - // Allow healing to interrupt us if we're standing around - if ( IsCurSchedule( SCHED_IDLE_STAND ) || - IsCurSchedule( SCHED_ALERT_STAND ) ) - { - SetCustomInterruptCondition( COND_VORTIGAUNT_CAN_HEAL ); - } - - // Always interrupt when healing - if ( m_eHealState != HEAL_STATE_NONE ) - { - // Interrupt if we're not already adjusting - if ( IsCurSchedule( SCHED_VORTIGAUNT_RUN_TO_PLAYER ) == false ) - { - SetCustomInterruptCondition( COND_VORTIGAUNT_HEAL_TARGET_TOO_FAR ); - SetCustomInterruptCondition( COND_VORTIGAUNT_HEAL_TARGET_BLOCKED ); - } - - // Interrupt if we're not already turning - if ( IsCurSchedule( SCHED_VORTIGAUNT_FACE_PLAYER ) == false ) - { - SetCustomInterruptCondition( COND_VORTIGAUNT_HEAL_TARGET_BEHIND_US ); - } - } -} - -//----------------------------------------------------------------------------- -// Purpose: Small beam from arm to nearby geometry -//----------------------------------------------------------------------------- -void CNPC_Vortigaunt::ArmBeam( int side, int beamType ) -{ - trace_t tr; - float flDist = 1.0; - - if ( m_iBeams >= VORTIGAUNT_MAX_BEAMS ) - return; - - Vector forward, right, up; - AngleVectors( GetLocalAngles(), &forward, &right, &up ); - Vector vecSrc = GetLocalOrigin() + up * 36 + right * side * 16 + forward * 32; - - for (int i = 0; i < 3; i++) - { - Vector vecAim = forward * random->RandomFloat( -1, 1 ) + right * side * random->RandomFloat( 0, 1 ) + up * random->RandomFloat( -1, 1 ); - trace_t tr1; - AI_TraceLine ( vecSrc, vecSrc + vecAim * 512, MASK_SOLID, this, COLLISION_GROUP_NONE, &tr1); - - // Don't hit the sky - if ( tr1.surface.flags & SURF_SKY ) - continue; - - // Choose a farther distance if we have one - if ( flDist > tr1.fraction ) - { - tr = tr1; - flDist = tr.fraction; - } - } - - // Couldn't find anything close enough - if ( flDist == 1.0 ) - return; - - // NOTE: We don't want to make the sounds on the walls! - // UTIL_ImpactTrace( &tr, DMG_CLUB ); - - m_pBeam[m_iBeams] = CBeam::BeamCreate( "sprites/lgtning.vmt", 3.0 ); - if (!m_pBeam[m_iBeams]) - return; - - m_pBeam[m_iBeams]->PointEntInit( tr.endpos, this ); - m_pBeam[m_iBeams]->SetEndAttachment( side < 0 ? m_iLeftHandAttachment : m_iRightHandAttachment ); - - if (beamType == VORTIGAUNT_BEAM_HEAL) - { - m_pBeam[m_iBeams]->SetColor( 0, 0, 255 ); - } - else - { - m_pBeam[m_iBeams]->SetColor( 96, 128, 16 ); - } - m_pBeam[m_iBeams]->SetBrightness( 64 ); - m_pBeam[m_iBeams]->SetNoise( 12.5 ); - m_pBeam[m_iBeams]->SetEndWidth( 6.0f ); - m_pBeam[m_iBeams]->SetWidth( 1.0f ); - m_pBeam[m_iBeams]->LiveForTime( 3.0f ); // Fail-safe - m_iBeams++; -} - -//------------------------------------------------------------------------------ -// Purpose : Put glowing sprites on hands -// Input : -// Output : -//------------------------------------------------------------------------------ -void CNPC_Vortigaunt::StartHandGlow( int beamType ) -{ - m_bGlowTurningOn = true; - m_fGlowAge = 0; - - if (beamType == VORTIGAUNT_BEAM_HEAL) - { - m_fGlowChangeTime = VORTIGAUNT_HEAL_GLOWGROW_TIME; - m_fGlowScale = 0.6f; - } - else - { - m_fGlowChangeTime = VORTIGAUNT_ZAP_GLOWGROW_TIME; - m_fGlowScale = 0.8f; - } - - if ( m_pLeftHandGlow == NULL ) - { - if ( beamType == VORTIGAUNT_BEAM_HEAL ) - { - m_pLeftHandGlow = CSprite::SpriteCreate( "sprites/physring1.vmt", GetLocalOrigin(), FALSE ); - m_pLeftHandGlow->SetAttachment( this, 4 ); - } - else - { - m_pLeftHandGlow = CSprite::SpriteCreate( "sprites/vortring1.vmt", GetLocalOrigin(), FALSE ); - m_pLeftHandGlow->SetAttachment( this, 3 ); - } - - m_pLeftHandGlow->SetTransparency( kRenderTransAddFrameBlend, 255, 255, 255, 0, kRenderFxNone ); - m_pLeftHandGlow->SetBrightness( 0 ); - m_pLeftHandGlow->SetScale( 0 ); - } - - if ( beamType != VORTIGAUNT_BEAM_HEAL ) - { - if ( m_pRightHandGlow == NULL ) - { - m_pRightHandGlow = CSprite::SpriteCreate( "sprites/vortring1.vmt", GetLocalOrigin(), FALSE ); - m_pRightHandGlow->SetAttachment( this, 4 ); - - m_pRightHandGlow->SetTransparency( kRenderTransAddFrameBlend, 255, 255, 255, 0, kRenderFxNone ); - m_pRightHandGlow->SetBrightness( 0 ); - m_pRightHandGlow->SetScale( 0 ); - } - } -} - - -//------------------------------------------------------------------------------ -// Purpose: Fade glow from hands. -//------------------------------------------------------------------------------ -void CNPC_Vortigaunt::EndHandGlow() -{ - m_bGlowTurningOn = false; - m_fGlowChangeTime = VORTIGAUNT_GLOWFADE_TIME; - - if ( m_pLeftHandGlow ) - { - m_pLeftHandGlow->SetScale( 0, 0.4f ); - m_pLeftHandGlow->FadeAndDie( 0.4f ); - } - - if ( m_pRightHandGlow ) - { - m_pRightHandGlow->SetScale( 0, 0.4f ); - m_pRightHandGlow->FadeAndDie( 0.4f ); - } -} - -//----------------------------------------------------------------------------- -// Purpose: vortigaunt shoots at noisy body target (fixes problems in cover, etc) -// NOTE: His weapon doesn't have any error -//----------------------------------------------------------------------------- -Vector CNPC_Vortigaunt::GetShootEnemyDir( const Vector &shootOrigin, bool bNoisy ) -{ - CBaseEntity *pEnemy = GetEnemy(); - - if ( pEnemy ) - { - return (pEnemy->BodyTarget(shootOrigin, bNoisy)-shootOrigin); - } - else - { - Vector forward; - AngleVectors( GetLocalAngles(), &forward ); - return forward; - } -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -bool CNPC_Vortigaunt::IsValidEnemy( CBaseEntity *pEnemy ) -{ - if ( IsRoller( pEnemy ) ) - { - CAI_BaseNPC *pNPC = pEnemy->MyNPCPointer(); - if ( pNPC && pNPC->GetEnemy() != NULL ) - return true; - return false; - } - - return BaseClass::IsValidEnemy( pEnemy ); -} - -//----------------------------------------------------------------------------- -// Purpose: Brighten all beams -//----------------------------------------------------------------------------- -void CNPC_Vortigaunt::BeamGlow( void ) -{ - int b = m_iBeams * 32; - if (b > 255) - b = 255; - - for (int i = 0; i < m_iBeams; i++) - { - if (m_pBeam[i]->GetBrightness() != 255) - { - m_pBeam[i]->SetBrightness( b ); - } - } -} - - -//----------------------------------------------------------------------------- -// Purpose: Creates a blast where the beam has struck a target -// Input : &vecOrigin - position to eminate from -//----------------------------------------------------------------------------- -void CNPC_Vortigaunt::CreateBeamBlast( const Vector &vecOrigin ) -{ - CSprite *pBlastSprite = CSprite::SpriteCreate( "sprites/vortring1.vmt", vecOrigin, true ); - if ( pBlastSprite != NULL ) - { - pBlastSprite->SetTransparency( kRenderTransAddFrameBlend, 255, 255, 255, 255, kRenderFxNone ); - pBlastSprite->SetBrightness( 255 ); - pBlastSprite->SetScale( random->RandomFloat( 1.0f, 1.5f ) ); - pBlastSprite->AnimateAndDie( 45.0f ); - } - - CPVSFilter filter( vecOrigin ); - te->GaussExplosion( filter, 0.0f, vecOrigin, Vector( 0, 0, 1 ), 0 ); -} - -#define COS_60 0.5f // sqrt(1)/2 - -//----------------------------------------------------------------------------- -// Purpose: Heavy damage directly forward -// Input : side - Handedness of the beam -//----------------------------------------------------------------------------- -void CNPC_Vortigaunt::ZapBeam( int side ) -{ - if ( m_iBeams >= VORTIGAUNT_MAX_BEAMS ) - return; - - Vector forward, right, up; - AngleVectors( GetLocalAngles(), &forward, &right, &up ); - - Vector vecSrc = GetLocalOrigin() + up * 36; - Vector vecAim = GetShootEnemyDir( vecSrc ); - float deflection = 0.01f; - - // If we're too far off our center, the shot must miss! - if ( DotProduct( vecAim, forward ) < COS_60 ) - { - // Missed, so just shoot forward - vecAim = forward + side * right * random->RandomFloat( 0, deflection ) + up * random->RandomFloat( -deflection, deflection ); - } - else - { - // Within the tolerance, so shoot directly - vecAim = vecAim + side * right * random->RandomFloat( 0, deflection ) + up * random->RandomFloat( -deflection, deflection ); - } - - trace_t tr; - - if ( m_bExtractingBugbait == true ) - { - CRagdollProp *pTest = dynamic_cast< CRagdollProp *>( GetTarget() ); - - if ( pTest ) - { - ragdoll_t *m_ragdoll = pTest->GetRagdoll(); - - if ( m_ragdoll ) - { - Vector vOrigin; - m_ragdoll->list[0].pObject->GetPosition( &vOrigin, 0 ); - - AI_TraceLine ( vecSrc, vOrigin, MASK_SHOT, this, COLLISION_GROUP_NONE, &tr); - } - - CRagdollBoogie::Create( pTest, 200, gpGlobals->curtime, 1.0f ); - } - } - else - { - AI_TraceLine ( vecSrc, vecSrc + vecAim * 1024, MASK_SHOT, this, COLLISION_GROUP_NONE, &tr); - } - - // Create a dynamic beam that will destroy itself when finished - CBeam *pBeam = CBeam::BeamCreate( "sprites/lgtning.vmt", 5.0 ); - if ( pBeam == NULL ) - return; - - pBeam->PointEntInit( tr.endpos, this ); - pBeam->SetEndAttachment( side < 0 ? m_iLeftHandAttachment : m_iRightHandAttachment ); - pBeam->SetColor( 180, 255, 96 ); - pBeam->SetBrightness( 255 ); - pBeam->SetNoise( 3 ); - pBeam->LiveForTime( 0.2f ); - - CBaseEntity *pEntity = tr.m_pEnt; - if ( pEntity != NULL && m_takedamage ) - { - CTakeDamageInfo dmgInfo( this, this, sk_vortigaunt_dmg_zap.GetFloat(), DMG_SHOCK ); - dmgInfo.SetDamagePosition( tr.endpos ); - VectorNormalize( vecAim );// not a unit vec yet - // hit like a 5kg object flying 400 ft/s - dmgInfo.SetDamageForce( 5 * 400 * 12 * vecAim ); - pEntity->DispatchTraceAttack( dmgInfo, vecAim, &tr ); - } - - // Create a cover for the end of the beam - CreateBeamBlast( tr.endpos ); -} - -//------------------------------------------------------------------------------ -// Purpose : Start the healing beam -// Input : side - Handedness of the beam -//------------------------------------------------------------------------------ -void CNPC_Vortigaunt::HealBeam( int side ) -{ - if ( m_iBeams >= VORTIGAUNT_MAX_BEAMS ) - return; - - if ( m_bHealBeamActive ) - return; - - Vector forward, right, up; - AngleVectors( GetLocalAngles(), &forward, &right, &up ); - - trace_t tr; - Vector vecSrc = GetLocalOrigin() + up * 36; - - m_pBeam[m_iBeams] = CBeam::BeamCreate( "sprites/physbeam.vmt", 6.0 ); - if (!m_pBeam[m_iBeams]) - return; - - m_pBeam[m_iBeams]->EntsInit( GetTarget(), this ); - m_pBeam[m_iBeams]->SetEndAttachment( side < 0 ? m_iLeftHandAttachment : m_iRightHandAttachment ); - m_pBeam[m_iBeams]->SetColor( 128, 128, 255 ); - - m_pBeam[m_iBeams]->SetBrightness( 255 ); - m_pBeam[m_iBeams]->SetNoise( 2 ); - m_pBeam[m_iBeams]->SetScrollRate( 15 ); - m_iBeams++; - - m_bHealBeamActive = true; -} - -//------------------------------------------------------------------------------ -// Purpose: Clear glow from hands immediately -//------------------------------------------------------------------------------ -void CNPC_Vortigaunt::ClearHandGlow( void ) -{ - if ( m_pLeftHandGlow != NULL ) - { - UTIL_Remove( m_pLeftHandGlow ); - m_pLeftHandGlow = NULL; - } - - if ( m_pRightHandGlow != NULL ) - { - UTIL_Remove( m_pRightHandGlow ); - m_pRightHandGlow = NULL; - } -} - -//------------------------------------------------------------------------------ -// Purpose: remove all beams -//------------------------------------------------------------------------------ -void CNPC_Vortigaunt::ClearBeams( void ) -{ - for (int i = 0; i < VORTIGAUNT_MAX_BEAMS; i++) - { - if (m_pBeam[i]) - { - UTIL_Remove( m_pBeam[i] ); - m_pBeam[i] = NULL; - } - } - - m_iBeams = 0; - m_nSkin = 0; - - // Stop looping suit charge sound. - if (m_iSuitSound > 1) - { - StopSound( "NPC_Vortigaunt.SuitCharge" ); - m_iSuitSound = 0; - } - - if ( m_bStopLoopingSounds ) - { - StopSound( "NPC_Vortigaunt.StartHealLoop" ); - StopSound( "NPC_Vortigaunt.StartShootLoop" ); - StopSound( "NPC_Vortigaunt.SuitCharge" ); - StopSound( "NPC_Vortigaunt.Shoot" ); - StopSound( "NPC_Vortigaunt.ZapPowerup" ); - m_bStopLoopingSounds = false; - } - - m_bHealBeamActive = false; -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CNPC_Vortigaunt::InputEnableArmorRecharge( inputdata_t &data ) -{ - m_bArmorRechargeEnabled = true; -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CNPC_Vortigaunt::InputDisableArmorRecharge( inputdata_t &data ) -{ - m_bArmorRechargeEnabled = false; -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CNPC_Vortigaunt::InputChargeTarget( inputdata_t &data ) -{ - CBaseEntity *pTarget = gEntList.FindEntityByName( NULL, data.value.String(), NULL, data.pActivator, data.pCaller ); - - // Must be valid - if ( pTarget == NULL ) - { - DevMsg( 1, "Unable to charge from unknown entity: %s!\n", data.value.String() ); - return; - } - - int playerArmor = (pTarget->IsPlayer()) ? ((CBasePlayer *)pTarget)->ArmorValue() : 0; - - if ( playerArmor >= 100 || ( pTarget->GetFlags() & FL_NOTARGET ) ) - { - m_OnFinishedChargingTarget.FireOutput( this, this ); - return; - } - - m_hHealTarget = pTarget; - - m_iCurrentRechargeGoal = playerArmor + sk_vortigaunt_armor_charge.GetInt(); - if ( m_iCurrentRechargeGoal > 100 ) - m_iCurrentRechargeGoal = 100; - m_bForceArmorRecharge = true; - - SetCondition( COND_PROVOKED ); -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CNPC_Vortigaunt::InputExtractBugbait( inputdata_t &data ) -{ - CBaseEntity *pTarget = gEntList.FindEntityByName( NULL, data.value.String(), NULL, data.pActivator, data.pCaller ); - - // Must be valid - if ( pTarget == NULL ) - { - DevMsg( 1, "Unable to extract bugbait from unknown entity %s!\n", data.value.String() ); - return; - } - - // Keep this as our target - SetTarget( pTarget ); - - // Start to extract - m_bExtractingBugbait = true; - SetSchedule( SCHED_VORTIGAUNT_EXTRACT_BUGBAIT ); -} - - -//----------------------------------------------------------------------------- -// The vort overloads the CNPC_PlayerCompanion version because he uses different -// rules. The player companion rules looked too sensitive to muck with. -//----------------------------------------------------------------------------- -bool CNPC_Vortigaunt::OnObstructionPreSteer( AILocalMoveGoal_t *pMoveGoal, float distClear, AIMoveResult_t *pResult ) -{ - if ( pMoveGoal->directTrace.flTotalDist - pMoveGoal->directTrace.flDistObstructed < GetHullWidth() * 1.5 ) - { - CAI_BaseNPC *pBlocker = pMoveGoal->directTrace.pObstruction->MyNPCPointer(); - if ( pBlocker && pBlocker->IsPlayerAlly() && !pBlocker->IsMoving() && !pBlocker->IsInAScript() ) - { - if ( pBlocker->ConditionInterruptsCurSchedule( COND_GIVE_WAY ) || - pBlocker->ConditionInterruptsCurSchedule( COND_PLAYER_PUSHING ) ) - { - // HACKHACK - pBlocker->GetMotor()->SetIdealYawToTarget( WorldSpaceCenter() ); - pBlocker->SetSchedule( SCHED_MOVE_AWAY ); - } - - } - } - - return BaseClass::OnObstructionPreSteer( pMoveGoal, distClear, pResult ); -} - -//----------------------------------------------------------------------------- -// Purpose: Allows the vortigaunt to use health regeneration -//----------------------------------------------------------------------------- -void CNPC_Vortigaunt::InputEnableHealthRegeneration( inputdata_t &data ) -{ - m_bRegenerateHealth = true; -} - -//----------------------------------------------------------------------------- -// Purpose: Stops the vortigaunt from using health regeneration (default) -//----------------------------------------------------------------------------- -void CNPC_Vortigaunt::InputDisableHealthRegeneration( inputdata_t &data ) -{ - m_bRegenerateHealth = false; -} - -extern int ACT_ANTLION_FLIP; - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -int CNPC_Vortigaunt::IRelationPriority( CBaseEntity *pTarget ) -{ - int priority = BaseClass::IRelationPriority( pTarget ); - - if ( pTarget->Classify() == CLASS_ANTLION ) - { - // Make vort prefer Antlions that are flipped onto their backs. - // UNLESS it has a different enemy that could melee attack it while its back is turned. - CAI_BaseNPC *pNPC = pTarget->MyNPCPointer(); - if ( pNPC && pNPC->GetActivity() == ACT_ANTLION_FLIP ) - { - if ( GetEnemy() && GetEnemy() != pTarget ) - { - // I have an enemy that is not this thing. If that enemy is near, I shouldn't become distracted. - if ( GetAbsOrigin().DistToSqr(GetEnemy()->GetAbsOrigin()) < Square(180) ) - return priority; - } - - priority++; - } - } - - return priority; -} - -//----------------------------------------------------------------------------- -// Purpose: Determines whether the heal gesture can successfully reach the player -// Output : Returns true on success, false on failure. -//----------------------------------------------------------------------------- -bool CNPC_Vortigaunt::HealGestureHasLOS( void ) -{ - //For now the player is always our target - CBaseEntity *pTargetEnt = AI_GetSinglePlayer(); - if ( pTargetEnt == NULL ) - return false; - - // Find our left hand as the starting point - Vector vecHandPos; - QAngle vecHandAngle; - GetAttachment( "rhand", vecHandPos, vecHandAngle ); - - // Trace to our target, skipping ourselves and the target - trace_t tr; - CTraceFilterSkipTwoEntities filter( this, pTargetEnt, COLLISION_GROUP_NONE ); - UTIL_TraceLine( vecHandPos, pTargetEnt->WorldSpaceCenter(), MASK_SHOT, &filter, &tr ); - - // Must be clear - if ( tr.fraction < 1.0f || tr.startsolid || tr.allsolid ) - return false; - - return true; -} - -//----------------------------------------------------------------------------- -// Purpose: Gather conditions for our healing behavior -//----------------------------------------------------------------------------- -void CNPC_Vortigaunt::GatherHealConditions( void ) -{ - // Start assuming that we'll succeed - ClearCondition( COND_VORTIGAUNT_HEAL_TARGET_TOO_FAR ); - ClearCondition( COND_VORTIGAUNT_HEAL_TARGET_BLOCKED ); - ClearCondition( COND_VORTIGAUNT_HEAL_TARGET_BEHIND_US ); - SetCondition( COND_VORTIGAUNT_HEAL_VALID ); - - // For now we only act on the player - CBasePlayer *pPlayer = AI_GetSinglePlayer(); - if ( pPlayer != NULL ) - { - Vector vecToPlayer = ( pPlayer->WorldSpaceCenter() - WorldSpaceCenter() ); - - // Make sure he's still within heal range - if ( vecToPlayer.LengthSqr() > (HEAL_RANGE*HEAL_RANGE) ) - { - SetCondition( COND_VORTIGAUNT_HEAL_TARGET_TOO_FAR ); - ClearCondition( COND_VORTIGAUNT_HEAL_VALID ); - } - - vecToPlayer.z = 0.0f; - VectorNormalize( vecToPlayer ); - Vector facingDir = BodyDirection2D(); - - // Check our direction towards the player - if ( DotProduct( vecToPlayer, facingDir ) < VIEW_FIELD_NARROW ) - { - SetCondition( COND_VORTIGAUNT_HEAL_TARGET_BEHIND_US ); - ClearCondition( COND_VORTIGAUNT_HEAL_VALID ); - } - - // Now ensure he's not blocked - if ( HealGestureHasLOS() == false ) - { - SetCondition( COND_VORTIGAUNT_HEAL_TARGET_BLOCKED ); - ClearCondition( COND_VORTIGAUNT_HEAL_VALID ); - } - } -} - -//----------------------------------------------------------------------------- -// Purpose: Gather conditions specific to this NPC -//----------------------------------------------------------------------------- -void CNPC_Vortigaunt::GatherConditions( void ) -{ - // Call our base - BaseClass::GatherConditions(); - - ClearCondition( COND_VORTIGAUNT_CAN_HEAL ); - - // See if we're able to heal now - if ( m_eHealState == HEAL_STATE_NONE ) - { - if ( ShouldHealTarget( NULL, false ) ) - { - SetCondition( COND_VORTIGAUNT_CAN_HEAL ); - } - } - else - { - // Get our state for healing - GatherHealConditions(); - } -} - -//------------------------------------------------------------------------------ -// -// Schedules -// -//------------------------------------------------------------------------------ - -AI_BEGIN_CUSTOM_NPC( npc_vortigaunt, CNPC_Vortigaunt ) - - DECLARE_USES_SCHEDULE_PROVIDER( CAI_LeadBehavior ) - - DECLARE_TASK(TASK_VORTIGAUNT_HEAL) - DECLARE_TASK(TASK_VORTIGAUNT_EXTRACT) - DECLARE_TASK(TASK_VORTIGAUNT_FIRE_EXTRACT_OUTPUT) - DECLARE_TASK(TASK_VORTIGAUNT_WAIT_FOR_PLAYER) - - DECLARE_TASK( TASK_VORTIGAUNT_EXTRACT_WARMUP ) - DECLARE_TASK( TASK_VORTIGAUNT_EXTRACT_COOLDOWN ) - DECLARE_TASK( TASK_VORTIGAUNT_GET_HEAL_TARGET ) - - DECLARE_ACTIVITY(ACT_VORTIGAUNT_AIM) - DECLARE_ACTIVITY(ACT_VORTIGAUNT_START_HEAL) - DECLARE_ACTIVITY(ACT_VORTIGAUNT_HEAL_LOOP) - DECLARE_ACTIVITY(ACT_VORTIGAUNT_END_HEAL) - DECLARE_ACTIVITY(ACT_VORTIGAUNT_TO_ACTION) - DECLARE_ACTIVITY(ACT_VORTIGAUNT_TO_IDLE) - DECLARE_ACTIVITY( ACT_VORTIGAUNT_HEAL ) - - DECLARE_CONDITION( COND_VORTIGAUNT_CAN_HEAL ) - DECLARE_CONDITION( COND_VORTIGAUNT_HEAL_TARGET_TOO_FAR ) - DECLARE_CONDITION( COND_VORTIGAUNT_HEAL_TARGET_BLOCKED ) - DECLARE_CONDITION( COND_VORTIGAUNT_HEAL_TARGET_BEHIND_US ) - DECLARE_CONDITION( COND_VORTIGAUNT_HEAL_VALID ) - - DECLARE_SQUADSLOT( SQUAD_SLOT_HEAL_PLAYER ) - - DECLARE_ANIMEVENT( AE_VORTIGAUNT_CLAW_LEFT ) - DECLARE_ANIMEVENT( AE_VORTIGAUNT_CLAW_RIGHT ) - DECLARE_ANIMEVENT( AE_VORTIGAUNT_ZAP_POWERUP ) - DECLARE_ANIMEVENT( AE_VORTIGAUNT_ZAP_SHOOT ) - DECLARE_ANIMEVENT( AE_VORTIGAUNT_ZAP_DONE ) - DECLARE_ANIMEVENT( AE_VORTIGAUNT_HEAL_STARTGLOW ) - DECLARE_ANIMEVENT( AE_VORTIGAUNT_HEAL_STARTBEAMS ) - DECLARE_ANIMEVENT( AE_VORTIGAUNT_HEAL_STARTSOUND ) - DECLARE_ANIMEVENT( AE_VORTIGAUNT_SWING_SOUND ) - DECLARE_ANIMEVENT( AE_VORTIGAUNT_SHOOT_SOUNDSTART ) - DECLARE_ANIMEVENT( AE_VORTIGAUNT_HEAL_PAUSE ) - - //========================================================= - // > SCHED_VORTIGAUNT_RANGE_ATTACK - //========================================================= - DEFINE_SCHEDULE - ( - SCHED_VORTIGAUNT_RANGE_ATTACK, - - " Tasks" - " TASK_STOP_MOVING 0" - " TASK_FACE_IDEAL 0" - " TASK_RANGE_ATTACK1 0" - " TASK_WAIT 0.2" // Wait a sec before killing beams - "" - " Interrupts" - ); - - - //========================================================= - // > SCHED_VORTIGAUNT_HEAL - //========================================================= - DEFINE_SCHEDULE - ( - SCHED_VORTIGAUNT_HEAL, - - " Tasks" - " TASK_VORTIGAUNT_GET_HEAL_TARGET 0" - " TASK_STOP_MOVING 0" - " TASK_SET_FAIL_SCHEDULE SCHEDULE:SCHED_VORTIGAUNT_STAND" - " TASK_GET_PATH_TO_TARGET 0" - " TASK_MOVE_TO_TARGET_RANGE 128" // Move within 128 of target ent (client) - " TASK_STOP_MOVING 0" - " TASK_FACE_PLAYER 0" - " TASK_VORTIGAUNT_HEAL 0" - "" - " Interrupts" - " COND_LIGHT_DAMAGE" - " COND_HEAVY_DAMAGE" - ); - - //========================================================= - // > SCHED_VORTIGAUNT_STAND - //========================================================= - DEFINE_SCHEDULE - ( - SCHED_VORTIGAUNT_STAND, - - " Tasks" - " TASK_STOP_MOVING 0" - " TASK_SET_ACTIVITY ACTIVITY:ACT_IDLE" - " TASK_WAIT 2" // repick IDLESTAND every two seconds." - //" TASK_TALKER_HEADRESET 0" // reset head position" - "" - " Interrupts" - " COND_NEW_ENEMY" - " COND_LIGHT_DAMAGE" - " COND_HEAVY_DAMAGE" - " COND_SMELL" - " COND_PROVOKED" - " COND_HEAR_COMBAT" - " COND_HEAR_DANGER" - ); - - //========================================================= - // > SCHED_VORTIGAUNT_EXTRACT_BUGBAIT - //========================================================= - DEFINE_SCHEDULE - ( - SCHED_VORTIGAUNT_EXTRACT_BUGBAIT, - - " Tasks" - " TASK_SET_FAIL_SCHEDULE SCHEDULE:SCHED_VORTIGAUNT_STAND" - " TASK_STOP_MOVING 0" - " TASK_GET_PATH_TO_TARGET 0" - " TASK_MOVE_TO_TARGET_RANGE 128" // Move within 128 of target ent (client) - " TASK_STOP_MOVING 0" - " TASK_VORTIGAUNT_WAIT_FOR_PLAYER 0" - " TASK_SPEAK_SENTENCE 500" // Start extracting sentence - " TASK_WAIT_FOR_SPEAK_FINISH 1" - " TASK_FACE_TARGET 0" - " TASK_WAIT_FOR_SPEAK_FINISH 1" - " TASK_VORTIGAUNT_EXTRACT_WARMUP 0" - " TASK_VORTIGAUNT_EXTRACT 0" - " TASK_VORTIGAUNT_EXTRACT_COOLDOWN 0" - " TASK_VORTIGAUNT_FIRE_EXTRACT_OUTPUT 0" - " TASK_SPEAK_SENTENCE 501" // Finish extracting sentence - " TASK_WAIT_FOR_SPEAK_FINISH 1" - " TASK_WAIT 2" - "" - " Interrupts" - ) - - //========================================================= - // > SCHED_VORTIGAUNT_FACE_PLAYER - //========================================================= - DEFINE_SCHEDULE - ( - SCHED_VORTIGAUNT_FACE_PLAYER, - - " Tasks" - " TASK_STOP_MOVING 0" - " TASK_TARGET_PLAYER 0" - " TASK_FACE_PLAYER 0" - "" - " Interrupts" - " COND_NEW_ENEMY" - " COND_LIGHT_DAMAGE" - " COND_HEAVY_DAMAGE" - ); - - //========================================================= - // > SCHED_VORTIGAUNT_RUN_TO_PLAYER - //========================================================= - DEFINE_SCHEDULE - ( - SCHED_VORTIGAUNT_RUN_TO_PLAYER, - - " Tasks" - " TASK_TARGET_PLAYER 0" - " TASK_GET_PATH_TO_TARGET 0" - " TASK_MOVE_TO_TARGET_RANGE 96" - "" - " Interrupts" - " COND_NEW_ENEMY" - " COND_LIGHT_DAMAGE" - " COND_HEAVY_DAMAGE" - ); - -AI_END_CUSTOM_NPC() diff --git a/src/src/dlls/hl2_dll/npc_vortigaunt_episodic.h b/src/src/dlls/hl2_dll/npc_vortigaunt_episodic.h deleted file mode 100644 index fdcf9c7..0000000 --- a/src/src/dlls/hl2_dll/npc_vortigaunt_episodic.h +++ /dev/null @@ -1,219 +0,0 @@ -//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// -// -// Purpose: This is the base version of the vortigaunt -// -//=============================================================================// - -#ifndef NPC_VORTIGAUNT_H -#define NPC_VORTIGAUNT_H -#ifdef _WIN32 -#pragma once -#endif - -#include "ai_basenpc.h" -#include "ai_behavior.h" -#include "ai_behavior_lead.h" -#include "ai_behavior_standoff.h" -#include "ai_behavior_assault.h" -#include "npc_playercompanion.h" - -#define VORTIGAUNT_MAX_BEAMS 8 - -class CBeam; -class CSprite; - -enum VortigauntHealState_t -{ - HEAL_STATE_NONE, - HEAL_STATE_WARMUP, - HEAL_STATE_HEALING, - HEAL_STATE_COOLDOWN, -}; - -//========================================================= -// >> CNPC_Vortigaunt -//========================================================= -class CNPC_Vortigaunt : public CNPC_PlayerCompanion -{ - DECLARE_CLASS( CNPC_Vortigaunt, CNPC_PlayerCompanion ); - -public: - virtual void Spawn( void ); - virtual void Precache( void ); - virtual float MaxYawSpeed( void ); - - virtual void PrescheduleThink( void ); - virtual void BuildScheduleTestBits( void ); - - virtual int RangeAttack1Conditions( float flDot, float flDist ); - - virtual void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - virtual void AlertSound( void ); - virtual Class_T Classify ( void ) { return CLASS_VORTIGAUNT; } - virtual void HandleAnimEvent( animevent_t *pEvent ); - virtual Activity NPC_TranslateActivity( Activity eNewActivity ); - - virtual void UpdateOnRemove( void ); - virtual void Event_Killed( const CTakeDamageInfo &info ); - virtual void GatherConditions( void ); - virtual void RunTask( const Task_t *pTask ); - virtual void StartTask( const Task_t *pTask ); - - // Navigation/Locomotion - virtual bool OnObstructionPreSteer( AILocalMoveGoal_t *pMoveGoal, float distClear, AIMoveResult_t *pResult ); - - virtual void DeclineFollowing( void ); - virtual bool CanBeUsedAsAFriend( void ); - virtual bool IsPlayerAlly( void ) { return true; } - - // Override these to set behavior - virtual int TranslateSchedule( int scheduleType ); - virtual int SelectSchedule( void ); - virtual bool IsValidEnemy( CBaseEntity *pEnemy ); - bool IsLeading( void ) { return ( GetRunningBehavior() == &m_LeadBehavior && m_LeadBehavior.HasGoal() ); } - - void DeathSound( const CTakeDamageInfo &info ); - void PainSound( const CTakeDamageInfo &info ); - - virtual void TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr ); - virtual void SpeakSentence( int sentType ); - - virtual int IRelationPriority( CBaseEntity *pTarget ); - virtual bool IsReadinessCapable( void ) { return true; } - virtual float GetReadinessDecay() { return 30.0f; } - virtual bool ShouldRegenerateHealth( void ) { return m_bRegenerateHealth; } - - void InputEnableArmorRecharge( inputdata_t &data ); - void InputDisableArmorRecharge( inputdata_t &data ); - void InputExtractBugbait( inputdata_t &data ); - void InputChargeTarget( inputdata_t &data ); - - // Health regeneration - void InputEnableHealthRegeneration( inputdata_t &data ); - void InputDisableHealthRegeneration( inputdata_t &data ); - -private: - - bool HealGestureHasLOS( void ); - bool PlayerBelowHealthPercentage( float flPerc ); - void StartHealing( void ); - void StopHealing( bool bInterrupt = false ); - void MaintainHealSchedule( void ); - bool ShouldHealTarget( CBaseEntity *pTarget, bool bResetTimer ); - int SelectHealSchedule( void ); - - Vector GetShootEnemyDir( const Vector &shootOrigin, bool bNoisy = true ); - void CreateBeamBlast( const Vector &vecOrigin ); - -private: - //========================================================= - // Vortigaunt schedules - //========================================================= - enum - { - SCHED_VORTIGAUNT_STAND = BaseClass::NEXT_SCHEDULE, - SCHED_VORTIGAUNT_RANGE_ATTACK, - SCHED_VORTIGAUNT_HEAL, - SCHED_VORTIGAUNT_EXTRACT_BUGBAIT, - SCHED_VORTIGAUNT_FACE_PLAYER, - SCHED_VORTIGAUNT_RUN_TO_PLAYER, - }; - - //========================================================= - // Vortigaunt Tasks - //========================================================= - enum - { - TASK_VORTIGAUNT_HEAL_WARMUP = BaseClass::NEXT_TASK, - TASK_VORTIGAUNT_HEAL, - TASK_VORTIGAUNT_EXTRACT_WARMUP, - TASK_VORTIGAUNT_EXTRACT, - TASK_VORTIGAUNT_EXTRACT_COOLDOWN, - TASK_VORTIGAUNT_FIRE_EXTRACT_OUTPUT, - TASK_VORTIGAUNT_WAIT_FOR_PLAYER, - TASK_VORTIGAUNT_GET_HEAL_TARGET, - }; - - //========================================================= - // Vortigaunt Conditions - //========================================================= - enum - { - COND_VORTIGAUNT_CAN_HEAL = BaseClass::NEXT_CONDITION, - COND_VORTIGAUNT_HEAL_TARGET_TOO_FAR, // Outside or heal range - COND_VORTIGAUNT_HEAL_TARGET_BLOCKED, // Blocked by an obstruction - COND_VORTIGAUNT_HEAL_TARGET_BEHIND_US, // Not within our "forward" range - COND_VORTIGAUNT_HEAL_VALID, // All conditions satisfied - }; - - // ------------ - // Beams - // ------------ - void ClearBeams( void ); - void ArmBeam( int side , int beamType); - void ZapBeam( int side ); - void BeamGlow( void ); - CHandle m_pBeam[VORTIGAUNT_MAX_BEAMS]; - int m_iBeams; - int m_nLightningSprite; - bool m_bHealBeamActive; - - // --------------- - // Glow - // ---------------- - void ClearHandGlow( void ); - float m_fGlowAge; - float m_fGlowScale; - float m_fGlowChangeTime; - bool m_bGlowTurningOn; - int m_nCurGlowIndex; - - CHandle m_pLeftHandGlow; - CHandle m_pRightHandGlow; - - void StartHandGlow( int beamType ); - void EndHandGlow( void ); - - // ---------------- - // Healing - // ---------------- - bool m_bRegenerateHealth; - float m_flNextHealTime; // Next time allowed to heal player - int m_nCurrentHealAmt; // How much healed this session - int m_nLastArmorAmt; // Player armor at end of last heal - int m_iSuitSound; // 0 = off, 1 = startup, 2 = going - float m_flSuitSoundTime; - EHANDLE m_hHealTarget; // The person that I'm going to heal. - - VortigauntHealState_t m_eHealState; - - void GatherHealConditions( void ); - void HealBeam( int side ); - - float m_flHealHinderedTime; - float m_flPainTime; - float m_nextLineFireTime; - bool m_bArmorRechargeEnabled; - bool m_bForceArmorRecharge; - int m_iCurrentRechargeGoal; - - bool m_bExtractingBugbait; - - COutputEvent m_OnFinishedExtractingBugbait; - COutputEvent m_OnFinishedChargingTarget; - COutputEvent m_OnPlayerUse; - - CAI_AssaultBehavior m_AssaultBehavior; - CAI_LeadBehavior m_LeadBehavior; - - //Adrian: Let's do it the right way! - int m_iLeftHandAttachment; - int m_iRightHandAttachment; - bool m_bStopLoopingSounds; - -public: - DECLARE_DATADESC(); - DEFINE_CUSTOM_AI; -}; - -#endif // NPC_VORTIGAUNT_H diff --git a/src/src/dlls/hl2_dll/player_control.cpp b/src/src/dlls/hl2_dll/player_control.cpp deleted file mode 100644 index 2de986c..0000000 --- a/src/src/dlls/hl2_dll/player_control.cpp +++ /dev/null @@ -1,266 +0,0 @@ -//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// -// -// Purpose: -// -// $NoKeywords: $ -//=============================================================================// - -#include "cbase.h" -#include "player_control.h" -#include "soundent.h" -#include "func_break.h" // For materials -#include "hl2_player.h" -#include "ai_hull.h" -#include "decals.h" -#include "shake.h" -#include "ndebugoverlay.h" - -// memdbgon must be the last include file in a .cpp file!!! -#include "tier0/memdbgon.h" - -BEGIN_DATADESC( CPlayer_Control ) - - DEFINE_FIELD( m_bActive, FIELD_BOOLEAN ), - DEFINE_FIELD( m_nSaveFOV, FIELD_INTEGER ), - DEFINE_FIELD( m_vSaveOrigin, FIELD_POSITION_VECTOR ), - DEFINE_FIELD( m_vSaveAngles, FIELD_VECTOR ), - DEFINE_FIELD( m_nSaveMoveType, FIELD_INTEGER ), - DEFINE_FIELD( m_nSaveMoveCollide, FIELD_INTEGER ), - DEFINE_FIELD( m_vSaveViewOffset, FIELD_VECTOR ), - DEFINE_FIELD( m_pSaveWeapon, FIELD_CLASSPTR ), - DEFINE_FIELD( m_nPClipTraceDir, FIELD_INTEGER), - DEFINE_FIELD( m_flCurrMinClipDist, FIELD_FLOAT), - DEFINE_FIELD( m_flLastMinClipDist, FIELD_FLOAT), - - // Inputs - DEFINE_INPUTFUNC( FIELD_VOID, "Activate", InputActivate ), - DEFINE_INPUTFUNC( FIELD_VOID, "Deactivate", InputDeactivate ), - DEFINE_INPUTFUNC( FIELD_FLOAT, "SetThrust", InputSetThrust ), - DEFINE_INPUTFUNC( FIELD_FLOAT, "SetSideThrust", InputSetSideThrust ), - -END_DATADESC() - - - -//------------------------------------------------------------------------------ -// Purpose: -//------------------------------------------------------------------------------ -void CPlayer_Control::Precache( void ) -{ - return; -} - -//------------------------------------------------------------------------------ -// Purpose: -//------------------------------------------------------------------------------ -void CPlayer_Control::Spawn( void ) -{ - Precache(); - SetFriction( 0.55 ); // deading the bounce a bit - - m_bActive = false; - - CreateVPhysics(); -} - -//----------------------------------------------------------------------------- - -bool CPlayer_Control::CreateVPhysics( void ) -{ - // Create the object in the physics system - VPhysicsInitNormal( SOLID_BBOX, 0, false ); - return true; -} - - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CPlayer_Control::ControlActivate( void ) -{ - m_bActive = true; - AddEffects( EF_NODRAW ); - m_nPClipTraceDir = PC_TRACE_LAST; - m_flCurrMinClipDist = PCONTROL_CLIP_DIST; - - SetNextThink( gpGlobals->curtime ); - - CHL2_Player* pPlayer = (CHL2_Player*)UTIL_GetLocalPlayer(); - - Assert( pPlayer ); - - // Save Data - m_nSaveFOV = pPlayer->GetFOV(); - m_vSaveOrigin = pPlayer->GetLocalOrigin(); - m_vSaveAngles = pPlayer->pl.v_angle; - m_nSaveMoveType = pPlayer->GetMoveType(); - m_nSaveMoveCollide = pPlayer->GetMoveCollide(); - m_vSaveViewOffset = pPlayer->GetViewOffset(); - m_pSaveWeapon = pPlayer->GetActiveWeapon(); - - pPlayer->AddSolidFlags( FSOLID_NOT_SOLID ); - pPlayer->SetLocalOrigin( GetLocalOrigin() ); - pPlayer->pl.v_angle = GetLocalAngles(); - pPlayer->SetViewOffset( vec3_origin ); - - DispatchUpdateTransmitState(); -} - - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CPlayer_Control::ControlDeactivate( void ) -{ - m_bActive = false; - RemoveEffects( EF_NODRAW ); - - SetThink(NULL); - SetTouch(NULL); - - CHL2_Player* pPlayer = (CHL2_Player*)UTIL_GetLocalPlayer(); - - Assert( pPlayer ); - - // Restore Data - pPlayer->SetFOV( this, m_nSaveFOV ); - pPlayer->RemoveSolidFlags( FSOLID_NOT_SOLID ); - pPlayer->SetLocalOrigin( m_vSaveOrigin ); - pPlayer->SetLocalAngles( m_vSaveAngles ); // Note: Set GetLocalAngles(), not pl->v_angle - pPlayer->SnapEyeAngles( m_vSaveAngles ); - pPlayer->StopFollowingEntity(); - pPlayer->SetMoveType( m_nSaveMoveType, m_nSaveMoveCollide ); - pPlayer->SetViewOffset( m_vSaveViewOffset ); - pPlayer->SetControlClass( CLASS_NONE ); - - DispatchUpdateTransmitState(); -} - - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CPlayer_Control::InputActivate( inputdata_t &inputdata ) -{ - ControlActivate(); -} - - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CPlayer_Control::InputDeactivate( inputdata_t &inputdata ) -{ - ControlDeactivate(); -} - - -//------------------------------------------------------------------------------ -// Purpose: -//------------------------------------------------------------------------------ -void CPlayer_Control::InputSetThrust( inputdata_t &inputdata ) -{ - // Should be handles by subclass - return; -} - - -//------------------------------------------------------------------------------ -// Purpose: -//------------------------------------------------------------------------------ -void CPlayer_Control::InputSetSideThrust( inputdata_t &inputdata ) -{ - // Should be handles by subclass - return; -} - - -//------------------------------------------------------------------------------ -// Purpose: -//------------------------------------------------------------------------------ -float CPlayer_Control::PlayerControlClipDistance(void) -{ - // Send out a curb feeler, but not in every direction on every time. Instead - // send out a feeling in one direction each time and keep track of the nearest - // player_control_clip - - // Reset if on last trace - if (m_nPClipTraceDir == PC_TRACE_LAST) - { - m_nPClipTraceDir = 0; - m_flLastMinClipDist = m_flCurrMinClipDist; - m_flCurrMinClipDist = PCONTROL_CLIP_DIST; - } - - Vector vForward,vRight,vUp; - AngleVectors( GetLocalAngles(), &vForward, &vRight,&vUp); - - Vector vTracePos = GetAbsOrigin(); - switch (m_nPClipTraceDir) - { - case PC_TRACE_LEFT: - { - vTracePos -= vRight*PCONTROL_CLIP_DIST; - } - case PC_TRACE_RIGHT: - { - vTracePos += vRight*PCONTROL_CLIP_DIST; - } - case PC_TRACE_UP: - { - vTracePos += vUp*PCONTROL_CLIP_DIST; - } - case PC_TRACE_DOWN: - { - vTracePos -= vUp*PCONTROL_CLIP_DIST; - } - case PC_TRACE_FORWARD: - { - vTracePos += 2*vForward*PCONTROL_CLIP_DIST; - } - } - - // Trace in a different direction next time - m_nPClipTraceDir++; - - - trace_t tr; - UTIL_TraceLine(GetAbsOrigin(), vTracePos, CONTENTS_MIST, this, COLLISION_GROUP_NONE, &tr); - - if (tr.fraction < 1.0) - { - surfacedata_t* pSurface = physprops->GetSurfaceData( tr.surface.surfaceProps ); - char m_chTextureType = pSurface->game.material; - - if (m_chTextureType == CHAR_TEX_CLIP) - { - float flClipDist = tr.fraction * (GetAbsOrigin()-vTracePos).Length(); - if (flClipDist < m_flCurrMinClipDist) - { - m_flCurrMinClipDist = flClipDist; - } - if (flClipDist < m_flLastMinClipDist) - { - m_flLastMinClipDist = flClipDist; - } - } - } - - return m_flLastMinClipDist; -} - -//------------------------------------------------------------------------------ -// Purpose: -//------------------------------------------------------------------------------ -int CPlayer_Control::UpdateTransmitState() -{ - if ( m_bActive ) - { - return SetTransmitState( FL_EDICT_ALWAYS ); - } - else - { - return BaseClass::UpdateTransmitState(); - } -} - diff --git a/src/src/dlls/hl2_dll/player_control.h b/src/src/dlls/hl2_dll/player_control.h deleted file mode 100644 index c478292..0000000 --- a/src/src/dlls/hl2_dll/player_control.h +++ /dev/null @@ -1,68 +0,0 @@ -//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// -// -// Purpose: -// -// $NoKeywords: $ -//=============================================================================// - -#ifndef PLAYER_CONTROL_H -#define PLAYER_CONTROL_H -#ifdef _WIN32 -#pragma once -#endif - -#include "basecombatcharacter.h" - - -enum PC_TraceDir_t -{ - PC_TRACE_LEFT, - PC_TRACE_RIGHT, - PC_TRACE_UP, - PC_TRACE_DOWN, - PC_TRACE_FORWARD, - PC_TRACE_LAST, -}; - -#define PCONTROL_CLIP_DIST 1600 - -class CPlayer_Control : public CBaseCombatCharacter -{ -public: - DECLARE_CLASS( CPlayer_Control, CBaseCombatCharacter ); - - void ControlActivate( void ); - void ControlDeactivate( void ); - - void Precache(void); - void Spawn(void); - bool CreateVPhysics( void ); - int UpdateTransmitState(); - - // Inputs - void InputActivate( inputdata_t &inputdata ); - void InputDeactivate( inputdata_t &inputdata ); - void InputSetThrust( inputdata_t &inputdata ); - void InputSetSideThrust( inputdata_t &inputdata ); - - float PlayerControlClipDistance(void); - - bool m_bActive; - - // Static - int m_nPClipTraceDir; - float m_flCurrMinClipDist; - float m_flLastMinClipDist; - - int m_nSaveFOV; - Vector m_vSaveOrigin; - QAngle m_vSaveAngles; - MoveType_t m_nSaveMoveType; - MoveCollide_t m_nSaveMoveCollide; - Vector m_vSaveViewOffset; - CBaseCombatWeapon* m_pSaveWeapon; - - DECLARE_DATADESC(); -}; - -#endif // PLAYER_CONTROL_H diff --git a/src/src/dlls/hl2_dll/player_manhack.cpp b/src/src/dlls/hl2_dll/player_manhack.cpp deleted file mode 100644 index 34ed840..0000000 --- a/src/src/dlls/hl2_dll/player_manhack.cpp +++ /dev/null @@ -1,400 +0,0 @@ -//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// -// -// Purpose: -// -// $NoKeywords: $ -//=============================================================================// - -#include "cbase.h" - -#if 0 -#include "ai_basenpc.h" -#include "basecombatweapon.h" // For SpawnBlood -#include "soundent.h" -#include "func_break.h" // For materials -#include "hl2_player.h" -#include "ai_hull.h" -#include "decals.h" -#include "shake.h" -#include "ndebugoverlay.h" -#include "player_control.h" -#include "IEffects.h" -#include "engine/IEngineSound.h" - -// memdbgon must be the last include file in a .cpp file!!! -#include "tier0/memdbgon.h" - -#define PMANHACK_OFFSET Vector(0,0,-18) -#define PMANHACK_HULL_MINS Vector(-22,-22,-22) -#define PMANHACK_HULL_MAXS Vector(22,22,22) -#define PMANHACK_MAX_SPEED 400 -#define PMANHACK_DECAY 6 - - -class CPlayer_Manhack : public CPlayer_Control -{ -public: - DECLARE_CLASS( CPlayer_Manhack, CPlayer_Control ); - - void Precache(void); - void Spawn(void); - bool CreateVPhysics( void ); - - // Inputs - void InputActivate( inputdata_t &inputdata ); - void InputDeactivate( inputdata_t &inputdata ); - void InputSetThrust( inputdata_t &inputdata ); - void InputSetSideThrust( inputdata_t &inputdata ); - - void FlyThink(void); - void CheckBladeTrace(trace_t &tr); - - DECLARE_DATADESC(); -}; - - -BEGIN_DATADESC( CPlayer_Manhack ) - - // Function Pointers - DEFINE_FUNCTION( FlyThink ), - -END_DATADESC() - -LINK_ENTITY_TO_CLASS( player_manhack, CPlayer_Manhack ); - - -//------------------------------------------------------------------------------ -// Purpose : -// Input : -// Output : -//------------------------------------------------------------------------------ -void CPlayer_Manhack::Precache( void ) -{ - PrecacheModel("models/manhack.mdl"); - PrecacheModel("models/manhack_sphere.mdl"); - - PrecacheScriptSound( "Player_Manhack.ThrustLow"" ); - PrecacheScriptSound( "Player_Manhack.ThrustHigh" ); - PrecacheScriptSound( "Player_Manhack.GrindFlesh" ); - PrecacheScriptSound( "Player_Manhack.Grind" ); - -} - -//------------------------------------------------------------------------------ -// Purpose : -// Input : -// Output : -//------------------------------------------------------------------------------ -void CPlayer_Manhack::Spawn( void ) -{ - Precache(); - m_flFriction = 0.55; // deading the bounce a bit - - SetModel( "models/manhack.mdl" ); - UTIL_SetSize(this, PMANHACK_HULL_MINS, PMANHACK_HULL_MAXS); - - m_bActive = false; - - CreateVPhysics(); -} - -//----------------------------------------------------------------------------- - -bool CPlayer_Manhack::CreateVPhysics( void ) -{ - // Create the object in the physics system - VPhysicsInitNormal( SOLID_BBOX, 0, false ); - - return true; -} - -//----------------------------------------------------------------------------- -// Purpose: Input handler for turning on the manhack -//----------------------------------------------------------------------------- -void CPlayer_Manhack::InputActivate( inputdata_t &inputdata ) -{ - BaseClass::InputActivate( inputdata ); - - SetThink(FlyThink); - - // Switch to a bigger model (a sphere) that keeps the player's - // camera outside of walls - VPhysicsDestroyObject(); - SetModel("models/manhack_sphere.mdl" ); - VPhysicsInitNormal( GetSolid(), GetSolidFlags(), false ); - - CHL2_Player* pPlayer = (CHL2_Player*)UTIL_GetLocalPlayer(); - - Assert( pPlayer ); - - pPlayer->SetFOV( 132 ); - pPlayer->FollowEntity( this ); - pPlayer->m_nControlClass = CLASS_MANHACK; - pPlayer->GiveNamedItem( "weapon_manhack" ); -} - -//----------------------------------------------------------------------------- -// Purpose: Input handler for turning off the manhack. -//----------------------------------------------------------------------------- -void CPlayer_Manhack::InputDeactivate( inputdata_t &inputdata ) -{ - BaseClass::InputDeactivate( inputdata ); - - CHL2_Player* pPlayer = (CHL2_Player*)UTIL_GetLocalPlayer(); - - Assert( pPlayer ); - - StopSound( pPlayer->entindex(), "Player_Manhack.GrindFlesh" ); - StopSound( pPlayer->entindex(), "Player_Manhack.Grind"); - StopSound( pPlayer->entindex(), "Player_Manhack.ThrustLow" ); - StopSound( pPlayer->entindex(), "Player_Manhack.ThrustHigh" ); - - // Remove manhack blade weapon from player's inventory - CBaseEntity* pBlade = (CBaseEntity*)(pPlayer->GetActiveWeapon()); - pPlayer->Weapon_Drop( GetActiveWeapon() ); - if (m_pSaveWeapon) - { - pPlayer->Weapon_Switch( m_pSaveWeapon ); - } - UTIL_Remove(pBlade); - - // Switch back to manhack model - VPhysicsDestroyObject(); - SetModel("models/manhack.mdl" ); - VPhysicsInitNormal( GetSolid(), GetSolidFlags(), false ); -} - -//------------------------------------------------------------------------------ -// Purpose: -//------------------------------------------------------------------------------ -void CPlayer_Manhack::InputSetThrust( inputdata_t &inputdata ) -{ - if (!m_bActive) - { - return; - } - - CBasePlayer* pPlayer = UTIL_GetLocalPlayer(); - - Assert( pPlayer ); - - if (inputdata.value.Float() == 0) - { - CPASAttenuationFilter filter( pPlayer, "Player_Manhack.ThrustLow" ); - EmitSound( filter, pPlayer->entindex(), "Player_Manhack.ThrustLow" ); - return; - } - CPASAttenuationFilter filter( pPlayer, "Player_Manhack.ThrustHigh" ); - EmitSound( filter, pPlayer->entindex(), "Player_Manhack.ThrustHigh" ); - - - Vector vForce; - pPlayer->EyeVectors( &vForce ); - vForce = vForce * inputdata.value.Float() * 600; - - IPhysicsObject* pPhysObj = VPhysicsGetObject(); - pPhysObj->ApplyForceCenter( vForce ); -} - - -//------------------------------------------------------------------------------ -// Purpose: -//------------------------------------------------------------------------------ -void CPlayer_Manhack::InputSetSideThrust( inputdata_t &inputdata ) -{ - if (!m_bActive) - { - return; - } - - CBasePlayer* pPlayer = UTIL_GetLocalPlayer(); - - Assert( pPlayer ); - - if (inputdata.value.Float() == 0) - { - CPASAttenuationFilter filter( pPlayer, "Player_Manhack.ThrustLow" ); - EmitSound( filter, pPlayer->entindex(), "Player_Manhack.ThrustLow" ); - return; - } - CPASAttenuationFilter filter( pPlayer, "Player_Manhack.ThrustHigh" ); - EmitSound( filter, pPlayer->entindex(), "Player_Manhack.ThrustHigh" ); - - - Vector vForce; - pPlayer->EyeVectors( 0, &vForce, 0 ); - vForce = vForce * inputdata.value.Float() * 600; - - IPhysicsObject* pPhysObj = VPhysicsGetObject(); - pPhysObj->ApplyForceCenter( vForce ); -} - - -//------------------------------------------------------------------------------ -// Purpose : -// Input : -// Output : -//------------------------------------------------------------------------------ -void CPlayer_Manhack::CheckBladeTrace(trace_t &tr) -{ - CBaseEntity* pHitEntity = NULL; - CBasePlayer* pPlayer = UTIL_GetLocalPlayer(); - - Assert( pPlayer ); - - if (tr.u.ent) - { - pHitEntity = CBaseEntity::Instance( tr.u.ent ); - - // Did I hit an entity that isn't a player? - if (pHitEntity && pHitEntity->Classify()!=CLASS_PLAYER) - { - CTakeDamageInfo info( this, this, 1, DMG_SLASH ); - CalculateMeleeDamageForce( &info, (tr.endpos - tr.endpos), tr.endpos ); - pHitEntity->TakeDamage( info ); - } - } - if (tr.fraction != 1.0 || tr.startsolid) - { - - CBaseCombatCharacter* pBCC = ToBaseCombatCharacter( pHitEntity ); - - if (pBCC) - { - // Spawn some extra blood in front of player to see - Vector vPlayerFacing; - pPlayer->EyeVectors( &vPlayerFacing ); - Vector vBloodPos = pPlayer->Center() + vPlayerFacing*30; - SpawnBlood(vBloodPos, g_vecAttackDir, pBCC->BloodColor(), 1.0); - - CPASAttenuationFilter filter( pPlayer, "Player_Manhack.GrindFlesh" ); - EmitSound( filter, pPlayer->entindex(), "Player_Manhack.GrindFlesh" ); - } - else - { - if (!(m_spawnflags & SF_NPC_GAG)) - { - CPASAttenuationFilter filter( pPlayer, "Player_Manhack.Grind" ); - EmitSound( filter, pPlayer->entindex(), "Player_Manhack.Grind" ); - } - // For decals and sparks we must trace a line in the direction of the surface norm - // that we hit. - Vector vCheck = GetAbsOrigin() - (tr.plane.normal * 24); - - UTIL_TraceLine( GetAbsOrigin()+PMANHACK_OFFSET, vCheck+PMANHACK_OFFSET,MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr ); - if (tr.fraction != 1.0) - { - g_pEffects->Sparks( tr.endpos ); - - CBroadcastRecipientFilter filter; - te->DynamicLight( filter, 0.0, - &tr.endpos, 255, 180, 100, 0, 10, 0.1, 0 ); - - - // Leave decal only if colliding horizontally - if ((DotProduct(Vector(0,0,1),tr.plane.normal)<0.5) && (DotProduct(Vector(0,0,-1),tr.plane.normal)<0.5)) - { - UTIL_DecalTrace( &tr, "ManhackCut" ); - } - } - } - } -} - -//----------------------------------------------------------------------------- -// Purpose: Manhack is still dangerous when dead -// Input : -// Output : -//----------------------------------------------------------------------------- -void CPlayer_Manhack::FlyThink() -{ - SetNextThink( gpGlobals->curtime ); - - // Get physics object - IPhysicsObject* pPhysObj = VPhysicsGetObject(); - if (!pPhysObj) return; - Vector vPhysPos; - pPhysObj->GetPosition(&vPhysPos,NULL); - - // Update the player's origin - CBasePlayer* pPlayer = UTIL_GetLocalPlayer(); - - Assert( pPlayer ); - - Vector vPlayerFacing; - pPlayer->EyeVectors( &vPlayerFacing ); - - - UTIL_SetOrigin(pPlayer,vPhysPos); - - float flBrightness; - if (random->RandomInt(0,1)==0) - { - flBrightness = 255; - } - else - { - flBrightness = 1; - } - color32 white = {flBrightness,flBrightness,flBrightness,20}; - UTIL_ScreenFade( pPlayer, white, 0.01, 0.1, FFADE_MODULATE ); - - flBrightness = random->RandomInt(0,255); - NDebugOverlay::ScreenText( 0.4, 0.15, "...M A N H A C K A C T I V A T E D...", 255, flBrightness, flBrightness, 255, 0.0); - - // ---------------------------------------- - // Trace forward to see if I hit anything - // ---------------------------------------- - trace_t tr; - Vector vVelocity; - GetVelocity( &vVelocity, NULL ); - vVelocity.z = 0; - Vector vCheckPos = GetAbsOrigin() + (vVelocity*gpGlobals->frametime); - - // Check in movement direction - UTIL_TraceHull( GetAbsOrigin()+PMANHACK_OFFSET, vCheckPos+PMANHACK_OFFSET, - Vector(-22,-22,-1), Vector(22,22,1), - MASK_SOLID, this, COLLISION_GROUP_NONE, &tr ); - CheckBladeTrace(tr); - - // Check in facing direction - UTIL_TraceHull( GetAbsOrigin()+PMANHACK_OFFSET, GetAbsOrigin() + vPlayerFacing*14 + PMANHACK_OFFSET, - Vector(-22,-22,-1), Vector(22,22,1), - MASK_SOLID, this, COLLISION_GROUP_NONE, &tr ); - CheckBladeTrace(tr); - - // ---------- - // Add decay - // ---------- - Vector vOldVelocity; - pPhysObj->GetVelocity(&vOldVelocity,NULL); - float flDecay = -PMANHACK_DECAY*gpGlobals->frametime; - if (flDecay < -1.0) - { - flDecay = -1.0; - } - pPhysObj->ApplyForceCenter( flDecay*vOldVelocity ); - - // ----------------------- - // Hover noise - // ----------------------- - float flNoise1 = 1000*sin(4*gpGlobals->curtime); - float flNoise = 12000+ flNoise1; - - Vector vForce = Vector(0,0,flNoise*gpGlobals->frametime); - pPhysObj->ApplyForceCenter( vForce ); - - // ----------------------- - // Limit velocity - // ----------------------- - pPhysObj->GetVelocity(&vOldVelocity,NULL); - if (vOldVelocity.Length() > PMANHACK_MAX_SPEED) - { - Vector vNewVelocity = vOldVelocity; - VectorNormalize(vNewVelocity); - vNewVelocity = vNewVelocity *PMANHACK_MAX_SPEED; - Vector vSubtract = vNewVelocity - vOldVelocity; - pPhysObj->AddVelocity(&vSubtract,NULL); - } -} -#endif \ No newline at end of file diff --git a/src/src/dlls/hl2_dll/player_missile.cpp b/src/src/dlls/hl2_dll/player_missile.cpp deleted file mode 100644 index 654b761..0000000 --- a/src/src/dlls/hl2_dll/player_missile.cpp +++ /dev/null @@ -1,543 +0,0 @@ -//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// -// -// Purpose: -// -// $NoKeywords: $ -//=============================================================================// - -#include "cbase.h" -#include "player_control.h" -#include "hl2_player.h" -#include "decals.h" -#include "shake.h" -#include "soundent.h" -#include "ndebugoverlay.h" -#include "smoke_trail.h" -#include "grenade_homer.h" -#include "vstdlib/random.h" -#include "engine/IEngineSound.h" - -// memdbgon must be the last include file in a .cpp file!!! -#include "tier0/memdbgon.h" - -#define PMISSILE_MISSILE_MODEL "models/weapons/w_missile.mdl" -#define PMISSILE_HULL_MINS Vector(-22,-22,-22) -#define PMISSILE_HULL_MAXS Vector(22,22,22) -#define PMISSILE_SPEED 800 -#define PMISSILE_TURN_RATE 100 -#define PMISSILE_DIE_TIME 2 -#define PMISSILE_TRAIL_LIFE 6 -#define PMISSILE_LOSE_CONTROL_DIST 30 -#define PMISSILE_DANGER_SOUND_DURATION 0.1 - - -extern short g_sModelIndexFireball; - - -class CPlayer_Missile : public CPlayer_Control -{ -public: - DECLARE_CLASS( CPlayer_Missile, CPlayer_Control ); - - void Precache(void); - void Spawn(void); - Class_T Classify( void); - - void ControlActivate( void ); - void ControlDeactivate( void ); - - // Inputs - void InputActivate( inputdata_t &inputdata ); - void InputDeactivate( inputdata_t &inputdata ); - - void Launch(void); - void FlyThink(void); - void ExplodeThink(void); - void RemoveThink(void); - void FlyTouch( CBaseEntity *pOther ); - void BlowUp(void); - void LoseMissileControl(void); - - void Event_Killed( const CTakeDamageInfo &info ); - int OnTakeDamage_Alive( const CTakeDamageInfo &info ); - - CPlayer_Missile(); - - float m_flLaunchDelay; - float m_flDamage; - float m_flDamageRadius; - CHandle m_hSmokeTrail; - Vector m_vSpawnPos; - QAngle m_vSpawnAng; - Vector m_vBounceVel; - bool m_bShake; - float m_flStatic; - float m_flNextDangerTime; - - DECLARE_DATADESC(); -}; - - -BEGIN_DATADESC( CPlayer_Missile ) - - DEFINE_KEYFIELD( m_flLaunchDelay, FIELD_FLOAT, "LaunchDelay"), - DEFINE_KEYFIELD( m_flDamage, FIELD_FLOAT, "Damage"), - DEFINE_KEYFIELD( m_flDamageRadius, FIELD_FLOAT, "DamageRadius"), - - - // Fields - DEFINE_FIELD( m_hSmokeTrail, FIELD_EHANDLE), - DEFINE_FIELD( m_vSpawnPos, FIELD_POSITION_VECTOR ), - DEFINE_FIELD( m_vSpawnAng, FIELD_VECTOR ), - DEFINE_FIELD( m_vBounceVel, FIELD_VECTOR ), - DEFINE_FIELD( m_bShake, FIELD_BOOLEAN ), - DEFINE_FIELD( m_flStatic, FIELD_FLOAT ), - DEFINE_FIELD( m_flNextDangerTime, FIELD_TIME ), - - - // Function Pointers - DEFINE_FUNCTION( Launch ), - DEFINE_FUNCTION( FlyThink ), - DEFINE_FUNCTION( ExplodeThink ), - DEFINE_FUNCTION( RemoveThink ), - DEFINE_FUNCTION( FlyTouch ), - -END_DATADESC() - -LINK_ENTITY_TO_CLASS( player_missile, CPlayer_Missile ); - -//------------------------------------------------------------------------------ -// Purpose : -//------------------------------------------------------------------------------ -void CPlayer_Missile::Precache( void ) -{ - PrecacheModel("models/manhack_sphere.mdl"); - PrecacheModel( PMISSILE_MISSILE_MODEL ); - - PrecacheScriptSound( "Player_Manhack.Fly" ); - PrecacheScriptSound( "Player_Manhack.Fire" ); - PrecacheScriptSound( "Player_Manhack.Damage" ); - -} - -//------------------------------------------------------------------------------ -// Purpose : -//------------------------------------------------------------------------------ -void CPlayer_Missile::Spawn( void ) -{ - Precache(); - SetMoveType( MOVETYPE_FLY ); - SetFriction( 0.55 ); // deading the bounce a bit - SetGravity(0.0); - m_iMaxHealth = m_iHealth; - m_iHealth = 0; - - SetSolid( SOLID_BBOX ); - AddEffects( EF_NODRAW ); - AddFlag( FL_OBJECT ); // So shows up in NPC Look() - - SetModel( "models/manhack_sphere.mdl" ); - UTIL_SetSize(this, PMISSILE_HULL_MINS, PMISSILE_HULL_MAXS); - - m_bActive = false; - m_vSpawnPos = GetLocalOrigin(); - m_vSpawnAng = GetLocalAngles(); -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CPlayer_Missile::InputActivate( inputdata_t &inputdata ) -{ - // Make sure not already active - if (m_bActive) - { - return; - } - - BaseClass::InputActivate( inputdata ); - - Vector origin = GetLocalOrigin(); - origin.z += 50; - SetLocalOrigin( origin ); - RemoveSolidFlags( FSOLID_NOT_SOLID ); - - // Using player angles to determine turning. Initailze to 0,0,0 - CHL2_Player* pPlayer = (CHL2_Player*)UTIL_GetLocalPlayer(); - - Assert( pPlayer ); - - pPlayer->SetLocalAngles( vec3_angle ); // Note: Set GetLocalAngles(), not pl.v_angle - pPlayer->SnapEyeAngles( vec3_angle ); // Force reset - pPlayer->SetFOV( this, 100 ); - - pPlayer->SetViewEntity( this ); - - m_flStatic = 0; - SetThink(Launch); - SetNextThink( gpGlobals->curtime + m_flLaunchDelay ); -} - - -//------------------------------------------------------------------------------ -// Purpose : -//------------------------------------------------------------------------------ -void CPlayer_Missile::Launch(void) -{ - m_lifeState = LIFE_ALIVE; - m_takedamage = DAMAGE_YES; - m_iHealth = m_iMaxHealth; - - // Shoot forward - Vector vVelocity; - AngleVectors( GetLocalAngles(), &vVelocity); - SetAbsVelocity( vVelocity*PMISSILE_SPEED ); - - EmitSound( "Player_Manhack.Fly" ); - EmitSound( "Player_Manhack.Fire" ); - - - SetThink(FlyThink); - SetTouch(FlyTouch); - SetNextThink( gpGlobals->curtime ); - - // Start smoke trail - SmokeTrail *pSmokeTrail = SmokeTrail::CreateSmokeTrail(); - if(pSmokeTrail) - { - pSmokeTrail->m_SpawnRate = 90; - pSmokeTrail->m_ParticleLifetime = PMISSILE_TRAIL_LIFE; - pSmokeTrail->m_StartColor.Init(0.1, 0.1, 0.1); - pSmokeTrail->m_EndColor.Init(0.5,0.5,0.5); - pSmokeTrail->m_StartSize = 10; - pSmokeTrail->m_EndSize = 50; - pSmokeTrail->m_SpawnRadius = 1; - pSmokeTrail->m_MinSpeed = 15; - pSmokeTrail->m_MaxSpeed = 25; - pSmokeTrail->SetLifetime(120); - pSmokeTrail->FollowEntity(this); - - m_hSmokeTrail = pSmokeTrail; - } -} - -//----------------------------------------------------------------------------- -// Purpose: Input handler for turning off the steam jet. -//----------------------------------------------------------------------------- -void CPlayer_Missile::InputDeactivate( inputdata_t &inputdata ) -{ - ControlDeactivate(); -} - - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CPlayer_Missile::ControlDeactivate( void ) -{ - BaseClass::ControlDeactivate(); - - CHL2_Player* pPlayer = (CHL2_Player*)UTIL_GetLocalPlayer(); - - Assert( pPlayer ); - - pPlayer->SetViewEntity( pPlayer ); - - if ( pPlayer->GetActiveWeapon() ) - { - pPlayer->GetActiveWeapon()->Deploy(); - } - - pPlayer->m_Local.m_iHideHUD &= ~HIDEHUD_WEAPONSELECTION; - - SetAbsVelocity( vec3_origin ); - SetLocalAngles( m_vSpawnAng ); - SetLocalOrigin( m_vSpawnPos ); - AddEffects( EF_NODRAW ); -} - - -//------------------------------------------------------------------------------ -// Purpose : -//------------------------------------------------------------------------------ -int CPlayer_Missile::OnTakeDamage_Alive( const CTakeDamageInfo &info ) -{ - if ( (info.GetDamageType() & DMG_MISSILEDEFENSE)) - { - if (random->RandomInt(0,1)==0) - { - EmitSound( "Player_Manhack.Damage" ); - } - m_bShake = true; - } - else - { - // UNDONE: Blow up to anything else for now - BlowUp(); - } - return BaseClass::OnTakeDamage_Alive( info ); -} - - -//----------------------------------------------------------------------------- -// Purpose: Blow it up -//----------------------------------------------------------------------------- -void CPlayer_Missile::Event_Killed( const CTakeDamageInfo &info ) -{ - BlowUp(); -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CPlayer_Missile::FlyTouch(CBaseEntity *pOther) -{ - BlowUp(); -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CPlayer_Missile::BlowUp(void) -{ - // Don't take damage any more - m_takedamage = DAMAGE_NO; - - // Mark as dead so won't be attacked - m_lifeState = LIFE_DEAD; - - // Stop fly and launch sounds - StopSound( "Player_Manhack.Fly" ); - StopSound( "Player_Manhack.Fire" ); - - CPASFilter filter( GetAbsOrigin() ); - te->Explosion( filter, 0.0, - &GetAbsOrigin(), - g_sModelIndexFireball, - 2.0, - 15, - TE_EXPLFLAG_NONE, - m_flDamageRadius, - m_flDamage ); - - Vector vecForward = GetAbsVelocity(); - VectorNormalize(vecForward); - trace_t tr; - UTIL_TraceLine ( GetAbsOrigin(), GetAbsOrigin() + 60*vecForward, MASK_SOLID_BRUSHONLY, - this, COLLISION_GROUP_NONE, &tr); - - UTIL_DecalTrace( &tr, "Scorch" ); - - UTIL_ScreenShake( GetAbsOrigin(), 25.0, 150.0, 1.0, 750, SHAKE_START ); - CSoundEnt::InsertSound ( SOUND_DANGER, GetAbsOrigin(), 1024, 3.0 ); - - RadiusDamage ( CTakeDamageInfo( this, this, m_flDamage, DMG_BLAST ), GetAbsOrigin(), m_flDamageRadius, CLASS_NONE, NULL ); - - SetThink(ExplodeThink); - SetTouch(NULL); - m_vBounceVel = -0.2 * GetAbsVelocity(); - AddSolidFlags( FSOLID_NOT_SOLID ); - - // Stop emitting smoke - if(m_hSmokeTrail) - { - m_hSmokeTrail->SetEmit(false); - } -} - -//----------------------------------------------------------------------------- -// Purpose: Manhack is still dangerous when dead -// Input : -// Output : -//----------------------------------------------------------------------------- -void CPlayer_Missile::FlyThink() -{ - SetNextThink( gpGlobals->curtime ); - - // ------------------- - // Get the player - // ------------------- - CBasePlayer* pPlayer = UTIL_GetLocalPlayer(); - if (!pPlayer) return; - - // --------------------------------------------------- - // Calulate amount of xturn from player mouse movement - // --------------------------------------------------- - QAngle vecViewAngles = pPlayer->EyeAngles(); - float xLev; - if (vecViewAngles.x < 180) - { - xLev = vecViewAngles.x/180; - } - else - { - xLev = (vecViewAngles.x-360)/180; - } - - // --------------------------------------------------- - // Calulate amount of xturn from player mouse movement - // --------------------------------------------------- - float yLev; - - // Keep yaw in bounds (don't let loop) - if (vecViewAngles.y > 90) - { - if (vecViewAngles.y < 180) - { - pPlayer->SetLocalAngles( QAngle( vecViewAngles.x - 360, 90, 0 ) ); - - QAngle newViewAngles = vecViewAngles; - newViewAngles.y = 90; - pPlayer->SnapEyeAngles( newViewAngles ); - } - else if (vecViewAngles.y < 270) - { - pPlayer->SetLocalAngles( QAngle( vecViewAngles.x, 270, 0 ) ); - - QAngle newViewAngles = vecViewAngles; - newViewAngles.y = 270; - pPlayer->SnapEyeAngles( newViewAngles ); - } - - } - - if (vecViewAngles.y < 180) - { - yLev = vecViewAngles.y/180; - } - else - { - yLev = (vecViewAngles.y-360)/180; - } - - //<> this is a temp HUD until we create a real one on the client - NDebugOverlay::ScreenText( 0.5, 0.5+0.2*xLev, "|", 255, 0, 0, 255, 0.0); - NDebugOverlay::ScreenText( 0.5-(0.1*yLev), 0.5, "=", 255, 0, 0, 255, 0.0); - NDebugOverlay::ScreenText( 0.5-(0.1*yLev), 0.5+0.2*xLev, "*", 255, 0, 0, 255, 0.0); - NDebugOverlay::ScreenText( 0.45, 0.5, "-----------------------", 0, 255, 0, 255, 0.0); - NDebugOverlay::ScreenText( 0.5, 0.425, "|", 0, 255, 0, 255, 0.0); - NDebugOverlay::ScreenText( 0.5, 0.45, "|", 0, 255, 0, 255, 0.0); - NDebugOverlay::ScreenText( 0.5, 0.475, "|", 0, 255, 0, 255, 0.0); - NDebugOverlay::ScreenText( 0.5, 0.5, "|", 0, 255, 0, 255, 0.0); - NDebugOverlay::ScreenText( 0.5, 0.525, "|", 0, 255, 0, 255, 0.0); - NDebugOverlay::ScreenText( 0.5, 0.55, "|", 0, 255, 0, 255, 0.0); - NDebugOverlay::ScreenText( 0.5, 0.575, "|", 0, 255, 0, 255, 0.0); - - // Add in turn - Vector vRight,vUp; - AngleVectors( GetLocalAngles(), 0, &vRight,&vUp); - QAngle angles = GetLocalAngles(); - - angles.x += PMISSILE_TURN_RATE*xLev*gpGlobals->frametime; - angles.y += PMISSILE_TURN_RATE*yLev*gpGlobals->frametime; - - if (m_bShake) - { - angles.x += random->RandomFloat(-3.0,3.0); - angles.y += random->RandomFloat(-3.0,3.0); - m_bShake = false; - } - - SetLocalAngles( angles ); - - // Reset velocity - Vector vVelocity; - AngleVectors( GetLocalAngles(), &vVelocity); - SetAbsVelocity( vVelocity*PMISSILE_SPEED ); - - // Add some screen noise - float flClipDist = PlayerControlClipDistance(); - - if (flClipDist < PMISSILE_LOSE_CONTROL_DIST) - { - LoseMissileControl(); - } - - // Average static over time - float flStatic = 255*(1-flClipDist/PCONTROL_CLIP_DIST); - m_flStatic = 0.9*m_flStatic + 0.1*flStatic; - color32 white = {255,255,255,m_flStatic}; - UTIL_ScreenFade( pPlayer, white, 0.01, 0.1, FFADE_MODULATE ); - - // Insert danger sound so NPCs run away from me - if (gpGlobals->curtime > m_flNextDangerTime) - { - CSoundEnt::InsertSound ( SOUND_DANGER, GetAbsOrigin(), 2000, PMISSILE_DANGER_SOUND_DURATION ); - m_flNextDangerTime = gpGlobals->curtime + PMISSILE_DANGER_SOUND_DURATION; - } -} - -//----------------------------------------------------------------------------- -// Purpose: Explode -// Input : -// Output : -//----------------------------------------------------------------------------- -void CPlayer_Missile::LoseMissileControl(void) -{ - // Create a missile to take the place of this one - CGrenadeHomer *pGrenade = (CGrenadeHomer*)CreateEntityByName( "grenade_homer" ); - if ( pGrenade ) - { - pGrenade->Spawn(); - pGrenade->SetLocalOrigin( GetLocalOrigin() ); - pGrenade->SetLocalAngles( GetLocalAngles() ); - pGrenade->SetModel( PMISSILE_MISSILE_MODEL ); - pGrenade->SetDamage(m_flDamage); - pGrenade->SetDamageRadius(m_flDamageRadius); - pGrenade->Launch(this,NULL,GetAbsVelocity(),0,0,HOMER_SMOKE_TRAIL_OFF); - pGrenade->m_hRocketTrail[0] = m_hSmokeTrail; - m_hSmokeTrail->FollowEntity(pGrenade); - } - - m_takedamage = DAMAGE_NO; - m_lifeState = LIFE_DEAD; - StopSound( "Player_Manhack.Fly" ); - ControlDeactivate(); -} - -//----------------------------------------------------------------------------- -// Purpose: Explode -// Input : -// Output : -//----------------------------------------------------------------------------- -void CPlayer_Missile::ExplodeThink() -{ - SetAbsVelocity( m_vBounceVel ); - - color32 black = {0,0,0,255}; - CHL2_Player* pPlayer = (CHL2_Player*)UTIL_GetLocalPlayer(); - - Assert( pPlayer ); - - UTIL_ScreenFade( pPlayer, black, 2.0, 0.1, FFADE_OUT ); - - SetThink(RemoveThink); - SetNextThink( gpGlobals->curtime + PMISSILE_DIE_TIME ); -} - -//----------------------------------------------------------------------------- -// Purpose: Remove me -//----------------------------------------------------------------------------- -void CPlayer_Missile::RemoveThink() -{ - ControlDeactivate(); -} - -//------------------------------------------------------------------------------ -// Purpose : -//------------------------------------------------------------------------------ -Class_T CPlayer_Missile::Classify( void) -{ - return CLASS_MISSILE; -}; - - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -CPlayer_Missile::CPlayer_Missile() -{ - m_vSpawnPos.Init(0,0,0); - m_vSpawnAng.Init(0,0,0); - m_vBounceVel.Init(0,0,0); -} diff --git a/src/src/dlls/hl2mp_dll/hl2mp_gameinterface.h b/src/src/dlls/hl2mp_dll/hl2mp_gameinterface.h deleted file mode 100644 index 61d923b..0000000 --- a/src/src/dlls/hl2mp_dll/hl2mp_gameinterface.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef HL2MP_GAMEINTERFACE_H -#define HL2MP_GAMEINTERFACE_H -#ifdef _WIN32 -#pragma once -#endif - -#include "utllinkedlist.h" - - -// These are created for map entities in order as the map entities are spawned. -class CMapEntityRef -{ -public: - int m_iEdict; // Which edict slot this entity got. -1 if CreateEntityByName failed. - int m_iSerialNumber; // The edict serial number. TODO used anywhere ? -}; - -extern CUtlLinkedList g_MapEntityRefs; - -#endif \ No newline at end of file diff --git a/src/src/dlls/playerinfomanager.cpp b/src/src/dlls/playerinfomanager.cpp deleted file mode 100644 index c9f7359..0000000 --- a/src/src/dlls/playerinfomanager.cpp +++ /dev/null @@ -1,134 +0,0 @@ -//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// -// -// Purpose: implementation of player info manager -// -//=============================================================================// - -#include "cbase.h" -#include "player.h" -#include "playerinfomanager.h" -#include "edict.h" - -extern CGlobalVars *gpGlobals; -static CPlayerInfoManager s_PlayerInfoManager; -static CPluginBotManager s_BotManager; - -namespace -{ - - // - // Old version support - // - abstract_class IPlayerInfo_V1 - { - public: - // returns the players name (UTF-8 encoded) - virtual const char *GetName() = 0; - // returns the userid (slot number) - virtual int GetUserID() = 0; - // returns the string of their network (i.e Steam) ID - virtual const char *GetNetworkIDString() = 0; - // returns the team the player is on - virtual int GetTeamIndex() = 0; - // changes the player to a new team (if the game dll logic allows it) - virtual void ChangeTeam( int iTeamNum ) = 0; - // returns the number of kills this player has (exact meaning is mod dependent) - virtual int GetFragCount() = 0; - // returns the number of deaths this player has (exact meaning is mod dependent) - virtual int GetDeathCount() = 0; - // returns if this player slot is actually valid - virtual bool IsConnected() = 0; - // returns the armor/health of the player (exact meaning is mod dependent) - virtual int GetArmorValue() = 0; - }; - - abstract_class IPlayerInfoManager_V1 - { - public: - virtual IPlayerInfo_V1 *GetPlayerInfo( edict_t *pEdict ) = 0; - }; - - - class CPlayerInfoManager_V1: public IPlayerInfoManager_V1 - { - public: - virtual IPlayerInfo_V1 *GetPlayerInfo( edict_t *pEdict ); - }; - - static CPlayerInfoManager_V1 s_PlayerInfoManager_V1; - - - IPlayerInfo_V1 *CPlayerInfoManager_V1::GetPlayerInfo( edict_t *pEdict ) - { - CBasePlayer *pPlayer = ( ( CBasePlayer * )CBaseEntity::Instance( pEdict )); - if ( pPlayer ) - { - return (IPlayerInfo_V1 *)pPlayer->GetPlayerInfo(); - } - else - { - return NULL; - } - } - - EXPOSE_SINGLE_INTERFACE_GLOBALVAR(CPlayerInfoManager, IPlayerInfoManager_V1, "PlayerInfoManager001", s_PlayerInfoManager); -}; - -IPlayerInfo *CPlayerInfoManager::GetPlayerInfo( edict_t *pEdict ) -{ - CBasePlayer *pPlayer = ( ( CBasePlayer * )CBaseEntity::Instance( pEdict )); - if ( pPlayer ) - { - return pPlayer->GetPlayerInfo(); - } - else - { - return NULL; - } -} - -CGlobalVars *CPlayerInfoManager::GetGlobalVars() -{ - return gpGlobals; -} - - - -IBotController *CPluginBotManager::GetBotController( edict_t *pEdict ) -{ - CBasePlayer *pPlayer = ( ( CBasePlayer * )CBaseEntity::Instance( pEdict )); - if ( pPlayer && pPlayer->IsBot() ) - { - return pPlayer->GetBotController(); - } - else - { - return NULL; - } -} - -edict_t *CPluginBotManager::CreateBot( const char *botname ) -{ - edict_t *pEdict = engine->CreateFakeClient( botname ); - if (!pEdict) - { - Msg( "Failed to create Bot.\n"); - return NULL; - } - - // Allocate a player entity for the bot, and call spawn - CBasePlayer *pPlayer = ((CBasePlayer*)CBaseEntity::Instance( pEdict )); - - pPlayer->ClearFlags(); - pPlayer->AddFlag( FL_CLIENT | FL_FAKECLIENT ); - - pPlayer->ChangeTeam( TEAM_UNASSIGNED ); - pPlayer->RemoveAllItems( true ); - pPlayer->Spawn(); - - return pEdict; -} - -EXPOSE_SINGLE_INTERFACE_GLOBALVAR(CPlayerInfoManager, IPlayerInfoManager, INTERFACEVERSION_PLAYERINFOMANAGER, s_PlayerInfoManager); -EXPOSE_SINGLE_INTERFACE_GLOBALVAR(CPluginBotManager, IBotManager, INTERFACEVERSION_PLAYERBOTMANAGER, s_BotManager); - diff --git a/src/src/dlls/pointteleport.cpp b/src/src/dlls/pointteleport.cpp deleted file mode 100644 index 596d1a3..0000000 --- a/src/src/dlls/pointteleport.cpp +++ /dev/null @@ -1,100 +0,0 @@ -//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// -// -// Purpose: Teleports a named entity to a given position and restores -// it's physics state -// -// $NoKeywords: $ -//=============================================================================// - -#include "cbase.h" - -// memdbgon must be the last include file in a .cpp file!!! -#include "tier0/memdbgon.h" - -#define SF_TELEPORT_TO_SPAWN_POS 0x00000001 - -class CPointTeleport : public CBaseEntity -{ - DECLARE_CLASS( CPointTeleport, CBaseEntity ); -public: - void Activate( void ); - - void InputTeleport( inputdata_t &inputdata ); - - Vector m_vSaveOrigin; - QAngle m_vSaveAngles; - - DECLARE_DATADESC(); -}; - - -LINK_ENTITY_TO_CLASS( point_teleport, CPointTeleport ); - - -BEGIN_DATADESC( CPointTeleport ) - - DEFINE_FIELD( m_vSaveOrigin, FIELD_VECTOR ), - DEFINE_FIELD( m_vSaveAngles, FIELD_VECTOR ), - - DEFINE_INPUTFUNC( FIELD_VOID, "Teleport", InputTeleport ), - -END_DATADESC() - - - - -//------------------------------------------------------------------------------ -// Purpose: -//------------------------------------------------------------------------------ -void CPointTeleport::Activate( void ) -{ - m_vSaveOrigin = GetAbsOrigin(); - m_vSaveAngles = GetAbsAngles(); - - CBaseEntity *pTarget = GetNextTarget(); - if (pTarget) - { - if ( pTarget->GetMoveParent() != NULL ) - { - Warning("ERROR: (%s) can't teleport object (%s) as it has a parent!\n",GetDebugName(),pTarget->GetDebugName()); - - BaseClass::Activate(); - return; - } - - if (m_spawnflags & SF_TELEPORT_TO_SPAWN_POS) - { - m_vSaveOrigin = pTarget->GetAbsOrigin(); - m_vSaveAngles = pTarget->GetAbsAngles(); - } - } - else if (m_spawnflags & SF_TELEPORT_TO_SPAWN_POS) - { - Warning("ERROR: (%s) target '%s' not found. Deleting.\n", GetDebugName(), STRING(m_target)); - UTIL_Remove(this); - return; - } - - BaseClass::Activate(); -} - - -//------------------------------------------------------------------------------ -// Purpose: -//------------------------------------------------------------------------------ -void CPointTeleport::InputTeleport( inputdata_t &inputdata ) -{ - CBaseEntity *pTarget = GetNextTarget(); - if (pTarget) - { - // If teleport object is in a movement hierarchy, remove it first - if ( pTarget->GetMoveParent() != NULL ) - { - Warning("ERROR: (%s) can't teleport object (%s) as it has a parent (%s)!\n",GetDebugName(),pTarget->GetDebugName(),pTarget->GetMoveParent()->GetDebugName()); - return; - } - - pTarget->Teleport( &m_vSaveOrigin, &m_vSaveAngles, NULL ); - } -} - diff --git a/src/src/dlls/ragdoll_manager.cpp b/src/src/dlls/ragdoll_manager.cpp deleted file mode 100644 index 5141300..0000000 --- a/src/src/dlls/ragdoll_manager.cpp +++ /dev/null @@ -1,105 +0,0 @@ -//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// -// -// Purpose: -// -// $NoKeywords: $ -//=============================================================================// - -#include "cbase.h" -#include "baseentity.h" -#include "sendproxy.h" -#include "ragdoll_shared.h" -#include "ai_basenpc.h" - -// memdbgon must be the last include file in a .cpp file!!! -#include "tier0/memdbgon.h" - -class CRagdollManager : public CBaseEntity -{ -public: - DECLARE_CLASS( CRagdollManager, CBaseEntity ); - DECLARE_SERVERCLASS(); - DECLARE_DATADESC(); - - CRagdollManager(); - - virtual void Activate(); - virtual int UpdateTransmitState(); - - void InputMaxRagdollCount(inputdata_t &data); - -public: - - CNetworkVar( int, m_iMaxRagdollCount ); - - bool m_bSaveImportant; -}; - - -IMPLEMENT_SERVERCLASS_ST_NOBASE( CRagdollManager, DT_RagdollManager ) - SendPropInt( SENDINFO( m_iMaxRagdollCount ), 6 ), -END_SEND_TABLE() - -LINK_ENTITY_TO_CLASS( game_ragdoll_manager, CRagdollManager ); - -BEGIN_DATADESC( CRagdollManager ) - - DEFINE_KEYFIELD( m_iMaxRagdollCount, FIELD_INTEGER, "MaxRagdollCount" ), - DEFINE_KEYFIELD( m_bSaveImportant, FIELD_BOOLEAN, "SaveImportant" ), - DEFINE_INPUTFUNC( FIELD_INTEGER, "SetMaxRagdollCount", InputMaxRagdollCount ), - -END_DATADESC() - -//----------------------------------------------------------------------------- -// Constructor -//----------------------------------------------------------------------------- -CRagdollManager::CRagdollManager( void ) -{ - m_iMaxRagdollCount = -1; -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : *pInfo - -// Output : int -//----------------------------------------------------------------------------- -int CRagdollManager::UpdateTransmitState() -{ - return SetTransmitState( FL_EDICT_ALWAYS ); -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CRagdollManager::Activate() -{ - BaseClass::Activate(); - - s_RagdollLRU.SetMaxRagdollCount( m_iMaxRagdollCount ); -} - -void CRagdollManager::InputMaxRagdollCount(inputdata_t &inputdata) -{ - m_iMaxRagdollCount = inputdata.value.Int(); - s_RagdollLRU.SetMaxRagdollCount( m_iMaxRagdollCount ); -} - -bool RagdollManager_SaveImportant( CAI_BaseNPC *pNPC ) -{ -#ifdef HL2_DLL - CRagdollManager *pEnt = (CRagdollManager *)gEntList.FindEntityByClassname( NULL, "game_ragdoll_manager" ); - - if ( pEnt == NULL ) - return false; - - if ( pEnt->m_bSaveImportant ) - { - if ( pNPC->Classify() == CLASS_PLAYER_ALLY || pNPC->Classify() == CLASS_PLAYER_ALLY_VITAL ) - { - return true; - } - } -#endif - - return false; -} diff --git a/src/src/dlls/saverestore_gamedll.cpp b/src/src/dlls/saverestore_gamedll.cpp deleted file mode 100644 index ec83465..0000000 --- a/src/src/dlls/saverestore_gamedll.cpp +++ /dev/null @@ -1,123 +0,0 @@ -//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// -// -// Purpose: -// -// $NoKeywords: $ -// -//=============================================================================// -#include "cbase.h" -#include "isaverestore.h" -#include "saverestoretypes.h" - -// memdbgon must be the last include file in a .cpp file!!! -#include "tier0/memdbgon.h" - -//----------------------------------------------------------------------------- -// Purpose: iterates through a typedescript data block, so it can insert key/value data into the block -// Input : *pObject - pointer to the struct or class the data is to be insterted into -// *pFields - description of the data -// iNumFields - number of fields contained in pFields -// char *szKeyName - name of the variable to look for -// char *szValue - value to set the variable to -// Output : Returns true if the variable is found and set, false if the key is not found. -//----------------------------------------------------------------------------- -bool ParseKeyvalue( void *pObject, typedescription_t *pFields, int iNumFields, const char *szKeyName, const char *szValue ) -{ - int i; - typedescription_t *pField; - - for ( i = 0; i < iNumFields; i++ ) - { - pField = &pFields[i]; - - int fieldOffset = pField->fieldOffset[ TD_OFFSET_NORMAL ]; - - // Check the nested classes, but only if they aren't in array form. - if ((pField->fieldType == FIELD_EMBEDDED) && (pField->fieldSize == 1)) - { - for ( datamap_t *dmap = pField->td; dmap != NULL; dmap = dmap->baseMap ) - { - void *pEmbeddedObject = (void*)((char*)pObject + fieldOffset); - if ( ParseKeyvalue( pEmbeddedObject, dmap->dataDesc, dmap->dataNumFields, szKeyName, szValue) ) - return true; - } - } - - if ( (pField->flags & FTYPEDESC_KEY) && !stricmp(pField->externalName, szKeyName) ) - { - switch( pField->fieldType ) - { - case FIELD_MODELNAME: - case FIELD_SOUNDNAME: - case FIELD_STRING: - (*(string_t *)((char *)pObject + fieldOffset)) = AllocPooledString( szValue ); - return true; - - case FIELD_TIME: - case FIELD_FLOAT: - (*(float *)((char *)pObject + fieldOffset)) = atof( szValue ); - return true; - - case FIELD_BOOLEAN: - (*(bool *)((char *)pObject + fieldOffset)) = (bool)(atoi( szValue ) != 0); - return true; - - case FIELD_CHARACTER: - (*(char *)((char *)pObject + fieldOffset)) = (char)atoi( szValue ); - return true; - - case FIELD_SHORT: - (*(short *)((char *)pObject + fieldOffset)) = (short)atoi( szValue ); - return true; - - case FIELD_INTEGER: - case FIELD_TICK: - (*(int *)((char *)pObject + fieldOffset)) = atoi( szValue ); - return true; - - case FIELD_POSITION_VECTOR: - case FIELD_VECTOR: - UTIL_StringToVector( (float *)((char *)pObject + fieldOffset), szValue ); - return true; - - case FIELD_VMATRIX: - case FIELD_VMATRIX_WORLDSPACE: - UTIL_StringToFloatArray( (float *)((char *)pObject + fieldOffset), 16, szValue ); - return true; - - case FIELD_MATRIX3X4_WORLDSPACE: - UTIL_StringToFloatArray( (float *)((char *)pObject + fieldOffset), 12, szValue ); - return true; - - case FIELD_COLOR32: - UTIL_StringToColor32( (color32 *) ((char *)pObject + fieldOffset), szValue ); - return true; - - case FIELD_CUSTOM: - { - SaveRestoreFieldInfo_t fieldInfo = - { - (char *)pObject + fieldOffset, - pObject, - pField - }; - pField->pSaveRestoreOps->Parse( fieldInfo, szValue ); - return true; - } - - default: - case FIELD_INTERVAL: // Fixme, could write this if needed - case FIELD_CLASSPTR: - case FIELD_MODELINDEX: - case FIELD_MATERIALINDEX: - case FIELD_EDICT: - Warning( "Bad field in entity!!\n" ); - Assert(0); - break; - } - } - } - - return false; -} - diff --git a/src/src/dlls/sdk/sdk_eventlog.cpp b/src/src/dlls/sdk/sdk_eventlog.cpp deleted file mode 100644 index a5c208f..0000000 --- a/src/src/dlls/sdk/sdk_eventlog.cpp +++ /dev/null @@ -1,55 +0,0 @@ -//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// -// -// Purpose: -// -// $NoKeywords: $ -// -//=============================================================================// -#include "cbase.h" -#include "../EventLog.h" -#include "KeyValues.h" - -class CSDKEventLog : public CEventLog -{ -private: - typedef CEventLog BaseClass; - -public: - virtual ~CSDKEventLog() {}; - -public: - bool PrintEvent( IGameEvent * event ) // override virtual function - { - if ( BaseClass::PrintEvent( event ) ) - { - return true; - } - - if ( Q_strcmp(event->GetName(), "sdk_") == 0 ) - { - return PrintSDKEvent( event ); - } - - return false; - } - -protected: - - bool PrintSDKEvent( IGameEvent * event ) // print Mod specific logs - { - //const char * name = event->GetName() + Q_strlen("sdk_"); // remove prefix - return false; - } - -}; - -CSDKEventLog g_SDKEventLog; - -//----------------------------------------------------------------------------- -// Singleton access -//----------------------------------------------------------------------------- -IGameSystem* GameLogSystem() -{ - return &g_SDKEventLog; -} - diff --git a/src/src/dlls/sdk/sdk_player.cpp b/src/src/dlls/sdk/sdk_player.cpp deleted file mode 100644 index 3aa61bb..0000000 --- a/src/src/dlls/sdk/sdk_player.cpp +++ /dev/null @@ -1,357 +0,0 @@ -//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// -// -// Purpose: Player for HL1. -// -// $NoKeywords: $ -//=============================================================================// - -#include "cbase.h" -#include "sdk_player.h" -#include "sdk_gamerules.h" -#include "weapon_sdkbase.h" -#include "predicted_viewmodel.h" -#include "iservervehicle.h" -#include "viewport_panel_names.h" - -extern int gEvilImpulse101; - -#define SDK_PLAYER_MODEL "models/player/terror.mdl" - - -// -------------------------------------------------------------------------------- // -// Player animation event. Sent to the client when a player fires, jumps, reloads, etc.. -// -------------------------------------------------------------------------------- // - -class CTEPlayerAnimEvent : public CBaseTempEntity -{ -public: - DECLARE_CLASS( CTEPlayerAnimEvent, CBaseTempEntity ); - DECLARE_SERVERCLASS(); - - CTEPlayerAnimEvent( const char *name ) : CBaseTempEntity( name ) - { - } - - CNetworkHandle( CBasePlayer, m_hPlayer ); - CNetworkVar( int, m_iEvent ); -}; - -#define THROWGRENADE_COUNTER_BITS 3 - -IMPLEMENT_SERVERCLASS_ST_NOBASE( CTEPlayerAnimEvent, DT_TEPlayerAnimEvent ) - SendPropEHandle( SENDINFO( m_hPlayer ) ), - SendPropInt( SENDINFO( m_iEvent ), Q_log2( PLAYERANIMEVENT_COUNT ) + 1, SPROP_UNSIGNED ), -END_SEND_TABLE() - -static CTEPlayerAnimEvent g_TEPlayerAnimEvent( "PlayerAnimEvent" ); - -void TE_PlayerAnimEvent( CBasePlayer *pPlayer, PlayerAnimEvent_t event ) -{ - CPVSFilter filter( (const Vector&)pPlayer->EyePosition() ); - - g_TEPlayerAnimEvent.m_hPlayer = pPlayer; - g_TEPlayerAnimEvent.m_iEvent = event; - g_TEPlayerAnimEvent.Create( filter, 0 ); -} - -// -------------------------------------------------------------------------------- // -// Tables. -// -------------------------------------------------------------------------------- // - -LINK_ENTITY_TO_CLASS( player, CSDKPlayer ); -PRECACHE_REGISTER(player); - -BEGIN_SEND_TABLE_NOBASE( CSDKPlayer, DT_SDKLocalPlayerExclusive ) - SendPropInt( SENDINFO( m_iShotsFired ), 8, SPROP_UNSIGNED ), -END_SEND_TABLE() - -IMPLEMENT_SERVERCLASS_ST( CSDKPlayer, DT_SDKPlayer ) - SendPropExclude( "DT_BaseAnimating", "m_flPoseParameter" ), - SendPropExclude( "DT_BaseAnimating", "m_flPlaybackRate" ), - SendPropExclude( "DT_BaseAnimating", "m_nSequence" ), - SendPropExclude( "DT_BaseEntity", "m_angRotation" ), - SendPropExclude( "DT_BaseAnimatingOverlay", "overlay_vars" ), - - // playeranimstate and clientside animation takes care of these on the client - SendPropExclude( "DT_ServerAnimationData" , "m_flCycle" ), - SendPropExclude( "DT_AnimTimeMustBeFirst" , "m_flAnimTime" ), - - // Data that only gets sent to the local player. - SendPropDataTable( "sdklocaldata", 0, &REFERENCE_SEND_TABLE(DT_SDKLocalPlayerExclusive), SendProxy_SendLocalDataTable ), - - SendPropAngle( SENDINFO_VECTORELEM(m_angEyeAngles, 0), 11 ), - SendPropAngle( SENDINFO_VECTORELEM(m_angEyeAngles, 1), 11 ), - SendPropEHandle( SENDINFO( m_hRagdoll ) ), - - SendPropInt( SENDINFO( m_iThrowGrenadeCounter ), THROWGRENADE_COUNTER_BITS, SPROP_UNSIGNED ), -END_SEND_TABLE() - -class CSDKRagdoll : public CBaseAnimatingOverlay -{ -public: - DECLARE_CLASS( CSDKRagdoll, CBaseAnimatingOverlay ); - DECLARE_SERVERCLASS(); - - // Transmit ragdolls to everyone. - virtual int UpdateTransmitState() - { - return SetTransmitState( FL_EDICT_ALWAYS ); - } - -public: - // In case the client has the player entity, we transmit the player index. - // In case the client doesn't have it, we transmit the player's model index, origin, and angles - // so they can create a ragdoll in the right place. - CNetworkHandle( CBaseEntity, m_hPlayer ); // networked entity handle - CNetworkVector( m_vecRagdollVelocity ); - CNetworkVector( m_vecRagdollOrigin ); -}; - -LINK_ENTITY_TO_CLASS( sdk_ragdoll, CSDKRagdoll ); - -IMPLEMENT_SERVERCLASS_ST_NOBASE( CSDKRagdoll, DT_SDKRagdoll ) - SendPropVector( SENDINFO(m_vecRagdollOrigin), -1, SPROP_COORD ), - SendPropEHandle( SENDINFO( m_hPlayer ) ), - SendPropModelIndex( SENDINFO( m_nModelIndex ) ), - SendPropInt ( SENDINFO(m_nForceBone), 8, 0 ), - SendPropVector ( SENDINFO(m_vecForce), -1, SPROP_NOSCALE ), - SendPropVector( SENDINFO( m_vecRagdollVelocity ) ) -END_SEND_TABLE() - - -// -------------------------------------------------------------------------------- // - -void cc_CreatePredictionError_f() -{ - CBaseEntity *pEnt = CBaseEntity::Instance( 1 ); - pEnt->SetAbsOrigin( pEnt->GetAbsOrigin() + Vector( 63, 0, 0 ) ); -} - -ConCommand cc_CreatePredictionError( "CreatePredictionError", cc_CreatePredictionError_f, "Create a prediction error", FCVAR_CHEAT ); - - -CSDKPlayer::CSDKPlayer() -{ - m_PlayerAnimState = CreatePlayerAnimState( this, this, LEGANIM_9WAY, true ); - - UseClientSideAnimation(); - m_angEyeAngles.Init(); - - SetViewOffset( SDK_PLAYER_VIEW_OFFSET ); - - m_iThrowGrenadeCounter = 0; -} - - -CSDKPlayer::~CSDKPlayer() -{ - m_PlayerAnimState->Release(); -} - - -CSDKPlayer *CSDKPlayer::CreatePlayer( const char *className, edict_t *ed ) -{ - CSDKPlayer::s_PlayerEdict = ed; - return (CSDKPlayer*)CreateEntityByName( className ); -} - -void CSDKPlayer::LeaveVehicle( const Vector &vecExitPoint, const QAngle &vecExitAngles ) -{ - BaseClass::LeaveVehicle( vecExitPoint, vecExitAngles ); - - //teleport physics shadow too - // Vector newPos = GetAbsOrigin(); - // QAngle newAng = GetAbsAngles(); - - // Teleport( &newPos, &newAng, &vec3_origin ); -} - -void CSDKPlayer::PreThink(void) -{ - // Riding a vehicle? - if ( IsInAVehicle() ) - { - // make sure we update the client, check for timed damage and update suit even if we are in a vehicle - UpdateClientData(); - CheckTimeBasedDamage(); - - // Allow the suit to recharge when in the vehicle. - CheckSuitUpdate(); - - WaterMove(); - return; - } - - BaseClass::PreThink(); -} - - -void CSDKPlayer::PostThink() -{ - BaseClass::PostThink(); - - QAngle angles = GetLocalAngles(); - angles[PITCH] = 0; - SetLocalAngles( angles ); - - // Store the eye angles pitch so the client can compute its animation state correctly. - m_angEyeAngles = EyeAngles(); - - m_PlayerAnimState->Update( m_angEyeAngles[YAW], m_angEyeAngles[PITCH] ); -} - - -void CSDKPlayer::Precache() -{ - PrecacheModel( SDK_PLAYER_MODEL ); - - BaseClass::Precache(); -} - -void CSDKPlayer::Spawn() -{ - SetModel( SDK_PLAYER_MODEL ); - SetMoveType( MOVETYPE_WALK ); - RemoveSolidFlags( FSOLID_NOT_SOLID ); - - m_hRagdoll = NULL; - - BaseClass::Spawn(); -} - -void CSDKPlayer::InitialSpawn( void ) -{ - BaseClass::InitialSpawn(); - - const ConVar *hostname = cvar->FindVar( "hostname" ); - const char *title = (hostname) ? hostname->GetString() : "MESSAGE OF THE DAY"; - - // open info panel on client showing MOTD: - KeyValues *data = new KeyValues("data"); - data->SetString( "title", title ); // info panel title - data->SetString( "type", "1" ); // show userdata from stringtable entry - data->SetString( "msg", "motd" ); // use this stringtable entry - data->SetString( "cmd", "impulse 101" );// exec this command if panel closed - - ShowViewPortPanel( PANEL_INFO, true, data ); - - data->deleteThis(); -} - -void CSDKPlayer::Event_Killed( const CTakeDamageInfo &info ) -{ - // Note: since we're dead, it won't draw us on the client, but we don't set EF_NODRAW - // because we still want to transmit to the clients in our PVS. - - BaseClass::Event_Killed( info ); - - CreateRagdollEntity(); -} - -void CSDKPlayer::CreateRagdollEntity() -{ - // If we already have a ragdoll, don't make another one. - CSDKRagdoll *pRagdoll = dynamic_cast< CSDKRagdoll* >( m_hRagdoll.Get() ); - - if ( !pRagdoll ) - { - // create a new one - pRagdoll = dynamic_cast< CSDKRagdoll* >( CreateEntityByName( "sdk_ragdoll" ) ); - } - - if ( pRagdoll ) - { - pRagdoll->m_hPlayer = this; - pRagdoll->m_vecRagdollOrigin = GetAbsOrigin(); - pRagdoll->m_vecRagdollVelocity = GetAbsVelocity(); - pRagdoll->m_nModelIndex = m_nModelIndex; - pRagdoll->m_nForceBone = m_nForceBone; - pRagdoll->m_vecForce = Vector(0,0,0); - } - - // ragdolls will be removed on round restart automatically - m_hRagdoll = pRagdoll; -} - -void CSDKPlayer::DoAnimationEvent( PlayerAnimEvent_t event ) -{ - if ( event == PLAYERANIMEVENT_THROW_GRENADE ) - { - // Grenade throwing has to synchronize exactly with the player's grenade weapon going away, - // and events get delayed a bit, so we let CCSPlayerAnimState pickup the change to this - // variable. - m_iThrowGrenadeCounter = (m_iThrowGrenadeCounter+1) % (1<DoAnimationEvent( event ); - TE_PlayerAnimEvent( this, event ); // Send to any clients who can see this guy. - } -} - -CWeaponSDKBase* CSDKPlayer::GetActiveSDKWeapon() const -{ - return dynamic_cast< CWeaponSDKBase* >( GetActiveWeapon() ); -} - -void CSDKPlayer::CreateViewModel( int index /*=0*/ ) -{ - Assert( index >= 0 && index < MAX_VIEWMODELS ); - - if ( GetViewModel( index ) ) - return; - - CPredictedViewModel *vm = ( CPredictedViewModel * )CreateEntityByName( "predicted_viewmodel" ); - if ( vm ) - { - vm->SetAbsOrigin( GetAbsOrigin() ); - vm->SetOwner( this ); - vm->SetIndex( index ); - DispatchSpawn( vm ); - vm->FollowEntity( this, false ); - m_hViewModel.Set( index, vm ); - } -} - -void CSDKPlayer::CheatImpulseCommands( int iImpulse ) -{ - if ( iImpulse != 101 ) - { - BaseClass::CheatImpulseCommands( iImpulse ); - return ; - } - gEvilImpulse101 = true; - - EquipSuit(); - - GiveNamedItem( "weapon_mp5" ); - GiveNamedItem( "weapon_grenade" ); - GiveNamedItem( "weapon_shotgun" ); - - // Give the player everything! - GiveAmmo( 90, AMMO_BULLETS ); - GiveAmmo( 3, AMMO_GRENADE ); - - if ( GetHealth() < 100 ) - { - TakeHealth( 25, DMG_GENERIC ); - } - - gEvilImpulse101 = false; -} - - -void CSDKPlayer::FlashlightTurnOn( void ) -{ - AddEffects( EF_DIMLIGHT ); -} - -void CSDKPlayer::FlashlightTurnOff( void ) -{ - RemoveEffects( EF_DIMLIGHT ); -} - -int CSDKPlayer::FlashlightIsOn( void ) -{ - return IsEffectActive( EF_DIMLIGHT ); -} diff --git a/src/src/dlls/sdk/sdk_player.h b/src/src/dlls/sdk/sdk_player.h deleted file mode 100644 index 66b22d5..0000000 --- a/src/src/dlls/sdk/sdk_player.h +++ /dev/null @@ -1,100 +0,0 @@ -//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// -// -// Purpose: Player for SDK Game -// -// $NoKeywords: $ -//=============================================================================// - -#ifndef SDK_PLAYER_H -#define SDK_PLAYER_H -#pragma once - - -#include "player.h" -#include "server_class.h" -#include "sdk_playeranimstate.h" -#include "sdk_shareddefs.h" - - -//============================================================================= -// >> SDK Game player -//============================================================================= -class CSDKPlayer : public CBasePlayer, public ISDKPlayerAnimStateHelpers -{ -public: - DECLARE_CLASS( CSDKPlayer, CBasePlayer ); - DECLARE_SERVERCLASS(); - DECLARE_PREDICTABLE(); - - CSDKPlayer(); - ~CSDKPlayer(); - - static CSDKPlayer *CreatePlayer( const char *className, edict_t *ed ); - static CSDKPlayer* Instance( int iEnt ); - - // This passes the event to the client's and server's CPlayerAnimState. - void DoAnimationEvent( PlayerAnimEvent_t event ); - - virtual void FlashlightTurnOn( void ); - virtual void FlashlightTurnOff( void ); - virtual int FlashlightIsOn( void ); - - virtual void PreThink(); - virtual void PostThink(); - virtual void Spawn(); - virtual void InitialSpawn(); - virtual void Precache(); - virtual void Event_Killed( const CTakeDamageInfo &info ); - virtual void LeaveVehicle( const Vector &vecExitPoint, const QAngle &vecExitAngles ); - - CWeaponSDKBase* GetActiveSDKWeapon() const; - virtual void CreateViewModel( int viewmodelindex = 0 ); - - virtual void CheatImpulseCommands( int iImpulse ); - - CNetworkVar( int, m_iThrowGrenadeCounter ); // used to trigger grenade throw animations. - CNetworkQAngle( m_angEyeAngles ); // Copied from EyeAngles() so we can send it to the client. - CNetworkVar( int, m_iShotsFired ); // number of shots fired recently - - // Tracks our ragdoll entity. - CNetworkHandle( CBaseEntity, m_hRagdoll ); // networked entity handle - -// In shared code. -public: - // ISDKPlayerAnimState overrides. - virtual CWeaponSDKBase* SDKAnim_GetActiveWeapon(); - virtual bool SDKAnim_CanMove(); - - - void FireBullet( - Vector vecSrc, - const QAngle &shootAngles, - float vecSpread, - int iDamage, - int iBulletType, - CBaseEntity *pevAttacker, - bool bDoEffects, - float x, - float y ); - -private: - - void CreateRagdollEntity(); - - ISDKPlayerAnimState *m_PlayerAnimState; -}; - - -inline CSDKPlayer *ToSDKPlayer( CBaseEntity *pEntity ) -{ - if ( !pEntity || !pEntity->IsPlayer() ) - return NULL; - -#ifdef _DEBUG - Assert( dynamic_cast( pEntity ) != 0 ); -#endif - return static_cast< CSDKPlayer* >( pEntity ); -} - - -#endif // SDK_PLAYER_H diff --git a/src/src/dlls/sdk/sdk_team.cpp b/src/src/dlls/sdk/sdk_team.cpp deleted file mode 100644 index 5f306f1..0000000 --- a/src/src/dlls/sdk/sdk_team.cpp +++ /dev/null @@ -1,40 +0,0 @@ -//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// -// -// Purpose: Team management class. Contains all the details for a specific team -// -// $NoKeywords: $ -//=============================================================================// -#include "cbase.h" -#include "sdk_team.h" -#include "entitylist.h" - -// memdbgon must be the last include file in a .cpp file!!! -#include "tier0/memdbgon.h" - - -// Datatable -IMPLEMENT_SERVERCLASS_ST(CSDKTeam, DT_SDKTeam) -END_SEND_TABLE() - -LINK_ENTITY_TO_CLASS( sdk_team_manager, CSDKTeam ); - -//----------------------------------------------------------------------------- -// Purpose: Get a pointer to the specified TF team manager -//----------------------------------------------------------------------------- -CSDKTeam *GetGlobalSDKTeam( int iIndex ) -{ - return (CSDKTeam*)GetGlobalTeam( iIndex ); -} - - -//----------------------------------------------------------------------------- -// Purpose: Needed because this is an entity, but should never be used -//----------------------------------------------------------------------------- -void CSDKTeam::Init( const char *pName, int iNumber ) -{ - BaseClass::Init( pName, iNumber ); - - // Only detect changes every half-second. - NetworkProp()->SetUpdateInterval( 0.75f ); -} - diff --git a/src/src/dlls/sdk/sdk_team.h b/src/src/dlls/sdk/sdk_team.h deleted file mode 100644 index e9ff063..0000000 --- a/src/src/dlls/sdk/sdk_team.h +++ /dev/null @@ -1,38 +0,0 @@ -//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// -// -// Purpose: Team management class. Contains all the details for a specific team -// -// $NoKeywords: $ -//=============================================================================// - -#ifndef SDK_TEAM_H -#define SDK_TEAM_H - -#ifdef _WIN32 -#pragma once -#endif - - -#include "utlvector.h" -#include "team.h" - - -//----------------------------------------------------------------------------- -// Purpose: Team Manager -//----------------------------------------------------------------------------- -class CSDKTeam : public CTeam -{ - DECLARE_CLASS( CSDKTeam, CTeam ); - DECLARE_SERVERCLASS(); - -public: - - // Initialization - virtual void Init( const char *pName, int iNumber ); -}; - - -extern CSDKTeam *GetGlobalSDKTeam( int iIndex ); - - -#endif // TF_TEAM_H diff --git a/src/src/dlls/server_scratch-2003.vcproj b/src/src/dlls/server_scratch-2003.vcproj deleted file mode 100644 index e16ce73..0000000 --- a/src/src/dlls/server_scratch-2003.vcproj +++ /dev/null @@ -1,3607 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/src/dlls/server_scratch-2005.vcproj b/src/src/dlls/server_scratch-2005.vcproj deleted file mode 100644 index 1b211c0..0000000 --- a/src/src/dlls/server_scratch-2005.vcproj +++ /dev/null @@ -1,4829 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/src/dlls/terrainmodmgr.cpp b/src/src/dlls/terrainmodmgr.cpp deleted file mode 100644 index dc5a189..0000000 --- a/src/src/dlls/terrainmodmgr.cpp +++ /dev/null @@ -1,71 +0,0 @@ -//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// -// -// Purpose: -// -// $NoKeywords: $ -//=============================================================================// - -#include "cbase.h" -#include "terrainmodmgr.h" -#include "terrainmodmgr_shared.h" -#include "gameinterface.h" -#include "player.h" - -// memdbgon must be the last include file in a .cpp file!!! -#include "tier0/memdbgon.h" - -void TerrainMod_Add( TerrainModType type, const CTerrainModParams ¶ms ) -{ - if ( IsXbox() ) - { - return; - } - - // Move players out of the way so they don't get stuck on the terrain. - float playerStartHeights[MAX_PLAYERS]; - - int i; - int nPlayers = min( MAX_PLAYERS, gpGlobals->maxClients ); - for( i=0; i < nPlayers; i++ ) - { - CBasePlayer *pPlayer = UTIL_PlayerByIndex( i+1 ); - - if( !pPlayer ) - continue; - - playerStartHeights[i] = pPlayer->GetAbsOrigin().z; - - // Cast a ray upwards to see if we can move the player out of the way. - trace_t trace; - UTIL_TraceEntity( - pPlayer, pPlayer->GetAbsOrigin(), - pPlayer->GetAbsOrigin() + Vector( 0, 0, params.m_flRadius*2 ), - MASK_SOLID, - &trace ); - - pPlayer->SetLocalOrigin( trace.endpos ); - } - - // Apply the mod. - engine->ApplyTerrainMod( type, params ); - - // Move players back down. - for( i=0; i < nPlayers; i++ ) - { - CBasePlayer *pPlayer = UTIL_PlayerByIndex( i+1 ); - - if( !pPlayer ) - continue; - - // Cast a ray upwards to see if we can move the player out of the way. - trace_t trace; - UTIL_TraceEntity( - pPlayer, - pPlayer->GetAbsOrigin(), - Vector( pPlayer->GetAbsOrigin().x, pPlayer->GetAbsOrigin().y, playerStartHeights[i] ), - MASK_SOLID, - &trace ); - - pPlayer->SetLocalOrigin( trace.endpos ); - } -} diff --git a/src/src/dlls/terrainmodmgr.h b/src/src/dlls/terrainmodmgr.h deleted file mode 100644 index 4c7da65..0000000 --- a/src/src/dlls/terrainmodmgr.h +++ /dev/null @@ -1,21 +0,0 @@ -//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// -// -// Purpose: -// -// $NoKeywords: $ -//=============================================================================// - -#ifndef TERRAINMODMGR_H -#define TERRAINMODMGR_H -#ifdef _WIN32 -#pragma once -#endif - -#include "vector.h" -#include "terrainmod.h" - -// Apply a terrain mod. -// The mod is applied on the server, and sent to all clients so they can apply it. -void TerrainMod_Add( TerrainModType type, const CTerrainModParams ¶ms ); - -#endif // TERRAINMODMGR_H diff --git a/src/src/dlls/vgui_gamedll_int.cpp b/src/src/dlls/vgui_gamedll_int.cpp deleted file mode 100644 index f6fdd6b..0000000 --- a/src/src/dlls/vgui_gamedll_int.cpp +++ /dev/null @@ -1,102 +0,0 @@ -//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= -#include "cbase.h" -#ifdef _WIN32 // no VGUI2 support under linux -#include "vgui_gamedll_int.h" -#include "ienginevgui.h" -#include -#include -#include -#include "tier0/vprof.h" -#include -#include - -using namespace vgui; - -#include - -// memdbgon must be the last include file in a .cpp file!!! -#include "tier0/memdbgon.h" - - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void VGUI_CreateGameDLLRootPanel( void ) -{ - // Just using PANEL_ROOT in HL2 right now -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void VGUI_DestroyGameDLLRootPanel( void ) -{ -} - -//----------------------------------------------------------------------------- -// Purpose: Game specific root panel -// Output : vgui::Panel -//----------------------------------------------------------------------------- -vgui::VPANEL VGui_GetGameDLLRootPanel( void ) -{ - if ( IsPC() ) - { - vgui::VPANEL root = enginevgui->GetPanel( PANEL_GAMEDLL ); - return root; - } - return NULL; -} - - - -bool VGui_Startup( CreateInterfaceFn appSystemFactory ) -{ - if ( !vgui::VGui_InitInterfacesList( "GAMEDLL", &appSystemFactory, 1 ) ) - return false; - - return true; -} - -bool VGui_PostInit() -{ - if ( IsPC() ) - { - // Create any root panels for .dll - VGUI_CreateGameDLLRootPanel(); - - // Make sure we have a panel - VPANEL root = VGui_GetGameDLLRootPanel(); - if ( !root ) - { - return false; - } - } - return true; -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void VGui_CreateGlobalPanels( void ) -{ -} - -void VGui_Shutdown() -{ - if ( IsPC() ) - { - VGUI_DestroyGameDLLRootPanel(); - - // Make sure anything "marked for deletion" - // actually gets deleted before this dll goes away - vgui::ivgui()->RunFrame(); - } -} - -#endif // _WIN32 - diff --git a/src/src/dlls/vgui_gamedll_int.h b/src/src/dlls/vgui_gamedll_int.h deleted file mode 100644 index 769210a..0000000 --- a/src/src/dlls/vgui_gamedll_int.h +++ /dev/null @@ -1,31 +0,0 @@ -//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= -#if !defined( VGUI_GAMEDLL_INT_H ) -#define VGUI_GAMEDLL_INT_H -#ifdef _WIN32 -#pragma once -#endif - -#include "interface.h" - -#include - -namespace vgui -{ - class Panel; -} - -bool VGui_Startup( CreateInterfaceFn appSystemFactory ); -bool VGui_PostInit(); -void VGui_Shutdown( void ); -void VGui_CreateGlobalPanels( void ); -vgui::VPANEL VGui_GetGameDLLRootPanel( void ); -void VGUI_CreateGameDLLRootPanel( void ); -void VGUI_DestroyGameDLLRootPanel( void ); -//void VGui_PreRender(); - -#endif // VGUI_GAMEDLL_INT_H diff --git a/src/src/dx10sdk/utilities/dx9_30/dx_proxy.dll b/src/src/dx10sdk/utilities/dx9_30/dx_proxy.dll new file mode 100644 index 0000000..f9865b1 Binary files /dev/null and b/src/src/dx10sdk/utilities/dx9_30/dx_proxy.dll differ diff --git a/src/src/dx9sdk/utilities/dx_proxy.dll b/src/src/dx9sdk/utilities/dx_proxy.dll new file mode 100644 index 0000000..7640fd8 Binary files /dev/null and b/src/src/dx9sdk/utilities/dx_proxy.dll differ diff --git a/src/src/everything_sdk-2003.sln b/src/src/everything_sdk-2003.sln deleted file mode 100644 index 01389e1..0000000 --- a/src/src/everything_sdk-2003.sln +++ /dev/null @@ -1,228 +0,0 @@ -Microsoft Visual Studio Solution File, Format Version 8.00 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "glview", "utils\glview\glview-2003.vcproj", "{BD1604CA-F401-4C4B-821C-251F5AE157FE}" - ProjectSection(ProjectDependencies) = postProject - {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720} = {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720} - {E1DA9FB8-FB4C-4B14-91A6-98BCED6B9720} = {E1DA9FB8-FB4C-4B14-91A6-98BCED6B9720} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "height2normal", "utils\height2normal\height2normal-2003.vcproj", "{0FDD99E4-130F-493C-8202-4C0236CC47EA}" - ProjectSection(ProjectDependencies) = postProject - {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720} = {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720} - {E1DA9FB8-FB4C-4B14-91A6-98BCED6B9720} = {E1DA9FB8-FB4C-4B14-91A6-98BCED6B9720} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "serverplugin_empty", "utils\serverplugin_sample\serverplugin_empty-2003.vcproj", "{B6572CBE-7C7F-4FFF-94DE-AFBBBAB11C64}" - ProjectSection(ProjectDependencies) = postProject - {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720} = {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720} - {E1DA9FB8-FB4C-4B14-91A6-98BCED6B9720} = {E1DA9FB8-FB4C-4B14-91A6-98BCED6B9720} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "studiomdl", "utils\studiomdl\studiomdl-2003.vcproj", "{AE28536E-885A-41BF-99A4-41A7E424B869}" - ProjectSection(ProjectDependencies) = postProject - {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720} = {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720} - {E1DA9FB8-FB4C-4B14-91A6-98BCED6B9720} = {E1DA9FB8-FB4C-4B14-91A6-98BCED6B9720} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tgadiff", "utils\tgadiff\tgadiff-2003.vcproj", "{0CE0AF8A-A977-4538-9D63-BCB76DE1BAC6}" - ProjectSection(ProjectDependencies) = postProject - {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720} = {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720} - {E1DA9FB8-FB4C-4B14-91A6-98BCED6B9720} = {E1DA9FB8-FB4C-4B14-91A6-98BCED6B9720} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vbsp", "utils\vbsp\vbsp-2003.vcproj", "{B78B6271-B19A-4CF6-926E-40B643548E23}" - ProjectSection(ProjectDependencies) = postProject - {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720} = {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720} - {E1DA9FB8-FB4C-4B14-91A6-98BCED6B9720} = {E1DA9FB8-FB4C-4B14-91A6-98BCED6B9720} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vice", "utils\vice\vice-2003.vcproj", "{3CE6E7A9-89EC-4304-8D72-5B602B4DBD09}" - ProjectSection(ProjectDependencies) = postProject - {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720} = {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vprojtomake", "utils\vprojtomake\vprojtomake-2003.vcproj", "{EA55446E-BC04-491C-A9F0-605DFCBB213A}" - ProjectSection(ProjectDependencies) = postProject - {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720} = {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vrad", "utils\vrad\vrad-2003.vcproj", "{FC0F5DE3-F09F-4EF6-98F9-BA762FFF268D}" - ProjectSection(ProjectDependencies) = postProject - {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720} = {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720} - {E1DA9FB8-FB4C-4B14-91A6-98BCED6B9720} = {E1DA9FB8-FB4C-4B14-91A6-98BCED6B9720} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vrad_launcher", "utils\vrad_launcher\vrad_launcher-2003.vcproj", "{914F19DF-64EC-4E7D-8B01-76477BF06479}" - ProjectSection(ProjectDependencies) = postProject - {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720} = {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vtf2tga", "utils\vtf2tga\vtf2tga-2003.vcproj", "{2A1F656C-053C-46A4-AE33-304C1D865E0C}" - ProjectSection(ProjectDependencies) = postProject - {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720} = {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720} - {E1DA9FB8-FB4C-4B14-91A6-98BCED6B9720} = {E1DA9FB8-FB4C-4B14-91A6-98BCED6B9720} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vtfdiff", "utils\vtfdiff\vtfdiff-2003.vcproj", "{0A368DE7-D34A-48D3-B517-996BFF2D0D5D}" - ProjectSection(ProjectDependencies) = postProject - {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720} = {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720} - {E1DA9FB8-FB4C-4B14-91A6-98BCED6B9720} = {E1DA9FB8-FB4C-4B14-91A6-98BCED6B9720} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vvis", "utils\vvis\vvis-2003.vcproj", "{5B065E70-6EE0-4B47-BA64-113D2F81220D}" - ProjectSection(ProjectDependencies) = postProject - {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720} = {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720} - {E1DA9FB8-FB4C-4B14-91A6-98BCED6B9720} = {E1DA9FB8-FB4C-4B14-91A6-98BCED6B9720} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vvis_launcher", "utils\vvis_launcher\vvis_launcher-2003.vcproj", "{4C0B9915-E8FF-4089-8927-FC934BFC1E4A}" - ProjectSection(ProjectDependencies) = postProject - {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720} = {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xwad", "utils\xwad\xwad-2003.vcproj", "{B850012C-98A2-42F7-B023-9F65C448D938}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vgui_controls", "vgui2\controls\vgui_controls-2003.vcproj", "{C3CEFD6F-5CDC-41DE-8D43-D932F508F51B}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "demoinfo", "utils\demoinfo\demoinfo-2003.vcproj", "{4FE3FDCA-9571-44B3-A521-C81448434490}" - ProjectSection(ProjectDependencies) = postProject - {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720} = {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "motionmapper", "utils\motionmapper\motionmapper-2003.vcproj", "{A882FC08-8B92-4D4F-89BF-75BCEC2BAE11}" - ProjectSection(ProjectDependencies) = postProject - {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720} = {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720} - {E1DA9FB8-FB4C-4B14-91A6-98BCED6B9720} = {E1DA9FB8-FB4C-4B14-91A6-98BCED6B9720} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "QC_Eyes", "utils\qc_eyes\QC_Eyes-2003.vcproj", "{D373436F-7DBF-468B-A3E4-601FB8556544}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mathlib", "mathlib\mathlib-2003.vcproj", "{E1DA9FB8-FB4C-4B14-91A6-98BCED6B9720}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tier1", "tier1\tier1-2003.vcproj", "{E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "phonemeextractor", "utils\phonemeextractor\phonemeextractor-2003.vcproj", "{8A35F55B-B5C2-47A0-8C4A-5857A8E20385}" - ProjectSection(ProjectDependencies) = postProject - {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720} = {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720} - {E1DA9FB8-FB4C-4B14-91A6-98BCED6B9720} = {E1DA9FB8-FB4C-4B14-91A6-98BCED6B9720} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "hlmv", "utils\hlmv\hlmv-2003.vcproj", "{F3704DBF-8055-413C-B027-399E5DBCA4DD}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Global - GlobalSection(SolutionConfiguration) = preSolution - Debug = Debug - Release = Release - EndGlobalSection - GlobalSection(ProjectDependencies) = postSolution - EndGlobalSection - GlobalSection(ProjectConfiguration) = postSolution - {BD1604CA-F401-4C4B-821C-251F5AE157FE}.Debug.ActiveCfg = Debug|Win32 - {BD1604CA-F401-4C4B-821C-251F5AE157FE}.Debug.Build.0 = Debug|Win32 - {BD1604CA-F401-4C4B-821C-251F5AE157FE}.Release.ActiveCfg = Release|Win32 - {BD1604CA-F401-4C4B-821C-251F5AE157FE}.Release.Build.0 = Release|Win32 - {0FDD99E4-130F-493C-8202-4C0236CC47EA}.Debug.ActiveCfg = Debug|Win32 - {0FDD99E4-130F-493C-8202-4C0236CC47EA}.Debug.Build.0 = Debug|Win32 - {0FDD99E4-130F-493C-8202-4C0236CC47EA}.Release.ActiveCfg = Release|Win32 - {0FDD99E4-130F-493C-8202-4C0236CC47EA}.Release.Build.0 = Release|Win32 - {B6572CBE-7C7F-4FFF-94DE-AFBBBAB11C64}.Debug.ActiveCfg = Debug|Win32 - {B6572CBE-7C7F-4FFF-94DE-AFBBBAB11C64}.Debug.Build.0 = Debug|Win32 - {B6572CBE-7C7F-4FFF-94DE-AFBBBAB11C64}.Release.ActiveCfg = Release|Win32 - {B6572CBE-7C7F-4FFF-94DE-AFBBBAB11C64}.Release.Build.0 = Release|Win32 - {AE28536E-885A-41BF-99A4-41A7E424B869}.Debug.ActiveCfg = Debug|Win32 - {AE28536E-885A-41BF-99A4-41A7E424B869}.Debug.Build.0 = Debug|Win32 - {AE28536E-885A-41BF-99A4-41A7E424B869}.Release.ActiveCfg = Release|Win32 - {AE28536E-885A-41BF-99A4-41A7E424B869}.Release.Build.0 = Release|Win32 - {0CE0AF8A-A977-4538-9D63-BCB76DE1BAC6}.Debug.ActiveCfg = Debug|Win32 - {0CE0AF8A-A977-4538-9D63-BCB76DE1BAC6}.Debug.Build.0 = Debug|Win32 - {0CE0AF8A-A977-4538-9D63-BCB76DE1BAC6}.Release.ActiveCfg = Release|Win32 - {0CE0AF8A-A977-4538-9D63-BCB76DE1BAC6}.Release.Build.0 = Release|Win32 - {B78B6271-B19A-4CF6-926E-40B643548E23}.Debug.ActiveCfg = Debug|Win32 - {B78B6271-B19A-4CF6-926E-40B643548E23}.Debug.Build.0 = Debug|Win32 - {B78B6271-B19A-4CF6-926E-40B643548E23}.Release.ActiveCfg = Release|Win32 - {B78B6271-B19A-4CF6-926E-40B643548E23}.Release.Build.0 = Release|Win32 - {3CE6E7A9-89EC-4304-8D72-5B602B4DBD09}.Debug.ActiveCfg = Debug|Win32 - {3CE6E7A9-89EC-4304-8D72-5B602B4DBD09}.Debug.Build.0 = Debug|Win32 - {3CE6E7A9-89EC-4304-8D72-5B602B4DBD09}.Release.ActiveCfg = Release|Win32 - {3CE6E7A9-89EC-4304-8D72-5B602B4DBD09}.Release.Build.0 = Release|Win32 - {EA55446E-BC04-491C-A9F0-605DFCBB213A}.Debug.ActiveCfg = Debug|Win32 - {EA55446E-BC04-491C-A9F0-605DFCBB213A}.Debug.Build.0 = Debug|Win32 - {EA55446E-BC04-491C-A9F0-605DFCBB213A}.Release.ActiveCfg = Release|Win32 - {EA55446E-BC04-491C-A9F0-605DFCBB213A}.Release.Build.0 = Release|Win32 - {FC0F5DE3-F09F-4EF6-98F9-BA762FFF268D}.Debug.ActiveCfg = Debug|Win32 - {FC0F5DE3-F09F-4EF6-98F9-BA762FFF268D}.Debug.Build.0 = Debug|Win32 - {FC0F5DE3-F09F-4EF6-98F9-BA762FFF268D}.Release.ActiveCfg = Release|Win32 - {FC0F5DE3-F09F-4EF6-98F9-BA762FFF268D}.Release.Build.0 = Release|Win32 - {914F19DF-64EC-4E7D-8B01-76477BF06479}.Debug.ActiveCfg = Debug|Win32 - {914F19DF-64EC-4E7D-8B01-76477BF06479}.Debug.Build.0 = Debug|Win32 - {914F19DF-64EC-4E7D-8B01-76477BF06479}.Release.ActiveCfg = Release|Win32 - {914F19DF-64EC-4E7D-8B01-76477BF06479}.Release.Build.0 = Release|Win32 - {2A1F656C-053C-46A4-AE33-304C1D865E0C}.Debug.ActiveCfg = Debug|Win32 - {2A1F656C-053C-46A4-AE33-304C1D865E0C}.Debug.Build.0 = Debug|Win32 - {2A1F656C-053C-46A4-AE33-304C1D865E0C}.Release.ActiveCfg = Release|Win32 - {2A1F656C-053C-46A4-AE33-304C1D865E0C}.Release.Build.0 = Release|Win32 - {0A368DE7-D34A-48D3-B517-996BFF2D0D5D}.Debug.ActiveCfg = Debug|Win32 - {0A368DE7-D34A-48D3-B517-996BFF2D0D5D}.Debug.Build.0 = Debug|Win32 - {0A368DE7-D34A-48D3-B517-996BFF2D0D5D}.Release.ActiveCfg = Release|Win32 - {0A368DE7-D34A-48D3-B517-996BFF2D0D5D}.Release.Build.0 = Release|Win32 - {5B065E70-6EE0-4B47-BA64-113D2F81220D}.Debug.ActiveCfg = Debug|Win32 - {5B065E70-6EE0-4B47-BA64-113D2F81220D}.Debug.Build.0 = Debug|Win32 - {5B065E70-6EE0-4B47-BA64-113D2F81220D}.Release.ActiveCfg = Release|Win32 - {5B065E70-6EE0-4B47-BA64-113D2F81220D}.Release.Build.0 = Release|Win32 - {4C0B9915-E8FF-4089-8927-FC934BFC1E4A}.Debug.ActiveCfg = Debug|Win32 - {4C0B9915-E8FF-4089-8927-FC934BFC1E4A}.Debug.Build.0 = Debug|Win32 - {4C0B9915-E8FF-4089-8927-FC934BFC1E4A}.Release.ActiveCfg = Release|Win32 - {4C0B9915-E8FF-4089-8927-FC934BFC1E4A}.Release.Build.0 = Release|Win32 - {B850012C-98A2-42F7-B023-9F65C448D938}.Debug.ActiveCfg = Debug|Win32 - {B850012C-98A2-42F7-B023-9F65C448D938}.Debug.Build.0 = Debug|Win32 - {B850012C-98A2-42F7-B023-9F65C448D938}.Release.ActiveCfg = Release|Win32 - {B850012C-98A2-42F7-B023-9F65C448D938}.Release.Build.0 = Release|Win32 - {C3CEFD6F-5CDC-41DE-8D43-D932F508F51B}.Debug.ActiveCfg = Debug|Win32 - {C3CEFD6F-5CDC-41DE-8D43-D932F508F51B}.Debug.Build.0 = Debug|Win32 - {C3CEFD6F-5CDC-41DE-8D43-D932F508F51B}.Release.ActiveCfg = Release|Win32 - {C3CEFD6F-5CDC-41DE-8D43-D932F508F51B}.Release.Build.0 = Release|Win32 - {4FE3FDCA-9571-44B3-A521-C81448434490}.Debug.ActiveCfg = Debug|Win32 - {4FE3FDCA-9571-44B3-A521-C81448434490}.Debug.Build.0 = Debug|Win32 - {4FE3FDCA-9571-44B3-A521-C81448434490}.Release.ActiveCfg = Release|Win32 - {4FE3FDCA-9571-44B3-A521-C81448434490}.Release.Build.0 = Release|Win32 - {A882FC08-8B92-4D4F-89BF-75BCEC2BAE11}.Debug.ActiveCfg = Debug|Win32 - {A882FC08-8B92-4D4F-89BF-75BCEC2BAE11}.Debug.Build.0 = Debug|Win32 - {A882FC08-8B92-4D4F-89BF-75BCEC2BAE11}.Release.ActiveCfg = Release|Win32 - {A882FC08-8B92-4D4F-89BF-75BCEC2BAE11}.Release.Build.0 = Release|Win32 - {D373436F-7DBF-468B-A3E4-601FB8556544}.Debug.ActiveCfg = Debug|Win32 - {D373436F-7DBF-468B-A3E4-601FB8556544}.Debug.Build.0 = Debug|Win32 - {D373436F-7DBF-468B-A3E4-601FB8556544}.Release.ActiveCfg = Release|Win32 - {D373436F-7DBF-468B-A3E4-601FB8556544}.Release.Build.0 = Release|Win32 - {E1DA9FB8-FB4C-4B14-91A6-98BCED6B9720}.Debug.ActiveCfg = Debug|Win32 - {E1DA9FB8-FB4C-4B14-91A6-98BCED6B9720}.Debug.Build.0 = Debug|Win32 - {E1DA9FB8-FB4C-4B14-91A6-98BCED6B9720}.Release.ActiveCfg = Release|Win32 - {E1DA9FB8-FB4C-4B14-91A6-98BCED6B9720}.Release.Build.0 = Release|Win32 - {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720}.Debug.ActiveCfg = Debug|Win32 - {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720}.Debug.Build.0 = Debug|Win32 - {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720}.Release.ActiveCfg = Release|Win32 - {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720}.Release.Build.0 = Release|Win32 - {8A35F55B-B5C2-47A0-8C4A-5857A8E20385}.Debug.ActiveCfg = Debug|Win32 - {8A35F55B-B5C2-47A0-8C4A-5857A8E20385}.Debug.Build.0 = Debug|Win32 - {8A35F55B-B5C2-47A0-8C4A-5857A8E20385}.Release.ActiveCfg = Release|Win32 - {8A35F55B-B5C2-47A0-8C4A-5857A8E20385}.Release.Build.0 = Release|Win32 - {F3704DBF-8055-413C-B027-399E5DBCA4DD}.Debug.ActiveCfg = Debug|Win32 - {F3704DBF-8055-413C-B027-399E5DBCA4DD}.Debug.Build.0 = Debug|Win32 - {F3704DBF-8055-413C-B027-399E5DBCA4DD}.Release.ActiveCfg = Release|Win32 - {F3704DBF-8055-413C-B027-399E5DBCA4DD}.Release.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - EndGlobalSection - GlobalSection(ExtensibilityAddIns) = postSolution - EndGlobalSection -EndGlobal diff --git a/src/src/everything_sdk-2005.sln b/src/src/everything_sdk-2005.sln index 0d5c287..632bf98 100644 --- a/src/src/everything_sdk-2005.sln +++ b/src/src/everything_sdk-2005.sln @@ -1,113 +1,109 @@ Microsoft Visual Studio Solution File, Format Version 9.00 # Visual Studio 2005 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "glview", "utils\glview\glview-2005.vcproj", "{BD1604CA-F401-4C4B-821C-251F5AE157FE}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Glview", "utils\glview\glview-2005.vcproj", "{BD1604CA-F401-4C4B-821C-251F5AE157FE}" ProjectSection(ProjectDependencies) = postProject - {E1DA9FB8-FB4C-4B14-91A6-98BCED6B9720} = {E1DA9FB8-FB4C-4B14-91A6-98BCED6B9720} + {884C66F2-7F84-4570-AE6C-B634C1113D69} = {884C66F2-7F84-4570-AE6C-B634C1113D69} {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720} = {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720} EndProjectSection EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "height2normal", "utils\height2normal\height2normal-2005.vcproj", "{0FDD99E4-130F-493C-8202-4C0236CC47EA}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Height2normal", "utils\height2normal\height2normal-2005.vcproj", "{0FDD99E4-130F-493C-8202-4C0236CC47EA}" ProjectSection(ProjectDependencies) = postProject {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720} = {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720} - {E1DA9FB8-FB4C-4B14-91A6-98BCED6B9720} = {E1DA9FB8-FB4C-4B14-91A6-98BCED6B9720} + {884C66F2-7F84-4570-AE6C-B634C1113D69} = {884C66F2-7F84-4570-AE6C-B634C1113D69} EndProjectSection EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "serverplugin_empty", "utils\serverplugin_sample\serverplugin_empty-2005.vcproj", "{B6572CBE-7C7F-4FFF-94DE-AFBBBAB11C64}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Serverplugin_empty", "utils\serverplugin_sample\serverplugin_empty-2005.vcproj", "{B6572CBE-7C7F-4FFF-94DE-AFBBBAB11C64}" ProjectSection(ProjectDependencies) = postProject {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720} = {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720} - {E1DA9FB8-FB4C-4B14-91A6-98BCED6B9720} = {E1DA9FB8-FB4C-4B14-91A6-98BCED6B9720} + {884C66F2-7F84-4570-AE6C-B634C1113D69} = {884C66F2-7F84-4570-AE6C-B634C1113D69} EndProjectSection EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "studiomdl", "utils\studiomdl\studiomdl-2005.vcproj", "{AE28536E-885A-41BF-99A4-41A7E424B869}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Tgadiff", "utils\tgadiff\tgadiff-2005.vcproj", "{0CE0AF8A-A977-4538-9D63-BCB76DE1BAC6}" ProjectSection(ProjectDependencies) = postProject - {E1DA9FB8-FB4C-4B14-91A6-98BCED6B9720} = {E1DA9FB8-FB4C-4B14-91A6-98BCED6B9720} + {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720} = {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720} + {884C66F2-7F84-4570-AE6C-B634C1113D69} = {884C66F2-7F84-4570-AE6C-B634C1113D69} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Vbsp", "utils\vbsp\vbsp-2005.vcproj", "{B78B6271-B19A-4CF6-926E-40B643548E23}" + ProjectSection(ProjectDependencies) = postProject + {884C66F2-7F84-4570-AE6C-B634C1113D69} = {884C66F2-7F84-4570-AE6C-B634C1113D69} {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720} = {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720} EndProjectSection EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tgadiff", "utils\tgadiff\tgadiff-2005.vcproj", "{0CE0AF8A-A977-4538-9D63-BCB76DE1BAC6}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Vice", "utils\vice\vice-2005.vcproj", "{3CE6E7A9-89EC-4304-8D72-5B602B4DBD09}" ProjectSection(ProjectDependencies) = postProject {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720} = {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720} - {E1DA9FB8-FB4C-4B14-91A6-98BCED6B9720} = {E1DA9FB8-FB4C-4B14-91A6-98BCED6B9720} + {884C66F2-7F84-4570-AE6C-B634C1113D69} = {884C66F2-7F84-4570-AE6C-B634C1113D69} EndProjectSection EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vbsp", "utils\vbsp\vbsp-2005.vcproj", "{B78B6271-B19A-4CF6-926E-40B643548E23}" - ProjectSection(ProjectDependencies) = postProject - {E1DA9FB8-FB4C-4B14-91A6-98BCED6B9720} = {E1DA9FB8-FB4C-4B14-91A6-98BCED6B9720} - {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720} = {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vice", "utils\vice\vice-2005.vcproj", "{3CE6E7A9-89EC-4304-8D72-5B602B4DBD09}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Vrad_launcher", "utils\vrad_launcher\vrad_launcher-2005.vcproj", "{914F19DF-64EC-4E7D-8B01-76477BF06479}" ProjectSection(ProjectDependencies) = postProject {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720} = {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720} EndProjectSection EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vprojtomake", "utils\vprojtomake\vprojtomake-2005.vcproj", "{EA55446E-BC04-491C-A9F0-605DFCBB213A}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Vtf2tga", "utils\vtf2tga\vtf2tga-2005.vcproj", "{2A1F656C-053C-46A4-AE33-304C1D865E0C}" ProjectSection(ProjectDependencies) = postProject {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720} = {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720} + {884C66F2-7F84-4570-AE6C-B634C1113D69} = {884C66F2-7F84-4570-AE6C-B634C1113D69} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Vtfdiff", "utils\vtfdiff\vtfdiff-2005.vcproj", "{0A368DE7-D34A-48D3-B517-996BFF2D0D5D}" + ProjectSection(ProjectDependencies) = postProject + {884C66F2-7F84-4570-AE6C-B634C1113D69} = {884C66F2-7F84-4570-AE6C-B634C1113D69} + {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720} = {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720} EndProjectSection EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vrad", "utils\vrad\vrad-2005.vcproj", "{FC0F5DE3-F09F-4EF6-98F9-BA762FFF268D}" - ProjectSection(ProjectDependencies) = postProject - {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720} = {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720} - {E1DA9FB8-FB4C-4B14-91A6-98BCED6B9720} = {E1DA9FB8-FB4C-4B14-91A6-98BCED6B9720} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vrad_launcher", "utils\vrad_launcher\vrad_launcher-2005.vcproj", "{914F19DF-64EC-4E7D-8B01-76477BF06479}" - ProjectSection(ProjectDependencies) = postProject - {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720} = {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vtf2tga", "utils\vtf2tga\vtf2tga-2005.vcproj", "{2A1F656C-053C-46A4-AE33-304C1D865E0C}" - ProjectSection(ProjectDependencies) = postProject - {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720} = {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720} - {E1DA9FB8-FB4C-4B14-91A6-98BCED6B9720} = {E1DA9FB8-FB4C-4B14-91A6-98BCED6B9720} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vtfdiff", "utils\vtfdiff\vtfdiff-2005.vcproj", "{0A368DE7-D34A-48D3-B517-996BFF2D0D5D}" - ProjectSection(ProjectDependencies) = postProject - {E1DA9FB8-FB4C-4B14-91A6-98BCED6B9720} = {E1DA9FB8-FB4C-4B14-91A6-98BCED6B9720} - {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720} = {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vvis", "utils\vvis\vvis-2005.vcproj", "{5B065E70-6EE0-4B47-BA64-113D2F81220D}" - ProjectSection(ProjectDependencies) = postProject - {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720} = {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720} - {E1DA9FB8-FB4C-4B14-91A6-98BCED6B9720} = {E1DA9FB8-FB4C-4B14-91A6-98BCED6B9720} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vvis_launcher", "utils\vvis_launcher\vvis_launcher-2005.vcproj", "{4C0B9915-E8FF-4089-8927-FC934BFC1E4A}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Vvis_launcher", "utils\vvis_launcher\vvis_launcher-2005.vcproj", "{4C0B9915-E8FF-4089-8927-FC934BFC1E4A}" ProjectSection(ProjectDependencies) = postProject {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720} = {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xwad", "utils\xwad\xwad-2005.vcproj", "{B850012C-98A2-42F7-B023-9F65C448D938}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vgui_controls", "vgui2\controls\vgui_controls-2005.vcproj", "{C3CEFD6F-5CDC-41DE-8D43-D932F508F51B}" -EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "demoinfo", "utils\demoinfo\demoinfo-2005.vcproj", "{4FE3FDCA-9571-44B3-A521-C81448434490}" ProjectSection(ProjectDependencies) = postProject {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720} = {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720} EndProjectSection EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "motionmapper", "utils\motionmapper\motionmapper-2005.vcproj", "{A882FC08-8B92-4D4F-89BF-75BCEC2BAE11}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Motionmapper", "utils\motionmapper\motionmapper-2005.vcproj", "{A882FC08-8B92-4D4F-89BF-75BCEC2BAE11}" ProjectSection(ProjectDependencies) = postProject - {E1DA9FB8-FB4C-4B14-91A6-98BCED6B9720} = {E1DA9FB8-FB4C-4B14-91A6-98BCED6B9720} + {884C66F2-7F84-4570-AE6C-B634C1113D69} = {884C66F2-7F84-4570-AE6C-B634C1113D69} {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720} = {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "QC_Eyes", "utils\qc_eyes\QC_Eyes-2005.vcproj", "{D373436F-7DBF-468B-A3E4-601FB8556544}" + ProjectSection(ProjectDependencies) = postProject + {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720} = {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720} + EndProjectSection EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mathlib", "mathlib\mathlib-2005.vcproj", "{E1DA9FB8-FB4C-4B14-91A6-98BCED6B9720}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mathlib", "mathlib\mathlib-2005.vcproj", "{884C66F2-7F84-4570-AE6C-B634C1113D69}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tier1", "tier1\tier1-2005.vcproj", "{E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "phonemeextractor", "utils\phonemeextractor\phonemeextractor-2005.vcproj", "{8A35F55B-B5C2-47A0-8C4A-5857A8E20385}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Phonemeextractor", "utils\phonemeextractor\phonemeextractor-2005.vcproj", "{8A35F55B-B5C2-47A0-8C4A-5857A8E20385}" ProjectSection(ProjectDependencies) = postProject {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720} = {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720} - {E1DA9FB8-FB4C-4B14-91A6-98BCED6B9720} = {E1DA9FB8-FB4C-4B14-91A6-98BCED6B9720} + {884C66F2-7F84-4570-AE6C-B634C1113D69} = {884C66F2-7F84-4570-AE6C-B634C1113D69} EndProjectSection EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "hlmv", "utils\hlmv\hlmv-2005.vcproj", "{F3704DBF-8055-413C-B027-399E5DBCA4DD}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vgui_controls", "vgui2\vgui_controls\vgui_controls-2005.vcproj", "{BF3EDBF5-ED65-4567-B348-504C1310A1BB}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Vrad_dll", "utils\vrad\vrad_dll-2005.vcproj", "{0DA02E11-F553-4DD1-83D1-F760F2D96862}" + ProjectSection(ProjectDependencies) = postProject + {884C66F2-7F84-4570-AE6C-B634C1113D69} = {884C66F2-7F84-4570-AE6C-B634C1113D69} + {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720} = {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Vvis_dll", "utils\vvis\vvis_dll-2005.vcproj", "{CB353257-04B0-4EC8-9E47-F2F17B2675C9}" + ProjectSection(ProjectDependencies) = postProject + {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720} = {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720} + {884C66F2-7F84-4570-AE6C-B634C1113D69} = {884C66F2-7F84-4570-AE6C-B634C1113D69} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vprojtomake", "utils\vprojtomake\vprojtomake-2005.vcproj", "{EA55446E-BC04-491C-A9F0-605DFCBB213A}" + ProjectSection(ProjectDependencies) = postProject + {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720} = {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720} + EndProjectSection EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -127,10 +123,6 @@ Global {B6572CBE-7C7F-4FFF-94DE-AFBBBAB11C64}.Debug|Win32.Build.0 = Debug|Win32 {B6572CBE-7C7F-4FFF-94DE-AFBBBAB11C64}.Release|Win32.ActiveCfg = Release|Win32 {B6572CBE-7C7F-4FFF-94DE-AFBBBAB11C64}.Release|Win32.Build.0 = Release|Win32 - {AE28536E-885A-41BF-99A4-41A7E424B869}.Debug|Win32.ActiveCfg = Debug|Win32 - {AE28536E-885A-41BF-99A4-41A7E424B869}.Debug|Win32.Build.0 = Debug|Win32 - {AE28536E-885A-41BF-99A4-41A7E424B869}.Release|Win32.ActiveCfg = Release|Win32 - {AE28536E-885A-41BF-99A4-41A7E424B869}.Release|Win32.Build.0 = Release|Win32 {0CE0AF8A-A977-4538-9D63-BCB76DE1BAC6}.Debug|Win32.ActiveCfg = Debug|Win32 {0CE0AF8A-A977-4538-9D63-BCB76DE1BAC6}.Debug|Win32.Build.0 = Debug|Win32 {0CE0AF8A-A977-4538-9D63-BCB76DE1BAC6}.Release|Win32.ActiveCfg = Release|Win32 @@ -143,14 +135,6 @@ Global {3CE6E7A9-89EC-4304-8D72-5B602B4DBD09}.Debug|Win32.Build.0 = Debug|Win32 {3CE6E7A9-89EC-4304-8D72-5B602B4DBD09}.Release|Win32.ActiveCfg = Release|Win32 {3CE6E7A9-89EC-4304-8D72-5B602B4DBD09}.Release|Win32.Build.0 = Release|Win32 - {EA55446E-BC04-491C-A9F0-605DFCBB213A}.Debug|Win32.ActiveCfg = Debug|Win32 - {EA55446E-BC04-491C-A9F0-605DFCBB213A}.Debug|Win32.Build.0 = Debug|Win32 - {EA55446E-BC04-491C-A9F0-605DFCBB213A}.Release|Win32.ActiveCfg = Release|Win32 - {EA55446E-BC04-491C-A9F0-605DFCBB213A}.Release|Win32.Build.0 = Release|Win32 - {FC0F5DE3-F09F-4EF6-98F9-BA762FFF268D}.Debug|Win32.ActiveCfg = Debug|Win32 - {FC0F5DE3-F09F-4EF6-98F9-BA762FFF268D}.Debug|Win32.Build.0 = Debug|Win32 - {FC0F5DE3-F09F-4EF6-98F9-BA762FFF268D}.Release|Win32.ActiveCfg = Release|Win32 - {FC0F5DE3-F09F-4EF6-98F9-BA762FFF268D}.Release|Win32.Build.0 = Release|Win32 {914F19DF-64EC-4E7D-8B01-76477BF06479}.Debug|Win32.ActiveCfg = Debug|Win32 {914F19DF-64EC-4E7D-8B01-76477BF06479}.Debug|Win32.Build.0 = Debug|Win32 {914F19DF-64EC-4E7D-8B01-76477BF06479}.Release|Win32.ActiveCfg = Release|Win32 @@ -163,10 +147,6 @@ Global {0A368DE7-D34A-48D3-B517-996BFF2D0D5D}.Debug|Win32.Build.0 = Debug|Win32 {0A368DE7-D34A-48D3-B517-996BFF2D0D5D}.Release|Win32.ActiveCfg = Release|Win32 {0A368DE7-D34A-48D3-B517-996BFF2D0D5D}.Release|Win32.Build.0 = Release|Win32 - {5B065E70-6EE0-4B47-BA64-113D2F81220D}.Debug|Win32.ActiveCfg = Debug|Win32 - {5B065E70-6EE0-4B47-BA64-113D2F81220D}.Debug|Win32.Build.0 = Debug|Win32 - {5B065E70-6EE0-4B47-BA64-113D2F81220D}.Release|Win32.ActiveCfg = Release|Win32 - {5B065E70-6EE0-4B47-BA64-113D2F81220D}.Release|Win32.Build.0 = Release|Win32 {4C0B9915-E8FF-4089-8927-FC934BFC1E4A}.Debug|Win32.ActiveCfg = Debug|Win32 {4C0B9915-E8FF-4089-8927-FC934BFC1E4A}.Debug|Win32.Build.0 = Debug|Win32 {4C0B9915-E8FF-4089-8927-FC934BFC1E4A}.Release|Win32.ActiveCfg = Release|Win32 @@ -175,10 +155,6 @@ Global {B850012C-98A2-42F7-B023-9F65C448D938}.Debug|Win32.Build.0 = Debug|Win32 {B850012C-98A2-42F7-B023-9F65C448D938}.Release|Win32.ActiveCfg = Release|Win32 {B850012C-98A2-42F7-B023-9F65C448D938}.Release|Win32.Build.0 = Release|Win32 - {C3CEFD6F-5CDC-41DE-8D43-D932F508F51B}.Debug|Win32.ActiveCfg = Debug|Win32 - {C3CEFD6F-5CDC-41DE-8D43-D932F508F51B}.Debug|Win32.Build.0 = Debug|Win32 - {C3CEFD6F-5CDC-41DE-8D43-D932F508F51B}.Release|Win32.ActiveCfg = Release|Win32 - {C3CEFD6F-5CDC-41DE-8D43-D932F508F51B}.Release|Win32.Build.0 = Release|Win32 {4FE3FDCA-9571-44B3-A521-C81448434490}.Debug|Win32.ActiveCfg = Debug|Win32 {4FE3FDCA-9571-44B3-A521-C81448434490}.Debug|Win32.Build.0 = Debug|Win32 {4FE3FDCA-9571-44B3-A521-C81448434490}.Release|Win32.ActiveCfg = Release|Win32 @@ -191,10 +167,10 @@ Global {D373436F-7DBF-468B-A3E4-601FB8556544}.Debug|Win32.Build.0 = Debug|Win32 {D373436F-7DBF-468B-A3E4-601FB8556544}.Release|Win32.ActiveCfg = Release|Win32 {D373436F-7DBF-468B-A3E4-601FB8556544}.Release|Win32.Build.0 = Release|Win32 - {E1DA9FB8-FB4C-4B14-91A6-98BCED6B9720}.Debug|Win32.ActiveCfg = Debug|Win32 - {E1DA9FB8-FB4C-4B14-91A6-98BCED6B9720}.Debug|Win32.Build.0 = Debug|Win32 - {E1DA9FB8-FB4C-4B14-91A6-98BCED6B9720}.Release|Win32.ActiveCfg = Release|Win32 - {E1DA9FB8-FB4C-4B14-91A6-98BCED6B9720}.Release|Win32.Build.0 = Release|Win32 + {884C66F2-7F84-4570-AE6C-B634C1113D69}.Debug|Win32.ActiveCfg = Debug|Win32 + {884C66F2-7F84-4570-AE6C-B634C1113D69}.Debug|Win32.Build.0 = Debug|Win32 + {884C66F2-7F84-4570-AE6C-B634C1113D69}.Release|Win32.ActiveCfg = Release|Win32 + {884C66F2-7F84-4570-AE6C-B634C1113D69}.Release|Win32.Build.0 = Release|Win32 {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720}.Debug|Win32.ActiveCfg = Debug|Win32 {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720}.Debug|Win32.Build.0 = Debug|Win32 {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720}.Release|Win32.ActiveCfg = Release|Win32 @@ -203,10 +179,22 @@ Global {8A35F55B-B5C2-47A0-8C4A-5857A8E20385}.Debug|Win32.Build.0 = Debug|Win32 {8A35F55B-B5C2-47A0-8C4A-5857A8E20385}.Release|Win32.ActiveCfg = Release|Win32 {8A35F55B-B5C2-47A0-8C4A-5857A8E20385}.Release|Win32.Build.0 = Release|Win32 - {F3704DBF-8055-413C-B027-399E5DBCA4DD}.Debug|Win32.ActiveCfg = Debug|Win32 - {F3704DBF-8055-413C-B027-399E5DBCA4DD}.Debug|Win32.Build.0 = Debug|Win32 - {F3704DBF-8055-413C-B027-399E5DBCA4DD}.Release|Win32.ActiveCfg = Release|Win32 - {F3704DBF-8055-413C-B027-399E5DBCA4DD}.Release|Win32.Build.0 = Release|Win32 + {BF3EDBF5-ED65-4567-B348-504C1310A1BB}.Debug|Win32.ActiveCfg = Debug|Win32 + {BF3EDBF5-ED65-4567-B348-504C1310A1BB}.Debug|Win32.Build.0 = Debug|Win32 + {BF3EDBF5-ED65-4567-B348-504C1310A1BB}.Release|Win32.ActiveCfg = Release|Win32 + {BF3EDBF5-ED65-4567-B348-504C1310A1BB}.Release|Win32.Build.0 = Release|Win32 + {0DA02E11-F553-4DD1-83D1-F760F2D96862}.Debug|Win32.ActiveCfg = Debug|Win32 + {0DA02E11-F553-4DD1-83D1-F760F2D96862}.Debug|Win32.Build.0 = Debug|Win32 + {0DA02E11-F553-4DD1-83D1-F760F2D96862}.Release|Win32.ActiveCfg = Release|Win32 + {0DA02E11-F553-4DD1-83D1-F760F2D96862}.Release|Win32.Build.0 = Release|Win32 + {CB353257-04B0-4EC8-9E47-F2F17B2675C9}.Debug|Win32.ActiveCfg = Debug|Win32 + {CB353257-04B0-4EC8-9E47-F2F17B2675C9}.Debug|Win32.Build.0 = Debug|Win32 + {CB353257-04B0-4EC8-9E47-F2F17B2675C9}.Release|Win32.ActiveCfg = Release|Win32 + {CB353257-04B0-4EC8-9E47-F2F17B2675C9}.Release|Win32.Build.0 = Release|Win32 + {EA55446E-BC04-491C-A9F0-605DFCBB213A}.Debug|Win32.ActiveCfg = Debug|Win32 + {EA55446E-BC04-491C-A9F0-605DFCBB213A}.Debug|Win32.Build.0 = Debug|Win32 + {EA55446E-BC04-491C-A9F0-605DFCBB213A}.Release|Win32.ActiveCfg = Release|Win32 + {EA55446E-BC04-491C-A9F0-605DFCBB213A}.Release|Win32.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/src/filecopy.bat b/src/src/filecopy.bat deleted file mode 100644 index 4a65768..0000000 --- a/src/src/filecopy.bat +++ /dev/null @@ -1,5 +0,0 @@ -@echo off -@if exist %2 attrib -r %2 -@if exist %2 del %2 -@copy %1 %2 -@if exist %2 attrib +r %2 diff --git a/src/src/game/client/achievement_notification_panel.cpp b/src/src/game/client/achievement_notification_panel.cpp new file mode 100644 index 0000000..89ac25a --- /dev/null +++ b/src/src/game/client/achievement_notification_panel.cpp @@ -0,0 +1,271 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#include "cbase.h" +#include "hud.h" +#include "hud_macros.h" +#include "hudelement.h" +#include "iclientmode.h" +#include "ienginevgui.h" +#include +#include +#include +#include +#include +#include +#include "achievement_notification_panel.h" +#include "steam/steam_api.h" +#include "iachievementmgr.h" +#include "fmtstr.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +using namespace vgui; + +#define ACHIEVEMENT_NOTIFICATION_DURATION 10.0f + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- + +DECLARE_HUDELEMENT_DEPTH( CAchievementNotificationPanel, 100 ); + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CAchievementNotificationPanel::CAchievementNotificationPanel( const char *pElementName ) : CHudElement( pElementName ), BaseClass( NULL, "AchievementNotificationPanel" ) +{ + Panel *pParent = g_pClientMode->GetViewport(); + SetParent( pParent ); + + m_flHideTime = 0; + m_pPanelBackground = new EditablePanel( this, "Notification_Background" ); + m_pIcon = new ImagePanel( this, "Notification_Icon" ); + m_pLabelHeading = new Label( this, "HeadingLabel", "" ); + m_pLabelTitle = new Label( this, "TitleLabel", "" ); + + m_pIcon->SetShouldScaleImage( true ); + + vgui::ivgui()->AddTickSignal( GetVPanel() ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CAchievementNotificationPanel::Init() +{ + ListenForGameEvent( "achievement_event" ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CAchievementNotificationPanel::ApplySchemeSettings( IScheme *pScheme ) +{ + // load control settings... + LoadControlSettings( "resource/UI/AchievementNotification.res" ); + + BaseClass::ApplySchemeSettings( pScheme ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CAchievementNotificationPanel::PerformLayout( void ) +{ + BaseClass::PerformLayout(); + + // Set background color of various elements. Need to do this in code, if we do it in res file it gets slammed by the + // scheme. (Incl. label background: some products don't have label background colors set in their scheme and helpfully slam it to white.) + SetBgColor( Color( 0, 0, 0, 0 ) ); + m_pLabelHeading->SetBgColor( Color( 0, 0, 0, 0 ) ); + m_pLabelTitle->SetBgColor( Color( 0, 0, 0, 0 ) ); + m_pPanelBackground->SetBgColor( Color( 62,70,55, 200 ) ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CAchievementNotificationPanel::FireGameEvent( IGameEvent * event ) +{ + const char *name = event->GetName(); + if ( 0 == Q_strcmp( name, "achievement_event" ) ) + { + const char *pchName = event->GetString( "achievement_name" ); + int iCur = event->GetInt( "cur_val" ); + int iMax = event->GetInt( "max_val" ); + wchar_t szLocalizedName[256]=L""; + + if ( IsPC() ) + { + // shouldn't ever get achievement progress if steam not running and user logged in, but check just in case + if ( !steamapicontext->SteamUserStats() ) + { + Msg( "Steam not running, achievement progress notification not displayed\n" ); + } + + // use Steam to show achievement progress UI + CGameID gameID( engine->GetAppID() ); + steamapicontext->SteamUserStats()->IndicateAchievementProgress( gameID, pchName, iCur, iMax ); + } + else + { + // on X360 we need to show our own achievement progress UI + + const wchar_t *pchLocalizedName = ACHIEVEMENT_LOCALIZED_NAME_FROM_STR( pchName ); + Assert( pchLocalizedName ); + if ( !pchLocalizedName || !pchLocalizedName[0] ) + return; + Q_wcsncpy( szLocalizedName, pchLocalizedName, sizeof( szLocalizedName ) ); + + // this is achievement progress, compose the message of form: " (<#>/)" + wchar_t szFmt[128]=L""; + wchar_t szText[512]=L""; + wchar_t szNumFound[16]=L""; + wchar_t szNumTotal[16]=L""; + _snwprintf( szNumFound, ARRAYSIZE( szNumFound ), L"%i", iCur ); + _snwprintf( szNumTotal, ARRAYSIZE( szNumTotal ), L"%i", iMax ); + + const wchar_t *pchFmt = g_pVGuiLocalize->Find( "#GameUI_Achievement_Progress_Fmt" ); + if ( !pchFmt || !pchFmt[0] ) + return; + Q_wcsncpy( szFmt, pchFmt, sizeof( szFmt ) ); + + g_pVGuiLocalize->ConstructString( szText, sizeof( szText ), szFmt, 3, szLocalizedName, szNumFound, szNumTotal ); + AddNotification( pchName, g_pVGuiLocalize->Find( "#GameUI_Achievement_Progress" ), szText ); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: Called on each tick +//----------------------------------------------------------------------------- +void CAchievementNotificationPanel::OnTick( void ) +{ + if ( ( m_flHideTime > 0 ) && ( m_flHideTime < gpGlobals->curtime ) ) + { + m_flHideTime = 0; + ShowNextNotification(); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CAchievementNotificationPanel::ShouldDraw( void ) +{ + return ( ( m_flHideTime > 0 ) && ( m_flHideTime > gpGlobals->curtime ) && CHudElement::ShouldDraw() ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CAchievementNotificationPanel::AddNotification( const char *szIconBaseName, const wchar_t *pHeading, const wchar_t *pTitle ) +{ + // put this notification in our queue + int iQueueItem = m_queueNotification.AddToTail(); + Notification_t ¬ification = m_queueNotification[iQueueItem]; + Q_strncpy( notification.szIconBaseName, szIconBaseName, ARRAYSIZE( notification.szIconBaseName ) ); + Q_wcsncpy( notification.szHeading, pHeading, sizeof( notification.szHeading ) ); + Q_wcsncpy( notification.szTitle, pTitle, sizeof( notification.szTitle ) ); + + // if we are not currently displaying a notification, go ahead and show this one + if ( 0 == m_flHideTime ) + { + ShowNextNotification(); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Shows next notification in queue if there is one +//----------------------------------------------------------------------------- +void CAchievementNotificationPanel::ShowNextNotification() +{ + // see if we have anything to do + if ( 0 == m_queueNotification.Count() ) + { + m_flHideTime = 0; + return; + } + + Notification_t ¬ification = m_queueNotification[ m_queueNotification.Head() ]; + + m_flHideTime = gpGlobals->curtime + ACHIEVEMENT_NOTIFICATION_DURATION; + + // set the text and icon in the dialog + SetDialogVariable( "heading", notification.szHeading ); + SetDialogVariable( "title", notification.szTitle ); + const char *pchIconBaseName = notification.szIconBaseName; + if ( pchIconBaseName && pchIconBaseName[0] ) + { + m_pIcon->SetImage( CFmtStr( "achievements/%s.vmt", pchIconBaseName ) ); + } + + // resize the panel so it always looks good + + // get fonts + HFont hFontHeading = m_pLabelHeading->GetFont(); + HFont hFontTitle = m_pLabelTitle->GetFont(); + // determine how wide the text strings are + int iHeadingWidth = UTIL_ComputeStringWidth( hFontHeading, notification.szHeading ); + int iTitleWidth = UTIL_ComputeStringWidth( hFontTitle, notification.szTitle ); + // use the widest string + int iTextWidth = max( iHeadingWidth, iTitleWidth ); + // don't let it be insanely wide + iTextWidth = min( iTextWidth, XRES( 300 ) ); + int iIconWidth = m_pIcon->GetWide(); + int iSpacing = XRES( 10 ); + int iPanelWidth = iSpacing + iIconWidth + iSpacing + iTextWidth + iSpacing; + int iPanelX = GetWide() - iPanelWidth; + int iIconX = iPanelX + iSpacing; + int iTextX = iIconX + iIconWidth + iSpacing; + // resize all the elements + SetXAndWide( m_pPanelBackground, iPanelX, iPanelWidth ); + SetXAndWide( m_pIcon, iIconX, iIconWidth ); + SetXAndWide( m_pLabelHeading, iTextX, iTextWidth ); + SetXAndWide( m_pLabelTitle, iTextX, iTextWidth ); + + m_queueNotification.Remove( m_queueNotification.Head() ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CAchievementNotificationPanel::SetXAndWide( Panel *pPanel, int x, int wide ) +{ + int xCur, yCur; + pPanel->GetPos( xCur, yCur ); + pPanel->SetPos( x, yCur ); + pPanel->SetWide( wide ); +} + +CON_COMMAND_F( achievement_notification_test, "Test the hud notification UI", FCVAR_CHEAT | FCVAR_DEVELOPMENTONLY ) +{ + static int iCount=0; + + CAchievementNotificationPanel *pPanel = GET_HUDELEMENT( CAchievementNotificationPanel ); + if ( pPanel ) + { + pPanel->AddNotification( "HL2_KILL_ODESSAGUNSHIP", L"Achievement Progress", ( 0 == ( iCount % 2 ) ? L"Test Notification Message A (1/10)" : + L"Test Message B" ) ); + } + +#if 0 + IGameEvent *event = gameeventmanager->CreateEvent( "achievement_event" ); + if ( event ) + { + const char *szTestStr[] = { "TF_GET_HEADSHOTS", "TF_PLAY_GAME_EVERYMAP", "TF_PLAY_GAME_EVERYCLASS", "TF_GET_HEALPOINTS" }; + event->SetString( "achievement_name", szTestStr[iCount%ARRAYSIZE(szTestStr)] ); + event->SetInt( "cur_val", ( iCount%9 ) + 1 ); + event->SetInt( "max_val", 10 ); + gameeventmanager->FireEvent( event ); + } +#endif + + iCount++; +} \ No newline at end of file diff --git a/src/src/game/client/achievement_notification_panel.h b/src/src/game/client/achievement_notification_panel.h new file mode 100644 index 0000000..1414462 --- /dev/null +++ b/src/src/game/client/achievement_notification_panel.h @@ -0,0 +1,57 @@ +//========= Copyright © 1996-2006, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef ACHIEVEMENT_NOTIFICATION_PANEL_H +#define ACHIEVEMENT_NOTIFICATION_PANEL_H +#ifdef _WIN32 +#pragma once +#endif + +#include +#include "hudelement.h" + +using namespace vgui; + +class CAchievementNotificationPanel : public CHudElement, public EditablePanel +{ + DECLARE_CLASS_SIMPLE( CAchievementNotificationPanel, EditablePanel ); + +public: + CAchievementNotificationPanel( const char *pElementName ); + + virtual void Init(); + virtual void ApplySchemeSettings( IScheme *scheme ); + virtual bool ShouldDraw( void ); + virtual void PerformLayout( void ); + virtual void LevelInit( void ) { m_flHideTime = 0; } + virtual void FireGameEvent( IGameEvent * event ); + virtual void OnTick( void ); + + void AddNotification( const char *szIconBaseName, const wchar_t *pHeading, const wchar_t *pTitle ); + +private: + void ShowNextNotification(); + void SetXAndWide( Panel *pPanel, int x, int wide ); + + float m_flHideTime; + + Label *m_pLabelHeading; + Label *m_pLabelTitle; + EditablePanel *m_pPanelBackground; + ImagePanel *m_pIcon; + + struct Notification_t + { + char szIconBaseName[255]; + wchar_t szHeading[255]; + wchar_t szTitle[255]; + }; + + CUtlLinkedList m_queueNotification; +}; + +#endif // ACHIEVEMENT_NOTIFICATION_PANEL_H \ No newline at end of file diff --git a/src/src/cl_dll/alphamaterialproxy.cpp b/src/src/game/client/alphamaterialproxy.cpp similarity index 88% rename from src/src/cl_dll/alphamaterialproxy.cpp rename to src/src/game/client/alphamaterialproxy.cpp index 943a59e..99808b0 100644 --- a/src/src/cl_dll/alphamaterialproxy.cpp +++ b/src/src/game/client/alphamaterialproxy.cpp @@ -20,6 +20,7 @@ public: virtual ~CAlphaMaterialProxy(); virtual bool Init( IMaterial *pMaterial, KeyValues *pKeyValues ); virtual void OnBind( C_BaseEntity *pEntity ); + virtual IMaterial *GetMaterial(); private: IMaterialVar *m_AlphaVar; @@ -50,4 +51,12 @@ void CAlphaMaterialProxy::OnBind( C_BaseEntity *pEnt ) } } +IMaterial *CAlphaMaterialProxy::GetMaterial() +{ + if ( !m_AlphaVar ) + return NULL; + + return m_AlphaVar->GetOwningMaterial(); +} + EXPOSE_INTERFACE( CAlphaMaterialProxy, IMaterialProxy, "Alpha" IMATERIAL_PROXY_INTERFACE_VERSION ); diff --git a/src/src/cl_dll/animatedentitytextureproxy.cpp b/src/src/game/client/animatedentitytextureproxy.cpp similarity index 100% rename from src/src/cl_dll/animatedentitytextureproxy.cpp rename to src/src/game/client/animatedentitytextureproxy.cpp diff --git a/src/src/cl_dll/animatedoffsettextureproxy.cpp b/src/src/game/client/animatedoffsettextureproxy.cpp similarity index 100% rename from src/src/cl_dll/animatedoffsettextureproxy.cpp rename to src/src/game/client/animatedoffsettextureproxy.cpp diff --git a/src/src/cl_dll/animatedtextureproxy.cpp b/src/src/game/client/animatedtextureproxy.cpp similarity index 100% rename from src/src/cl_dll/animatedtextureproxy.cpp rename to src/src/game/client/animatedtextureproxy.cpp diff --git a/src/src/cl_dll/animatespecifictextureproxy.cpp b/src/src/game/client/animatespecifictextureproxy.cpp similarity index 100% rename from src/src/cl_dll/animatespecifictextureproxy.cpp rename to src/src/game/client/animatespecifictextureproxy.cpp diff --git a/src/src/cl_dll/animationlayer.h b/src/src/game/client/animationlayer.h similarity index 94% rename from src/src/cl_dll/animationlayer.h rename to src/src/game/client/animationlayer.h index 096a795..77e75e7 100644 --- a/src/src/cl_dll/animationlayer.h +++ b/src/src/game/client/animationlayer.h @@ -22,6 +22,7 @@ public: ALLOW_DATATABLES_PRIVATE_ACCESS(); C_AnimationLayer(); + void Reset(); void SetOrder( int order ); @@ -29,7 +30,7 @@ public: bool IsActive( void ); - CRangeCheckedVar m_nSequence; + CRangeCheckedVar m_nSequence; CRangeCheckedVar m_flPrevCycle; CRangeCheckedVar m_flWeight; int m_nOrder; @@ -49,6 +50,11 @@ public: inline C_AnimationLayer::C_AnimationLayer() +{ + Reset(); +} + +inline void C_AnimationLayer::Reset() { m_nSequence = 0; m_flPrevCycle = 0; @@ -92,7 +98,7 @@ inline float C_AnimationLayer::GetFadeout( float flCurTime ) } -inline C_AnimationLayer LoopingLerp( float flPercent, C_AnimationLayer from, C_AnimationLayer to ) +inline C_AnimationLayer LoopingLerp( float flPercent, C_AnimationLayer& from, C_AnimationLayer& to ) { C_AnimationLayer output; @@ -122,7 +128,7 @@ inline C_AnimationLayer Lerp( float flPercent, const C_AnimationLayer& from, con return output; } -inline C_AnimationLayer LoopingLerp_Hermite( float flPercent, C_AnimationLayer prev, C_AnimationLayer from, C_AnimationLayer to ) +inline C_AnimationLayer LoopingLerp_Hermite( float flPercent, C_AnimationLayer& prev, C_AnimationLayer& from, C_AnimationLayer& to ) { C_AnimationLayer output; diff --git a/src/src/cl_dll/baseanimatedtextureproxy.cpp b/src/src/game/client/baseanimatedtextureproxy.cpp similarity index 91% rename from src/src/cl_dll/baseanimatedtextureproxy.cpp rename to src/src/game/client/baseanimatedtextureproxy.cpp index 9aa06da..f4af78e 100644 --- a/src/src/cl_dll/baseanimatedtextureproxy.cpp +++ b/src/src/game/client/baseanimatedtextureproxy.cpp @@ -9,11 +9,15 @@ #include "materialsystem/IMaterial.h" #include "materialsystem/IMaterialVar.h" #include "materialsystem/ITexture.h" -#include +#include "tier1/KeyValues.h" +#include "toolframework_client.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" +// forward declarations +void ToolFramework_RecordMaterialParams( IMaterial *pMaterial ); + //----------------------------------------------------------------------------- // Constructor, destructor: //----------------------------------------------------------------------------- @@ -121,4 +125,14 @@ void CBaseAnimatedTextureProxy::OnBind( void *pEntity ) } m_AnimatedTextureFrameNumVar->SetIntValue( intFrame ); + + if ( ToolsEnabled() ) + { + ToolFramework_RecordMaterialParams( GetMaterial() ); + } +} + +IMaterial *CBaseAnimatedTextureProxy::GetMaterial() +{ + return m_AnimatedTextureVar->GetOwningMaterial(); } diff --git a/src/src/cl_dll/baseanimatedtextureproxy.h b/src/src/game/client/baseanimatedtextureproxy.h similarity index 97% rename from src/src/cl_dll/baseanimatedtextureproxy.h rename to src/src/game/client/baseanimatedtextureproxy.h index c6aa758..1f6704f 100644 --- a/src/src/cl_dll/baseanimatedtextureproxy.h +++ b/src/src/game/client/baseanimatedtextureproxy.h @@ -24,6 +24,7 @@ public: virtual bool Init( IMaterial *pMaterial, KeyValues *pKeyValues ); virtual void OnBind( void *pC_BaseEntity ); virtual void Release( void ) { delete this; } + virtual IMaterial *GetMaterial(); protected: // derived classes must implement this; it returns the time diff --git a/src/src/cl_dll/baseclientrendertargets.cpp b/src/src/game/client/baseclientrendertargets.cpp similarity index 84% rename from src/src/cl_dll/baseclientrendertargets.cpp rename to src/src/game/client/baseclientrendertargets.cpp index fdacd8f..7337583 100644 --- a/src/src/cl_dll/baseclientrendertargets.cpp +++ b/src/src/game/client/baseclientrendertargets.cpp @@ -4,31 +4,28 @@ // Provides Init functions for common render textures used by the engine. // Mod makers can inherit from this class, and call the Create functions for // only the render textures the want for their mod. -// -// $NoKeywords: $ //=============================================================================// + #include "cbase.h" #include "baseclientrendertargets.h" // header #include "materialsystem/imaterialsystemhardwareconfig.h" // Hardware config checks - -ITexture* CBaseClientRenderTargets::CreateWaterReflectionTexture( IMaterialSystem* pMaterialSystem ) +ITexture* CBaseClientRenderTargets::CreateWaterReflectionTexture( IMaterialSystem* pMaterialSystem, int iSize ) { return pMaterialSystem->CreateNamedRenderTargetTextureEx2( "_rt_WaterReflection", - 1024, 1024, RT_SIZE_PICMIP, + iSize, iSize, RT_SIZE_PICMIP, pMaterialSystem->GetBackBufferFormat(), MATERIAL_RT_DEPTH_SHARED, TEXTUREFLAGS_CLAMPS | TEXTUREFLAGS_CLAMPT, CREATERENDERTARGETFLAGS_HDR ); } - -ITexture* CBaseClientRenderTargets::CreateWaterRefractionTexture( IMaterialSystem* pMaterialSystem ) +ITexture* CBaseClientRenderTargets::CreateWaterRefractionTexture( IMaterialSystem* pMaterialSystem, int iSize ) { return pMaterialSystem->CreateNamedRenderTargetTextureEx2( "_rt_WaterRefraction", - 1024, 1024, RT_SIZE_PICMIP, + iSize, iSize, RT_SIZE_PICMIP, // This is different than reflection because it has to have alpha for fog factor. IMAGE_FORMAT_RGBA8888, MATERIAL_RT_DEPTH_SHARED, @@ -36,12 +33,11 @@ ITexture* CBaseClientRenderTargets::CreateWaterRefractionTexture( IMaterialSyste CREATERENDERTARGETFLAGS_HDR ); } - -ITexture* CBaseClientRenderTargets::CreateCameraTexture( IMaterialSystem* pMaterialSystem ) +ITexture* CBaseClientRenderTargets::CreateCameraTexture( IMaterialSystem* pMaterialSystem, int iSize ) { return pMaterialSystem->CreateNamedRenderTargetTextureEx2( "_rt_Camera", - 256, 256, RT_SIZE_DEFAULT, + iSize, iSize, RT_SIZE_DEFAULT, pMaterialSystem->GetBackBufferFormat(), MATERIAL_RT_DEPTH_SHARED, 0, @@ -55,14 +51,14 @@ ITexture* CBaseClientRenderTargets::CreateCameraTexture( IMaterialSystem* pMater // Input : pMaterialSystem - the engine's material system (our singleton is not yet inited at the time this is called) // pHardwareConfig - the user hardware config, useful for conditional render target setup //----------------------------------------------------------------------------- -void CBaseClientRenderTargets::InitClientRenderTargets( IMaterialSystem* pMaterialSystem, IMaterialSystemHardwareConfig* pHardwareConfig ) +void CBaseClientRenderTargets::InitClientRenderTargets( IMaterialSystem* pMaterialSystem, IMaterialSystemHardwareConfig* pHardwareConfig, int iWaterTextureSize, int iCameraTextureSize ) { // Water effects - m_WaterReflectionTexture.Init( CreateWaterReflectionTexture( pMaterialSystem ) ); - m_WaterRefractionTexture.Init ( CreateWaterRefractionTexture( pMaterialSystem ) ); + m_WaterReflectionTexture.Init( CreateWaterReflectionTexture( pMaterialSystem, iWaterTextureSize ) ); + m_WaterRefractionTexture.Init( CreateWaterRefractionTexture( pMaterialSystem, iWaterTextureSize ) ); // Monitors - m_CameraTexture.Init ( CreateCameraTexture( pMaterialSystem ) ); + m_CameraTexture.Init( CreateCameraTexture( pMaterialSystem, iCameraTextureSize ) ); } //----------------------------------------------------------------------------- diff --git a/src/src/cl_dll/baseclientrendertargets.h b/src/src/game/client/baseclientrendertargets.h similarity index 87% rename from src/src/cl_dll/baseclientrendertargets.h rename to src/src/game/client/baseclientrendertargets.h index 324632e..448b1dc 100644 --- a/src/src/cl_dll/baseclientrendertargets.h +++ b/src/src/game/client/baseclientrendertargets.h @@ -21,7 +21,7 @@ #pragma once #endif -#include "cl_dll\iclientrendertargets.h" // base class with interfaces called by the engine +#include "game/client/iclientrendertargets.h" // base class with interfaces called by the engine #include "materialsystem\imaterialsystem.h" // for material system classes and interfaces @@ -35,7 +35,7 @@ class CBaseClientRenderTargets : public IClientRenderTargets DECLARE_CLASS_GAMEROOT( CBaseClientRenderTargets, IClientRenderTargets ); public: // Interface called by engine during material system startup. - virtual void InitClientRenderTargets ( IMaterialSystem* pMaterialSystem, IMaterialSystemHardwareConfig* pHardwareConfig ); + virtual void InitClientRenderTargets ( IMaterialSystem* pMaterialSystem, IMaterialSystemHardwareConfig* pHardwareConfig, int iWaterTextureSize = 1024, int iCameraTextureSize = 256 ); // Shutdown all custom render targets here. virtual void ShutdownClientRenderTargets ( void ); @@ -52,9 +52,9 @@ protected: CTextureReference m_CameraTexture; // Init functions for the common render targets - ITexture* CreateWaterReflectionTexture( IMaterialSystem* pMaterialSystem ); - ITexture* CreateWaterRefractionTexture( IMaterialSystem* pMaterialSystem ); - ITexture* CreateCameraTexture( IMaterialSystem* pMaterialSystem ); + ITexture* CreateWaterReflectionTexture( IMaterialSystem* pMaterialSystem, int iSize = 1024 ); + ITexture* CreateWaterRefractionTexture( IMaterialSystem* pMaterialSystem, int iSize = 1024 ); + ITexture* CreateCameraTexture( IMaterialSystem* pMaterialSystem, int iSize = 256 ); }; diff --git a/src/src/game/client/basepresence.cpp b/src/src/game/client/basepresence.cpp new file mode 100644 index 0000000..10c1c9e --- /dev/null +++ b/src/src/game/client/basepresence.cpp @@ -0,0 +1,94 @@ +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: Base presence implementation for PC +// +//=====================================================================================// + +#include "cbase.h" +#include "basepresence.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +// Default global singleton. Mods should override this. +static CBasePresence s_basePresence; +IPresence *presence = NULL; + +//----------------------------------------------------------------------------- +// Steam version of Rich Presence is a WIP, so PC implementation is stubbed for now. +//----------------------------------------------------------------------------- +bool CBasePresence::Init( void ) +{ + if ( !presence ) + { + // Mod didn't override, default to base implementation + presence = &s_basePresence; + } + return true; +} +void CBasePresence::Shutdown( void ) +{ + // TODO: Implement for PC +} +void CBasePresence::Update( float frametime ) +{ + // TODO: Implement for PC +} +void CBasePresence::UserSetContext( unsigned int nUserIndex, unsigned int nContextId, unsigned int nContextValue, bool bAsync ) +{ + // TODO: Implement for PC +} +void CBasePresence::UserSetProperty( unsigned int nUserIndex, unsigned int nPropertyId, unsigned int nBytes, const void *pvValue, bool bAsync ) +{ + // TODO: Implement for PC +} +void CBasePresence::SetupGameProperties( CUtlVector< XUSER_CONTEXT > &contexts, CUtlVector< XUSER_PROPERTY > &properties ) +{ + // TODO: Implement for PC +} +unsigned int CBasePresence::GetPresenceID( const char *pIDName ) +{ + return 0; +} +const char *CBasePresence::GetPropertyIdString( const uint id ) +{ + return NULL; +} +void CBasePresence::GetPropertyDisplayString( uint id, uint value, char *pOutput, int nBytes ) +{ +} +void CBasePresence::StartStatsReporting( HANDLE handle, bool bArbitrated ) +{ +} +void CBasePresence::SetStat( uint iPropertyId, int iPropertyValue, int dataType ) +{ +} +void CBasePresence::UploadStats() +{ +} + +//--------------------------------------------------------- +// Debug support +//--------------------------------------------------------- +void CBasePresence::DebugUserSetContext( const CCommand &args ) +{ + if ( args.ArgC() == 3 ) + { + UserSetContext( 0, atoi( args.Arg( 1 ) ), atoi( args.Arg( 2 ) ) ); + } + else + { + Warning( "user_context \n" ); + } +} +void CBasePresence::DebugUserSetProperty( const CCommand &args ) +{ + if ( args.ArgC() == 3 ) + { + UserSetProperty( 0, strtoul( args.Arg( 1 ), NULL, 0 ), sizeof(int), args.Arg( 2 ) ); + } + else + { + Warning( "user_property \n" ); + } +} diff --git a/src/src/game/client/basepresence.h b/src/src/game/client/basepresence.h new file mode 100644 index 0000000..add7368 --- /dev/null +++ b/src/src/game/client/basepresence.h @@ -0,0 +1,55 @@ +//====== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======= +// +// Purpose: Base implementation of the IPresence interface +// +//============================================================================= + +#ifndef BASEPRESENCE_H +#define BASEPRESENCE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "ipresence.h" +#include "igamesystem.h" + +//----------------------------------------------------------------------------- +// Purpose: Common implementation for setting user contexts and properties. +// Each client should inherit from this to implement mod-specific presence info. +//----------------------------------------------------------------------------- +class CBasePresence : public IPresence, public CAutoGameSystemPerFrame +{ +public: + // CBaseGameSystemPerFrame overrides + virtual bool Init( void ); + virtual void Shutdown( void ); + virtual void Update( float frametime ); + virtual char const *Name( void ) { return "presence"; } + + // IPresence Interface + virtual void UserSetContext( unsigned int nUserIndex, unsigned int nContextId, unsigned int nContextValue, bool bAsync = false ); + virtual void UserSetProperty( unsigned int nUserIndex, unsigned int nPropertyId, unsigned int nBytes, const void *pvValue, bool bAsync = false ); + virtual void SetupGameProperties( CUtlVector< XUSER_CONTEXT > &contexts, CUtlVector< XUSER_PROPERTY > &properties ); + virtual uint GetPresenceID( const char *pIdName ); + virtual void GetPropertyDisplayString( uint id, uint value, char *pOutput, int nBytes ); + virtual const char *GetPropertyIdString( const uint id ); + + // Stats reporting + virtual void StartStatsReporting( HANDLE handle, bool bArbitrated ); + virtual void SetStat( uint iPropertyId, int iPropertyValue, int dataType ); + virtual void UploadStats(); + +protected: + bool m_bArbitrated; + bool m_bReportingStats; + HANDLE m_hSession; + CUtlVector< XUSER_PROPERTY > m_PlayerStats; + + //--------------------------------------------------------- + // Debug support + //--------------------------------------------------------- + CON_COMMAND_MEMBER_F( CBasePresence, "user_context", DebugUserSetContext, "Set a Rich Presence Context: user_context ", 0 ) + CON_COMMAND_MEMBER_F( CBasePresence, "user_property", DebugUserSetProperty, "Set a Rich Presence Property: user_property ", 0 ) +}; + +#endif // BASEPRESENCE_H diff --git a/src/src/game/client/basepresence_xbox.cpp b/src/src/game/client/basepresence_xbox.cpp new file mode 100644 index 0000000..d1a80f2 --- /dev/null +++ b/src/src/game/client/basepresence_xbox.cpp @@ -0,0 +1,167 @@ +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: Base rich presence implementation for Xbox360 +// +//=====================================================================================// + +#include "cbase.h" +#include "basepresence.h" +#include "cdll_client_int.h" +#include "ixboxsystem.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +// Default global instance. Mods should override this. +static CBasePresence s_basePresence; +IPresence *presence = NULL; + +//----------------------------------------------------------------------------- +// Purpose: Init +//----------------------------------------------------------------------------- +bool CBasePresence::Init( void ) +{ + if ( !presence ) + { + // Mod didn't override, default to base implementation + presence = &s_basePresence; + } + return true; +} + + +//----------------------------------------------------------------------------- +// Purpose: Shutdown +//----------------------------------------------------------------------------- +void CBasePresence::Shutdown( void ) +{ + // Do nothing +} + + +//----------------------------------------------------------------------------- +// Purpose: Per-frame update +//----------------------------------------------------------------------------- +void CBasePresence::Update( float frametime ) +{ + // Do nothing +} + + +//----------------------------------------------------------------------------- +// Contexts are strings that describe the current state of the game. +//----------------------------------------------------------------------------- +void CBasePresence::UserSetContext( unsigned int nUserIndex, unsigned int nContextId, unsigned int nContextValue, bool bAsync ) +{ + if ( !xboxsystem->UserSetContext( nUserIndex, nContextId, nContextValue, bAsync ) ) + { + Warning( "CBasePresence: UserSetContext failed.\n" ); + } +} + + +//----------------------------------------------------------------------------- +// Properties are (usually) numeric values that can be insterted into context strings. +//----------------------------------------------------------------------------- +void CBasePresence::UserSetProperty( unsigned int nUserIndex, unsigned int nPropertyId, unsigned int nBytes, const void *pvValue, bool bAsync ) +{ + if ( !xboxsystem->UserSetProperty( nUserIndex, nPropertyId, nBytes, pvValue, bAsync ) ) + { + Warning( "CBasePresence: UserSetProperty failed.\n" ); + } +} + +//----------------------------------------------------------------------------- +// Get game session properties from matchmaking. +//----------------------------------------------------------------------------- +void CBasePresence::SetupGameProperties( CUtlVector< XUSER_CONTEXT > &contexts, CUtlVector< XUSER_PROPERTY > &properties ) +{ + Assert( 0 ); +} + +//----------------------------------------------------------------------------- +// Convert a string to a presence ID. +//----------------------------------------------------------------------------- +uint CBasePresence::GetPresenceID( const char *pIdName ) +{ + Assert( 0 ); + return 0; +} + +//----------------------------------------------------------------------------- +// Convert a presence ID to a string. +//----------------------------------------------------------------------------- +const char *CBasePresence::GetPropertyIdString( const uint id ) +{ + Assert( 0 ); + return NULL; +} + +//----------------------------------------------------------------------------- +// Get display string for a game property. +//----------------------------------------------------------------------------- +void CBasePresence::GetPropertyDisplayString( uint id, uint value, char *pOutput, int nBytes ) +{ + Assert( 0 ); +} + +//----------------------------------------------------------------------------- +// Set up for reporting stats to Live. +//----------------------------------------------------------------------------- +void CBasePresence::StartStatsReporting( HANDLE handle, bool bArbitrated ) +{ + m_bArbitrated = bArbitrated; + m_hSession = handle; + m_bReportingStats = true; + m_PlayerStats.RemoveAll(); +} + +//----------------------------------------------------------------------------- +// Set a specific stat property. +//----------------------------------------------------------------------------- +void CBasePresence::SetStat( uint iPropertyId, int iPropertyValue, int dataType ) +{ + if ( m_bReportingStats ) + { + XUSER_PROPERTY prop; + prop.dwPropertyId = iPropertyId; + prop.value.nData = iPropertyValue; + prop.value.type = dataType; + m_PlayerStats.AddToTail( prop ); + } +} + +//----------------------------------------------------------------------------- +// Upload the stats to Live. +//----------------------------------------------------------------------------- +void CBasePresence::UploadStats() +{ + Assert( 0 ); +} + +//--------------------------------------------------------- +// Debug support +//--------------------------------------------------------- +void CBasePresence::DebugUserSetContext( const CCommand &args ) +{ + if ( args.ArgC() == 3 ) + { + UserSetContext( XBX_GetPrimaryUserId(), atoi( args.Arg( 1 ) ), atoi( args.Arg( 2 ) ) ); + } + else + { + Warning( "user_context \n" ); + } +} +void CBasePresence::DebugUserSetProperty( const CCommand &args ) +{ + if ( args.ArgC() == 3 ) + { + int value = atoi( args.Arg( 2 ) ); + UserSetProperty( XBX_GetPrimaryUserId(), strtoul( args.Arg( 1 ), NULL, 0 ), sizeof(int), &value ); + } + else + { + Warning( "user_property \n" ); + } +} diff --git a/src/src/cl_dll/beamdraw.cpp b/src/src/game/client/beamdraw.cpp similarity index 85% rename from src/src/cl_dll/beamdraw.cpp rename to src/src/game/client/beamdraw.cpp index 42edadd..2bf99ab 100644 --- a/src/src/cl_dll/beamdraw.cpp +++ b/src/src/game/client/beamdraw.cpp @@ -24,218 +24,6 @@ extern ConVar r_DrawBeams; static IMaterial *g_pBeamWireframeMaterial; -// ------------------------------------------------------------------------------------------ // -// CBeamSegDraw implementation. -// ------------------------------------------------------------------------------------------ // -void CBeamSegDraw::Start( int nSegs, IMaterial *pMaterial, CMeshBuilder *pMeshBuilder, int nMeshVertCount ) -{ - Assert( nSegs >= 2 ); - - m_nSegsDrawn = 0; - m_nTotalSegs = nSegs; - - if ( pMeshBuilder ) - { - m_pMeshBuilder = pMeshBuilder; - m_nMeshVertCount = nMeshVertCount; - } - else - { - m_pMeshBuilder = NULL; - m_nMeshVertCount = 0; - - if ( ShouldDrawInWireFrameMode() || r_DrawBeams.GetInt() == 2 ) - { - if ( !g_pBeamWireframeMaterial ) - g_pBeamWireframeMaterial = materials->FindMaterial("shadertest/wireframevertexcolor", TEXTURE_GROUP_OTHER); - pMaterial = g_pBeamWireframeMaterial; - } - - IMesh *pMesh = materials->GetDynamicMesh( true, NULL, NULL, pMaterial ); - m_Mesh.Begin( pMesh, MATERIAL_TRIANGLE_STRIP, (nSegs-1) * 2 ); - } -} - -inline void CBeamSegDraw::ComputeNormal( const Vector &vStartPos, const Vector &vNextPos, Vector *pNormal ) -{ - // vTangentY = line vector for beam - Vector vTangentY; - VectorSubtract( vStartPos, vNextPos, vTangentY ); - - // vDirToBeam = vector from viewer origin to beam - Vector vDirToBeam; - VectorSubtract( vStartPos, CurrentViewOrigin(), vDirToBeam ); - - // Get a vector that is perpendicular to us and perpendicular to the beam. - // This is used to fatten the beam. - CrossProduct( vTangentY, vDirToBeam, *pNormal ); - VectorNormalizeFast( *pNormal ); -} - -inline void CBeamSegDraw::SpecifySeg( const Vector &vNormal ) -{ - // SUCKY: Need to do a fair amount more work to get the tangent owing to the averaged normal - Vector vDirToBeam, vTangentY; - VectorSubtract( m_Seg.m_vPos, CurrentViewOrigin(), vDirToBeam ); - CrossProduct( vDirToBeam, vNormal, vTangentY ); - VectorNormalizeFast( vTangentY ); - - // Build the endpoints. - Vector vPoint1, vPoint2; - VectorMA( m_Seg.m_vPos, m_Seg.m_flWidth*0.5f, vNormal, vPoint1 ); - VectorMA( m_Seg.m_vPos, -m_Seg.m_flWidth*0.5f, vNormal, vPoint2 ); - - if ( m_pMeshBuilder ) - { - // Specify the points. - m_pMeshBuilder->Position3fv( vPoint1.Base() ); - m_pMeshBuilder->Color4f( VectorExpand( m_Seg.m_vColor ), m_Seg.m_flAlpha ); - m_pMeshBuilder->TexCoord2f( 0, 0, m_Seg.m_flTexCoord ); - m_pMeshBuilder->TexCoord2f( 1, 0, m_Seg.m_flTexCoord ); - m_pMeshBuilder->TangentS3fv( vNormal.Base() ); - m_pMeshBuilder->TangentT3fv( vTangentY.Base() ); - m_pMeshBuilder->AdvanceVertex(); - - m_pMeshBuilder->Position3fv( vPoint2.Base() ); - m_pMeshBuilder->Color4f( VectorExpand( m_Seg.m_vColor ), m_Seg.m_flAlpha ); - m_pMeshBuilder->TexCoord2f( 0, 1, m_Seg.m_flTexCoord ); - m_pMeshBuilder->TexCoord2f( 1, 1, m_Seg.m_flTexCoord ); - m_pMeshBuilder->TangentS3fv( vNormal.Base() ); - m_pMeshBuilder->TangentT3fv( vTangentY.Base() ); - m_pMeshBuilder->AdvanceVertex(); - - if ( m_nSegsDrawn > 1 ) - { - int nBase = ( ( m_nSegsDrawn - 2 ) * 2 ) + m_nMeshVertCount; - - m_pMeshBuilder->FastIndex( nBase ); - m_pMeshBuilder->FastIndex( nBase + 1 ); - m_pMeshBuilder->FastIndex( nBase + 2 ); - m_pMeshBuilder->FastIndex( nBase + 1 ); - m_pMeshBuilder->FastIndex( nBase + 3 ); - m_pMeshBuilder->FastIndex( nBase + 2 ); - } - } - else - { - // Specify the points. - m_Mesh.Position3fv( vPoint1.Base() ); - m_Mesh.Color4f( VectorExpand( m_Seg.m_vColor ), m_Seg.m_flAlpha ); - m_Mesh.TexCoord2f( 0, 0, m_Seg.m_flTexCoord ); - m_Mesh.TexCoord2f( 1, 0, m_Seg.m_flTexCoord ); - m_Mesh.TangentS3fv( vNormal.Base() ); - m_Mesh.TangentT3fv( vTangentY.Base() ); - m_Mesh.AdvanceVertex(); - - m_Mesh.Position3fv( vPoint2.Base() ); - m_Mesh.Color4f( VectorExpand( m_Seg.m_vColor ), m_Seg.m_flAlpha ); - m_Mesh.TexCoord2f( 0, 1, m_Seg.m_flTexCoord ); - m_Mesh.TexCoord2f( 1, 1, m_Seg.m_flTexCoord ); - m_Mesh.TangentS3fv( vNormal.Base() ); - m_Mesh.TangentT3fv( vTangentY.Base() ); - m_Mesh.AdvanceVertex(); - } -} - -void CBeamSegDraw::NextSeg( CBeamSeg *pSeg ) -{ - if ( m_nSegsDrawn > 0 ) - { - // Get a vector that is perpendicular to us and perpendicular to the beam. - // This is used to fatten the beam. - Vector vNormal, vAveNormal; - ComputeNormal( m_Seg.m_vPos, pSeg->m_vPos, &vNormal ); - - if ( m_nSegsDrawn > 1 ) - { - // Average this with the previous normal - VectorAdd( vNormal, m_vNormalLast, vAveNormal ); - vAveNormal *= 0.5f; - VectorNormalizeFast( vAveNormal ); - } - else - { - vAveNormal = vNormal; - } - - m_vNormalLast = vNormal; - SpecifySeg( vAveNormal ); - } - - m_Seg = *pSeg; - ++m_nSegsDrawn; - - if( m_nSegsDrawn == m_nTotalSegs ) - { - SpecifySeg( m_vNormalLast ); - } -} - -void CBeamSegDraw::End() -{ - if ( m_pMeshBuilder ) - { - m_pMeshBuilder = NULL; - return; - } - - m_Mesh.End( false, true ); -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : &normal - -//----------------------------------------------------------------------------- -void CBeamSegDrawArbitrary::SetNormal( const Vector &normal ) -{ - m_vNormalLast = normal; -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : *pSeg - -//----------------------------------------------------------------------------- -void CBeamSegDrawArbitrary::NextSeg( CBeamSeg *pSeg ) -{ - if ( m_nSegsDrawn > 0 ) - { - Vector segDir = ( m_PrevSeg.m_vPos - pSeg->m_vPos ); - VectorNormalize( segDir ); - - Vector normal = CrossProduct( segDir, m_vNormalLast ); - SpecifySeg( normal ); - } - - m_PrevSeg = m_Seg; - m_Seg = *pSeg; - ++m_nSegsDrawn; -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : &vNextPos - -//----------------------------------------------------------------------------- -void CBeamSegDrawArbitrary::SpecifySeg( const Vector &vNormal ) -{ - // Build the endpoints. - Vector vPoint1, vPoint2; - VectorMA( m_Seg.m_vPos, m_Seg.m_flWidth*0.5f, vNormal, vPoint1 ); - VectorMA( m_Seg.m_vPos, -m_Seg.m_flWidth*0.5f, vNormal, vPoint2 ); - - // Specify the points. - m_Mesh.Position3fv( vPoint1.Base() ); - m_Mesh.Color4f( VectorExpand( m_Seg.m_vColor ), m_Seg.m_flAlpha ); - m_Mesh.TexCoord2f( 0, 0, m_Seg.m_flTexCoord ); - m_Mesh.TexCoord2f( 1, 0, m_Seg.m_flTexCoord ); - m_Mesh.AdvanceVertex(); - - m_Mesh.Position3fv( vPoint2.Base() ); - m_Mesh.Color4f( VectorExpand( m_Seg.m_vColor ), m_Seg.m_flAlpha ); - m_Mesh.TexCoord2f( 0, 1, m_Seg.m_flTexCoord ); - m_Mesh.TexCoord2f( 1, 1, m_Seg.m_flTexCoord ); - m_Mesh.AdvanceVertex(); -} - //----------------------------------------------------------------------------- // Purpose: Retrieve sprite object and set it up for rendering // Input : *pSpriteModel - @@ -255,18 +43,19 @@ CEngineSprite *Draw_SetSpriteTexture( const model_t *pSpriteModel, int frame, in if( !material ) return NULL; + CMatRenderContextPtr pRenderContext( materials ); if ( ShouldDrawInWireFrameMode() || r_DrawBeams.GetInt() == 2 ) { if ( !g_pBeamWireframeMaterial ) g_pBeamWireframeMaterial = materials->FindMaterial( "shadertest/wireframevertexcolor", TEXTURE_GROUP_OTHER ); - materials->Bind( g_pBeamWireframeMaterial, NULL ); + pRenderContext->Bind( g_pBeamWireframeMaterial, NULL ); return psprite; } psprite->SetFrame( frame ); psprite->SetRenderMode( rendermode ); - materials->Bind( material ); + pRenderContext->Bind( material ); return psprite; } @@ -292,7 +81,8 @@ void DrawHalo(IMaterial* pMaterial, const Vector& source, float scale, float con } } - IMesh* pMesh = materials->GetDynamicMesh( ); + CMatRenderContextPtr pRenderContext( materials ); + IMesh* pMesh = pRenderContext->GetDynamicMesh( ); CMeshBuilder meshBuilder; meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 ); @@ -367,7 +157,8 @@ void DrawSprite( const Vector &vecOrigin, float flWidth, float flHeight, color32 CMeshBuilder meshBuilder; Vector point; - IMesh* pMesh = materials->GetDynamicMesh( ); + CMatRenderContextPtr pRenderContext( materials ); + IMesh* pMesh = pRenderContext->GetDynamicMesh( ); meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 ); @@ -539,13 +330,14 @@ void DrawSegs( int noise_divisions, float *prgNoise, const model_t* spritemodel, ComputeBeamPerpendicular( delta, &perp1 ); // Specify all the segments. + CMatRenderContextPtr pRenderContext( g_pMaterialSystem ); CBeamSegDraw segDraw; - segDraw.Start( segments, NULL ); + segDraw.Start( pRenderContext, segments, NULL ); for ( i = 0; i < segments; i++ ) { Assert( noiseIndex < (noise_divisions<<16) ); - CBeamSeg curSeg; + BeamSeg_t curSeg; curSeg.m_flAlpha = 1; fraction = i * div; @@ -739,8 +531,9 @@ void DrawTeslaSegs( int noise_divisions, float *prgNoise, const model_t* spritem ComputeBeamPerpendicular( delta, &perp ); // Specify all the segments. + CMatRenderContextPtr pRenderContext( g_pMaterialSystem ); CBeamSegDraw segDraw; - segDraw.Start( segments, NULL ); + segDraw.Start( pRenderContext, segments, NULL ); // Keep track of how many times we've branched int iBranches = 0; @@ -751,7 +544,7 @@ void DrawTeslaSegs( int noise_divisions, float *prgNoise, const model_t* spritem for ( i = 0; i < segments; i++ ) { - CBeamSeg curSeg; + BeamSeg_t curSeg; curSeg.m_flAlpha = 1; fraction = i * div; @@ -907,8 +700,9 @@ void DrawSplineSegs( int noise_divisions, float *prgNoise, IMaterial *pBeamMaterial = pBeamSprite->GetMaterial(); + CMatRenderContextPtr pRenderContext( g_pMaterialSystem ); CBeamSegDraw segDraw; - segDraw.Start( (segments-1)*(numAttachments-1), pBeamMaterial ); + segDraw.Start( pRenderContext, (segments-1)*(numAttachments-1), pBeamMaterial ); CEngineSprite *pHaloSprite = (CEngineSprite *)modelinfo->GetModelExtraData( halosprite ); IMaterial *pHaloMaterial = NULL; @@ -949,8 +743,6 @@ void DrawSplineSegs( int noise_divisions, float *prgNoise, Vector pEnd; // end of current beam Vector pNext; // attachment point after the current beam - - for (int j=0;j 1.0) fade = 1.0; float haloColor[3]; VectorScale( color, fade, haloColor ); - materials->Bind(pHaloMaterial); + pRenderContext->Bind(pHaloMaterial); float curWidth = (fBestFraction*(endSegWidth-startSegWidth))+startSegWidth; DrawHalo(pHaloMaterial,vHaloPos,flHaloScale*curWidth/endWidth,haloColor, flHDRColorScale); } @@ -1173,7 +965,7 @@ void DrawSplineSegs( int noise_divisions, float *prgNoise, // ------------------------ if (pHaloMaterial) { - materials->Bind(pHaloMaterial); + pRenderContext->Bind(pHaloMaterial); DrawHalo(pHaloMaterial,pEnd,flHaloScale,scaledColor, flHDRColorScale); } } @@ -1258,7 +1050,8 @@ void DrawDisk( int noise_divisions, float *prgNoise, const model_t* spritemodel, w = freq * delta[2]; - IMesh* pMesh = materials->GetDynamicMesh( ); + CMatRenderContextPtr pRenderContext( materials ); + IMesh* pMesh = pRenderContext->GetDynamicMesh( ); CMeshBuilder meshBuilder; meshBuilder.Begin( pMesh, MATERIAL_TRIANGLE_STRIP, (segments - 1) * 2 ); @@ -1353,7 +1146,8 @@ void DrawCylinder( int noise_divisions, float *prgNoise, const model_t* spritemo vLast = fmod(freq*speed,1); // Scroll speed 3.5 -- initial texture position, scrolls 3.5/sec (1.0 is entire texture) scale = scale * length; - IMesh* pMesh = materials->GetDynamicMesh( ); + CMatRenderContextPtr pRenderContext( materials ); + IMesh* pMesh = pRenderContext->GetDynamicMesh( ); CMeshBuilder meshBuilder; meshBuilder.Begin( pMesh, MATERIAL_TRIANGLE_STRIP, (segments - 1) * 2 ); @@ -1477,7 +1271,8 @@ void DrawRing( int noise_divisions, float *prgNoise, void (*pfnNoise)( float *no j = segments / 8; - IMesh* pMesh = materials->GetDynamicMesh( ); + CMatRenderContextPtr pRenderContext( materials ); + IMesh* pMesh = pRenderContext->GetDynamicMesh( ); CMeshBuilder meshBuilder; meshBuilder.Begin( pMesh, MATERIAL_TRIANGLE_STRIP, (segments) * 2 ); @@ -1620,7 +1415,8 @@ void DrawBeamFollow( const model_t* spritemodel, BeamTrail_t* pHead, int frame, pTraverse = pTraverse->next; } - IMesh* pMesh = materials->GetDynamicMesh( ); + CMatRenderContextPtr pRenderContext( materials ); + IMesh* pMesh = pRenderContext->GetDynamicMesh( ); CMeshBuilder meshBuilder; meshBuilder.Begin( pMesh, MATERIAL_QUADS, count ); @@ -1698,10 +1494,11 @@ void DrawBeamQuadratic( const Vector &start, const Vector &control, const Vector { int subdivisions = 16; + CMatRenderContextPtr pRenderContext( g_pMaterialSystem ); CBeamSegDraw beamDraw; - beamDraw.Start( subdivisions+1, NULL ); + beamDraw.Start( pRenderContext, subdivisions+1, NULL ); - CBeamSeg seg; + BeamSeg_t seg; seg.m_flAlpha = 1.0; seg.m_flWidth = width; diff --git a/src/src/cl_dll/beamdraw.h b/src/src/game/client/beamdraw.h similarity index 81% rename from src/src/cl_dll/beamdraw.h rename to src/src/game/client/beamdraw.h index 87974ea..dc34e0b 100644 --- a/src/src/cl_dll/beamdraw.h +++ b/src/src/game/client/beamdraw.h @@ -1,9 +1,9 @@ -//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: // // $NoKeywords: $ -//=============================================================================// +//===========================================================================// #if !defined( BEAMDRAW_H ) #define BEAMDRAW_H #ifdef _WIN32 @@ -12,7 +12,8 @@ #include "materialsystem/imaterial.h" #include "materialsystem/imesh.h" -#include "vector.h" +#include "mathlib/vector.h" +#include "tier2/beamsegdraw.h" #include "c_pixel_visibility.h" #define NOISE_DIVISIONS 128 @@ -119,60 +120,13 @@ public: bool m_bCalculatedNoise; float m_flHDRColorScale; + +#ifdef PORTAL + bool m_bDrawInMainRender; + bool m_bDrawInPortalRender; +#endif //#ifdef PORTAL }; -// ---------------------------------------------------------------- // -// CBeamSegDraw is a simple interface to beam rendering. -// ---------------------------------------------------------------- // -class CBeamSeg -{ -public: - Vector m_vPos; - Vector m_vColor; - float m_flTexCoord; // Y texture coordinate - float m_flWidth; - float m_flAlpha; -}; - -class CBeamSegDraw -{ -public: - // Pass null for pMaterial if you have already set the material you want. - void Start( int nSegs, IMaterial *pMaterial=0, CMeshBuilder *pMeshBuilder = NULL, int nMeshVertCount = 0 ); - virtual void NextSeg( CBeamSeg *pSeg ); - void End(); - -protected: - - void SpecifySeg( const Vector &vNextPos ); - void ComputeNormal( const Vector &vStartPos, const Vector &vNextPos, Vector *pNormal ); - - CMeshBuilder *m_pMeshBuilder; - int m_nMeshVertCount; - - CMeshBuilder m_Mesh; - CBeamSeg m_Seg; - - int m_nTotalSegs; - int m_nSegsDrawn; - - Vector m_vNormalLast; -}; - -class CBeamSegDrawArbitrary : public CBeamSegDraw -{ -public: - - void SetNormal( const Vector &normal ); - - void NextSeg( CBeamSeg *pSeg ); - -protected: - - CBeamSeg m_PrevSeg; - - void SpecifySeg( const Vector &vNextPos ); -}; int ScreenTransform( const Vector& point, Vector& screen ); diff --git a/src/src/cl_dll/bone_merge_cache.cpp b/src/src/game/client/bone_merge_cache.cpp similarity index 92% rename from src/src/cl_dll/bone_merge_cache.cpp rename to src/src/game/client/bone_merge_cache.cpp index ff28f67..ca635ac 100644 --- a/src/src/cl_dll/bone_merge_cache.cpp +++ b/src/src/game/client/bone_merge_cache.cpp @@ -78,11 +78,11 @@ void CBoneMergeCache::UpdateCache() m_BoneMergeBits[i>>3] |= ( 1 << ( i & 7 ) ); - if ( ( m_pFollowHdr->pBone( parentBoneIndex )->flags & BONE_USED_BY_BONE_MERGE ) == 0 ) + if ( ( m_pFollowHdr->boneFlags( parentBoneIndex ) & BONE_USED_BY_BONE_MERGE ) == 0 ) { m_nFollowBoneSetupMask = BONE_USED_BY_ANYTHING; - Warning("Performance warning: Mark bone '%s' in model '%s' as being used by bone merge in the .qc!\n", - m_pFollowHdr->pBone( parentBoneIndex )->pszName(), m_pFollowHdr->pszName() ); + Warning("Performance warning: Merge with '%s'. Mark bone '%s' in model '%s' as being used by bone merge in the .qc!\n", + pOwnerHdr->pszName(), m_pFollowHdr->pBone( parentBoneIndex )->pszName(), m_pFollowHdr->pszName() ); } } @@ -120,7 +120,7 @@ void CBoneMergeCache::MergeMatchingBones( int boneMask ) int iParentBone = m_MergedBones[i].m_iParentBone; // Only update bones reference by the bone mask. - if ( !( m_pOwnerHdr->pBone( iOwnerBone )->flags & boneMask ) ) + if ( !( m_pOwnerHdr->boneFlags( iOwnerBone ) & boneMask ) ) continue; MatrixCopy( m_pFollow->GetBone( iParentBone ), m_pOwner->GetBoneForWrite( iOwnerBone ) ); diff --git a/src/src/cl_dll/bone_merge_cache.h b/src/src/game/client/bone_merge_cache.h similarity index 98% rename from src/src/cl_dll/bone_merge_cache.h rename to src/src/game/client/bone_merge_cache.h index a7b404e..7960cde 100644 --- a/src/src/cl_dll/bone_merge_cache.h +++ b/src/src/game/client/bone_merge_cache.h @@ -15,7 +15,7 @@ class C_BaseAnimating; class CStudioHdr; -#include "vector.h" +#include "mathlib/vector.h" class CBoneMergeCache diff --git a/src/src/game/client/bonetoworldarray.h b/src/src/game/client/bonetoworldarray.h new file mode 100644 index 0000000..fae2ceb --- /dev/null +++ b/src/src/game/client/bonetoworldarray.h @@ -0,0 +1,70 @@ +//========== Copyright © 2006, Valve Corporation, All rights reserved. ======== +// +// Purpose: +// +//============================================================================= + +#ifndef BONETOWORLDARRAY_H +#define BONETOWORLDARRAY_H + +#include "tier0/tslist.h" + +#if defined( _WIN32 ) +#pragma once +#endif + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +template +class CBoneToWorldArrays +{ +public: + enum + { + ALIGNMENT = 128, + }; + + CBoneToWorldArrays() + { + const int SIZE_ARRAY = AlignValue( sizeof(matrix3x4_t) * MAXSTUDIOBONES, ALIGNMENT ); + m_pBase = (matrix3x4_t *)_aligned_malloc( SIZE_ARRAY * NUM_ARRAYS, ALIGNMENT ); + for ( int i = 0; i < NUM_ARRAYS; i++ ) + { + matrix3x4_t *pArray = (matrix3x4_t *)((byte *)m_pBase + SIZE_ARRAY * i); + Assert( (size_t)pArray % ALIGNMENT == 0 ); + Free( pArray ); + } + } + + ~CBoneToWorldArrays() + { + _aligned_free( m_pBase ); + } + + int NumArrays() + { + return NUM_ARRAYS; + } + + matrix3x4_t *Alloc( bool bBlock = true ) + { + TSLNodeBase_t *p; + while ( ( p = m_Free.Pop() ) == NULL && bBlock ) + { + ThreadPause(); + } + return (matrix3x4_t *)p; + } + + void Free( matrix3x4_t *p ) + { + m_Free.Push( (TSLNodeBase_t *) p ); + } + +private: + CTSListBase m_Free; + matrix3x4_t *m_pBase; +}; + +#endif // BONETOWORLDARRAY_H diff --git a/src/src/cl_dll/c_ai_basehumanoid.cpp b/src/src/game/client/c_ai_basehumanoid.cpp similarity index 100% rename from src/src/cl_dll/c_ai_basehumanoid.cpp rename to src/src/game/client/c_ai_basehumanoid.cpp diff --git a/src/src/cl_dll/c_ai_basenpc.cpp b/src/src/game/client/c_ai_basenpc.cpp similarity index 56% rename from src/src/cl_dll/c_ai_basenpc.cpp rename to src/src/game/client/c_ai_basenpc.cpp index e3c544a..a39cbef 100644 --- a/src/src/cl_dll/c_ai_basenpc.cpp +++ b/src/src/game/client/c_ai_basenpc.cpp @@ -8,7 +8,7 @@ #include "c_AI_BaseNPC.h" #include "engine/IVDebugOverlay.h" -#ifdef HL2_DLL +#if defined( HL2_DLL ) || defined( HL2_EPISODIC ) #include "c_basehlplayer.h" #endif @@ -17,6 +17,8 @@ // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" +#define PING_MAX_TIME 2.0 + IMPLEMENT_CLIENTCLASS_DT( C_AI_BaseNPC, DT_AI_BaseNPC, CAI_BaseNPC ) RecvPropInt( RECVINFO( m_lifeState ) ), RecvPropBool( RECVINFO( m_bPerformAvoidance ) ), @@ -28,6 +30,7 @@ IMPLEMENT_CLIENTCLASS_DT( C_AI_BaseNPC, DT_AI_BaseNPC, CAI_BaseNPC ) RecvPropInt( RECVINFO( m_iSpeedModSpeed ) ), RecvPropInt( RECVINFO( m_bSpeedModActive ) ), RecvPropBool( RECVINFO( m_bImportanRagdoll ) ), + RecvPropFloat( RECVINFO( m_flTimePingEffect ) ), END_RECV_TABLE() extern ConVar cl_npc_speedmod_intime; @@ -98,19 +101,74 @@ void C_AI_BaseNPC::ClientThink( void ) } } #endif // HL2_DLL + +#ifdef HL2_EPISODIC + C_BaseHLPlayer *pPlayer = dynamic_cast( C_BasePlayer::GetLocalPlayer() ); + + if ( pPlayer && m_flTimePingEffect > gpGlobals->curtime ) + { + float fPingEffectTime = m_flTimePingEffect - gpGlobals->curtime; + + if ( fPingEffectTime > 0.0f ) + { + Vector vRight, vUp; + Vector vMins, vMaxs; + + float fFade; + + if( fPingEffectTime <= 1.0f ) + { + fFade = 1.0f - (1.0f - fPingEffectTime); + } + else + { + fFade = 1.0f; + } + + GetRenderBounds( vMins, vMaxs ); + AngleVectors (pPlayer->GetAbsAngles(), NULL, &vRight, &vUp ); + Vector p1 = GetAbsOrigin() + vRight * vMins.x + vUp * vMins.z; + Vector p2 = GetAbsOrigin() + vRight * vMaxs.x + vUp * vMins.z; + Vector p3 = GetAbsOrigin() + vUp * vMaxs.z; + + int r = 0 * fFade; + int g = 255 * fFade; + int b = 0 * fFade; + + debugoverlay->AddLineOverlay( p1, p2, r, g, b, true, 0.05f ); + debugoverlay->AddLineOverlay( p2, p3, r, g, b, true, 0.05f ); + debugoverlay->AddLineOverlay( p3, p1, r, g, b, true, 0.05f ); + } + } +#endif } void C_AI_BaseNPC::OnDataChanged( DataUpdateType_t type ) { BaseClass::OnDataChanged( type ); - if ( ShouldModifyPlayerSpeed() == true ) + if ( ( ShouldModifyPlayerSpeed() == true ) || ( m_flTimePingEffect > gpGlobals->curtime ) ) { SetNextClientThink( CLIENT_THINK_ALWAYS ); } } -void C_AI_BaseNPC::GetRagdollCurSequence( matrix3x4_t *curBones, float flTime ) +void C_AI_BaseNPC::GetRagdollInitBoneArrays( matrix3x4_t *pDeltaBones0, matrix3x4_t *pDeltaBones1, matrix3x4_t *pCurrentBones, float boneDt ) { - GetRagdollCurSequenceWithDeathPose( this, curBones, flTime, m_iDeathPose, m_iDeathFrame ); + ForceSetupBonesAtTime( pDeltaBones0, gpGlobals->curtime - boneDt ); + GetRagdollCurSequenceWithDeathPose( this, pDeltaBones1, gpGlobals->curtime, m_iDeathPose, m_iDeathFrame ); + float ragdollCreateTime = PhysGetSyncCreateTime(); + if ( ragdollCreateTime != gpGlobals->curtime ) + { + // The next simulation frame begins before the end of this frame + // so initialize the ragdoll at that time so that it will reach the current + // position at curtime. Otherwise the ragdoll will simulate forward from curtime + // and pop into the future a bit at this point of transition + ForceSetupBonesAtTime( pCurrentBones, ragdollCreateTime ); + } + else + { + SetupBones( pCurrentBones, MAXSTUDIOBONES, BONE_USED_BY_ANYTHING, gpGlobals->curtime ); + } } + diff --git a/src/src/cl_dll/c_ai_basenpc.h b/src/src/game/client/c_ai_basenpc.h similarity index 90% rename from src/src/cl_dll/c_ai_basenpc.h rename to src/src/game/client/c_ai_basenpc.h index 3dd93a1..61e318e 100644 --- a/src/src/cl_dll/c_ai_basenpc.h +++ b/src/src/game/client/c_ai_basenpc.h @@ -29,7 +29,7 @@ public: bool ShouldAvoidObstacle( void ){ return m_bPerformAvoidance; } virtual bool AddRagdollToFadeQueue( void ) { return m_bFadeCorpse; } - virtual void GetRagdollCurSequence( matrix3x4_t *curBones, float flTime ); + virtual void GetRagdollInitBoneArrays( matrix3x4_t *pDeltaBones0, matrix3x4_t *pDeltaBones1, matrix3x4_t *pCurrentBones, float boneDt ); int GetDeathPose( void ) { return m_iDeathPose; } @@ -43,16 +43,17 @@ public: private: C_AI_BaseNPC( const C_AI_BaseNPC & ); // not defined, not accessible - bool m_bPerformAvoidance; - bool m_bIsMoving; - bool m_bFadeCorpse; + float m_flTimePingEffect; int m_iDeathPose; int m_iDeathFrame; int m_iSpeedModRadius; int m_iSpeedModSpeed; - bool m_bSpeedModActive; + bool m_bPerformAvoidance; + bool m_bIsMoving; + bool m_bFadeCorpse; + bool m_bSpeedModActive; bool m_bImportanRagdoll; }; diff --git a/src/src/cl_dll/c_baseanimating.cpp b/src/src/game/client/c_baseanimating.cpp similarity index 77% rename from src/src/cl_dll/c_baseanimating.cpp rename to src/src/game/client/c_baseanimating.cpp index 83f7774..2697c3c 100644 --- a/src/src/cl_dll/c_baseanimating.cpp +++ b/src/src/game/client/c_baseanimating.cpp @@ -1,9 +1,9 @@ -//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +//===== Copy right © 1996-2005, Valve Corporation, All rights reserved. ==// // // Purpose: // // $NoKeywords: $ -//=============================================================================// +//===========================================================================// #include "cbase.h" #include "c_baseanimating.h" #include "c_Sprite.h" @@ -44,6 +44,13 @@ #include "toolframework/itoolframework.h" #include "datacache/idatacache.h" #include "gamestringpool.h" +#include "jigglebones.h" +#include "toolframework_client.h" +#include "vstdlib/jobthread.h" +#include "bonetoworldarray.h" +#include "posedebugger.h" +#include "tier0/ICommandLine.h" +#include "prediction.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -60,15 +67,14 @@ const float RUN_SPEED_ESTIMATE_SQR = 150.0f * 150.0f; #endif -CLIENTEFFECT_REGISTER_BEGIN( PrecacheBaseAnimating ) -CLIENTEFFECT_MATERIAL( "sprites/fire" ) -CLIENTEFFECT_REGISTER_END() - mstudioevent_t *GetEventIndexForSequence( mstudioseqdesc_t &seqdesc ); C_EntityDissolve *DissolveEffect( C_BaseAnimating *pTarget, float flTime ); C_EntityFlame *FireEffect( C_BaseAnimating *pTarget, C_BaseEntity *pServerFire, float *flScaleEnd, float *flTimeStart, float *flTimeEnd ); bool NPC_IsImportantNPC( C_BaseAnimating *pAnimating ); +void VCollideWireframe_ChangeCallback( IConVar *pConVar, char const *pOldString, float flOldValue ); + +ConVar vcollide_wireframe( "vcollide_wireframe", "0", FCVAR_CHEAT, "Render physics collision models in wireframe", VCollideWireframe_ChangeCallback ); bool C_AnimationLayer::IsActive( void ) { @@ -133,8 +139,24 @@ BEGIN_RECV_TABLE_NOBASE( C_BaseAnimating, DT_ServerAnimationData ) END_RECV_TABLE() +void RecvProxy_Sequence( const CRecvProxyData *pData, void *pStruct, void *pOut ) +{ + // Have the regular proxy store the data. + RecvProxy_Int32ToInt32( pData, pStruct, pOut ); + + C_BaseAnimating *pAnimating = (C_BaseAnimating *)pStruct; + + if ( !pAnimating ) + return; + + pAnimating->SetReceivedSequence(); + + // render bounds may have changed + pAnimating->UpdateVisibility(); +} + IMPLEMENT_CLIENTCLASS_DT(C_BaseAnimating, DT_BaseAnimating, CBaseAnimating) - RecvPropInt(RECVINFO(m_nSequence)), + RecvPropInt(RECVINFO(m_nSequence), 0, RecvProxy_Sequence), RecvPropInt(RECVINFO(m_nForceBone)), RecvPropVector(RECVINFO(m_vecForce)), RecvPropInt(RECVINFO(m_nSkin)), @@ -261,20 +283,6 @@ C_ClientRagdoll::C_ClientRagdoll( bool bRestoring ) void C_ClientRagdoll::OnSave( void ) { - C_EntityFlame *pFireChild = dynamic_cast( GetEffectEntity() ); - - if ( pFireChild ) - { - for ( int i = 0; i < NUM_HITBOX_FIRES; i++ ) - { - if ( pFireChild->m_pFireSmoke[i] != NULL ) - { - m_flScaleEnd[i] = pFireChild->m_pFireSmoke[i]->m_flScaleEnd; - m_flScaleTimeStart[i] = pFireChild->m_pFireSmoke[i]->m_flScaleTimeStart; - m_flScaleTimeEnd[i] = pFireChild->m_pFireSmoke[i]->m_flScaleTimeEnd; - } - } - } } void C_ClientRagdoll::OnRestore( void ) @@ -326,7 +334,7 @@ void C_ClientRagdoll::OnRestore( void ) pRagdollT->list[0].parentIndex = -1; pRagdollT->list[0].originParentSpace.Init(); - RagdollActivate( *pRagdollT, modelinfo->GetVCollide( GetModelIndex() ), GetModelIndex(), false ); + RagdollActivate( *pRagdollT, modelinfo->GetVCollide( GetModelIndex() ), GetModelIndex(), true ); RagdollSetupAnimatedFriction( physenv, pRagdollT, GetModelIndex() ); m_pRagdoll->BuildRagdollBounds( this ); @@ -355,6 +363,8 @@ void C_ClientRagdoll::OnRestore( void ) void C_ClientRagdoll::ImpactTrace( trace_t *pTrace, int iDamageType, char *pCustomImpactName ) { + VPROF( "C_ClientRagdoll::ImpactTrace" ); + IPhysicsObject *pPhysicsObject = VPhysicsGetObject(); if( !pPhysicsObject ) @@ -553,42 +563,40 @@ void C_ClientRagdoll::ClientThink( void ) //----------------------------------------------------------------------------- // Purpose: clear out any face/eye values stored in the material system //----------------------------------------------------------------------------- -void C_ClientRagdoll::SetupWeights( void ) +float C_ClientRagdoll::LastBoneChangedTime() { - BaseClass::SetupWeights( ); + // When did this last change? + return m_pRagdoll ? m_pRagdoll->GetLastVPhysicsUpdateTime() : -FLT_MAX; +} - static float destweight[MAXSTUDIOFLEXDESC]; - static bool bIsInited = false; + +//----------------------------------------------------------------------------- +// Purpose: clear out any face/eye values stored in the material system +//----------------------------------------------------------------------------- +void C_ClientRagdoll::SetupWeights( const matrix3x4_t *pBoneToWorld, int nFlexWeightCount, float *pFlexWeights, float *pFlexDelayedWeights ) +{ + BaseClass::SetupWeights( pBoneToWorld, nFlexWeightCount, pFlexWeights, pFlexDelayedWeights ); CStudioHdr *hdr = GetModelPtr(); if ( !hdr ) - { return; - } - if (hdr->numflexdesc() > 0) + int nFlexDescCount = hdr->numflexdesc(); + if ( nFlexDescCount ) { - if (!bIsInited) - { - int i; - for (i = 0; i < MAXSTUDIOFLEXDESC; i++) - { - destweight[i] = 0.0f; - } - bIsInited = true; - } - modelrender->SetFlexWeights( hdr->numflexdesc(), destweight ); + Assert( !pFlexDelayedWeights ); + memset( pFlexWeights, 0, nFlexWeightCount * sizeof(float) ); } - if (m_iEyeAttachment > 0) + if ( m_iEyeAttachment > 0 ) { matrix3x4_t attToWorld; - if (GetAttachment( m_iEyeAttachment, attToWorld )) + if ( GetAttachment( m_iEyeAttachment, attToWorld ) ) { Vector local, tmp; local.Init( 1000.0f, 0.0f, 0.0f ); VectorTransform( local, attToWorld, tmp ); - modelrender->SetViewTarget( tmp ); + modelrender->SetViewTarget( GetModelPtr(), GetBody(), tmp ); } } } @@ -618,6 +626,22 @@ void C_ClientRagdoll::Release( void ) // Incremented each frame in InvalidateModelBones. Models compare this value to what it // was last time they setup their bones to determine if they need to re-setup their bones. static unsigned long g_iModelBoneCounter = 0; +CUtlVector g_PreviousBoneSetups; +static unsigned long g_iPreviousBoneCounter = (unsigned)-1; + +class C_BaseAnimatingGameSystem : public CAutoGameSystem +{ + void LevelShutdownPostEntity() + { + g_iPreviousBoneCounter = (unsigned)-1; + if ( g_PreviousBoneSetups.Count() != 0 ) + { + Msg( "%d entities in bone setup array. Should have been cleaned up by now\n", g_PreviousBoneSetups.Count() ); + g_PreviousBoneSetups.RemoveAll(); + } + } +} g_BaseAnimatingGameSystem; + //----------------------------------------------------------------------------- // Purpose: convert axis rotations to a quaternion @@ -627,9 +651,8 @@ C_BaseAnimating::C_BaseAnimating() : m_iv_flPoseParameter( "C_BaseAnimating::m_iv_flPoseParameter" ), m_iv_flEncodedController("C_BaseAnimating::m_iv_flEncodedController") { -#ifdef _DEBUG m_vecForce.Init(); -#endif + m_nForceBone = -1; m_ClientSideAnimationListHandle = INVALID_CLIENTSIDEANIMATION_LIST_HANDLE; @@ -647,6 +670,8 @@ C_BaseAnimating::C_BaseAnimating() : AddBaseAnimatingInterpolatedVars(); m_iMostRecentModelBoneCounter = 0xFFFFFFFF; + m_iMostRecentBoneSetupRequest = g_iPreviousBoneCounter - 1; + m_flLastBoneSetupTime = -FLT_MAX; m_vecPreRagdollMins = vec3_origin; m_vecPreRagdollMaxs = vec3_origin; @@ -677,6 +702,9 @@ C_BaseAnimating::C_BaseAnimating() : m_iAccumulatedBoneMask = 0; #endif m_pStudioHdr = NULL; + m_hStudioHdr = MDLHANDLE_INVALID; + + m_bReceivedSequence = false; } //----------------------------------------------------------------------------- @@ -684,6 +712,9 @@ C_BaseAnimating::C_BaseAnimating() : //----------------------------------------------------------------------------- C_BaseAnimating::~C_BaseAnimating() { + int i = g_PreviousBoneSetups.Find( this ); + if ( i != -1 ) + g_PreviousBoneSetups.FastRemove( i ); RemoveFromClientSideAnimationList(); TermRopes(); @@ -692,15 +723,16 @@ C_BaseAnimating::~C_BaseAnimating() delete m_pIk; delete m_pBoneMergeCache; Studio_DestroyBoneCache( m_hitboxBoneCacheHandle ); + UnlockStudioHdr(); delete m_pStudioHdr; + delete m_pJiggleBones; } -bool C_BaseAnimating::UsesFrameBufferTexture( void ) +bool C_BaseAnimating::UsesPowerOfTwoFrameBufferTexture( void ) { - return modelinfo->IsUsingFBTexture( GetModel() ); + return modelinfo->IsUsingFBTexture( GetModel(), GetSkin(), GetBody(), GetClientRenderable() ); } - //----------------------------------------------------------------------------- // VPhysics object //----------------------------------------------------------------------------- @@ -770,8 +802,17 @@ void C_BaseAnimating::SetPredictable( bool state ) UpdateRelevantInterpolatedVars(); } +//----------------------------------------------------------------------------- +// Purpose: sets client side animation +//----------------------------------------------------------------------------- +void C_BaseAnimating::UseClientSideAnimation() +{ + m_bClientSideAnimation = true; +} + void C_BaseAnimating::UpdateRelevantInterpolatedVars() { + MDLCACHE_CRITICAL_SECTION(); // Remove any interpolated vars that need to be removed. if ( !GetPredictable() && !IsClientCreated() && GetModelPtr() && GetModelPtr()->SequencesAvailable() ) { @@ -803,10 +844,70 @@ void C_BaseAnimating::RemoveBaseAnimatingInterpolatedVars() RemoveVar( &m_flCycle, false ); } +void C_BaseAnimating::LockStudioHdr() +{ + AUTO_LOCK( m_StudioHdrInitLock ); + const model_t *mdl = GetModel(); + if (mdl) + { + m_hStudioHdr = modelinfo->GetCacheHandle( mdl ); + if ( m_hStudioHdr != MDLHANDLE_INVALID ) + { + const studiohdr_t *pStudioHdr = mdlcache->LockStudioHdr( m_hStudioHdr ); + CStudioHdr *pStudioHdrContainer = NULL; + if ( !m_pStudioHdr ) + { + if ( pStudioHdr ) + { + pStudioHdrContainer = new CStudioHdr; + pStudioHdrContainer->Init( pStudioHdr, mdlcache ); + } + else + { + m_hStudioHdr = MDLHANDLE_INVALID; + } + } + else + { + pStudioHdrContainer = m_pStudioHdr; + } + + Assert( ( pStudioHdr == NULL && pStudioHdrContainer == NULL ) || pStudioHdrContainer->GetRenderHdr() == pStudioHdr ); + + if ( pStudioHdrContainer && pStudioHdrContainer->GetVirtualModel() ) + { + MDLHandle_t hVirtualModel = (MDLHandle_t)pStudioHdrContainer->GetRenderHdr()->virtualModel; + mdlcache->LockStudioHdr( hVirtualModel ); + } + m_pStudioHdr = pStudioHdrContainer; // must be last to ensure virtual model correctly set up + } + } +} + +void C_BaseAnimating::UnlockStudioHdr() +{ + if ( m_pStudioHdr ) + { + const model_t *mdl = GetModel(); + if (mdl) + { + mdlcache->UnlockStudioHdr( m_hStudioHdr ); + if ( m_pStudioHdr->GetVirtualModel() ) + { + MDLHandle_t hVirtualModel = (MDLHandle_t)m_pStudioHdr->GetRenderHdr()->virtualModel; + mdlcache->UnlockStudioHdr( hVirtualModel ); + } + } + } +} + + + CStudioHdr *C_BaseAnimating::OnNewModel() { if (m_pStudioHdr) { + UnlockStudioHdr(); delete m_pStudioHdr; m_pStudioHdr = NULL; } @@ -814,10 +915,16 @@ CStudioHdr *C_BaseAnimating::OnNewModel() // remove transition animations playback m_SequenceTransitioner.RemoveAll(); + if (m_pJiggleBones) + { + delete m_pJiggleBones; + m_pJiggleBones = NULL; + } + if ( !GetModel() ) return NULL; - m_pStudioHdr = new CStudioHdr( modelinfo->GetStudiomodel( GetModel() ), mdlcache ); + LockStudioHdr(); UpdateRelevantInterpolatedVars(); @@ -855,20 +962,21 @@ CStudioHdr *C_BaseAnimating::OnNewModel() } // Don't reallocate unless a different size. - if ( m_Attachments.Count() != hdr->GetNumAttachments()) + if ( m_Attachments.Count() != hdr->GetNumAttachments() ) { m_Attachments.SetSize( hdr->GetNumAttachments() ); -#ifdef _DEBUG // This is to make sure we don't use the attachment before its been set up for ( int i=0; i < m_Attachments.Count(); i++ ) { - float *pOrg = m_Attachments[i].m_vOrigin.Base(); - float *pAng = m_Attachments[i].m_angRotation.Base(); - pOrg[0] = pOrg[1] = pOrg[2] = VEC_T_NAN; - pAng[0] = pAng[1] = pAng[2] = VEC_T_NAN; - } + m_Attachments[i].m_bAnglesComputed = false; + m_Attachments[i].m_nLastFramecount = 0; +#ifdef _DEBUG + m_Attachments[i].m_AttachmentToWorld.Invalidate(); + m_Attachments[i].m_angRotation.Init( VEC_T_NAN, VEC_T_NAN, VEC_T_NAN ); + m_Attachments[i].m_vOriginVelocity.Init( VEC_T_NAN, VEC_T_NAN, VEC_T_NAN ); #endif + } } @@ -901,7 +1009,7 @@ CStudioHdr *C_BaseAnimating::OnNewModel() SetBoneController( i, 0.0 ); } - InitRopes(); + InitModelEffects(); // lookup generic eye attachment, if exists m_iEyeAttachment = LookupAttachment( "eyes" ); @@ -916,41 +1024,15 @@ CStudioHdr *C_BaseAnimating::OnNewModel() AddEFlags( EFL_USE_PARTITION_WHEN_NOT_SOLID ); } - return hdr; -} - -//----------------------------------------------------------------------------- -// Purpose: return a pointer to an updated studiomdl cache cache -//----------------------------------------------------------------------------- - -CStudioHdr *C_BaseAnimating::GetModelPtr() const -{ - // GetModelPtr() is often called before OnNewModel() so go ahead and set it up first chance. -#ifdef _DEBUG - IDataCacheSection *pModelCache = datacache->FindSection( "ModelData" ); - AssertOnce( pModelCache->IsFrameLocking() ); -#endif - if (!m_pStudioHdr) + // Most entities clear out their sequences when they change models on the server, but + // not all entities network down their m_nSequence (like multiplayer game player entities), + // so we need to clear it out here. + if ( ShouldResetSequenceOnNewModel() ) { - m_pStudioHdr = new CStudioHdr( mdlcache ); + SetSequence(0); } - // see if the cache hasn't been unlocked since last we checked - if (m_pStudioHdr->IsReadyForAccess()) - return m_pStudioHdr; - - const model_t *mdl = GetModel(); - if (!mdl) - return NULL; - - studiohdr_t *hdr = modelinfo->GetStudiomodel( mdl ); - - m_pStudioHdr->Init( hdr ); - - if (m_pStudioHdr->IsReadyForAccess()) - return m_pStudioHdr; - - return NULL; + return hdr; } //----------------------------------------------------------------------------- @@ -994,16 +1076,27 @@ void C_BaseAnimating::GetBoneTransform( int iBone, matrix3x4_t &pBoneToWorld ) MatrixCopy( *pmatrix, pBoneToWorld ); } - -void C_BaseAnimating::InitRopes() +//----------------------------------------------------------------------------- +// Purpose: Setup to initialize our model effects once the model's loaded +//----------------------------------------------------------------------------- +void C_BaseAnimating::InitModelEffects( void ) { + m_bInitModelEffects = true; TermRopes(); - +} + +//----------------------------------------------------------------------------- +// Purpose: Load the model's keyvalues section and create effects listed inside it +//----------------------------------------------------------------------------- +void C_BaseAnimating::DelayedInitModelEffects( void ) +{ + m_bInitModelEffects = false; + // Parse the keyvalues and see if they want to make ropes on this model. KeyValues * modelKeyValues = new KeyValues(""); if ( modelKeyValues->LoadFromBuffer( modelinfo->GetModelName( GetModel() ), modelinfo->GetModelKeyValueText( GetModel() ) ) ) { - // Do we have a build point section? + // Do we have a cables section? KeyValues *pkvAllCables = modelKeyValues->FindKey("Cables"); if ( pkvAllCables ) { @@ -1014,6 +1107,43 @@ void C_BaseAnimating::InitRopes() m_Ropes.AddToTail( pRope ); } } + + // Do we have a particles section? + KeyValues *pkvAllParticleEffects = modelKeyValues->FindKey("Particles"); + if ( pkvAllParticleEffects ) + { + // Start grabbing the sounds and slotting them in + for ( KeyValues *pSingleEffect = pkvAllParticleEffects->GetFirstSubKey(); pSingleEffect; pSingleEffect = pSingleEffect->GetNextKey() ) + { + const char *pszParticleEffect = pSingleEffect->GetString( "name", "" ); + const char *pszAttachment = pSingleEffect->GetString( "attachment_point", "" ); + const char *pszAttachType = pSingleEffect->GetString( "attachment_type", "" ); + + // Convert attach type + int iAttachType = GetAttachTypeFromString( pszAttachType ); + if ( iAttachType == -1 ) + { + Warning("Invalid attach type specified for particle effect in model '%s' keyvalues section. Trying to spawn effect '%s' with attach type of '%s'\n", GetModelName(), pszParticleEffect, pszAttachType ); + return; + } + + // Convert attachment point + int iAttachment = atoi(pszAttachment); + // See if we can find any attachment points matching the name + if ( pszAttachment[0] != '0' && iAttachment == 0 ) + { + iAttachment = LookupAttachment( pszAttachment ); + if ( iAttachment == -1 ) + { + Warning("Failed to find attachment point specified for particle effect in model '%s' keyvalues section. Trying to spawn effect '%s' on attachment named '%s'\n", GetModelName(), pszParticleEffect, pszAttachment ); + return; + } + } + + // Spawn the particle effect + ParticleProp()->Create( pszParticleEffect, (ParticleAttachment_t)iAttachType, iAttachment ); + } + } } modelKeyValues->deleteThis(); @@ -1070,9 +1200,10 @@ void C_BaseAnimating::GetPoseParameters( CStudioHdr *pStudioHdr, float poseParam } -#if _DEBUG - if (Q_stristr( pStudioHdr->pszName(), r_sequence_debug.GetString()) != NULL) +#if 0 // _DEBUG + if (/* Q_stristr( pStudioHdr->pszName(), r_sequence_debug.GetString()) != NULL || */ r_sequence_debug.GetInt() == entindex()) { + DevMsgRT( "%s\n", pStudioHdr->pszName() ); DevMsgRT( "%6.2f : ", gpGlobals->curtime ); for( i=0; i < pStudioHdr->GetNumPoseParameters(); i++) { @@ -1110,6 +1241,7 @@ void C_BaseAnimating::GetCachedBoneMatrix( int boneIndex, matrix3x4_t &out ) MatrixCopy( GetBone( boneIndex ), out ); } + //----------------------------------------------------------------------------- // Purpose: move position and rotation transforms into global matrices //----------------------------------------------------------------------------- @@ -1164,7 +1296,7 @@ void C_BaseAnimating::BuildTransformations( CStudioHdr *hdr, Vector *pos, Quater for (int i = 0; i < hdr->numbones(); i++) { // Only update bones reference by the bone mask. - if ( !( hdr->pBone( i )->flags & boneMask ) ) + if ( !( hdr->boneFlags( i ) & boneMask ) ) continue; if ( m_pBoneMergeCache && m_pBoneMergeCache->IsBoneMerged( i ) ) @@ -1189,17 +1321,50 @@ void C_BaseAnimating::BuildTransformations( CStudioHdr *hdr, Vector *pos, Quater Assert( fabs( pos[i].y ) < 100000 ); Assert( fabs( pos[i].z ) < 100000 ); - if (pbones[i].parent == -1) + if ( (hdr->boneFlags( i ) & BONE_ALWAYS_PROCEDURAL) && + (hdr->pBone( i )->proctype & STUDIO_PROC_JIGGLE) ) + { + // + // Physics-based "jiggle" bone + // Bone is assumed to be along the Z axis + // Pitch around X, yaw around Y + // + + // compute desired bone orientation + matrix3x4_t goalMX; + + if (pbones[i].parent == -1) + { + ConcatTransforms( cameraTransform, bonematrix, goalMX ); + } + else + { + ConcatTransforms( GetBone( pbones[i].parent ), bonematrix, goalMX ); + } + + // get jiggle properties from QC data + mstudiojigglebone_t *jiggleInfo = (mstudiojigglebone_t *)pbones[i].pProcedure( ); + + if (!m_pJiggleBones) + { + m_pJiggleBones = new CJiggleBones; + } + + // do jiggle physics + m_pJiggleBones->BuildJiggleTransformations( i, gpGlobals->curtime, jiggleInfo, goalMX, GetBoneForWrite( i ) ); + + } + else if (hdr->boneParent(i) == -1) { ConcatTransforms( cameraTransform, bonematrix, GetBoneForWrite( i ) ); } else { - ConcatTransforms( GetBone( pbones[i].parent ), bonematrix, GetBoneForWrite( i ) ); + ConcatTransforms( GetBone( hdr->boneParent(i) ), bonematrix, GetBoneForWrite( i ) ); } } - if (pbones[i].parent == -1) + if (hdr->boneParent(i) == -1) { // Apply client-side effects to the transformation matrix ApplyBoneMatrixTransform( GetBoneForWrite( i ) ); @@ -1297,7 +1462,6 @@ void C_BaseAnimating::CreateUnragdollInfo( C_BaseAnimating *pRagdoll ) Q_memset( m_pRagdollInfo, 0, sizeof( *m_pRagdollInfo ) ); int numbones = hdr->numbones(); - mstudiobone_t *pbones = hdr->pBone( 0 ); m_pRagdollInfo->m_bActive = true; m_pRagdollInfo->m_flSaveTime = gpGlobals->curtime; @@ -1308,14 +1472,14 @@ void C_BaseAnimating::CreateUnragdollInfo( C_BaseAnimating *pRagdoll ) matrix3x4_t inverted; matrix3x4_t output; - if ( pbones[i].parent == -1 ) + if ( hdr->boneParent(i) == -1 ) { // Decompose into parent space MatrixInvert( parentTransform, inverted ); } else { - MatrixInvert( pRagdoll->m_BoneAccessor.GetBone( pbones[ i ].parent ), inverted ); + MatrixInvert( pRagdoll->m_BoneAccessor.GetBone( hdr->boneParent(i) ), inverted ); } ConcatTransforms( inverted, pRagdoll->m_BoneAccessor.GetBone( i ), output ); @@ -1393,15 +1557,14 @@ bool C_BaseAnimating::RetrieveRagdollInfo( Vector *pos, Quaternion *q ) // Should we collide? //----------------------------------------------------------------------------- -CollideType_t C_BaseAnimating::ShouldCollide( ) +CollideType_t C_BaseAnimating::GetCollideType( void ) { if ( IsRagdoll() ) return ENTITY_SHOULD_RESPOND; - return BaseClass::ShouldCollide(); + return BaseClass::GetCollideType(); } - //----------------------------------------------------------------------------- // Purpose: if the active sequence changes, keep track of the previous ones and decay them based on their decay rate //----------------------------------------------------------------------------- @@ -1412,6 +1575,12 @@ void C_BaseAnimating::MaintainSequenceTransitions( CStudioHdr *hdr, float flCycl if ( !hdr ) return; + if ( prediction->InPrediction() ) + { + m_nPrevNewSequenceParity = m_nNewSequenceParity; + return; + } + m_SequenceTransitioner.CheckForSequenceChange( hdr, GetSequence(), @@ -1440,10 +1609,10 @@ void C_BaseAnimating::MaintainSequenceTransitions( CStudioHdr *hdr, float flCycl flCycle = blend->m_flCycle + dt * blend->m_flPlaybackRate * GetSequenceCycleRate( hdr, blend->m_nSequence ); flCycle = ClampCycle( flCycle, IsSequenceLooping( hdr, blend->m_nSequence ) ); -#if _DEBUG - if (Q_stristr( hdr->pszName(), r_sequence_debug.GetString()) != NULL) +#if 1 // _DEBUG + if (/*Q_stristr( hdr->pszName(), r_sequence_debug.GetString()) != NULL || */ r_sequence_debug.GetInt() == entindex()) { - DevMsgRT( "%6.2f : %30s : %5.3f : %4.2f +\n", gpGlobals->curtime, hdr->pSeqdesc( blend->m_nSequence ).pszLabel(), flCycle, (float)blend->m_flWeight ); + DevMsgRT( "%8.4f : %30s : %5.3f : %4.2f +\n", gpGlobals->curtime, hdr->pSeqdesc( blend->m_nSequence ).pszLabel(), flCycle, (float)blend->m_flWeight ); } #endif @@ -1518,14 +1687,14 @@ void C_BaseAnimating::StandardBlendingRules( CStudioHdr *hdr, Vector pos[], Quat // build root animation float fCycle = GetCycle(); -#if _DEBUG - if (Q_stristr( hdr->pszName(), r_sequence_debug.GetString()) != NULL) +#if 1 //_DEBUG + if (/* Q_stristr( hdr->pszName(), r_sequence_debug.GetString()) != NULL || */ r_sequence_debug.GetInt() == entindex()) { - DevMsgRT( "%6.2f : %30s : %5.3f : %4.2f\n", currentTime, hdr->pSeqdesc( GetSequence() ).pszLabel(), fCycle, 1.0 ); + DevMsgRT( "%8.4f : %30s : %5.3f : %4.2f\n", currentTime, hdr->pSeqdesc( GetSequence() ).pszLabel(), fCycle, 1.0 ); } #endif - InitPose( hdr, pos, q ); + InitPose( hdr, pos, q, boneMask ); AccumulatePose( hdr, m_pIk, pos, q, GetSequence(), fCycle, poseparam, boneMask, 1.0, currentTime ); @@ -1546,6 +1715,16 @@ void C_BaseAnimating::StandardBlendingRules( CStudioHdr *hdr, Vector pos[], Quat CalcBoneAdj( hdr, pos, q, controllers, boneMask ); } UnragdollBlend( hdr, pos, q, currentTime ); + +#ifdef STUDIO_ENABLE_PERF_COUNTERS +#if _DEBUG + if (Q_stristr( hdr->pszName(), r_sequence_debug.GetString()) != NULL) + { + DevMsgRT( "layers %4d : bones %4d : animated %4d\n", hdr->m_nPerfAnimationLayers, hdr->m_nPerfUsedBones, hdr->m_nPerfAnimatedBones ); + } +#endif +#endif + } @@ -1554,15 +1733,31 @@ void C_BaseAnimating::StandardBlendingRules( CStudioHdr *hdr, Vector pos[], Quat // Input : number - which point // Output : float * - the attachment point //----------------------------------------------------------------------------- -bool C_BaseAnimating::PutAttachment( int number, const Vector &origin, const QAngle &angles ) +bool C_BaseAnimating::PutAttachment( int number, const matrix3x4_t &attachmentToWorld ) { if ( number < 1 || number > m_Attachments.Count() ) - { return false; - } - m_Attachments[number-1].m_vOrigin = origin; - m_Attachments[number-1].m_angRotation = angles; + CAttachmentData *pAtt = &m_Attachments[number-1]; + if ( gpGlobals->frametime > 0 && pAtt->m_nLastFramecount > 0 && pAtt->m_nLastFramecount == gpGlobals->framecount - 1 ) + { + Vector vecPreviousOrigin, vecOrigin; + MatrixPosition( pAtt->m_AttachmentToWorld, vecPreviousOrigin ); + MatrixPosition( attachmentToWorld, vecOrigin ); + pAtt->m_vOriginVelocity = (vecOrigin - vecPreviousOrigin) / gpGlobals->frametime; + } + else + { + pAtt->m_vOriginVelocity.Init(); + } + pAtt->m_nLastFramecount = gpGlobals->framecount; + pAtt->m_bAnglesComputed = false; + pAtt->m_AttachmentToWorld = attachmentToWorld; + +#ifdef _DEBUG + pAtt->m_angRotation.Init( VEC_T_NAN, VEC_T_NAN, VEC_T_NAN ); +#endif + return true; } @@ -1593,23 +1788,28 @@ void C_BaseAnimating::SetupBones_AttachmentHelper( CStudioHdr *hdr ) } // FIXME: this shouldn't be here, it should client side on-demand only and hooked into the bone cache!! - QAngle angles; - Vector origin; - MatrixAngles( world, angles, origin ); - FormatViewModelAttachment( i, origin, angles ); - PutAttachment( i + 1, origin, angles ); + FormatViewModelAttachment( i, world ); + PutAttachment( i + 1, world ); } } bool C_BaseAnimating::CalcAttachments() { VPROF( "C_BaseAnimating::CalcAttachments" ); + + // Make sure m_CachedBones is valid. - if ( !SetupBones( NULL, -1, BONE_USED_BY_ATTACHMENT, gpGlobals->curtime ) ) - { - return false; - } - return true; + return SetupBones( NULL, -1, BONE_USED_BY_ATTACHMENT, gpGlobals->curtime ); +} + +//----------------------------------------------------------------------------- +// Purpose: Returns the world location and world angles of an attachment +// Input : attachment name +// Output : location and angles +//----------------------------------------------------------------------------- +bool C_BaseAnimating::GetAttachment( const char *szName, Vector &absOrigin, QAngle &absAngles ) +{ + return GetAttachment( LookupAttachment( szName ), absOrigin, absAngles ); } //----------------------------------------------------------------------------- @@ -1622,8 +1822,7 @@ bool C_BaseAnimating::GetAttachment( int number, Vector &origin, QAngle &angles // Note: this could be more efficient, but we want the matrix3x4_t version of GetAttachment to be the origin of // attachment generation, so a derived class that wants to fudge attachments only // has to reimplement that version. This also makes it work like the server in that regard. - matrix3x4_t attachmentToWorld; - if ( !GetAttachment( number, attachmentToWorld) ) + if ( number < 1 || number > m_Attachments.Count() || !CalcAttachments() ) { // Set this to the model origin/angles so that we don't have stack fungus in origin and angles. origin = GetAbsOrigin(); @@ -1631,14 +1830,60 @@ bool C_BaseAnimating::GetAttachment( int number, Vector &origin, QAngle &angles return false; } - MatrixAngles( attachmentToWorld, angles ); + CAttachmentData *pData = &m_Attachments[number-1]; + if ( !pData->m_bAnglesComputed ) + { + MatrixAngles( pData->m_AttachmentToWorld, pData->m_angRotation ); + pData->m_bAnglesComputed = true; + } + angles = pData->m_angRotation; + MatrixPosition( pData->m_AttachmentToWorld, origin ); + return true; +} + +bool C_BaseAnimating::GetAttachment( int number, matrix3x4_t& matrix ) +{ + if ( number < 1 || number > m_Attachments.Count() ) + return false; + + if ( !CalcAttachments() ) + return false; + + matrix = m_Attachments[number-1].m_AttachmentToWorld; + return true; +} + + +//----------------------------------------------------------------------------- +// Purpose: Get attachment point by index (position only) +// Input : number - which point +//----------------------------------------------------------------------------- +bool C_BaseAnimating::GetAttachment( int number, Vector &origin ) +{ + // Note: this could be more efficient, but we want the matrix3x4_t version of GetAttachment to be the origin of + // attachment generation, so a derived class that wants to fudge attachments only + // has to reimplement that version. This also makes it work like the server in that regard. + matrix3x4_t attachmentToWorld; + if ( !GetAttachment( number, attachmentToWorld ) ) + { + // Set this to the model origin/angles so that we don't have stack fungus in origin and angles. + origin = GetAbsOrigin(); + return false; + } + MatrixPosition( attachmentToWorld, origin ); return true; } -// UNDONE: Should be able to do this directly!!! -// Attachments begin as matrices!! -bool C_BaseAnimating::GetAttachment( int number, matrix3x4_t& matrix ) + +bool C_BaseAnimating::GetAttachment( const char *szName, Vector &absOrigin ) +{ + return GetAttachment( LookupAttachment( szName ), absOrigin ); +} + + + +bool C_BaseAnimating::GetAttachmentVelocity( int number, Vector &originVel, Quaternion &angleVel ) { if ( number < 1 || number > m_Attachments.Count() ) { @@ -1648,13 +1893,13 @@ bool C_BaseAnimating::GetAttachment( int number, matrix3x4_t& matrix ) if ( !CalcAttachments() ) return false; - Vector &origin = m_Attachments[number-1].m_vOrigin; - QAngle &angles = m_Attachments[number-1].m_angRotation; - AngleMatrix( angles, origin, matrix ); + originVel = m_Attachments[number-1].m_vOriginVelocity; + angleVel.Init(); return true; } + //----------------------------------------------------------------------------- // Returns the attachment in local space //----------------------------------------------------------------------------- @@ -1674,7 +1919,7 @@ bool C_BaseAnimating::GetAttachmentLocal( int iAttachment, Vector &origin, QAngl { matrix3x4_t attachmentToEntity; - if (GetAttachmentLocal( iAttachment, attachmentToEntity )) + if ( GetAttachmentLocal( iAttachment, attachmentToEntity ) ) { origin.Init( attachmentToEntity[0][3], attachmentToEntity[1][3], attachmentToEntity[2][3] ); MatrixAngles( attachmentToEntity, angles ); @@ -1683,36 +1928,44 @@ bool C_BaseAnimating::GetAttachmentLocal( int iAttachment, Vector &origin, QAngl return false; } +bool C_BaseAnimating::GetAttachmentLocal( int iAttachment, Vector &origin ) +{ + matrix3x4_t attachmentToEntity; + + if ( GetAttachmentLocal( iAttachment, attachmentToEntity ) ) + { + MatrixPosition( attachmentToEntity, origin ); + return true; + } + return false; +} + //----------------------------------------------------------------------------- // Purpose: Move sound location to center of body //----------------------------------------------------------------------------- - bool C_BaseAnimating::GetSoundSpatialization( SpatializationInfo_t& info ) { - C_BaseAnimating::PushAllowBoneAccess( true, false ); - bool bret = BaseClass::GetSoundSpatialization( info ); - C_BaseAnimating::PopBoneAccess(); - - if ( bret ) { - // move sound origin to center if npc has IK - if ( info.pOrigin && IsNPC() && m_pIk) - { - *info.pOrigin = GetAbsOrigin(); - - Vector mins, maxs, center; - - modelinfo->GetModelBounds( GetModel(), mins, maxs ); - VectorAdd( mins, maxs, center ); - VectorScale( center, 0.5f, center ); - - (*info.pOrigin) += center; - } - return true; + C_BaseAnimating::AutoAllowBoneAccess boneaccess( true, false ); + if ( !BaseClass::GetSoundSpatialization( info ) ) + return false; } - return false; + // move sound origin to center if npc has IK + if ( info.pOrigin && IsNPC() && m_pIk) + { + *info.pOrigin = GetAbsOrigin(); + + Vector mins, maxs, center; + + modelinfo->GetModelBounds( GetModel(), mins, maxs ); + VectorAdd( mins, maxs, center ); + VectorScale( center, 0.5f, center ); + + (*info.pOrigin) += center; + } + return true; } @@ -1721,6 +1974,10 @@ bool C_BaseAnimating::IsViewModel() const return false; } +bool C_BaseAnimating::IsMenuModel() const +{ + return false; +} // UNDONE: Seems kind of silly to have this when we also have the cached bones in C_BaseAnimating CBoneCache *C_BaseAnimating::GetBoneCache( CStudioHdr *pStudioHdr ) @@ -1729,7 +1986,7 @@ CBoneCache *C_BaseAnimating::GetBoneCache( CStudioHdr *pStudioHdr ) CBoneCache *pcache = Studio_GetBoneCache( m_hitboxBoneCacheHandle ); if ( pcache ) { - if ( pcache->IsValid( gpGlobals->curtime ) ) + if ( pcache->IsValid( gpGlobals->curtime, 0.0 ) ) { // in memory and still valid, use it! return pcache; @@ -1784,6 +2041,9 @@ public: if ( CTraceFilterSimple::ShouldHitEntity(pServerEntity, contentsMask) ) { C_BaseEntity *pEntity = EntityFromEntityHandle( pServerEntity ); + if ( !pEntity ) + return true; + if ( pEntity->IsNPC() || pEntity->IsPlayer() ) return false; @@ -1904,7 +2164,7 @@ void C_BaseAnimating::CalculateIKLocks( float currentTime ) if (trace.startsolid) { // trace from back towards hip - Vector tmp = estGround - pTarget->trace.p1; + Vector tmp = estGround - pTarget->trace.closest; tmp.NormalizeInPlace(); ray.Init( estGround - tmp * pTarget->est.height, estGround, Vector(-r,-r,0), Vector(r,r,1) ); @@ -1929,28 +2189,41 @@ void C_BaseAnimating::CalculateIKLocks( float currentTime ) { if (trace.DidHitWorld()) { - // clamp normal - if (trace.plane.normal.z < 0.707) + // clamp normal to 33 degrees + const float limit = 0.832; + float dot = DotProduct(trace.plane.normal, up); + if (dot < limit) { - float d = sqrt( 0.5 / (trace.plane.normal.x * trace.plane.normal.x + trace.plane.normal.y * trace.plane.normal.y) ); - trace.plane.normal.x = d * trace.plane.normal.x; - trace.plane.normal.y = d * trace.plane.normal.y; - trace.plane.normal.z = 0.707; + Assert( dot >= 0 ); + // subtract out up component + Vector diff = trace.plane.normal - up * dot; + // scale remainder such that it and the up vector are a unit vector + float d = sqrt( (1 - limit * limit) / DotProduct( diff, diff ) ); + trace.plane.normal = up * limit + d * diff; } - + // FIXME: this is wrong with respect to contact position and actual ankle offset pTarget->SetPosWithNormalOffset( trace.endpos, trace.plane.normal ); pTarget->SetNormal( trace.plane.normal ); + pTarget->SetOnWorld( true ); // only do this on forward tracking or commited IK ground rules if (pTarget->est.release < 0.1) { // keep track of ground height - if (minHeight > pTarget->est.pos.z ) - minHeight = pTarget->est.pos.z; + float offset = DotProduct( pTarget->est.pos, up ); + if (minHeight > offset ) + minHeight = offset; - if (maxHeight < pTarget->est.pos.z ) - maxHeight = pTarget->est.pos.z; + if (maxHeight < offset ) + maxHeight = offset; } + // FIXME: if we don't drop legs, running down hills looks horrible + /* + if (DotProduct( pTarget->est.pos, up ) < DotProduct( estGround, up )) + { + pTarget->est.pos = estGround; + } + */ } else if (trace.DidHitNonWorldEntity()) { @@ -1960,13 +2233,20 @@ void C_BaseAnimating::CalculateIKLocks( float currentTime ) // only do this on forward tracking or commited IK ground rules if (pTarget->est.release < 0.1) { - // keep track of ground height - if (minHeight > pTarget->est.pos.z ) - minHeight = pTarget->est.pos.z; + float offset = DotProduct( pTarget->est.pos, up ); + if (minHeight > offset ) + minHeight = offset; - if (maxHeight < pTarget->est.pos.z ) - maxHeight = pTarget->est.pos.z; + if (maxHeight < offset ) + maxHeight = offset; } + // FIXME: if we don't drop legs, running down hills looks horrible + /* + if (DotProduct( pTarget->est.pos, up ) < DotProduct( estGround, up )) + { + pTarget->est.pos = estGround; + } + */ } else { @@ -1981,8 +2261,9 @@ void C_BaseAnimating::CalculateIKLocks( float currentTime ) } else { - pTarget->SetPos( trace.startpos ); + pTarget->SetPos( trace.endpos ); pTarget->SetAngles( GetRenderAngles() ); + pTarget->SetOnWorld( true ); } } @@ -2041,9 +2322,13 @@ void C_BaseAnimating::CalculateIKLocks( float currentTime ) } #if defined( HL2_CLIENT_DLL ) - if (minHeight < FLT_MAX) + // Let's not bother sending IK Ground Contact info in MP games + if ( 1 == gpGlobals->maxClients ) { - input->AddIKGroundContactInfo( entindex(), minHeight, maxHeight ); + if (minHeight < FLT_MAX) + { + input->AddIKGroundContactInfo( entindex(), minHeight, maxHeight ); + } } #endif @@ -2111,9 +2396,61 @@ CMouthInfo *C_BaseAnimating::GetMouth( void ) return &m_mouth; } +#ifdef DEBUG_BONE_SETUP_THREADING +ConVar cl_warn_thread_contested_bone_setup("cl_warn_thread_contested_bone_setup", "0" ); +#endif +ConVar cl_threaded_bone_setup("cl_threaded_bone_setup", "0", 0, "Enable parallel processing of C_BaseAnimating::SetupBones()" ); + //----------------------------------------------------------------------------- // Purpose: Do the default sequence blending rules as done in HL1 //----------------------------------------------------------------------------- + +static void SetupBonesOnBaseAnimating( C_BaseAnimating *&pBaseAnimating ) +{ + if ( !pBaseAnimating->GetMoveParent() ) + pBaseAnimating->SetupBones( NULL, -1, -1, gpGlobals->curtime ); +} + +static void PreThreadedBoneSetup() +{ + mdlcache->BeginLock(); +} + +static void PostThreadedBoneSetup() +{ + mdlcache->EndLock(); +} + +static bool g_bInThreadedBoneSetup; +static bool g_bDoThreadedBoneSetup; + +void C_BaseAnimating::InitBoneSetupThreadPool() +{ +} + +void C_BaseAnimating::ShutdownBoneSetupThreadPool() +{ +} + +void C_BaseAnimating::ThreadedBoneSetup() +{ + g_bDoThreadedBoneSetup = cl_threaded_bone_setup.GetBool(); + if ( g_bDoThreadedBoneSetup ) + { + int nCount = g_PreviousBoneSetups.Count(); + if ( nCount > 1 ) + { + g_bInThreadedBoneSetup = true; + + ParallelProcess( g_PreviousBoneSetups.Base(), nCount, &SetupBonesOnBaseAnimating, &PreThreadedBoneSetup, &PostThreadedBoneSetup ); + + g_bInThreadedBoneSetup = false; + } + } + g_iPreviousBoneCounter++; + g_PreviousBoneSetups.RemoveAll(); +} + bool C_BaseAnimating::SetupBones( matrix3x4_t *pBoneToWorldOut, int nMaxBones, int boneMask, float currentTime ) { VPROF_BUDGET( "C_BaseAnimating::SetupBones", VPROF_BUDGETGROUP_CLIENT_ANIMATION ); @@ -2135,6 +2472,11 @@ bool C_BaseAnimating::SetupBones( matrix3x4_t *pBoneToWorldOut, int nMaxBones, i if ( GetSequence() == -1 ) return false; + if ( boneMask == -1 ) + { + boneMask = m_iPrevBoneMask; + } + // We should get rid of this someday when we have solutions for the odd cases where a bone doesn't // get setup and its transform is asked for later. if ( cl_SetupAllBones.GetInt() ) @@ -2148,14 +2490,63 @@ bool C_BaseAnimating::SetupBones( matrix3x4_t *pBoneToWorldOut, int nMaxBones, i boneMask |= BONE_USED_BY_ANYTHING; } - if( m_iMostRecentModelBoneCounter != g_iModelBoneCounter ) + if ( g_bInThreadedBoneSetup ) + { + if ( !m_BoneSetupLock.TryLock() ) + { + return false; + } + } + +#ifdef DEBUG_BONE_SETUP_THREADING + if ( cl_warn_thread_contested_bone_setup.GetBool() ) + { + if ( !m_BoneSetupLock.TryLock() ) + { + Msg( "Contested bone setup in frame %d!\n", gpGlobals->framecount ); + } + else + { + m_BoneSetupLock.Unlock(); + } + } +#endif + + AUTO_LOCK( m_BoneSetupLock ); + + if ( g_bInThreadedBoneSetup ) + { + m_BoneSetupLock.Unlock(); + } + + if ( m_iMostRecentModelBoneCounter != g_iModelBoneCounter ) { // Clear out which bones we've touched this frame if this is // the first time we've seen this object this frame. - m_BoneAccessor.SetReadableBones( 0 ); - m_BoneAccessor.SetWritableBones( 0 ); + if ( LastBoneChangedTime() >= m_flLastBoneSetupTime ) + { + m_BoneAccessor.SetReadableBones( 0 ); + m_BoneAccessor.SetWritableBones( 0 ); + m_flLastBoneSetupTime = currentTime; + } m_iPrevBoneMask = m_iAccumulatedBoneMask; m_iAccumulatedBoneMask = 0; + +#ifdef STUDIO_ENABLE_PERF_COUNTERS + CStudioHdr *hdr = GetModelPtr(); + if (hdr) + { + hdr->ClearPerfCounters(); + } +#endif + } + + int nBoneCount = m_CachedBoneData.Count(); + if ( g_bDoThreadedBoneSetup && !g_bInThreadedBoneSetup && ( nBoneCount >= 16 ) && !GetMoveParent() && m_iMostRecentBoneSetupRequest != g_iPreviousBoneCounter ) + { + m_iMostRecentBoneSetupRequest = g_iPreviousBoneCounter; + Assert( g_PreviousBoneSetups.Find( this ) == -1 ); + g_PreviousBoneSetups.AddToTail( this ); } // Keep track of everthing asked for over the entire frame @@ -2211,9 +2602,15 @@ bool C_BaseAnimating::SetupBones( matrix3x4_t *pBoneToWorldOut, int nMaxBones, i if ( m_pIk ) { + if (Teleported() || IsEffectActive(EF_NOINTERP)) + m_pIk->ClearTargets(); + m_pIk->Init( hdr, GetRenderAngles(), GetRenderOrigin(), currentTime, gpGlobals->framecount, bonesMaskNeedRecalc ); } + // Let pose debugger know that we are blending + g_pPoseDebugger->StartBlending( this, hdr ); + StandardBlendingRules( hdr, pos, q, currentTime, bonesMaskNeedRecalc ); CBoneBitList boneComputed; @@ -2261,11 +2658,14 @@ bool C_BaseAnimating::SetupBones( matrix3x4_t *pBoneToWorldOut, int nMaxBones, i C_BaseAnimating* C_BaseAnimating::FindFollowedEntity() { - C_BaseEntity *follow = GetFollowedEntity(); + if ( !follow ) return NULL; + if ( follow->IsDormant() ) + return NULL; + if ( !follow->GetModel() ) { Warning( "mod_studio: MOVETYPE_FOLLOW with no model.\n" ); @@ -2289,6 +2689,7 @@ C_BaseAnimating* C_BaseAnimating::FindFollowedEntity() void C_BaseAnimating::InvalidateBoneCache() { m_iMostRecentModelBoneCounter = g_iModelBoneCounter - 1; + m_flLastBoneSetupTime = -FLT_MAX; } @@ -2305,10 +2706,12 @@ struct BoneAccess { bAllowBoneAccessForNormalModels = false; bAllowBoneAccessForViewModels = false; + tag = NULL; } bool bAllowBoneAccessForNormalModels; bool bAllowBoneAccessForViewModels; + char const *tag; }; static CUtlVector< BoneAccess > g_BoneAccessStack; @@ -2323,27 +2726,21 @@ bool C_BaseAnimating::IsBoneAccessAllowed() const } // (static function) -void C_BaseAnimating::AllowBoneAccess( bool bAllowForNormalModels, bool bAllowForViewModels ) -{ - Assert( g_BoneAccessStack.Count() == 0 ); - // Make sure it's empty... - g_BoneAccessStack.RemoveAll(); - - g_BoneAcessBase.bAllowBoneAccessForNormalModels = bAllowForNormalModels; - g_BoneAcessBase.bAllowBoneAccessForViewModels = bAllowForViewModels; -} - -void C_BaseAnimating::PushAllowBoneAccess( bool bAllowForNormalModels, bool bAllowForViewModels ) +void C_BaseAnimating::PushAllowBoneAccess( bool bAllowForNormalModels, bool bAllowForViewModels, char const *tagPush ) { BoneAccess save = g_BoneAcessBase; g_BoneAccessStack.AddToTail( save ); + Assert( g_BoneAccessStack.Count() < 32 ); // Most likely we are leaking "PushAllowBoneAccess" calls if PopBoneAccess is never called. Consider using AutoAllowBoneAccess. g_BoneAcessBase.bAllowBoneAccessForNormalModels = bAllowForNormalModels; g_BoneAcessBase.bAllowBoneAccessForViewModels = bAllowForViewModels; + g_BoneAcessBase.tag = tagPush; } -void C_BaseAnimating::PopBoneAccess( void ) +void C_BaseAnimating::PopBoneAccess( char const *tagPop ) { + // Validate that pop matches the push + Assert( ( g_BoneAcessBase.tag == tagPop ) || ( g_BoneAcessBase.tag && g_BoneAcessBase.tag != ( char const * ) 1 && tagPop && tagPop != ( char const * ) 1 && !strcmp( g_BoneAcessBase.tag, tagPop ) ) ); int lastIndex = g_BoneAccessStack.Count() - 1; if ( lastIndex < 0 ) { @@ -2354,6 +2751,16 @@ void C_BaseAnimating::PopBoneAccess( void ) g_BoneAccessStack.Remove( lastIndex ); } +C_BaseAnimating::AutoAllowBoneAccess::AutoAllowBoneAccess( bool bAllowForNormalModels, bool bAllowForViewModels ) +{ + C_BaseAnimating::PushAllowBoneAccess( bAllowForNormalModels, bAllowForViewModels, ( char const * ) 1 ); +} + +C_BaseAnimating::AutoAllowBoneAccess::~AutoAllowBoneAccess( ) +{ + C_BaseAnimating::PopBoneAccess( ( char const * ) 1 ); +} + // (static function) void C_BaseAnimating::InvalidateBoneCaches() { @@ -2385,6 +2792,11 @@ int C_BaseAnimating::DrawModel( int flags ) extraFlags |= STUDIO_WIREFRAME; } + if ( flags & STUDIO_SHADOWDEPTHTEXTURE ) + { + extraFlags |= STUDIO_SHADOWDEPTHTEXTURE; + } + // Necessary for lighting blending CreateModelInstance(); @@ -2399,15 +2811,7 @@ int C_BaseAnimating::DrawModel( int flags ) if ( follow ) { // recompute master entity bone structure - int baseDrawn = 0; - if ( C_BasePlayer::ShouldDrawLocalPlayer() ) - { - baseDrawn = follow->DrawModel( STUDIO_RENDER ); - } - else - { - baseDrawn = follow->DrawModel( 0 ); - } + int baseDrawn = follow->DrawModel( 0 ); // draw entity // FIXME: Currently only draws if aiment is drawn. @@ -2426,14 +2830,13 @@ int C_BaseAnimating::DrawModel( int flags ) return drawn; } -ConVar vcollide_wireframe( "vcollide_wireframe", "0", FCVAR_CHEAT ); - - //----------------------------------------------------------------------------- // Gets the hitbox-to-world transforms, returns false if there was a problem //----------------------------------------------------------------------------- bool C_BaseAnimating::HitboxToWorldTransforms( matrix3x4_t *pHitboxToWorld[MAXSTUDIOBONES] ) { + MDLCACHE_CRITICAL_SECTION(); + if ( !GetModel() ) return false; @@ -2453,8 +2856,71 @@ bool C_BaseAnimating::HitboxToWorldTransforms( matrix3x4_t *pHitboxToWorld[MAXST return true; } +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +bool C_BaseAnimating::OnPostInternalDrawModel( ClientModelRenderInfo_t *pInfo ) +{ + return true; +} + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +bool C_BaseAnimating::OnInternalDrawModel( ClientModelRenderInfo_t *pInfo ) +{ + if ( m_hLightingOriginRelative.Get() ) + { + C_InfoLightingRelative *pInfoLighting = assert_cast( m_hLightingOriginRelative.Get() ); + pInfoLighting->GetLightingOffset( pInfo->lightingOffset ); + pInfo->pLightingOffset = &pInfo->lightingOffset; + } + if ( m_hLightingOrigin ) + { + pInfo->pLightingOrigin = &(m_hLightingOrigin->GetAbsOrigin()); + } + + return true; +} + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +void C_BaseAnimating::DoInternalDrawModel( ClientModelRenderInfo_t *pInfo, DrawModelState_t *pState, matrix3x4_t *pBoneToWorldArray ) +{ + if ( pState) + { + modelrender->DrawModelExecute( *pState, *pInfo, pBoneToWorldArray ); + } + + if ( vcollide_wireframe.GetBool() ) + { + if ( IsRagdoll() ) + { + m_pRagdoll->DrawWireframe(); + } + else if ( IsSolid() && CollisionProp()->GetSolid() == SOLID_VPHYSICS ) + { + vcollide_t *pCollide = modelinfo->GetVCollide( GetModelIndex() ); + if ( pCollide && pCollide->solidCount == 1 ) + { + static color32 debugColor = {0,255,255,0}; + matrix3x4_t matrix; + AngleMatrix( GetAbsAngles(), GetAbsOrigin(), matrix ); + engine->DebugDrawPhysCollide( pCollide->solids[0], NULL, matrix, debugColor ); + if ( VPhysicsGetObject() ) + { + static color32 debugColorPhys = {255,0,0,0}; + matrix3x4_t matrix; + VPhysicsGetObject()->GetPositionMatrix( &matrix ); + engine->DebugDrawPhysCollide( pCollide->solids[0], NULL, matrix, debugColorPhys ); + } + } + } + } +} + - //----------------------------------------------------------------------------- // Purpose: Draws the object // Input : flags - @@ -2482,59 +2948,44 @@ int C_BaseAnimating::InternalDrawModel( int flags ) flags |= STUDIO_ITEM_BLINK; } - ModelRenderInfo_t sInfo; - sInfo.flags = flags; - sInfo.pRenderable = this; - sInfo.instance = GetModelInstance(); - sInfo.entity_index = index; - sInfo.pModel = GetModel(); - sInfo.origin = GetRenderOrigin(); - sInfo.angles = GetRenderAngles(); - sInfo.skin = m_nSkin; - sInfo.body = m_nBody; - sInfo.hitboxset = m_nHitboxSet; + ClientModelRenderInfo_t info; + ClientModelRenderInfo_t *pInfo; - matrix3x4_t matLightingOffset; - if ( m_hLightingOriginRelative.Get() ) + pInfo = &info; + + pInfo->flags = flags; + pInfo->pRenderable = this; + pInfo->instance = GetModelInstance(); + pInfo->entity_index = index; + pInfo->pModel = GetModel(); + pInfo->origin = GetRenderOrigin(); + pInfo->angles = GetRenderAngles(); + pInfo->skin = GetSkin(); + pInfo->body = m_nBody; + pInfo->hitboxset = m_nHitboxSet; + + if ( !OnInternalDrawModel( pInfo ) ) { - C_InfoLightingRelative *pInfoLighting = assert_cast( m_hLightingOriginRelative.Get() ); - pInfoLighting->GetLightingOffset( matLightingOffset ); - sInfo.pLightingOffset = &matLightingOffset; - } - if ( m_hLightingOrigin ) - { - sInfo.pLightingOrigin = &(m_hLightingOrigin->GetAbsOrigin()); + return 0; } - int drawn = modelrender->DrawModelEx( sInfo ); - - if ( vcollide_wireframe.GetBool() ) + Assert( !pInfo->pModelToWorld); + if ( !pInfo->pModelToWorld ) { - if ( IsRagdoll() ) - { - m_pRagdoll->DrawWireframe(); - } - else - { - vcollide_t *pCollide = modelinfo->GetVCollide( GetModelIndex() ); - if ( pCollide && pCollide->solidCount == 1 ) - { - static color32 debugColor = {0,255,255,0}; - matrix3x4_t matrix; - AngleMatrix( GetAbsAngles(), GetAbsOrigin(), matrix ); - engine->DebugDrawPhysCollide( pCollide->solids[0], NULL, matrix, debugColor ); - if ( VPhysicsGetObject() ) - { - static color32 debugColorPhys = {255,0,0,0}; - matrix3x4_t matrix; - VPhysicsGetObject()->GetPositionMatrix( &matrix ); - engine->DebugDrawPhysCollide( pCollide->solids[0], NULL, matrix, debugColorPhys ); - } - } - } + pInfo->pModelToWorld = &pInfo->modelToWorld; + + // Turns the origin + angles into a matrix + AngleMatrix( pInfo->angles, pInfo->origin, pInfo->modelToWorld ); } - return drawn; + DrawModelState_t state; + matrix3x4_t *pBoneToWorld; + bool bMarkAsDrawn = modelrender->DrawModelSetup( *pInfo, &state, NULL, &pBoneToWorld ); + DoInternalDrawModel( pInfo, ( bMarkAsDrawn && ( pInfo->flags & STUDIO_RENDER ) ) ? &state : NULL, pBoneToWorld ); + + OnPostInternalDrawModel( pInfo ); + + return bMarkAsDrawn; } extern ConVar muzzleflash_light; @@ -2583,7 +3034,7 @@ void C_BaseAnimating::DoAnimationEvents( CStudioHdr *pStudioHdr ) float flEventCycle = GetCycle(); // If we're invisible, don't draw the muzzle flash - bool bIsInvisible = !IsVisible() && !IsViewModel(); + bool bIsInvisible = !IsVisible() && !IsViewModel() && !IsMenuModel(); if ( bIsInvisible && !clienttools->IsInRecordingMode() ) return; @@ -2891,6 +3342,56 @@ void C_BaseAnimating::FireEvent( const Vector& origin, const QAngle& angles, int switch( event ) { + case AE_CL_CREATE_PARTICLE_EFFECT: + { + int iAttachment = -1; + int iAttachType = PATTACH_ABSORIGIN_FOLLOW; + char token[256]; + char szParticleEffect[256]; + + // Get the particle effect name + const char *p = options; + p = nexttoken(token, p, ' '); + if ( token ) + { + Q_strncpy( szParticleEffect, token, sizeof(szParticleEffect) ); + } + + // Get the attachment type + p = nexttoken(token, p, ' '); + if ( token ) + { + iAttachType = GetAttachTypeFromString( token ); + if ( iAttachType == -1 ) + { + Warning("Invalid attach type specified for particle effect anim event. Trying to spawn effect '%s' with attach type of '%s'\n", szParticleEffect, token ); + return; + } + } + + // Get the attachment point index + p = nexttoken(token, p, ' '); + if ( token ) + { + iAttachment = atoi(token); + + // See if we can find any attachment points matching the name + if ( token[0] != '0' && iAttachment == 0 ) + { + iAttachment = LookupAttachment( token ); + if ( iAttachment == -1 ) + { + Warning("Failed to find attachment point specified for particle effect anim event. Trying to spawn effect '%s' on attachment named '%s'\n", szParticleEffect, token ); + return; + } + } + } + + // Spawn the particle effect + ParticleProp()->Create( szParticleEffect, (ParticleAttachment_t)iAttachType, iAttachment ); + } + break; + case AE_CL_PLAYSOUND: { CLocalPlayerFilter filter; @@ -2911,80 +3412,6 @@ void C_BaseAnimating::FireEvent( const Vector& origin, const QAngle& angles, int StopSound( GetSoundSourceIndex(), options ); } break; - case AE_CLIENT_EFFECT_ATTACH: - { - int iAttachment = -1; - int iParam = 0; - char token[128]; - char effectFunc[128]; - - const char *p = options; - - p = nexttoken(token, p, ' '); - - if( token ) - { - Q_strncpy( effectFunc, token, sizeof(effectFunc) ); - } - - p = nexttoken(token, p, ' '); - - if( token ) - { - iAttachment = atoi(token); - } - - p = nexttoken(token, p, ' '); - - if( token ) - { - iParam = atoi(token); - } - - if ( iAttachment != -1 && m_Attachments.Count() >= iAttachment ) - { - GetAttachment( iAttachment, attachOrigin, attachAngles ); - - // Fill out the generic data - CEffectData data; - data.m_vOrigin = attachOrigin; - data.m_vAngles = attachAngles; - AngleVectors( attachAngles, &data.m_vNormal ); - data.m_hEntity = GetRefEHandle(); - data.m_nAttachmentIndex = iAttachment + 1; - data.m_fFlags = iParam; - - DispatchEffect( effectFunc, data ); - } - } - break; - - // Spark - case CL_EVENT_SPARK0: - { - Vector vecForward; - GetAttachment( 1, attachOrigin, attachAngles ); - AngleVectors( attachAngles, &vecForward ); - g_pEffects->Sparks( attachOrigin, atoi( options ), 1, &vecForward ); - } - break; - - // Sound - case CL_EVENT_SOUND: // Client side sound - { - CLocalPlayerFilter filter; - - if ( m_Attachments.Count() > 0) - { - GetAttachment( 1, attachOrigin, attachAngles ); - EmitSound( filter, GetSoundSourceIndex(), options, &attachOrigin ); - } - else - { - EmitSound( filter, GetSoundSourceIndex(), options ); - } - } - break; case CL_EVENT_FOOTSTEP_LEFT: { @@ -3078,7 +3505,193 @@ void C_BaseAnimating::FireEvent( const Vector& origin, const QAngle& angles, int } break; - // Generic dispatch effect hook + case AE_MUZZLEFLASH: + { + // Send out the effect for a player +#if defined ( HL2MP ) || defined ( SDK_DLL ) // works for the modified CSS weapons included in the new template sdk. + // HL2MP - Make third person muzzleflashes as reliable as the first person ones + // while in third person the view model dispatches the muzzleflash event - note: the weapon models dispatch them too, but not frequently. + if ( IsViewModel() ) + { + C_BasePlayer *pPlayer = ToBasePlayer( dynamic_cast(this)->GetOwner() ); + if ( pPlayer && pPlayer == C_BasePlayer::GetLocalPlayer()) + { + if ( ::input->CAM_IsThirdPerson() ) + { + // Dispatch on the weapon - the player model doesn't have the attachments in hl2mp. + C_BaseCombatWeapon *pWeapon = pPlayer->GetActiveWeapon(); + if ( !pWeapon ) + break; + pWeapon->DispatchMuzzleEffect( options, false ); + break; + } + } + } + + // Check if we're a weapon, if we belong to the local player, and if the local player is in third person - if all are true, don't do a muzzleflash in this instance, because + // we're using the view models dispatch for smoothness. + if ( dynamic_cast< C_BaseCombatWeapon *>(this) != NULL ) + { + C_BaseCombatWeapon *pWeapon = dynamic_cast< C_BaseCombatWeapon *>(this); + if ( pWeapon && pWeapon->GetOwner() == C_BasePlayer::GetLocalPlayer() && ::input->CAM_IsThirdPerson() ) + break; + } + +#endif + DispatchMuzzleEffect( options, true ); + break; + } + + case AE_NPC_MUZZLEFLASH: + { + // Send out the effect for an NPC + DispatchMuzzleEffect( options, false ); + break; + } + + // OBSOLETE EVENTS. REPLACED BY NEWER SYSTEMS. + // See below in FireObsoleteEvent() for comments on what to use instead. + case AE_CLIENT_EFFECT_ATTACH: + case CL_EVENT_DISPATCHEFFECT0: + case CL_EVENT_DISPATCHEFFECT1: + case CL_EVENT_DISPATCHEFFECT2: + case CL_EVENT_DISPATCHEFFECT3: + case CL_EVENT_DISPATCHEFFECT4: + case CL_EVENT_DISPATCHEFFECT5: + case CL_EVENT_DISPATCHEFFECT6: + case CL_EVENT_DISPATCHEFFECT7: + case CL_EVENT_DISPATCHEFFECT8: + case CL_EVENT_DISPATCHEFFECT9: + case CL_EVENT_MUZZLEFLASH0: + case CL_EVENT_MUZZLEFLASH1: + case CL_EVENT_MUZZLEFLASH2: + case CL_EVENT_MUZZLEFLASH3: + case CL_EVENT_NPC_MUZZLEFLASH0: + case CL_EVENT_NPC_MUZZLEFLASH1: + case CL_EVENT_NPC_MUZZLEFLASH2: + case CL_EVENT_NPC_MUZZLEFLASH3: + case CL_EVENT_SPARK0: + case CL_EVENT_SOUND: + FireObsoleteEvent( origin, angles, event, options ); + break; + + case AE_CL_ENABLE_BODYGROUP: + { + int index = FindBodygroupByName( options ); + if ( index >= 0 ) + { + SetBodygroup( index, 1 ); + } + } + break; + + case AE_CL_DISABLE_BODYGROUP: + { + int index = FindBodygroupByName( options ); + if ( index >= 0 ) + { + SetBodygroup( index, 0 ); + } + } + break; + + case AE_CL_BODYGROUP_SET_VALUE: + { + char szBodygroupName[256]; + int value = 0; + + char token[256]; + + const char *p = options; + + // Bodygroup Name + p = nexttoken(token, p, ' '); + if ( token ) + { + Q_strncpy( szBodygroupName, token, sizeof(szBodygroupName) ); + } + + // Get the desired value + p = nexttoken(token, p, ' '); + if ( token ) + { + value = atoi( token ); + } + + int index = FindBodygroupByName( szBodygroupName ); + if ( index >= 0 ) + { + SetBodygroup( index, value ); + } + } + break; + + default: + break; + } +} + +//----------------------------------------------------------------------------- +// Purpose: These events are all obsolete events, left here to support old games. +// Their systems have all been replaced with better ones. +//----------------------------------------------------------------------------- +void C_BaseAnimating::FireObsoleteEvent( const Vector& origin, const QAngle& angles, int event, const char *options ) +{ + Vector attachOrigin; + QAngle attachAngles; + + switch( event ) + { + // Obsolete. Use the AE_CL_CREATE_PARTICLE_EFFECT event instead, which uses the artist driven particle system & editor. + case AE_CLIENT_EFFECT_ATTACH: + { + int iAttachment = -1; + int iParam = 0; + char token[128]; + char effectFunc[128]; + + const char *p = options; + + p = nexttoken(token, p, ' '); + + if( token ) + { + Q_strncpy( effectFunc, token, sizeof(effectFunc) ); + } + + p = nexttoken(token, p, ' '); + + if( token ) + { + iAttachment = atoi(token); + } + + p = nexttoken(token, p, ' '); + + if( token ) + { + iParam = atoi(token); + } + + if ( iAttachment != -1 && m_Attachments.Count() >= iAttachment ) + { + GetAttachment( iAttachment, attachOrigin, attachAngles ); + + // Fill out the generic data + CEffectData data; + data.m_vOrigin = attachOrigin; + data.m_vAngles = attachAngles; + AngleVectors( attachAngles, &data.m_vNormal ); + data.m_hEntity = GetRefEHandle(); + data.m_nAttachmentIndex = iAttachment + 1; + data.m_fFlags = iParam; + + DispatchEffect( effectFunc, data ); + } + } + break; + + // Obsolete. Use the AE_CL_CREATE_PARTICLE_EFFECT event instead, which uses the artist driven particle system & editor. case CL_EVENT_DISPATCHEFFECT0: case CL_EVENT_DISPATCHEFFECT1: case CL_EVENT_DISPATCHEFFECT2: @@ -3153,21 +3766,7 @@ void C_BaseAnimating::FireEvent( const Vector& origin, const QAngle& angles, int } break; - case AE_MUZZLEFLASH: - { - // Send out the effect for a player - DispatchMuzzleEffect( options, true ); - break; - } - - case AE_NPC_MUZZLEFLASH: - { - // Send out the effect for an NPC - DispatchMuzzleEffect( options, false ); - break; - } - - // Old muzzleflashes + // Obsolete. Use the AE_MUZZLEFLASH / AE_NPC_MUZZLEFLASH events instead. case CL_EVENT_MUZZLEFLASH0: case CL_EVENT_MUZZLEFLASH1: case CL_EVENT_MUZZLEFLASH2: @@ -3199,7 +3798,7 @@ void C_BaseAnimating::FireEvent( const Vector& origin, const QAngle& angles, int iAttachment = 3; break; - // Third person muzzle flashes + // Third person muzzle flashes case CL_EVENT_NPC_MUZZLEFLASH0: iAttachment = 0; bFirstPerson = false; @@ -3220,7 +3819,33 @@ void C_BaseAnimating::FireEvent( const Vector& origin, const QAngle& angles, int bFirstPerson = false; break; } - +#if defined ( SDK_DLL ) + // HACKHACKHACK for third person. Will hacks ever be unnecessary? -- These Events are obsolete + // in third person, make first person muzzle flashes NOT dispatch! + if ( IsViewModel() ) + { + C_BasePlayer *pPlayer = ToBasePlayer( dynamic_cast(this)->GetOwner() ); + if ( pPlayer && pPlayer == C_BasePlayer::GetLocalPlayer()) + { + if ( ::input->CAM_IsThirdPerson() ) + { +// Don't do anything now, the sample weapon models in the new SDK don't use these events anymore - just back out if any models are 'taken' from other mods like css. +#if 0 + // Dispatch on the weapon + C_BaseCombatWeapon *pWeapon = pPlayer->GetActiveWeapon(); + if ( !pWeapon ) break; + + if ( iAttachment != -1 ) + { + if ( pWeapon->GetAttachment( iAttachment+1, attachOrigin, attachAngles ) ) + tempents->MuzzleFlash( attachOrigin, attachAngles, atoi( options ), pWeapon->GetRefEHandle(), false ); + } +#endif + break; + } + } + } +#endif if ( iAttachment != -1 && m_Attachments.Count() > iAttachment ) { GetAttachment( iAttachment+1, attachOrigin, attachAngles ); @@ -3231,12 +3856,41 @@ void C_BaseAnimating::FireEvent( const Vector& origin, const QAngle& angles, int } break; + // Obsolete: Use the AE_CL_CREATE_PARTICLE_EFFECT event instead, which uses the artist driven particle system & editor. + case CL_EVENT_SPARK0: + { + Vector vecForward; + GetAttachment( 1, attachOrigin, attachAngles ); + AngleVectors( attachAngles, &vecForward ); + g_pEffects->Sparks( attachOrigin, atoi( options ), 1, &vecForward ); + } + break; + + // Obsolete: Use the AE_CL_PLAYSOUND event instead, which doesn't rely on a magic number in the .qc + case CL_EVENT_SOUND: + { + CLocalPlayerFilter filter; + + if ( m_Attachments.Count() > 0) + { + GetAttachment( 1, attachOrigin, attachAngles ); + EmitSound( filter, GetSoundSourceIndex(), options, &attachOrigin ); + } + else + { + EmitSound( filter, GetSoundSourceIndex(), options ); + } + } + break; + default: break; } } - +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- bool C_BaseAnimating::IsSelfAnimating() { if ( m_bClientSideAnimation ) @@ -3441,6 +4095,18 @@ void C_BaseAnimating::PreDataUpdate( DataUpdateType_t updateType ) { m_flOldCycle = GetCycle(); m_nOldSequence = GetSequence(); + + int i; + for ( i=0;icurtime - 0.1f; - float curanimtime = gpGlobals->curtime; + ForceSetupBonesAtTime( pDeltaBones0, gpGlobals->curtime - boneDt ); + ForceSetupBonesAtTime( pDeltaBones1, gpGlobals->curtime ); + float ragdollCreateTime = PhysGetSyncCreateTime(); + if ( ragdollCreateTime != gpGlobals->curtime ) + { + // The next simulation frame begins before the end of this frame + // so initialize the ragdoll at that time so that it will reach the current + // position at curtime. Otherwise the ragdoll will simulate forward from curtime + // and pop into the future a bit at this point of transition + ForceSetupBonesAtTime( pCurrentBones, ragdollCreateTime ); + } + else + { + memcpy( pCurrentBones, m_CachedBoneData.Base(), sizeof( matrix3x4_t ) * m_CachedBoneData.Count() ); + } +} +C_BaseAnimating *C_BaseAnimating::CreateRagdollCopy() +{ //Adrian: We now create a separate entity that becomes this entity's ragdoll. //That way the server side version of this entity can go away. //Plus we can hook save/restore code to these ragdolls so they don't fall on restore anymore. - C_BaseAnimating *pRagdoll = this; - if ( bCopyEntity ) + C_ClientRagdoll *pRagdoll = new C_ClientRagdoll( false ); + if ( pRagdoll == NULL ) + return NULL; + + TermRopes(); + + const model_t *model = GetModel(); + const char *pModelName = modelinfo->GetModelName( model ); + + if ( pRagdoll->InitializeAsClientEntity( pModelName, RENDER_GROUP_OPAQUE_ENTITY ) == false ) { - C_ClientRagdoll *pRagdollCopy = new C_ClientRagdoll( false ); - if ( pRagdollCopy == NULL ) - return NULL; - - pRagdoll = pRagdollCopy; - - TermRopes(); - - const model_t *model = GetModel(); - const char *pModelName = modelinfo->GetModelName( model ); - - if ( pRagdoll->InitializeAsClientEntity( pModelName, RENDER_GROUP_OPAQUE_ENTITY ) == false ) - { - pRagdoll->Release(); - return NULL; - } - - // move my current model instance to the ragdoll's so decals are preserved. - SnatchModelInstance( pRagdoll ); - - // We need to take these from the entity - pRagdoll->SetAbsOrigin( GetAbsOrigin() ); - pRagdoll->SetAbsAngles( GetAbsAngles() ); - - pRagdoll->IgniteRagdoll( this ); - pRagdoll->TransferDissolveFrom( this ); - pRagdoll->InitRopes(); - - if ( AddRagdollToFadeQueue() == true ) - { - pRagdollCopy->m_bImportant = NPC_IsImportantNPC( this ); - s_RagdollLRU.MoveToTopOfLRU( pRagdoll, pRagdollCopy->m_bImportant ); - pRagdollCopy->m_bFadeOut = true; - } - - m_builtRagdoll = true; - AddEffects( EF_NODRAW ); - - if ( IsEffectActive( EF_NOSHADOW ) ) - { - pRagdoll->AddEffects( EF_NOSHADOW ); - } - - pRagdoll->m_nRenderFX = kRenderFxRagdoll; - pRagdoll->SetRenderMode( GetRenderMode() ); - pRagdoll->SetRenderColor( GetRenderColor().r, GetRenderColor().g, GetRenderColor().b, GetRenderColor().a ); - - pRagdoll->m_nBody = m_nBody; - pRagdoll->m_nSkin = m_nSkin; - pRagdoll->m_vecForce = m_vecForce; - pRagdoll->m_nForceBone = m_nForceBone; - pRagdoll->SetNextClientThink( CLIENT_THINK_ALWAYS ); - - pRagdoll->SetModelName( AllocPooledString(pModelName) ); + pRagdoll->Release(); + return NULL; } - - pRagdoll->m_builtRagdoll = true; + + // move my current model instance to the ragdoll's so decals are preserved. + SnatchModelInstance( pRagdoll ); + + // We need to take these from the entity + pRagdoll->SetAbsOrigin( GetAbsOrigin() ); + pRagdoll->SetAbsAngles( GetAbsAngles() ); + + pRagdoll->IgniteRagdoll( this ); + pRagdoll->TransferDissolveFrom( this ); + pRagdoll->InitModelEffects(); + + if ( AddRagdollToFadeQueue() == true ) + { + pRagdoll->m_bImportant = NPC_IsImportantNPC( this ); + s_RagdollLRU.MoveToTopOfLRU( pRagdoll, pRagdoll->m_bImportant ); + pRagdoll->m_bFadeOut = true; + } + + m_builtRagdoll = true; + AddEffects( EF_NODRAW ); + + if ( IsEffectActive( EF_NOSHADOW ) ) + { + pRagdoll->AddEffects( EF_NOSHADOW ); + } + + pRagdoll->m_nRenderFX = kRenderFxRagdoll; + pRagdoll->SetRenderMode( GetRenderMode() ); + pRagdoll->SetRenderColor( GetRenderColor().r, GetRenderColor().g, GetRenderColor().b, GetRenderColor().a ); + + pRagdoll->m_nBody = m_nBody; + pRagdoll->m_nSkin = GetSkin(); + pRagdoll->m_vecForce = m_vecForce; + pRagdoll->m_nForceBone = m_nForceBone; + pRagdoll->SetNextClientThink( CLIENT_THINK_ALWAYS ); + + pRagdoll->SetModelName( AllocPooledString(pModelName) ); + return pRagdoll; +} + +C_BaseAnimating *C_BaseAnimating::BecomeRagdollOnClient() +{ + MoveToLastReceivedPosition( true ); + GetAbsOrigin(); + C_BaseAnimating *pRagdoll = CreateRagdollCopy(); + + matrix3x4_t boneDelta0[MAXSTUDIOBONES]; + matrix3x4_t boneDelta1[MAXSTUDIOBONES]; + matrix3x4_t currentBones[MAXSTUDIOBONES]; + const float boneDt = 0.1f; + GetRagdollInitBoneArrays( boneDelta0, boneDelta1, currentBones, boneDt ); + pRagdoll->InitAsClientRagdoll( boneDelta0, boneDelta1, currentBones, boneDt ); + return pRagdoll; +} + +bool C_BaseAnimating::InitAsClientRagdoll( const matrix3x4_t *pDeltaBones0, const matrix3x4_t *pDeltaBones1, const matrix3x4_t *pCurrentBonePosition, float boneDt ) +{ + CStudioHdr *hdr = GetModelPtr(); + if ( !hdr || m_pRagdoll || m_builtRagdoll ) + return false; + + m_builtRagdoll = true; // Store off our old mins & maxs - pRagdoll->m_vecPreRagdollMins = WorldAlignMins(); - pRagdoll->m_vecPreRagdollMaxs = WorldAlignMaxs(); + m_vecPreRagdollMins = WorldAlignMins(); + m_vecPreRagdollMaxs = WorldAlignMaxs(); - matrix3x4_t preBones[MAXSTUDIOBONES]; - matrix3x4_t curBones[MAXSTUDIOBONES]; // Force MOVETYPE_STEP interpolation MoveType_t savedMovetype = GetMoveType(); @@ -3630,50 +4328,38 @@ C_BaseAnimating * C_BaseAnimating::BecomeRagdollOnClient( bool bCopyEntity ) // HACKHACK: force time to last interpolation position m_flPlaybackRate = 1; - GetRagdollPreSequence( preBones, prevanimtime ); - GetRagdollCurSequence( curBones, curanimtime ); - - pRagdoll->m_pRagdoll = CreateRagdoll( - pRagdoll, - hdr, - m_vecForce, - m_nForceBone, - CBoneAccessor( preBones ), - CBoneAccessor( curBones ), - m_BoneAccessor, - curanimtime - prevanimtime ); + m_pRagdoll = CreateRagdoll( this, hdr, m_vecForce, m_nForceBone, pDeltaBones0, pDeltaBones1, pCurrentBonePosition, boneDt ); // Cause the entity to recompute its shadow type and make a // version which only updates when physics state changes // NOTE: We have to do this after m_pRagdoll is assigned above // because that's what ShadowCastType uses to figure out which type of shadow to use. - pRagdoll->DestroyShadow(); - pRagdoll->CreateShadow(); + DestroyShadow(); + CreateShadow(); // Cache off ragdoll bone positions/quaternions - if ( pRagdoll->m_bStoreRagdollInfo && pRagdoll->m_pRagdoll ) + if ( m_bStoreRagdollInfo && m_pRagdoll ) { matrix3x4_t parentTransform; AngleMatrix( GetAbsAngles(), GetAbsOrigin(), parentTransform ); // FIXME/CHECK: This might be too expensive to do every frame??? - SaveRagdollInfo( hdr->numbones(), parentTransform, pRagdoll->m_BoneAccessor ); + SaveRagdollInfo( hdr->numbones(), parentTransform, m_BoneAccessor ); } SetMoveType( savedMovetype ); // Now set the dieragdoll sequence to get transforms for all // non-simulated bones - pRagdoll->m_nRestoreSequence = GetSequence(); - pRagdoll->SetSequence( SelectWeightedSequence( ACT_DIERAGDOLL ) ); - pRagdoll->m_nPrevSequence = GetSequence(); - pRagdoll->m_flPlaybackRate = 0; - pRagdoll->UpdatePartitionListEntry(); + m_nRestoreSequence = GetSequence(); + SetSequence( SelectWeightedSequence( ACT_DIERAGDOLL ) ); + m_nPrevSequence = GetSequence(); + m_flPlaybackRate = 0; + UpdatePartitionListEntry(); - NoteRagdollCreationTick( pRagdoll ); + NoteRagdollCreationTick( this ); UpdateVisibility(); - - return pRagdoll; + return true; } @@ -3747,8 +4433,6 @@ void C_BaseAnimating::OnDataChanged( DataUpdateType_t updateType ) // build a ragdoll if necessary if ( m_nRenderFX == kRenderFxRagdoll && !m_builtRagdoll ) { - MoveToLastReceivedPosition( true ); - GetAbsOrigin(); BecomeRagdollOnClient(); } @@ -3828,12 +4512,11 @@ int C_BaseAnimating::LookupRandomAttachment( const char *pAttachmentNameSubstrin void C_BaseAnimating::ClientSideAnimationChanged() { - if ( !m_bClientSideAnimation ) + if ( !m_bClientSideAnimation || m_ClientSideAnimationListHandle == INVALID_CLIENTSIDEANIMATION_LIST_HANDLE ) return; MDLCACHE_CRITICAL_SECTION(); - Assert(m_ClientSideAnimationListHandle != INVALID_CLIENTSIDEANIMATION_LIST_HANDLE); clientanimating_t &anim = g_ClientSideAnimationList.Element(m_ClientSideAnimationListHandle); Assert(anim.pAnimating == this); anim.flags = ComputeClientSideAnimationFlags(); @@ -3875,6 +4558,11 @@ void C_BaseAnimating::UpdateClientSideAnimation() void C_BaseAnimating::Simulate() { + if ( m_bInitModelEffects ) + { + DelayedInitModelEffects(); + } + if ( gpGlobals->frametime != 0.0f ) { DoAnimationEvents( GetModelPtr() ); @@ -3917,7 +4605,9 @@ bool C_BaseAnimating::TestCollision( const Ray_t &ray, unsigned int fContentsMas // Add those and the client hitboxes will be robust bool C_BaseAnimating::TestHitboxes( const Ray_t &ray, unsigned int fContentsMask, trace_t& tr ) { - VPROF( "C_BaseAnimating::TestCollision" ); + VPROF( "C_BaseAnimating::TestHitboxes" ); + + MDLCACHE_CRITICAL_SECTION(); CStudioHdr *pStudioHdr = GetModelPtr(); if (!pStudioHdr) @@ -3938,7 +4628,7 @@ bool C_BaseAnimating::TestHitboxes( const Ray_t &ray, unsigned int fContentsMask matrix3x4_t *hitboxbones[MAXSTUDIOBONES]; pCache->ReadCachedBonePointers( hitboxbones, pStudioHdr->numbones() ); - if ( TraceToStudio( ray, pStudioHdr, set, hitboxbones, fContentsMask, tr ) ) + if ( TraceToStudio( physprops, ray, pStudioHdr, set, hitboxbones, fContentsMask, tr ) ) { mstudiobbox_t *pbox = set->pHitbox( tr.hitbox ); mstudiobone_t *pBone = pStudioHdr->pBone(pbox->bone); @@ -4237,6 +4927,7 @@ float C_BaseAnimating::FrameAdvance( float flInterval ) { flNewCycle = (flNewCycle < 0.0f) ? 0.0f : 1.0f; } + m_bSequenceFinished = true; } SetCycle( flNewCycle ); @@ -4254,6 +4945,7 @@ void C_BaseAnimating::ResetSequenceInfo( void ) CStudioHdr *pStudioHdr = GetModelPtr(); m_flGroundSpeed = GetSequenceGroundSpeed( pStudioHdr, GetSequence() ); + m_bSequenceLoops = ((GetSequenceFlags( pStudioHdr, GetSequence() ) & STUDIO_LOOPING) != 0); // m_flAnimTime = gpGlobals->time; m_flPlaybackRate = 1.0; m_bSequenceFinished = false; @@ -4557,9 +5249,18 @@ void C_BaseAnimating::ClearRagdoll() { if ( m_pRagdoll ) { - delete m_pRagdoll; + // immediately mark the member ragdoll as being NULL, + // so that we have no reentrancy problems with the delete + // (such as the disappearance of the ragdoll physics waking up + // IVP which causes other objects to move and have a touch + // callback on the ragdoll entity, which was a crash on TF) + // That is to say: it is vital that the member be cleared out + // BEFORE the delete occurs. + CRagdoll * RESTRICT pDoomed = m_pRagdoll; m_pRagdoll = NULL; + delete pDoomed; + // Set to null so that the destructor's call to DestroyObject won't destroy // m_pObjects[ 0 ] twice since that's the physics object for the prop VPhysicsSetObject( NULL ); @@ -4786,6 +5487,7 @@ public: bool ShouldDraw( void ); int DrawModel( int flags ); + bool TestCollision( const Ray_t &ray, unsigned int mask, trace_t& trace ); private: int m_modelIndex; @@ -4797,6 +5499,14 @@ IMPLEMENT_CLIENTCLASS_DT( C_BoneFollower, DT_BoneFollower, CBoneFollower ) RecvPropInt( RECVINFO( m_solidIndex ) ), END_RECV_TABLE() +void VCollideWireframe_ChangeCallback( IConVar *pConVar, char const *pOldString, float flOldValue ) +{ + for ( C_BaseEntity *pEntity = ClientEntityList().FirstBaseEntity(); pEntity; pEntity = ClientEntityList().NextBaseEntity(pEntity) ) + { + pEntity->UpdateVisibility(); + } +} + //----------------------------------------------------------------------------- // Purpose: Returns whether object should render. //----------------------------------------------------------------------------- @@ -4821,6 +5531,23 @@ int C_BoneFollower::DrawModel( int flags ) return 1; } +bool C_BoneFollower::TestCollision( const Ray_t &ray, unsigned int mask, trace_t& trace ) +{ + vcollide_t *pCollide = modelinfo->GetVCollide( m_modelIndex ); + Assert( pCollide && pCollide->solidCount > m_solidIndex ); + + physcollision->TraceBox( ray, pCollide->solids[m_solidIndex], GetAbsOrigin(), GetAbsAngles(), &trace ); + + if ( trace.fraction >= 1 ) + return false; + + // return owner as trace hit + trace.m_pEnt = GetOwnerEntity(); + trace.hitgroup = 0;//m_hitGroup; + trace.physicsbone = 0;//m_physicsBone; // UNDONE: Get physics bone index & hitgroup + return trace.DidHit(); +} + void C_BaseAnimating::DisableMuzzleFlash() { @@ -4922,7 +5649,7 @@ void C_BaseAnimating::UpdateClientSideAnimations() } } -CBoneList *C_BaseAnimating::RecordBones( CStudioHdr *hdr ) +CBoneList *C_BaseAnimating::RecordBones( CStudioHdr *hdr, matrix3x4_t *pBoneState ) { if ( !ToolsEnabled() ) return NULL; @@ -4941,8 +5668,6 @@ CBoneList *C_BaseAnimating::RecordBones( CStudioHdr *hdr ) boneList->m_nBones = hdr->numbones(); - m_BoneAccessor.SetReadableBones( BONE_USED_BY_ANYTHING ); - for ( int i = 0; i < hdr->numbones(); i++ ) { matrix3x4_t inverted; @@ -4965,10 +5690,10 @@ CBoneList *C_BaseAnimating::RecordBones( CStudioHdr *hdr ) } else { - MatrixInvert( m_BoneAccessor.GetBone( bone->parent ), inverted ); + MatrixInvert( pBoneState[ bone->parent ], inverted ); } - ConcatTransforms( inverted, m_BoneAccessor.GetBone( i ), output ); + ConcatTransforms( inverted, pBoneState[ i ], output ); MatrixAngles( output, boneList->m_quatRot[ i ], @@ -4986,22 +5711,30 @@ void C_BaseAnimating::GetToolRecordingState( KeyValues *msg ) VPROF_BUDGET( "C_BaseAnimating::GetToolRecordingState", VPROF_BUDGETGROUP_TOOLS ); // Force the animation to drive bones - SetupBones( NULL, -1, BONE_USED_BY_ANYTHING, gpGlobals->curtime ); + CStudioHdr *hdr = GetModelPtr(); + matrix3x4_t *pBones = (matrix3x4_t*)_alloca( ( hdr ? hdr->numbones() : 1 ) * sizeof(matrix3x4_t) ); + if ( hdr ) + { + SetupBones( pBones, hdr->numbones(), BONE_USED_BY_ANYTHING, gpGlobals->curtime ); + } + else + { + SetupBones( NULL, -1, BONE_USED_BY_ANYTHING, gpGlobals->curtime ); + } BaseClass::GetToolRecordingState( msg ); static BaseAnimatingRecordingState_t state; - state.m_nSkin = m_nSkin; + state.m_nSkin = GetSkin(); state.m_nBody = m_nBody; state.m_nSequence = m_nSequence; state.m_pBoneList = NULL; msg->SetPtr( "baseanimating", &state ); msg->SetInt( "viewmodel", IsViewModel() ? 1 : 0 ); - CStudioHdr *hdr = GetModelPtr(); - if ( hdr ) + if ( hdr ) { - state.m_pBoneList = RecordBones( hdr ); + state.m_pBoneList = RecordBones( hdr, pBones ); } } @@ -5009,9 +5742,9 @@ void C_BaseAnimating::CleanupToolRecordingState( KeyValues *msg ) { if ( !ToolsEnabled() ) return; - + BaseAnimatingRecordingState_t *pState = (BaseAnimatingRecordingState_t*)msg->GetPtr( "baseanimating" ); - if ( pState->m_pBoneList ) + if ( pState && pState->m_pBoneList ) { pState->m_pBoneList->Release(); } @@ -5019,11 +5752,11 @@ void C_BaseAnimating::CleanupToolRecordingState( KeyValues *msg ) BaseClass::CleanupToolRecordingState( msg ); } -int C_BaseAnimating::GetNumFlexControllers( void ) +LocalFlexController_t C_BaseAnimating::GetNumFlexControllers( void ) { CStudioHdr *pstudiohdr = GetModelPtr( ); if (! pstudiohdr) - return 0; + return LocalFlexController_t(0); return pstudiohdr->numflexcontrollers(); } @@ -5039,7 +5772,7 @@ const char *C_BaseAnimating::GetFlexDescFacs( int iFlexDesc ) return pflexdesc->pszFACS( ); } -const char *C_BaseAnimating::GetFlexControllerName( int iFlexController ) +const char *C_BaseAnimating::GetFlexControllerName( LocalFlexController_t iFlexController ) { CStudioHdr *pstudiohdr = GetModelPtr( ); if (! pstudiohdr) @@ -5050,7 +5783,7 @@ const char *C_BaseAnimating::GetFlexControllerName( int iFlexController ) return pflexcontroller->pszName( ); } -const char *C_BaseAnimating::GetFlexControllerType( int iFlexController ) +const char *C_BaseAnimating::GetFlexControllerType( LocalFlexController_t iFlexController ) { CStudioHdr *pstudiohdr = GetModelPtr( ); if (! pstudiohdr) @@ -5069,3 +5802,19 @@ unsigned char C_BaseAnimating::GetClientSideFade( void ) { return UTIL_ComputeEntityFade( this, m_fadeMinDist, m_fadeMaxDist, m_flFadeScale ); } + +//----------------------------------------------------------------------------- +// Purpose: Note that we've been transmitted a sequence +//----------------------------------------------------------------------------- +void C_BaseAnimating::SetReceivedSequence( void ) +{ + m_bReceivedSequence = true; +} + +//----------------------------------------------------------------------------- +// Purpose: See if we should force reset our sequence on a new model +//----------------------------------------------------------------------------- +bool C_BaseAnimating::ShouldResetSequenceOnNewModel( void ) +{ + return ( m_bReceivedSequence == false ); +} diff --git a/src/src/cl_dll/c_baseanimating.h b/src/src/game/client/c_baseanimating.h similarity index 78% rename from src/src/cl_dll/c_baseanimating.h rename to src/src/game/client/c_baseanimating.h index c3ec404..8476583 100644 --- a/src/src/cl_dll/c_baseanimating.h +++ b/src/src/game/client/c_baseanimating.h @@ -24,6 +24,8 @@ #include "bone_accessor.h" #include "bone_merge_cache.h" #include "ragdoll_shared.h" +#include "tier0/threadtools.h" +#include "datacache/idatacache.h" #define LIPSYNC_POSEPARAM_NAME "mouth" #define NUM_HITBOX_FIRES 10 @@ -43,11 +45,21 @@ class C_RopeKeyframe; class CBoneBitList; class CBoneList; class KeyValues; +class CJiggleBones; FORWARD_DECLARE_HANDLE( memhandle_t ); +typedef unsigned short MDLHandle_t; extern ConVar vcollide_wireframe; +struct ClientModelRenderInfo_t : public ModelRenderInfo_t +{ + // Added space for lighting origin override. Just allocated space, need to set base pointer + matrix3x4_t lightingOffset; + + // Added space for model to world matrix. Just allocated space, need to set base pointer + matrix3x4_t modelToWorld; +}; struct RagdollInfo_t { @@ -62,8 +74,11 @@ struct RagdollInfo_t class CAttachmentData { public: - Vector m_vOrigin; + matrix3x4_t m_AttachmentToWorld; QAngle m_angRotation; + Vector m_vOriginVelocity; + int m_nLastFramecount : 31; + int m_bAnglesComputed : 1; }; @@ -91,7 +106,7 @@ public: virtual C_BaseAnimating* GetBaseAnimating() { return this; } - bool UsesFrameBufferTexture( void ); + bool UsesPowerOfTwoFrameBufferTexture( void ); virtual bool Interpolate( float currentTime ); virtual void Simulate(); @@ -105,10 +120,10 @@ public: virtual void GetBoneControllers(float controllers[MAXSTUDIOBONECTRLS]); virtual float SetBoneController ( int iController, float flValue ); - int GetNumFlexControllers( void ); + LocalFlexController_t GetNumFlexControllers( void ); const char *GetFlexDescFacs( int iFlexDesc ); - const char *GetFlexControllerName( int iFlexController ); - const char *GetFlexControllerType( int iFlexController ); + const char *GetFlexControllerName( LocalFlexController_t iFlexController ); + const char *GetFlexControllerType( LocalFlexController_t iFlexController ); virtual void GetAimEntOrigin( IClientEntity *pAttachedTo, Vector *pAbsOrigin, QAngle *pAbsAngles ); @@ -131,8 +146,11 @@ public: virtual void UpdateIKLocks( float currentTime ); virtual void CalculateIKLocks( float currentTime ); virtual int DrawModel( int flags ); - virtual int InternalDrawModel( int flags ); - + virtual int InternalDrawModel( int flags ); + virtual bool OnInternalDrawModel( ClientModelRenderInfo_t *pInfo ); + virtual bool OnPostInternalDrawModel( ClientModelRenderInfo_t *pInfo ); + void DoInternalDrawModel( ClientModelRenderInfo_t *pInfo, DrawModelState_t *pState, matrix3x4_t *pBoneToWorldArray = NULL ); + // virtual CMouthInfo *GetMouth(); virtual void ControlMouth( CStudioHdr *pStudioHdr ); @@ -140,6 +158,14 @@ public: // override in sub-classes virtual void DoAnimationEvents( CStudioHdr *pStudio ); virtual void FireEvent( const Vector& origin, const QAngle& angles, int event, const char *options ); + virtual void FireObsoleteEvent( const Vector& origin, const QAngle& angles, int event, const char *options ); + +#if defined ( SDK_DLL ) || defined ( HL2MP ) + virtual void ResetEventsParity() { m_nPrevResetEventsParity = -1; } // used to force animation events to function on players so the muzzleflashes and other events occur + // so new functions don't have to be made to parse the models like CSS does in ProcessMuzzleFlashEvent + // allows the multiplayer world weapon models to declare the muzzleflashes, and other effects like sp + // without the need to script it and add extra parsing code. +#endif // Parses and distributes muzzle flash events virtual bool DispatchMuzzleEffect( const char *options, bool isFirstPerson ); @@ -149,8 +175,10 @@ public: virtual CStudioHdr *OnNewModel( void ); CStudioHdr *GetModelPtr() const; + void InvalidateMdlCache(); virtual void SetPredictable( bool state ); + void UseClientSideAnimation(); // C_BaseClientShader **p_ClientShaders; @@ -211,25 +239,34 @@ public: virtual bool GetSoundSpatialization( SpatializationInfo_t& info ); // Attachments. - bool GetAttachment( int number, Vector &origin, QAngle &angles ); + bool GetAttachment( const char *szName, Vector &absOrigin ); + bool GetAttachment( const char *szName, Vector &absOrigin, QAngle &absAngles ); + + // Inherited from C_BaseEntity + virtual bool GetAttachment( int number, Vector &origin ); + virtual bool GetAttachment( int number, Vector &origin, QAngle &angles ); virtual bool GetAttachment( int number, matrix3x4_t &matrix ); + virtual bool GetAttachmentVelocity( int number, Vector &originVel, Quaternion &angleVel ); // Returns the attachment in local space bool GetAttachmentLocal( int iAttachment, matrix3x4_t &attachmentToLocal ); bool GetAttachmentLocal( int iAttachment, Vector &origin, QAngle &angles ); + bool GetAttachmentLocal( int iAttachment, Vector &origin ); // Should this object cast render-to-texture shadows? virtual ShadowType_t ShadowCastType(); // Should we collide? - virtual CollideType_t ShouldCollide( ); + virtual CollideType_t GetCollideType( void ); virtual bool TestCollision( const Ray_t &ray, unsigned int fContentsMask, trace_t& tr ); virtual bool TestHitboxes( const Ray_t &ray, unsigned int fContentsMask, trace_t& tr ); // returns true if we're currently being ragdolled bool IsRagdoll() const; - virtual C_BaseAnimating * BecomeRagdollOnClient( bool bCopyEntity = true ); // returns ragdoll-owning entity + virtual C_BaseAnimating *BecomeRagdollOnClient(); + C_BaseAnimating *CreateRagdollCopy(); + bool InitAsClientRagdoll( const matrix3x4_t *pDeltaBones0, const matrix3x4_t *pDeltaBones1, const matrix3x4_t *pCurrentBonePosition, float boneDt ); void IgniteRagdoll( C_BaseAnimating *pSource ); void TransferDissolveFrom( C_BaseAnimating *pSource ); virtual void SaveRagdollInfo( int numbones, const matrix3x4_t &cameraTransform, CBoneAccessor &pBoneToWorld ); @@ -237,6 +274,8 @@ public: virtual void Clear( void ); void ClearRagdoll(); void CreateUnragdollInfo( C_BaseAnimating *pRagdoll ); + void ForceSetupBonesAtTime( matrix3x4_t *pBonesOut, float flTime ); + virtual void GetRagdollInitBoneArrays( matrix3x4_t *pDeltaBones0, matrix3x4_t *pDeltaBones1, matrix3x4_t *pCurrentBones, float boneDt ); // For shadows rendering the correct body + sequence... virtual int GetBody() { return m_nBody; } @@ -297,6 +336,7 @@ public: virtual bool IsActivityFinished( void ) { return m_bSequenceFinished; } inline bool IsSequenceFinished( void ); + inline bool SequenceLoops( void ) { return m_bSequenceLoops; } // All view model attachments origins are stretched so you can place entities at them and // they will match up with where the attachment winds up being drawn on the view model, since @@ -319,9 +359,18 @@ public: // Used for debugging. Will produce asserts if someone tries to setup bones or // attachments before it's allowed. - static void AllowBoneAccess( bool bAllowForNormalModels, bool bAllowForViewModels ); - static void PushAllowBoneAccess( bool bAllowForNormalModels, bool bAllowForViewModels ); - static void PopBoneAccess( void ); + // Use the "AutoAllowBoneAccess" class to auto push/pop bone access. + // Use a distinct "tag" when pushing/popping - asserts when push/pop tags do not match. + struct AutoAllowBoneAccess + { + AutoAllowBoneAccess( bool bAllowForNormalModels, bool bAllowForViewModels ); + ~AutoAllowBoneAccess( void ); + }; + static void PushAllowBoneAccess( bool bAllowForNormalModels, bool bAllowForViewModels, char const *tagPush ); + static void PopBoneAccess( char const *tagPop ); + static void ThreadedBoneSetup(); + static void InitBoneSetupThreadPool(); + static void ShutdownBoneSetupThreadPool(); // Invalidate bone caches so all SetupBones() calls force bone transforms to be regenerated. static void InvalidateBoneCaches(); @@ -340,7 +389,8 @@ public: // Update client side animations static void UpdateClientSideAnimations(); - void InitRopes(); + // Load the model's keyvalues section and create effects listed inside it + void InitModelEffects( void ); // Sometimes the server wants to update the client's cycle to get the two to run in sync (for proper hit detection) virtual void SetServerIntendedCycle( float intended ) { intended; } @@ -354,41 +404,51 @@ public: inline float SequenceDuration( int iSequence ) { return SequenceDuration(GetModelPtr(), iSequence); } int FindTransitionSequence( int iCurrentSequence, int iGoalSequence, int *piDir ); - virtual void GetRagdollPreSequence( matrix3x4_t *preBones, float flTime ); - virtual void GetRagdollCurSequence( matrix3x4_t *curBones, float flTime ); - void RagdollMoved( void ); virtual void GetToolRecordingState( KeyValues *msg ); virtual void CleanupToolRecordingState( KeyValues *msg ); - void RecordBones( CStudioHdr *hdr, KeyValues *kvBones ); + void SetReceivedSequence( void ); + virtual bool ShouldResetSequenceOnNewModel( void ); + + virtual bool IsViewModel() const; protected: // View models scale their attachment positions to account for FOV. To get the unmodified // attachment position (like if you're rendering something else during the view model's DrawModel call), // use TransformViewModelAttachmentToWorld. - virtual void FormatViewModelAttachment( int nAttachment, Vector &vecOrigin, QAngle &angle ) {} + virtual void FormatViewModelAttachment( int nAttachment, matrix3x4_t &attachmentToWorld ) {} // View models say yes to this. - virtual bool IsViewModel() const; bool IsBoneAccessAllowed() const; CMouthInfo& MouthInfo(); + // Models used in a ModelPanel say yes to this + virtual bool IsMenuModel() const; + // Allow studio models to tell C_BaseEntity what their m_nBody value is virtual int GetStudioBody( void ) { return m_nBody; } -private: - CBoneList* RecordBones( CStudioHdr *hdr ); - virtual bool CalcAttachments(); - bool PutAttachment( int number, const Vector &origin, const QAngle &angles ); + +private: + // This method should return true if the bones have changed + SetupBones needs to be called + virtual float LastBoneChangedTime() { return FLT_MAX; } + + CBoneList* RecordBones( CStudioHdr *hdr, matrix3x4_t *pBoneState ); + + bool PutAttachment( int number, const matrix3x4_t &attachmentToWorld ); void TermRopes(); + void DelayedInitModelEffects( void ); + void UpdateRelevantInterpolatedVars(); void AddBaseAnimatingInterpolatedVars(); void RemoveBaseAnimatingInterpolatedVars(); + void LockStudioHdr(); + void UnlockStudioHdr(); public: CRagdoll *m_pRagdoll; @@ -414,14 +474,18 @@ protected: // Decomposed ragdoll info bool m_bStoreRagdollInfo; RagdollInfo_t *m_pRagdollInfo; + Vector m_vecForce; + int m_nForceBone; // Is bone cache valid // bone transformation matrix unsigned long m_iMostRecentModelBoneCounter; + unsigned long m_iMostRecentBoneSetupRequest; int m_iPrevBoneMask; int m_iAccumulatedBoneMask; CBoneAccessor m_BoneAccessor; + CThreadFastMutex m_BoneSetupLock; ClientSideAnimationListHandle_t m_ClientSideAnimationListHandle; @@ -439,9 +503,7 @@ private: float m_flGroundSpeed; // computed linear movement rate for current sequence float m_flLastEventCheck; // cycle index of when events were last checked bool m_bSequenceFinished;// flag set when StudioAdvanceFrame moves across a frame boundry - - Vector m_vecForce; - int m_nForceBone; + bool m_bSequenceLoops; // true if the sequence loops // Mouth lipsync/envelope following values CMouthInfo m_mouth; @@ -451,6 +513,7 @@ private: // Animation blending factors float m_flPoseParameter[MAXSTUDIOPOSEPARAM]; CInterpolatedVarArray< float, MAXSTUDIOPOSEPARAM > m_iv_flPoseParameter; + float m_flOldPoseParameters[MAXSTUDIOPOSEPARAM]; int m_nPrevSequence; int m_nRestoreSequence; @@ -464,6 +527,7 @@ private: float m_flEncodedController[MAXSTUDIOBONECTRLS]; CInterpolatedVarArray< float, MAXSTUDIOBONECTRLS > m_iv_flEncodedController; + float m_flOldEncodedController[MAXSTUDIOBONECTRLS]; // Clientside animation bool m_bClientSideAnimation; @@ -481,18 +545,23 @@ private: // Current animation sequence int m_nSequence; + bool m_bReceivedSequence; // Current cycle location from server +protected: float m_flCycle; CInterpolatedVar< float > m_iv_flCycle; float m_flOldCycle; +private: int m_nOldSequence; CBoneMergeCache *m_pBoneMergeCache; // This caches the strcmp lookups that it has to do // when merg CUtlVector< matrix3x4_t > m_CachedBoneData; // never access this directly. Use m_BoneAccessor. memhandle_t m_hitboxBoneCacheHandle; - + float m_flLastBoneSetupTime; + CJiggleBones *m_pJiggleBones; + // Calculated attachment points CUtlVector m_Attachments; @@ -505,8 +574,12 @@ private: CNetworkVar( unsigned char, m_nMuzzleFlashParity ); unsigned char m_nOldMuzzleFlashParity; + bool m_bInitModelEffects; + private: mutable CStudioHdr *m_pStudioHdr; + mutable MDLHandle_t m_hStudioHdr; + CThreadFastMutex m_StudioHdrInitLock; }; enum @@ -530,7 +603,7 @@ public: virtual void OnPVSStatusChanged( bool bInPVS ); virtual void Release( void ); - virtual void SetupWeights( void ); + virtual void SetupWeights( const matrix3x4_t *pBoneToWorld, int nFlexWeightCount, float *pFlexWeights, float *pFlexDelayedWeights ); virtual void ImpactTrace( trace_t *pTrace, int iDamageType, char *pCustomImpactName ); void ClientThink( void ); void ReleaseRagdoll( void ) { m_bReleaseRagdoll = true; } @@ -544,6 +617,7 @@ public: virtual void SUB_Remove( void ); void FadeOut( void ); + virtual float LastBoneChangedTime(); bool m_bFadeOut; bool m_bImportant; @@ -606,6 +680,34 @@ inline float C_BaseAnimating::GetCycle() const return m_flCycle; } +//----------------------------------------------------------------------------- +// Purpose: return a pointer to an updated studiomdl cache cache +//----------------------------------------------------------------------------- + +inline CStudioHdr *C_BaseAnimating::GetModelPtr() const +{ +#ifdef _DEBUG + // GetModelPtr() is often called before OnNewModel() so go ahead and set it up first chance. + static IDataCacheSection *pModelCache = datacache->FindSection( "ModelData" ); + AssertOnce( pModelCache->IsFrameLocking() ); +#endif + if ( !m_pStudioHdr && GetModel() ) + { + const_cast(this)->LockStudioHdr(); + } + return ( m_pStudioHdr && m_pStudioHdr->IsValid() ) ? m_pStudioHdr : NULL; +} + + +inline void C_BaseAnimating::InvalidateMdlCache() +{ + UnlockStudioHdr(); + if ( m_pStudioHdr != NULL ) + { + delete m_pStudioHdr; + m_pStudioHdr = NULL; + } +} //----------------------------------------------------------------------------- // Sequence access diff --git a/src/src/cl_dll/c_baseanimatingoverlay.cpp b/src/src/game/client/c_baseanimatingoverlay.cpp similarity index 88% rename from src/src/cl_dll/c_baseanimatingoverlay.cpp rename to src/src/game/client/c_baseanimatingoverlay.cpp index e2223c2..c849f45 100644 --- a/src/src/cl_dll/c_baseanimatingoverlay.cpp +++ b/src/src/game/client/c_baseanimatingoverlay.cpp @@ -207,6 +207,8 @@ void C_BaseAnimatingOverlay::GetRenderBounds( Vector& theMins, Vector& theMaxs ) void C_BaseAnimatingOverlay::CheckForLayerChanges( CStudioHdr *hdr, float currentTime ) { CDisableRangeChecks disableRangeChecks; + + bool bLayersChanged = false; // FIXME: damn, there has to be a better way than this. int i; @@ -229,13 +231,14 @@ void C_BaseAnimatingOverlay::CheckForLayerChanges( CStudioHdr *hdr, float curren if ( pHead && pPrev1 && pHead->m_nSequence != pPrev1->m_nSequence ) { - #if _DEBUG - if (Q_stristr( hdr->pszName(), r_sequence_debug.GetString()) != NULL) + bLayersChanged = true; + #if 1 // _DEBUG + if (/* Q_stristr( hdr->pszName(), r_sequence_debug.GetString()) != NULL || */ r_sequence_debug.GetInt() == entindex()) { - DevMsgRT( "(%5.2f : %30s : %5.3f : %4.2f : %1d)\n", t0, hdr->pSeqdesc( pHead->m_nSequence ).pszLabel(), (float)pHead->m_flCycle, (float)pHead->m_flWeight, i ); - DevMsgRT( "(%5.2f : %30s : %5.3f : %4.2f : %1d)\n", t1, hdr->pSeqdesc( pPrev1->m_nSequence ).pszLabel(), (float)pPrev1->m_flCycle, (float)pPrev1->m_flWeight, i ); + DevMsgRT( "(%7.4f : %30s : %5.3f : %4.2f : %1d)\n", t0, hdr->pSeqdesc( pHead->m_nSequence ).pszLabel(), (float)pHead->m_flCycle, (float)pHead->m_flWeight, i ); + DevMsgRT( "(%7.4f : %30s : %5.3f : %4.2f : %1d)\n", t1, hdr->pSeqdesc( pPrev1->m_nSequence ).pszLabel(), (float)pPrev1->m_flCycle, (float)pPrev1->m_flWeight, i ); if (pPrev2) - DevMsgRT( "(%5.2f : %30s : %5.3f : %4.2f : %1d)\n", t2, hdr->pSeqdesc( pPrev2->m_nSequence ).pszLabel(), (float)pPrev2->m_flCycle, (float)pPrev2->m_flWeight, i ); + DevMsgRT( "(%7.4f : %30s : %5.3f : %4.2f : %1d)\n", t2, hdr->pSeqdesc( pPrev2->m_nSequence ).pszLabel(), (float)pPrev2->m_flCycle, (float)pPrev2->m_flWeight, i ); } #endif @@ -280,6 +283,12 @@ void C_BaseAnimatingOverlay::CheckForLayerChanges( CStudioHdr *hdr, float curren m_flOverlayPrevEventCycle[i] = pHead->m_flPrevCycle - 0.01; } } + + if (bLayersChanged) + { + // render bounds may have changed + UpdateVisibility(); + } } @@ -359,12 +368,12 @@ void C_BaseAnimatingOverlay::AccumulateLayers( CStudioHdr *hdr, Vector pos[], Qu AccumulatePose( hdr, m_pIk, pos, q, m_AnimOverlay[i].m_nSequence, fCycle, poseparam, boneMask, fWeight, currentTime ); -#if _DEBUG - if (Q_stristr( hdr->pszName(), r_sequence_debug.GetString()) != NULL) +#if 1 // _DEBUG + if (/* Q_stristr( hdr->pszName(), r_sequence_debug.GetString()) != NULL || */ r_sequence_debug.GetInt() == entindex()) { if (1) { - DevMsgRT( "%6.2f : %30s : %5.3f : %4.2f : %1d\n", currentTime, hdr->pSeqdesc( m_AnimOverlay[i].m_nSequence ).pszLabel(), fCycle, fWeight, i ); + DevMsgRT( "%8.4f : %30s : %5.3f : %4.2f : %1d\n", currentTime, hdr->pSeqdesc( m_AnimOverlay[i].m_nSequence ).pszLabel(), fCycle, fWeight, i ); } else { @@ -396,8 +405,23 @@ void C_BaseAnimatingOverlay::AccumulateLayers( CStudioHdr *hdr, Vector pos[], Qu } } #endif + +//#define DEBUG_TF2_OVERLAYS +#if defined( DEBUG_TF2_OVERLAYS ) + engine->Con_NPrintf( 10 + j, "%30s %6.2f : %6.2f : %1d", hdr->pSeqdesc( m_AnimOverlay[i].m_nSequence ).pszLabel(), fCycle, fWeight, i ); + } + else + { + engine->Con_NPrintf( 10 + j, "%30s %6.2f : %6.2f : %1d", " ", 0.f, 0.f, i ); +#endif } } +#if defined( DEBUG_TF2_OVERLAYS ) + else + { + engine->Con_NPrintf( 10 + j, "%30s %6.2f : %6.2f : %1d", " ", 0.f, 0.f, i ); + } +#endif } } @@ -432,9 +456,14 @@ void C_BaseAnimatingOverlay::DoAnimationEvents( CStudioHdr *pStudioHdr ) if (m_AnimOverlay[j].m_flCycle == m_flOverlayPrevEventCycle[j]) continue; - // check for looping - BOOL bLooped = false; - if (m_AnimOverlay[j].m_flCycle <= m_flOverlayPrevEventCycle[j]) + bool bLoopingSequence = IsSequenceLooping( m_AnimOverlay[j].m_nSequence ); + + bool bLooped = false; + + //in client code, m_flOverlayPrevEventCycle is set to -1 when we first start an overlay, looping or not + if ( bLoopingSequence && + m_flOverlayPrevEventCycle[j] > 0.0f && + m_AnimOverlay[j].m_flCycle <= m_flOverlayPrevEventCycle[j] ) { if (m_flOverlayPrevEventCycle[j] - m_AnimOverlay[j].m_flCycle > 0.5) { @@ -519,3 +548,19 @@ void C_BaseAnimatingOverlay::DoAnimationEvents( CStudioHdr *pStudioHdr ) } } +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CStudioHdr *C_BaseAnimatingOverlay::OnNewModel() +{ + CStudioHdr *hdr = BaseClass::OnNewModel(); + + // Clear out animation layers + for ( int i=0; i < m_AnimOverlay.Count(); i++ ) + { + m_AnimOverlay[i].Reset(); + m_AnimOverlay[i].m_nOrder = MAX_OVERLAYS; + } + + return hdr; +} \ No newline at end of file diff --git a/src/src/cl_dll/c_baseanimatingoverlay.h b/src/src/game/client/c_baseanimatingoverlay.h similarity index 97% rename from src/src/cl_dll/c_baseanimatingoverlay.h rename to src/src/game/client/c_baseanimatingoverlay.h index 3415e88..0afb6f4 100644 --- a/src/src/cl_dll/c_baseanimatingoverlay.h +++ b/src/src/game/client/c_baseanimatingoverlay.h @@ -27,6 +27,8 @@ public: C_BaseAnimatingOverlay(); + virtual CStudioHdr *OnNewModel(); + C_AnimationLayer* GetAnimOverlay( int i ); void SetNumAnimOverlays( int num ); // This makes sure there is space for this # of layers. int GetNumAnimOverlays() const; diff --git a/src/src/cl_dll/c_basecombatcharacter.cpp b/src/src/game/client/c_basecombatcharacter.cpp similarity index 80% rename from src/src/cl_dll/c_basecombatcharacter.cpp rename to src/src/game/client/c_basecombatcharacter.cpp index 6f0f9da..ad79425 100644 --- a/src/src/cl_dll/c_basecombatcharacter.cpp +++ b/src/src/game/client/c_basecombatcharacter.cpp @@ -46,18 +46,39 @@ int C_BaseCombatCharacter::GetAmmoCount( char *szName ) const } */ +//----------------------------------------------------------------------------- +// Purpose: Overload our muzzle flash and send it to any actively held weapon +//----------------------------------------------------------------------------- +void C_BaseCombatCharacter::DoMuzzleFlash() +{ + // Our weapon takes our muzzle flash command + C_BaseCombatWeapon *pWeapon = GetActiveWeapon(); + if ( pWeapon ) + { + pWeapon->DoMuzzleFlash(); + //NOTENOTE: We do not chain to the base here + } + else + { + BaseClass::DoMuzzleFlash(); + } +} IMPLEMENT_CLIENTCLASS(C_BaseCombatCharacter, DT_BaseCombatCharacter, CBaseCombatCharacter); // Only send active weapon index to local player BEGIN_RECV_TABLE_NOBASE( C_BaseCombatCharacter, DT_BCCLocalPlayerExclusive ) RecvPropTime( RECVINFO( m_flNextAttack ) ), - RecvPropArray3( RECVINFO_ARRAY(m_hMyWeapons), RecvPropEHandle( RECVINFO( m_hMyWeapons[0] ) ) ), END_RECV_TABLE(); BEGIN_RECV_TABLE(C_BaseCombatCharacter, DT_BaseCombatCharacter) RecvPropDataTable( "bcc_localdata", 0, 0, &REFERENCE_RECV_TABLE(DT_BCCLocalPlayerExclusive) ), RecvPropEHandle( RECVINFO( m_hActiveWeapon ) ), + RecvPropArray3( RECVINFO_ARRAY(m_hMyWeapons), RecvPropEHandle( RECVINFO( m_hMyWeapons[0] ) ) ), + +#ifdef INVASION_CLIENT_DLL + RecvPropInt( RECVINFO( m_iPowerups ) ), +#endif END_RECV_TABLE() diff --git a/src/src/cl_dll/c_basecombatcharacter.h b/src/src/game/client/c_basecombatcharacter.h similarity index 67% rename from src/src/cl_dll/c_basecombatcharacter.h rename to src/src/game/client/c_basecombatcharacter.h index 1c639d0..c3d8adf 100644 --- a/src/src/cl_dll/c_basecombatcharacter.h +++ b/src/src/game/client/c_basecombatcharacter.h @@ -62,6 +62,8 @@ public: // Blood color (see BLOOD_COLOR_* macros in baseentity.h) void SetBloodColor( int nBloodColor ); + virtual void DoMuzzleFlash(); + public: float m_flNextAttack; @@ -82,6 +84,32 @@ private: //----------------------- +#ifdef INVASION_CLIENT_DLL +public: + virtual void Release( void ); + virtual void SetDormant( bool bDormant ); + virtual void OnPreDataChanged( DataUpdateType_t updateType ); + virtual void OnDataChanged( DataUpdateType_t updateType ); + virtual void ClientThink( void ); + + // TF2 Powerups + virtual bool CanBePoweredUp( void ) { return true; } + bool HasPowerup( int iPowerup ) { return ( m_iPowerups & (1 << iPowerup) ) != 0; }; + virtual void PowerupStart( int iPowerup, bool bInitial ); + virtual void PowerupEnd( int iPowerup ); + void RemoveAllPowerups( void ); + + // Powerup effects + void AddEMPEffect( float flSize ); + void AddBuffEffect( float flSize ); + + C_WeaponCombatShield *GetShield( void ); + +public: + int m_iPowerups; + int m_iPrevPowerups; +#endif + }; inline C_BaseCombatCharacter *ToBaseCombatCharacter( C_BaseEntity *pEntity ) @@ -96,6 +124,24 @@ inline C_BaseCombatCharacter *ToBaseCombatCharacter( C_BaseEntity *pEntity ) #endif } +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +inline int C_BaseCombatCharacter::WeaponCount() const +{ + return MAX_WEAPONS; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : i - +//----------------------------------------------------------------------------- +inline C_BaseCombatWeapon *C_BaseCombatCharacter::GetWeapon( int i ) const +{ + Assert( (i >= 0) && (i < MAX_WEAPONS) ); + return m_hMyWeapons[i].Get(); +} + EXTERN_RECV_TABLE(DT_BaseCombatCharacter); #endif // C_BASECOMBATCHARACTER_H diff --git a/src/src/cl_dll/c_basecombatweapon.cpp b/src/src/game/client/c_basecombatweapon.cpp similarity index 88% rename from src/src/cl_dll/c_basecombatweapon.cpp rename to src/src/game/client/c_basecombatweapon.cpp index 7e22c68..a7914d0 100644 --- a/src/src/cl_dll/c_basecombatweapon.cpp +++ b/src/src/game/client/c_basecombatweapon.cpp @@ -15,6 +15,7 @@ #include "hltvcamera.h" #include "tier1/KeyValues.h" #include "toolframework/itoolframework.h" +#include "toolframework_client.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -75,11 +76,15 @@ void C_BaseCombatWeapon::NotifyShouldTransmit( ShouldTransmitState_t state ) //----------------------------------------------------------------------------- -// Purpose: +// Purpose: To wrap PORTAL mod specific functionality into one place //----------------------------------------------------------------------------- static inline bool ShouldDrawLocalPlayer( void ) { +#if defined( PORTAL ) + return true; +#else return C_BasePlayer::ShouldDrawLocalPlayer(); +#endif } //----------------------------------------------------------------------------- @@ -140,11 +145,7 @@ void C_BaseCombatWeapon::OnDataChanged( DataUpdateType_t updateType ) } else // weapon carried by other player or not at all { - // BRJ 10/14/02 - // FIXME: Remove when Yahn's client-side prediction is done - // It's a hacky workaround for the model indices fighting - // (GetRenderBounds uses the model index, which is for the view model) - SetModelIndex( GetWorldModelIndex() ); + EnsureCorrectRenderingModel(); } UpdateVisibility(); @@ -178,6 +179,9 @@ bool C_BaseCombatWeapon::IsCarrierAlive() const //----------------------------------------------------------------------------- ShadowType_t C_BaseCombatWeapon::ShadowCastType() { + if ( IsEffectActive( /*EF_NODRAW |*/ EF_NOSHADOW ) ) + return SHADOWS_NONE; + if (!IsBeingCarried()) return SHADOWS_RENDER_TO_TEXTURE; @@ -243,15 +247,6 @@ void C_BaseCombatWeapon::DrawCrosshair() if ( !crosshair ) return; - // Check to see if the player is in VGUI mode... - if (player->IsInVGuiInputMode()) - { - CHudTexture *pArrow = gHUD.GetIcon( "arrow" ); - - crosshair->SetCrosshair( pArrow, gHUD.m_clrNormal ); - return; - } - // Find out if this weapon's auto-aimed onto a target bool bOnTarget = ( m_iState == WEAPON_IS_ONTARGET ); @@ -425,6 +420,9 @@ bool C_BaseCombatWeapon::ShouldDraw( void ) //----------------------------------------------------------------------------- bool C_BaseCombatWeapon::ShouldDrawPickup( void ) { + if ( GetWeaponFlags() & ITEM_FLAG_NOITEMPICKUP ) + return false; + if ( m_bJustRestored ) return false; @@ -458,9 +456,40 @@ int C_BaseCombatWeapon::DrawModel( int flags ) return false; } + // See comment below + EnsureCorrectRenderingModel(); + return BaseClass::DrawModel( flags ); } +// If the local player is visible (thirdperson mode, tf2 taunts, etc., then make sure that we are using the +// w_ (world) model not the v_ (view) model or else the model can flicker, etc. +// Otherwise, if we're not the local player, always use the world model +void C_BaseCombatWeapon::EnsureCorrectRenderingModel() +{ + C_BasePlayer *localplayer = C_BasePlayer::GetLocalPlayer(); + if ( localplayer && + localplayer == GetOwner() && + !ShouldDrawLocalPlayer() ) + { + return; + } + + // BRJ 10/14/02 + // FIXME: Remove when Yahn's client-side prediction is done + // It's a hacky workaround for the model indices fighting + // (GetRenderBounds uses the model index, which is for the view model) + SetModelIndex( GetWorldModelIndex() ); + + // Validate our current sequence just in case ( in theory the view and weapon models should have the same sequences for sequences that overlap at least ) + CStudioHdr *pStudioHdr = GetModelPtr(); + if ( pStudioHdr && + GetSequence() >= pStudioHdr->GetNumSeq() ) + { + SetSequence( 0 ); + } +} + //----------------------------------------------------------------------------- // tool recording //----------------------------------------------------------------------------- @@ -478,15 +507,19 @@ void C_BaseCombatWeapon::GetToolRecordingState( KeyValues *msg ) BaseClass::GetToolRecordingState( msg ); - if ( m_iState == WEAPON_IS_ACTIVE ) + if ( m_iState == WEAPON_NOT_CARRIED ) { BaseEntityRecordingState_t *pBaseEntity = (BaseEntityRecordingState_t*)msg->GetPtr( "baseentity" ); - pBaseEntity->m_bVisible = true; + pBaseEntity->m_nOwner = -1; } - else if ( m_iState == WEAPON_NOT_CARRIED ) + else { - BaseEntityRecordingState_t *pBaseEntity = (BaseEntityRecordingState_t*)msg->GetPtr( "baseentity" ); - pBaseEntity->m_nOwner = 0; + msg->SetInt( "worldmodel", 1 ); + if ( m_iState == WEAPON_IS_ACTIVE ) + { + BaseEntityRecordingState_t *pBaseEntity = (BaseEntityRecordingState_t*)msg->GetPtr( "baseentity" ); + pBaseEntity->m_bVisible = true; + } } if ( nModelIndex != nWorldModelIndex ) diff --git a/src/src/cl_dll/c_basecombatweapon.h b/src/src/game/client/c_basecombatweapon.h similarity index 100% rename from src/src/cl_dll/c_basecombatweapon.h rename to src/src/game/client/c_basecombatweapon.h diff --git a/src/src/cl_dll/c_basedoor.cpp b/src/src/game/client/c_basedoor.cpp similarity index 100% rename from src/src/cl_dll/c_basedoor.cpp rename to src/src/game/client/c_basedoor.cpp diff --git a/src/src/cl_dll/c_basedoor.h b/src/src/game/client/c_basedoor.h similarity index 100% rename from src/src/cl_dll/c_basedoor.h rename to src/src/game/client/c_basedoor.h diff --git a/src/src/cl_dll/c_baseentity.cpp b/src/src/game/client/c_baseentity.cpp similarity index 89% rename from src/src/cl_dll/c_baseentity.cpp rename to src/src/game/client/c_baseentity.cpp index 92858b6..8d94e4b 100644 --- a/src/src/cl_dll/c_baseentity.cpp +++ b/src/src/game/client/c_baseentity.cpp @@ -25,7 +25,7 @@ #include "interface.h" #include "materialsystem/IMaterialSystem.h" #include "soundinfo.h" -#include "vmatrix.h" +#include "mathlib/vmatrix.h" #include "isaverestore.h" #include "interval.h" #include "engine/ivdebugoverlay.h" @@ -37,6 +37,9 @@ #include "datacache/imdlcache.h" #include "toolframework/itoolframework.h" #include "toolframework_client.h" +#include "decals.h" +#include "cdll_bounded_cvars.h" +#include "inetchannelinfo.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -49,40 +52,33 @@ static bool g_bWasSkipping = (bool)-1; +static bool g_bWasThreaded =(bool)-1; +static int g_nThreadModeTicks = 0; +static ConVar cl_interp_threadmodeticks( "cl_interp_threadmodeticks", "0", 0, "Additional interpolation ticks to use when interpolating with threaded engine mode set." ); -void cc_cl_interp_changed( ConVar *var, const char *pOldString ) +void cc_cl_interp_all_changed( IConVar *pConVar, const char *pOldString, float flOldValue ) { - C_BaseEntityIterator iterator; - C_BaseEntity *pEnt; - while ( (pEnt = iterator.Next()) != NULL ) - { - pEnt->Interp_UpdateInterpolationAmounts( pEnt->GetVarMapping() ); - } -} - -void cc_cl_interp_all_changed( ConVar *var, const char *pOldString ) -{ - if ( var->GetInt() ) + ConVarRef var( pConVar ); + if ( var.GetInt() ) { C_BaseEntityIterator iterator; C_BaseEntity *pEnt; while ( (pEnt = iterator.Next()) != NULL ) { if ( pEnt->ShouldInterpolate() ) + { pEnt->AddToInterpolationList(); + } } } } static ConVar cl_extrapolate( "cl_extrapolate", "1", FCVAR_CHEAT, "Enable/disable extrapolation if interpolation history runs out." ); -static ConVar cl_interpolate( "cl_interpolate", "1.0", FCVAR_USERINFO, "Interpolate entities on the client." ); -static ConVar cl_interp ( "cl_interp", "0.1", FCVAR_USERINFO | FCVAR_DEMO, "Interpolate object positions starting this many seconds in past", true, 0.01, true, 1.0, cc_cl_interp_changed ); -static ConVar cl_interp_npcs( "cl_interp_npcs", "0.0", FCVAR_USERINFO, "Interpolate NPC positions starting this many seconds in past (or cl_interp, if greater)", 0, 0, 0, 0, cc_cl_interp_changed ); +static ConVar cl_interp_npcs( "cl_interp_npcs", "0.0", FCVAR_USERINFO, "Interpolate NPC positions starting this many seconds in past (or cl_interp, if greater)" ); static ConVar cl_interp_all( "cl_interp_all", "0", 0, "Disable interpolation list optimizations.", 0, 0, 0, 0, cc_cl_interp_all_changed ); -//APSFIXME - Temp until I fix -ConVar r_drawmodeldecals( "r_drawmodeldecals", IsXbox() ? "0" : "1" ); +ConVar r_drawmodeldecals( "r_drawmodeldecals", "1" ); extern ConVar cl_showerror; int C_BaseEntity::m_nPredictionRandomSeed = -1; C_BasePlayer *C_BaseEntity::m_pPredictionPlayer = NULL; @@ -242,7 +238,7 @@ public: virtual void RemoveFromList( ClientEntityHandle_t remove ) = 0; virtual int Count() = 0; - virtual C_BaseEntity *Get( int index ) = 0; + virtual IClientRenderable *Get( int index ) = 0; }; class CRecordingList : public IRecordingList @@ -252,7 +248,7 @@ public: virtual void RemoveFromList( ClientEntityHandle_t remove ); virtual int Count(); - virtual C_BaseEntity *Get( int index ); + IClientRenderable *Get( int index ); private: CUtlVector< ClientEntityHandle_t > m_Recording; }; @@ -289,18 +285,18 @@ void CRecordingList::RemoveFromList( ClientEntityHandle_t remove ) //----------------------------------------------------------------------------- // Purpose: // Input : slot - -// Output : C_BaseEntity +// Output : IClientRenderable //----------------------------------------------------------------------------- -C_BaseEntity *CRecordingList::Get( int index ) +IClientRenderable *CRecordingList::Get( int index ) { - return cl_entitylist->GetBaseEntityFromHandle( m_Recording[ index ] ); + return cl_entitylist->GetClientRenderableFromHandle( m_Recording[ index ] ); } //----------------------------------------------------------------------------- // Purpose: // Output : int //----------------------------------------------------------------------------- -int CRecordingList::Count( void ) +int CRecordingList::Count() { return m_Recording.Count(); } @@ -320,24 +316,24 @@ int CRecordingList::Count( void ) //----------------------------------------------------------------------------- void RecvProxy_AnimTime( const CRecvProxyData *pData, void *pStruct, void *pOut ) { + C_BaseEntity *pEntity = ( C_BaseEntity * )pStruct; + Assert( pOut == &pEntity->m_flAnimTime ); + int t; int tickbase; int addt; - C_BaseEntity *pEntity = ( C_BaseEntity * )pStruct; - Assert( pOut == &pEntity->m_flAnimTime ); - // Unpack the data. addt = pData->m_Value.m_Int; // Note, this needs to be encoded relative to packet timestamp, not raw client clock - tickbase = 100 * (int)( gpGlobals->tickcount / 100 ); + tickbase = gpGlobals->GetNetworkBase( gpGlobals->tickcount, pEntity->entindex() ); t = tickbase; // and then go back to floating point time. t += addt; // Add in an additional up to 256 100ths from the server - // center animtime around current time. + // center m_flAnimTime around current time. while (t < gpGlobals->tickcount - 127) t += 256; while (t > gpGlobals->tickcount + 127) @@ -348,6 +344,9 @@ void RecvProxy_AnimTime( const CRecvProxyData *pData, void *pStruct, void *pOut void RecvProxy_SimulationTime( const CRecvProxyData *pData, void *pStruct, void *pOut ) { + C_BaseEntity *pEntity = ( C_BaseEntity * )pStruct; + Assert( pOut == &pEntity->m_flSimulationTime ); + int t; int tickbase; int addt; @@ -356,21 +355,18 @@ void RecvProxy_SimulationTime( const CRecvProxyData *pData, void *pStruct, void addt = pData->m_Value.m_Int; // Note, this needs to be encoded relative to packet timestamp, not raw client clock - tickbase = 100 * (int)( gpGlobals->tickcount / 100 ); + tickbase = gpGlobals->GetNetworkBase( gpGlobals->tickcount, pEntity->entindex() ); t = tickbase; // and then go back to floating point time. t += addt; // Add in an additional up to 256 100ths from the server - // center animtime around current time. + // center m_flSimulationTime around current time. while (t < gpGlobals->tickcount - 127) t += 256; while (t > gpGlobals->tickcount + 127) t -= 256; - C_BaseEntity *pEntity = ( C_BaseEntity * )pStruct; - Assert( pOut == &pEntity->m_flSimulationTime ); - pEntity->m_flSimulationTime = ( t * TICK_INTERVAL ); } @@ -393,15 +389,7 @@ void RecvProxy_ToolRecording( const CRecvProxyData *pData, void *pStruct, void * return; CBaseEntity *pEnt = (CBaseEntity *)pStruct; - pEnt->SetToolRecording( pData->m_Value.m_Int == 0 ? false : true ); - if ( pEnt->IsToolRecording() ) - { - recordinglist->AddToList( pEnt->GetClientHandle() ); - } - else - { - recordinglist->RemoveFromList( pEnt->GetClientHandle() ); - } + pEnt->SetToolRecording( pData->m_Value.m_Int != 0 ); } #pragma optimize( "g", on ) @@ -453,7 +441,11 @@ BEGIN_RECV_TABLE_NOBASE(C_BaseEntity, DT_BaseEntity) RecvPropInt( RECVINFO(m_flSimulationTime), 0, RecvProxy_SimulationTime ), RecvPropVector( RECVINFO_NAME( m_vecNetworkOrigin, m_vecOrigin ) ), +#if PREDICTION_ERROR_CHECK_LEVEL > 1 + RecvPropVector( RECVINFO_NAME( m_angNetworkAngles, m_angRotation ) ), +#else RecvPropQAngles( RECVINFO_NAME( m_angNetworkAngles, m_angRotation ) ), +#endif RecvPropInt(RECVINFO(m_nModelIndex) ), RecvPropInt(RECVINFO(m_fEffects), 0, RecvProxy_EffectFlags ), @@ -514,7 +506,7 @@ BEGIN_PREDICTION_DATA_NO_BASE( C_BaseEntity ) // DEFINE_PRED_FIELD( m_pMovePeer, FIELD_EHANDLE ), // DEFINE_PRED_FIELD( m_pMovePrevPeer, FIELD_EHANDLE ), - DEFINE_PRED_FIELD_TOL( m_vecNetworkOrigin, FIELD_VECTOR, FTYPEDESC_INSENDTABLE, 0.125f ), + DEFINE_PRED_FIELD_TOL( m_vecNetworkOrigin, FIELD_VECTOR, FTYPEDESC_INSENDTABLE, 0.002f ), DEFINE_PRED_FIELD( m_angNetworkAngles, FIELD_VECTOR, FTYPEDESC_INSENDTABLE | FTYPEDESC_NOERRORCHECK ), DEFINE_FIELD( m_vecAbsOrigin, FIELD_VECTOR ), DEFINE_FIELD( m_angAbsRotation, FIELD_VECTOR ), @@ -575,6 +567,7 @@ void SpewInterpolatedVar( CInterpolatedVar< Vector > *pVar ) Msg( "--------------------------------------------------\n" ); int i = pVar->GetHead(); CApparentVelocity apparent; + float prevtime = 0.0f; while ( 1 ) { float changetime; @@ -583,7 +576,97 @@ void SpewInterpolatedVar( CInterpolatedVar< Vector > *pVar ) break; float vel = apparent.AddSample( changetime, *pVal ); - Msg( "%6.6f: (%.2f %.2f %.2f), vel: %.2f\n", changetime, VectorExpand( *pVal ), vel ); + Msg( "%6.6f: (%.2f %.2f %.2f), vel: %.2f [dt %.1f]\n", changetime, VectorExpand( *pVal ), vel, prevtime == 0.0f ? 0.0f : 1000.0f * ( changetime - prevtime ) ); + i = pVar->GetNext( i ); + prevtime = changetime; + } + Msg( "--------------------------------------------------\n" ); +} + +void SpewInterpolatedVar( CInterpolatedVar< Vector > *pVar, float flNow, float flInterpAmount, bool bSpewAllEntries = true ) +{ + float target = flNow - flInterpAmount; + + Msg( "--------------------------------------------------\n" ); + int i = pVar->GetHead(); + CApparentVelocity apparent; + float newtime = 999999.0f; + Vector newVec( 0, 0, 0 ); + bool bSpew = true; + + while ( 1 ) + { + float changetime; + Vector *pVal = pVar->GetHistoryValue( i, changetime ); + if ( !pVal ) + break; + + if ( bSpew && target >= changetime ) + { + Vector o; + pVar->DebugInterpolate( &o, flNow ); + bool bInterp = newtime != 999999.0f; + float frac = 0.0f; + char desc[ 32 ]; + + if ( bInterp ) + { + frac = ( target - changetime ) / ( newtime - changetime ); + Q_snprintf( desc, sizeof( desc ), "interpolated [%.2f]", frac ); + } + else + { + bSpew = true; + int savei = i; + i = pVar->GetNext( i ); + float oldtertime = 0.0f; + pVar->GetHistoryValue( i, oldtertime ); + + if ( changetime != oldtertime ) + { + frac = ( target - changetime ) / ( changetime - oldtertime ); + } + + Q_snprintf( desc, sizeof( desc ), "extrapolated [%.2f]", frac ); + i = savei; + } + + if ( bSpew ) + { + Msg( " > %6.6f: (%.2f %.2f %.2f) %s for %.1f msec\n", + target, + VectorExpand( o ), + desc, + 1000.0f * ( target - changetime ) ); + bSpew = false; + } + } + + float vel = apparent.AddSample( changetime, *pVal ); + if ( bSpewAllEntries ) + { + Msg( " %6.6f: (%.2f %.2f %.2f), vel: %.2f [dt %.1f]\n", changetime, VectorExpand( *pVal ), vel, newtime == 999999.0f ? 0.0f : 1000.0f * ( newtime - changetime ) ); + } + i = pVar->GetNext( i ); + newtime = changetime; + newVec = *pVal; + } + Msg( "--------------------------------------------------\n" ); +} +void SpewInterpolatedVar( CInterpolatedVar< float > *pVar ) +{ + Msg( "--------------------------------------------------\n" ); + int i = pVar->GetHead(); + CApparentVelocity apparent; + while ( 1 ) + { + float changetime; + float *pVal = pVar->GetHistoryValue( i, changetime ); + if ( !pVal ) + break; + + float vel = apparent.AddSample( changetime, *pVal ); + Msg( "%6.6f: (%.2f), vel: %.2f\n", changetime, *pVal, vel ); i = pVar->GetNext( i ); } Msg( "--------------------------------------------------\n" ); @@ -615,16 +698,31 @@ void GetInterpolatedVarTimeRange( CInterpolatedVar *pVar, float &flMin, float //----------------------------------------------------------------------------- void C_BaseEntity::SetAbsQueriesValid( bool bValid ) { - s_bAbsQueriesValid = bValid; + // @MULTICORE: Always allow in worker threads, assume higher level code is handling correctly + if ( !ThreadInMainThread() ) + return; + + if ( !bValid ) + { + s_bAbsQueriesValid = false; + } + else + { + s_bAbsQueriesValid = true; + } } bool C_BaseEntity::IsAbsQueriesValid( void ) { + if ( !ThreadInMainThread() ) + return true; return s_bAbsQueriesValid; } void C_BaseEntity::PushEnableAbsRecomputations( bool bEnable ) { + if ( !ThreadInMainThread() ) + return; if ( g_iAbsRecomputationStackPos < ARRAYSIZE( g_bAbsRecomputationStack ) ) { g_bAbsRecomputationStack[g_iAbsRecomputationStackPos] = s_bAbsRecomputationEnabled; @@ -639,6 +737,8 @@ void C_BaseEntity::PushEnableAbsRecomputations( bool bEnable ) void C_BaseEntity::PopEnableAbsRecomputations() { + if ( !ThreadInMainThread() ) + return; if ( g_iAbsRecomputationStackPos > 0 ) { --g_iAbsRecomputationStackPos; @@ -652,6 +752,8 @@ void C_BaseEntity::PopEnableAbsRecomputations() void C_BaseEntity::EnableAbsRecomputations( bool bEnable ) { + if ( !ThreadInMainThread() ) + return; // This should only be called at the frame level. Use PushEnableAbsRecomputations // if you're blocking out a section of code. Assert( g_iAbsRecomputationStackPos == 0 ); @@ -661,6 +763,8 @@ void C_BaseEntity::EnableAbsRecomputations( bool bEnable ) bool C_BaseEntity::IsAbsRecomputationsEnabled() { + if ( !ThreadInMainThread() ) + return true; return s_bAbsRecomputationEnabled; } @@ -698,6 +802,8 @@ void C_BaseEntity::Interp_SetupMappings( VarMapping_t *map ) void C_BaseEntity::Interp_RestoreToLastNetworked( VarMapping_t *map ) { + PREDICTION_TRACKVALUECHANGESCOPE_ENTITY( this, "restoretolastnetworked" ); + Vector oldOrigin = GetLocalOrigin(); QAngle oldAngles = GetLocalAngles(); @@ -739,6 +845,17 @@ void C_BaseEntity::Interp_HierarchyUpdateInterpolationAmounts() inline int C_BaseEntity::Interp_Interpolate( VarMapping_t *map, float currentTime ) { int bNoMoreChanges = 1; + if ( currentTime < map->m_lastInterpolationTime ) + { + for ( int i = 0; i < map->m_nInterpolatedEntries; i++ ) + { + VarMapEntry_t *e = &map->m_Entries[ i ]; + + e->m_bNeedsToInterpolate = true; + } + } + map->m_lastInterpolationTime = currentTime; + for ( int i = 0; i < map->m_nInterpolatedEntries; i++ ) { VarMapEntry_t *e = &map->m_Entries[ i ]; @@ -818,7 +935,10 @@ C_BaseEntity::C_BaseEntity() : m_bToolRecording = false; m_ToolHandle = 0; m_nLastRecordedFrame = -1; + m_bRecordInTools = true; #endif + + ParticleProp()->Init( this ); } @@ -842,6 +962,7 @@ void C_BaseEntity::Clear( void ) { m_bDormant = true; + m_nCreationTick = -1; m_RefEHandle.Term(); m_ModelInstance = MODEL_INSTANCE_INVALID; m_ShadowHandle = CLIENTSHADOW_INVALID_HANDLE; @@ -938,6 +1059,8 @@ bool C_BaseEntity::Init( int entnum, int iSerialNum ) Interp_SetupMappings( GetVarMapping() ); + m_nCreationTick = gpGlobals->tickcount; + return true; } @@ -1063,11 +1186,10 @@ const CBaseHandle& C_BaseEntity::GetRefEHandle() const //----------------------------------------------------------------------------- void C_BaseEntity::Release() { - C_BaseAnimating::PushAllowBoneAccess( true, true ); - - UnlinkFromHierarchy(); - - C_BaseAnimating::PopBoneAccess(); + { + C_BaseAnimating::AutoAllowBoneAccess boneaccess( true, true ); + UnlinkFromHierarchy(); + } // Note that this must be called from here, not the destructor, because otherwise the // vtable is hosed and the derived classes function is not going to get called!!! @@ -1134,6 +1256,20 @@ int C_BaseEntity::VPhysicsGetObjectList( IPhysicsObject **pList, int listMax ) return 0; } +bool C_BaseEntity::VPhysicsIsFlesh( void ) +{ + IPhysicsObject *pList[VPHYSICS_MAX_OBJECT_LIST_COUNT]; + int count = VPhysicsGetObjectList( pList, ARRAYSIZE(pList) ); + for ( int i = 0; i < count; i++ ) + { + int material = pList[i]->GetMaterialIndex(); + const surfacedata_t *pSurfaceData = physprops->GetSurfaceData( material ); + // Is flesh ?, don't allow pickup + if ( pSurfaceData->game.material == CHAR_TEX_ANTLION || pSurfaceData->game.material == CHAR_TEX_FLESH || pSurfaceData->game.material == CHAR_TEX_BLOODYFLESH || pSurfaceData->game.material == CHAR_TEX_ALIENFLESH ) + return true; + } + return false; +} //----------------------------------------------------------------------------- // Returns the health fraction @@ -1196,6 +1332,12 @@ void C_BaseEntity::UpdateVisibility() //----------------------------------------------------------------------------- bool C_BaseEntity::ShouldDraw() { +// Only test this in tf2 +#if defined( INVASION_CLIENT_DLL ) + // Let the client mode (like commander mode) reject drawing entities. + if (g_pClientMode && !g_pClientMode->ShouldDrawEntity(this) ) + return false; +#endif // Some rendermodes prevent rendering if ( m_nRenderMode == kRenderNone ) @@ -1620,12 +1762,20 @@ bool C_BaseEntity::IsTransparent( void ) return modelIsTransparent || (m_nRenderMode != kRenderNormal); } +bool C_BaseEntity::IsTwoPass( void ) +{ + return modelinfo->IsTranslucentTwoPass( GetModel() ); +} -bool C_BaseEntity::UsesFrameBufferTexture() +bool C_BaseEntity::UsesPowerOfTwoFrameBufferTexture() { return false; } +bool C_BaseEntity::UsesFullFrameBufferTexture() +{ + return false; +} //----------------------------------------------------------------------------- // Purpose: Get pointer to CMouthInfo data @@ -1701,12 +1851,25 @@ bool C_BaseEntity::GetAttachment( int number, Vector &origin, QAngle &angles ) return true; } +bool C_BaseEntity::GetAttachment( int number, Vector &origin ) +{ + origin = GetAbsOrigin(); + return true; +} + bool C_BaseEntity::GetAttachment( int number, matrix3x4_t &matrix ) { MatrixCopy( EntityToWorldTransform(), matrix ); return true; } +bool C_BaseEntity::GetAttachmentVelocity( int number, Vector &originVel, Quaternion &angleVel ) +{ + originVel = GetAbsVelocity(); + angleVel.Init(); + return true; +} + //----------------------------------------------------------------------------- // Purpose: Get this entity's rendering clip plane if one is defined @@ -1724,13 +1887,21 @@ float *C_BaseEntity::GetRenderClipPlane( void ) //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- -int C_BaseEntity::DrawBrushModel( bool sort ) +int C_BaseEntity::DrawBrushModel( bool bSort, bool bShadowDepth ) { VPROF_BUDGET( "C_BaseEntity::DrawBrushModel", VPROF_BUDGETGROUP_BRUSHMODEL_RENDERING ); // Identity brushes are drawn in view->DrawWorld as an optimization Assert ( modelinfo->GetModelType( model ) == mod_brush ); - render->DrawBrushModel( this, (model_t *)model, GetAbsOrigin(), GetAbsAngles(), sort ); + if ( bShadowDepth ) + { + render->DrawBrushModelShadowDepth( this, (model_t *)model, GetAbsOrigin(), GetAbsAngles(), bSort ); + } + else + { + render->DrawBrushModel( this, (model_t *)model, GetAbsOrigin(), GetAbsAngles(), bSort ); + } + return 1; } @@ -1753,7 +1924,7 @@ int C_BaseEntity::DrawModel( int flags ) switch ( modelType ) { case mod_brush: - drawn = DrawBrushModel( flags & STUDIO_TRANSPARENCY ? true : false ); + drawn = DrawBrushModel( flags & STUDIO_TRANSPARENCY ? true : false, flags & STUDIO_SHADOWDEPTHTEXTURE ? true : false ); break; case mod_studio: // All studio models must be derived from C_BaseAnimating. Issue warning. @@ -1785,10 +1956,11 @@ bool C_BaseEntity::SetupBones( matrix3x4_t *pBoneToWorldOut, int nMaxBones, int //----------------------------------------------------------------------------- // Purpose: Setup vertex weights for drawing //----------------------------------------------------------------------------- -void C_BaseEntity::SetupWeights( ) +void C_BaseEntity::SetupWeights( const matrix3x4_t *pBoneToWorld, int nFlexWeightCount, float *pFlexWeights, float *pFlexDelayedWeights ) { } + //----------------------------------------------------------------------------- // Purpose: Process any local client-side animation events //----------------------------------------------------------------------------- @@ -1800,7 +1972,7 @@ void C_BaseEntity::DoAnimationEvents( ) void C_BaseEntity::UpdatePartitionListEntry() { // Don't add the world entity - CollideType_t shouldCollide = ShouldCollide(); + CollideType_t shouldCollide = GetCollideType(); // Choose the list based on what kind of collisions we want int list = PARTITION_CLIENT_NON_STATIC_EDICTS; @@ -1915,12 +2087,14 @@ void C_BaseEntity::PreDataUpdate( DataUpdateType_t updateType ) Spawn(); } +#if 0 // Yahn suggesting commenting this out as a fix to demo recording not working // If the entity moves itself every FRAME on the server but doesn't update animtime, // then use the current server time as the time for interpolation. - if ( !IsSelfAnimating() ) + if ( IsSelfAnimating() ) { - m_flAnimTime = engine->GetLastTimeStamp(); + m_flAnimTime = engine->GetLastTimeStamp(); } +#endif m_vecOldOrigin = GetNetworkOrigin(); m_vecOldAngRotation = GetNetworkAngles(); @@ -2045,6 +2219,7 @@ void C_BaseEntity::MarkAimEntsDirty() void C_BaseEntity::CalcAimEntPositions() { + VPROF("CalcAimEntPositions"); int i; int c = g_AimEntsList.Count(); for ( i = 0; i < c; ++i ) @@ -2223,7 +2398,6 @@ void C_BaseEntity::ValidateModelIndex( void ) SetModelByIndex( m_nModelIndex ); } - //----------------------------------------------------------------------------- // Purpose: Entity data has been parsed and unpacked. Now do any necessary decoding, munging // Input : bnewentity - was this entity new in this update packet? @@ -2232,6 +2406,8 @@ void C_BaseEntity::PostDataUpdate( DataUpdateType_t updateType ) { MDLCACHE_CRITICAL_SECTION(); + PREDICTION_TRACKVALUECHANGESCOPE_ENTITY( this, "postdataupdate" ); + // NOTE: This *has* to happen first. Otherwise, Origin + angles may be wrong if ( m_nRenderFX == kRenderFxRagdoll && updateType == DATA_UPDATE_CREATED ) { @@ -2266,7 +2442,10 @@ void C_BaseEntity::PostDataUpdate( DataUpdateType_t updateType ) // Detect simulation changes bool simulationChanged = originChanged || anglesChanged || simTimeChanged; - if ( !GetPredictable() && !IsClientCreated() ) + bool bPredictable = GetPredictable(); + + // For non-predicted and non-client only ents, we need to latch network values into the interpolation histories + if ( !bPredictable && !IsClientCreated() ) { if ( animTimeChanged ) { @@ -2278,6 +2457,12 @@ void C_BaseEntity::PostDataUpdate( DataUpdateType_t updateType ) OnLatchInterpolatedVariables( LATCH_SIMULATION_VAR ); } } + // For predictables, we also need to store off the last networked value + else if ( bPredictable ) + { + // Just store off last networked value for use in prediction + OnStoreLastNetworkedValue(); + } // Deal with hierarchy. Have to do it here (instead of in a proxy) // because this is the only point at which all entities are loaded @@ -2297,6 +2482,8 @@ void C_BaseEntity::PostDataUpdate( DataUpdateType_t updateType ) m_flProxyRandomValue = random->RandomFloat( 0, 1 ); ResetLatched(); + + m_nCreationTick = gpGlobals->tickcount; } CheckInitPredictable( "PostDataUpdate" ); @@ -2322,6 +2509,12 @@ void C_BaseEntity::PostDataUpdate( DataUpdateType_t updateType ) if ( Teleported() || IsEffectActive(EF_NOINTERP) ) AddToTeleportList(); } + + // if we changed parents, recalculate visibility + if ( m_hOldMoveParent != m_hNetworkMoveParent ) + { + UpdateVisibility(); + } } //----------------------------------------------------------------------------- @@ -2332,7 +2525,7 @@ void C_BaseEntity::CheckInitPredictable( const char *context ) { #if !defined( NO_ENTITY_PREDICTION ) // Prediction is disabled - if ( !cl_predict.GetBool() ) + if ( !cl_predict->GetInt() ) return; C_BasePlayer *player = C_BasePlayer::GetLocalPlayer(); @@ -2415,6 +2608,45 @@ bool C_BaseEntity::SetModel( const char *pModelName ) return false; } } + +void C_BaseEntity::OnStoreLastNetworkedValue() +{ + bool bRestore = false; + Vector savePos; + QAngle saveAng; + + // Kind of a hack, but we want to latch the actual networked value for origin/angles, not what's sitting in m_vecOrigin in the + // ragdoll case where we don't copy it over in MoveToLastNetworkOrigin + if ( m_nRenderFX == kRenderFxRagdoll && GetPredictable() ) + { + bRestore = true; + savePos = GetLocalOrigin(); + saveAng = GetLocalAngles(); + + MoveToLastReceivedPosition( true ); + } + + int c = m_VarMap.m_Entries.Count(); + for ( int i = 0; i < c; i++ ) + { + VarMapEntry_t *e = &m_VarMap.m_Entries[ i ]; + IInterpolatedVar *watcher = e->watcher; + + int type = watcher->GetType(); + + if ( type & EXCLUDE_AUTO_LATCH ) + continue; + + watcher->NoteLastNetworkedValue(); + } + + if ( bRestore ) + { + SetLocalOrigin( savePos ); + SetLocalAngles( saveAng ); + } +} + //----------------------------------------------------------------------------- // Purpose: The animtime is about to be changed in a network update, store off various fields so that // we can use them to do blended sequence transitions, etc. @@ -2425,6 +2657,10 @@ void C_BaseEntity::OnLatchInterpolatedVariables( int flags ) { float changetime = GetLastChangeTime( flags ); + bool bUpdateLastNetworkedValue = !(flags & INTERPOLATE_OMIT_UPDATE_LAST_NETWORKED) ? true : false; + + PREDICTION_TRACKVALUECHANGESCOPE_ENTITY( this, bUpdateLastNetworkedValue ? "latch+net" : "latch" ); + int c = m_VarMap.m_Entries.Count(); for ( int i = 0; i < c; i++ ) { @@ -2439,7 +2675,7 @@ void C_BaseEntity::OnLatchInterpolatedVariables( int flags ) if ( type & EXCLUDE_AUTO_LATCH ) continue; - if ( watcher->NoteChanged( changetime ) ) + if ( watcher->NoteChanged( changetime, bUpdateLastNetworkedValue ) ) e->m_bNeedsToInterpolate = true; } @@ -2449,7 +2685,6 @@ void C_BaseEntity::OnLatchInterpolatedVariables( int flags ) } } - int CBaseEntity::BaseInterpolatePart1( float ¤tTime, Vector &oldOrigin, QAngle &oldAngles, int &bNoMoreChanges ) { // Don't mess with the world!!! @@ -2468,7 +2703,7 @@ int CBaseEntity::BaseInterpolatePart1( float ¤tTime, Vector &oldOrigin, QA if ( GetPredictable() || IsClientCreated() ) { C_BasePlayer *localplayer = C_BasePlayer::GetLocalPlayer(); - if ( localplayer ) + if ( localplayer && currentTime == gpGlobals->curtime ) { currentTime = localplayer->GetFinalPredictedTime(); currentTime -= TICK_INTERVAL; @@ -2486,6 +2721,9 @@ int CBaseEntity::BaseInterpolatePart1( float ¤tTime, Vector &oldOrigin, QA return INTERPOLATE_CONTINUE; } +#if 0 +static ConVar cl_watchplayer( "cl_watchplayer", "-1", 0 ); +#endif void C_BaseEntity::BaseInterpolatePart2( Vector &oldOrigin, QAngle &oldAngles, int nChangeFlags ) { @@ -2503,6 +2741,21 @@ void C_BaseEntity::BaseInterpolatePart2( Vector &oldOrigin, QAngle &oldAngles, i { InvalidatePhysicsRecursive( nChangeFlags ); } + +#if 0 + if ( IsPlayer() && + cl_watchplayer.GetInt() == entindex() && + C_BasePlayer::GetLocalPlayer() && + GetTeam() == C_BasePlayer::GetLocalPlayer()->GetTeam() ) + { + // SpewInterpolatedVar( &m_iv_vecOrigin, gpGlobals->curtime, GetInterpolationAmount( LATCH_SIMULATION_VAR ), false ); + Vector vel; + EstimateAbsVelocity( vel ); + float spd = vel.Length(); + + Msg( "estimated %f\n", spd ); + } +#endif } @@ -2534,23 +2787,16 @@ bool C_BaseEntity::Interpolate( float currentTime ) return true; } -// force all entries to interpolate (optimization may skip some that are necessary for special effects like ragdolls) -void C_BaseEntity::ForceAllInterpolate() -{ - VarMapping_t *map = GetVarMapping(); - for ( int i = 0; i < map->m_nInterpolatedEntries; i++ ) - { - VarMapEntry_t *e = &map->m_Entries[ i ]; - - e->m_bNeedsToInterpolate = true; - } -} - CStudioHdr *C_BaseEntity::OnNewModel() { return NULL; } +void C_BaseEntity::OnNewParticleEffect( const char *pszParticleName, CNewParticleEffect *pNewParticleEffect ) +{ + return; +} + // Above this velocity and we'll assume a warp/teleport #define MAX_INTERPOLATE_VELOCITY 4000.0f #define MAX_INTERPOLATE_VELOCITY_PLAYER 1250.0f @@ -2813,6 +3059,9 @@ void C_BaseEntity::Simulate() AddEntity(); // Legacy support. Once-per-frame stuff should go in Simulate(). } +// Defined in engine +static ConVar cl_interpolate( "cl_interpolate", "1.0f", FCVAR_USERINFO | FCVAR_DEVELOPMENTONLY ); + // (static function) void C_BaseEntity::InterpolateServerEntities() { @@ -2826,9 +3075,20 @@ void C_BaseEntity::InterpolateServerEntities() s_bInterpolate = false; } - if ( IsSimulatingOnAlternateTicks() != g_bWasSkipping ) + // Don't interpolate, either, if we are timing out + INetChannelInfo *nci = engine->GetNetChannelInfo(); + if ( nci && nci->GetTimeSinceLastReceived() > 0.5f ) + { + s_bInterpolate = false; + } + + if ( IsSimulatingOnAlternateTicks() != g_bWasSkipping || + IsEngineThreaded() != g_bWasThreaded || + cl_interp_threadmodeticks.GetInt() != g_nThreadModeTicks ) { g_bWasSkipping = IsSimulatingOnAlternateTicks(); + g_bWasThreaded = IsEngineThreaded(); + g_nThreadModeTicks = cl_interp_threadmodeticks.GetInt(); C_BaseEntityIterator iterator; C_BaseEntity *pEnt; @@ -2846,7 +3106,7 @@ void C_BaseEntity::InterpolateServerEntities() context.EnableExtrapolation( true ); } - // Smoothly interplate position for server entities. + // Smoothly interpolate position for server entities. ProcessTeleportList(); ProcessInterpolatedList(); } @@ -2929,6 +3189,10 @@ void C_BaseEntity::SetThinkHandle( ClientThinkHandle_t hThink ) //----------------------------------------------------------------------------- void C_BaseEntity::ComputeFxBlend( void ) { + // Don't recompute if we've already computed this frame + if ( m_nFXComputeFrame == gpGlobals->framecount ) + return; + MDLCACHE_CRITICAL_SECTION(); int blend=0; float offset; @@ -3121,10 +3385,7 @@ void C_BaseEntity::ComputeFxBlend( void ) } m_nRenderFXBlend = blend; - -#ifdef _DEBUG m_nFXComputeFrame = gpGlobals->framecount; -#endif // Update the render group if ( GetRenderHandle() != INVALID_CLIENT_RENDER_HANDLE ) @@ -3163,7 +3424,7 @@ void C_BaseEntity::GetColorModulation( float* color ) //----------------------------------------------------------------------------- // Returns true if we should add this to the collision list //----------------------------------------------------------------------------- -CollideType_t C_BaseEntity::ShouldCollide( ) +CollideType_t C_BaseEntity::GetCollideType( void ) { if ( !m_nModelIndex || !model ) return ENTITY_SHOULD_NOT_COLLIDE; @@ -3392,7 +3653,7 @@ C_Team *C_BaseEntity::GetTeam( void ) // Purpose: // Output : int //----------------------------------------------------------------------------- -int C_BaseEntity::GetTeamNumber( void ) +int C_BaseEntity::GetTeamNumber( void ) const { return m_iTeamNum; } @@ -3520,6 +3781,8 @@ void C_BaseEntity::SetDormant( bool bDormant ) // Kill drawing if we became dormant. UpdateVisibility(); + + ParticleProp()->OwnerSetDormantTo( bDormant ); } //----------------------------------------------------------------------------- @@ -3537,6 +3800,17 @@ bool C_BaseEntity::IsDormant( void ) return false; } +//----------------------------------------------------------------------------- +// Purpose: Tells the entity that it's about to be destroyed due to the client receiving +// an uncompressed update that's caused it to destroy all entities & recreate them. +//----------------------------------------------------------------------------- +void C_BaseEntity::SetDestroyedOnRecreateEntities( void ) +{ + // Robin: We need to destroy all our particle systems immediately, because + // we're about to be recreated, and their owner EHANDLEs will match up to + // the new entity, but it won't know anything about them. + ParticleProp()->StopEmissionAndDestroyImmediately(); +} //----------------------------------------------------------------------------- // These methods recompute local versions as well as set abs versions @@ -3852,6 +4126,13 @@ void C_BaseEntity::CalcAbsolutePosition( ) return; } + AUTO_LOCK( m_CalcAbsolutePositionMutex ); + + if ((m_iEFlags & EFL_DIRTY_ABSTRANSFORM) == 0) // need second check in event another thread grabbed mutex and did the calculation + { + return; + } + RemoveEFlags( EFL_DIRTY_ABSTRANSFORM ); if (!m_pMoveParent) @@ -3912,6 +4193,13 @@ void C_BaseEntity::CalcAbsoluteVelocity() if ((m_iEFlags & EFL_DIRTY_ABSVELOCITY ) == 0) return; + AUTO_LOCK( m_CalcAbsoluteVelocityMutex ); + + if ((m_iEFlags & EFL_DIRTY_ABSVELOCITY) == 0) // need second check in event another thread grabbed mutex and did the calculation + { + return; + } + m_iEFlags &= ~EFL_DIRTY_ABSVELOCITY; CBaseEntity *pMoveParent = GetMoveParent(); @@ -3923,6 +4211,19 @@ void C_BaseEntity::CalcAbsoluteVelocity() VectorRotate( m_vecVelocity, pMoveParent->EntityToWorldTransform(), m_vecAbsVelocity ); + + // Add in the attachments velocity if it exists + if ( m_iParentAttachment != 0 ) + { + Vector vOriginVel; + Quaternion vAngleVel; + if ( pMoveParent->GetAttachmentVelocity( m_iParentAttachment, vOriginVel, vAngleVel ) ) + { + m_vecAbsVelocity += vOriginVel; + return; + } + } + // Now add in the parent abs velocity m_vecAbsVelocity += pMoveParent->GetAbsVelocity(); } @@ -4078,7 +4379,7 @@ void C_BaseEntity::PreEntityPacketReceived( int commands_acknowledged ) bool copyintermediate = ( commands_acknowledged > 0 ) ? true : false; Assert( GetPredictable() ); - Assert( cl_predict.GetBool() ); + Assert( cl_predict->GetInt() ); // First copy in any intermediate predicted data for non-networked fields if ( copyintermediate ) @@ -4109,7 +4410,7 @@ void C_BaseEntity::PostEntityPacketReceived( void ) { #if !defined( NO_ENTITY_PREDICTION ) Assert( GetPredictable() ); - Assert( cl_predict.GetBool() ); + Assert( cl_predict->GetInt() ); // Always mark as changed AddDataChangeEvent( this, DATA_UPDATE_DATATABLE_CHANGED, &m_DataChangeEventRef ); @@ -4257,15 +4558,16 @@ const char *C_BaseEntity::GetClassname( void ) outstr[ 0 ] = 0; bool gotname = false; #ifndef NO_ENTITY_PREDICTION - const char *mapname = GetClassMap().Lookup( GetPredDescMap() ? GetPredDescMap()->dataClassName : _GetClassName() ); -#else - const char *mapname = GetClassMap().Lookup( _GetClassName() ); -#endif - if ( mapname && mapname[ 0 ] ) + if ( GetPredDescMap() ) { - Q_snprintf( outstr, sizeof( outstr ), "%s", mapname ); - gotname = true; + const char *mapname = GetClassMap().Lookup( GetPredDescMap()->dataClassName ); + if ( mapname && mapname[ 0 ] ) + { + Q_snprintf( outstr, sizeof( outstr ), "%s", mapname ); + gotname = true; + } } +#endif if ( !gotname ) { @@ -4300,18 +4602,40 @@ C_BaseEntity *CreateEntityByName( const char *className ) #ifdef _DEBUG CON_COMMAND( cl_sizeof, "Determines the size of the specified client class." ) { - if ( engine->Cmd_Argc() != 2 ) + if ( args.ArgC() != 2 ) { Msg( "cl_sizeof \n" ); return; } - int size = GetClassMap().GetClassSize( engine->Cmd_Argv(1 ) ); + int size = GetClassMap().GetClassSize( args[ 1 ] ); - Msg( "%s is %i bytes\n", engine->Cmd_Argv(1), size ); + Msg( "%s is %i bytes\n", args[ 1 ], size ); } #endif +CON_COMMAND_F( dlight_debug, "Creates a dlight in front of the player", FCVAR_CHEAT ) +{ + dlight_t *el = effects->CL_AllocDlight( 1 ); + C_BasePlayer *player = C_BasePlayer::GetLocalPlayer(); + if ( !player ) + return; + Vector start = player->EyePosition(); + Vector forward; + player->EyeVectors( &forward ); + Vector end = start + forward * MAX_TRACE_LENGTH; + trace_t tr; + UTIL_TraceLine( start, end, MASK_SHOT_HULL & (~CONTENTS_GRATE), player, COLLISION_GROUP_NONE, &tr ); + el->origin = tr.endpos - forward * 12.0f; + el->radius = 200; + el->decay = el->radius / 5.0f; + el->die = gpGlobals->curtime + 5.0f; + el->color.r = 255; + el->color.g = 192; + el->color.b = 64; + el->color.exponent = 5; + +} //----------------------------------------------------------------------------- // Purpose: // Output : Returns true on success, false on failure. @@ -4630,6 +4954,8 @@ void C_BaseEntity::AllocateIntermediateData( void ) m_pIntermediateData[ i ] = new unsigned char[ allocsize ]; Q_memset( m_pIntermediateData[ i ], 0, allocsize ); } + + m_nIntermediateDataCount = 0; #endif } @@ -4648,6 +4974,8 @@ void C_BaseEntity::DestroyIntermediateData( void ) } delete[] m_pOriginalData; m_pOriginalData = NULL; + + m_nIntermediateDataCount = 0; #endif } @@ -4879,15 +5207,33 @@ int C_BaseEntity::ComputePackedSize_R( datamap_t *map ) break; case FIELD_FLOAT: - case FIELD_STRING: case FIELD_VECTOR: case FIELD_QUATERNION: + case FIELD_INTEGER: + case FIELD_EHANDLE: + { + // These should be dword aligned + current_position = (current_position + 3) & ~3; + field->fieldOffset[ TD_OFFSET_PACKED ] = current_position; + Assert( field->fieldSize >= 1 ); + current_position += g_FieldSizes[ field->fieldType ] * field->fieldSize; + } + break; + + case FIELD_SHORT: + { + // This should be word aligned + current_position = (current_position + 1) & ~1; + field->fieldOffset[ TD_OFFSET_PACKED ] = current_position; + Assert( field->fieldSize >= 1 ); + current_position += g_FieldSizes[ field->fieldType ] * field->fieldSize; + } + break; + + case FIELD_STRING: case FIELD_COLOR32: case FIELD_BOOLEAN: - case FIELD_INTEGER: - case FIELD_SHORT: case FIELD_CHARACTER: - case FIELD_EHANDLE: { field->fieldOffset[ TD_OFFSET_PACKED ] = current_position; Assert( field->fieldSize >= 1 ); @@ -4972,18 +5318,24 @@ void C_BaseEntity::ToggleBBoxVisualization( int fVisFlags ) //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- -static void ToggleBBoxVisualization( int fVisFlags ) +static void ToggleBBoxVisualization( int fVisFlags, const CCommand &args ) { CBaseEntity *pHit; int iEntity = -1; - if ( engine->Cmd_Argc() >= 2 ) - iEntity = atoi( engine->Cmd_Argv( 1 ) ); + if ( args.ArgC() >= 2 ) + { + iEntity = atoi( args[ 1 ] ); + } if ( iEntity == -1 ) + { pHit = FindEntityInFrontOfLocalPlayer(); + } else + { pHit = cl_entitylist->GetBaseEntity( iEntity ); + } if ( pHit ) { @@ -4994,34 +5346,29 @@ static void ToggleBBoxVisualization( int fVisFlags ) //----------------------------------------------------------------------------- // Purpose: Command to toggle visualizations of bboxes on the client //----------------------------------------------------------------------------- -static void ToggleBBoxVisualization_f( void ) +CON_COMMAND_F( cl_ent_bbox, "Displays the client's bounding box for the entity under the crosshair.", FCVAR_CHEAT ) { - ToggleBBoxVisualization( CBaseEntity::VISUALIZE_COLLISION_BOUNDS ); + ToggleBBoxVisualization( CBaseEntity::VISUALIZE_COLLISION_BOUNDS, args ); } -static ConCommand cl_ent_bbox( "cl_ent_bbox", ToggleBBoxVisualization_f, "Displays the client's bounding box for the entity under the crosshair.", FCVAR_CHEAT ); //----------------------------------------------------------------------------- // Purpose: Command to toggle visualizations of bboxes on the client //----------------------------------------------------------------------------- -static void ToggleAbsBoxVisualization_f( void ) +CON_COMMAND_F( cl_ent_absbox, "Displays the client's absbox for the entity under the crosshair.", FCVAR_CHEAT ) { - ToggleBBoxVisualization( CBaseEntity::VISUALIZE_SURROUNDING_BOUNDS ); + ToggleBBoxVisualization( CBaseEntity::VISUALIZE_SURROUNDING_BOUNDS, args ); } -static ConCommand cl_ent_absbox( "cl_ent_absbox", ToggleAbsBoxVisualization_f, "Displays the client's absbox for the entity under the crosshair.", FCVAR_CHEAT ); //----------------------------------------------------------------------------- // Purpose: Command to toggle visualizations of bboxes on the client //----------------------------------------------------------------------------- -static void ToggleRBoxVisualization_f( void ) +CON_COMMAND_F( cl_ent_rbox, "Displays the client's render box for the entity under the crosshair.", FCVAR_CHEAT ) { - ToggleBBoxVisualization( CBaseEntity::VISUALIZE_RENDER_BOUNDS ); + ToggleBBoxVisualization( CBaseEntity::VISUALIZE_RENDER_BOUNDS, args ); } -static ConCommand cl_ent_rbox( "cl_ent_rbox", ToggleRBoxVisualization_f, "Displays the client's render box for the entity under the crosshair.", FCVAR_CHEAT ); - - //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- @@ -5074,21 +5421,17 @@ RenderGroup_t C_BaseEntity::GetRenderGroup() // translucency here because the proxy may have changed it. if (modelinfo->ModelHasMaterialProxy( GetModel() )) { - modelinfo->RecomputeTranslucency( const_cast(GetModel()) ); + modelinfo->RecomputeTranslucency( const_cast(GetModel()), GetSkin(), GetBody(), GetClientRenderable() ); } // NOTE: Bypassing the GetFXBlend protection logic because we want this to // be able to be called from AddToLeafSystem. -#ifdef _DEBUG int nTempComputeFrame = m_nFXComputeFrame; m_nFXComputeFrame = gpGlobals->framecount; -#endif int nFXBlend = GetFxBlend(); -#ifdef _DEBUG m_nFXComputeFrame = nTempComputeFrame; -#endif // Don't need to sort invisible stuff if ( nFXBlend == 0 ) @@ -5144,6 +5487,9 @@ int C_BaseEntity::SaveData( const char *context, int slot, int type ) else { Q_snprintf( sz, sizeof( sz ), "%s SaveData(slot %02i)", context, slot ); + + // Remember high water mark so that we can detect below if we are reading from a slot not yet predicted into... + m_nIntermediateDataCount = slot; } CPredictionCopy copyHelper( type, dest, PC_DATA_PACKED, this, PC_DATA_NORMAL ); @@ -5180,6 +5526,10 @@ int C_BaseEntity::RestoreData( const char *context, int slot, int type ) else { Q_snprintf( sz, sizeof( sz ), "%s RestoreData(slot %02i)", context, slot ); + + // This assert will fire if the server ack'd a CUserCmd which we hadn't predicted yet... + // In that case, we'd be comparing "old" data from this "unused" slot with the networked data and reporting all kinds of prediction errors possibly. + Assert( slot <= m_nIntermediateDataCount ); } // some flags shouldn't be predicted - as we find them, add them to the savedEFlagsMask @@ -5240,6 +5590,7 @@ void C_BaseEntity::EstimateAbsVelocity( Vector& vel ) void C_BaseEntity::Interp_Reset( VarMapping_t *map ) { + PREDICTION_TRACKVALUECHANGESCOPE_ENTITY( this, "reset" ); int c = map->m_Entries.Count(); for ( int i = 0; i < c; i++ ) { @@ -5287,7 +5638,6 @@ static float AdjustInterpolationAmount( C_BaseEntity *pEntity, float baseInterpo } //------------------------------------- - float C_BaseEntity::GetInterpolationAmount( int flags ) { // If single player server is "skipping ticks" everything needs to interpolate for a bit longer @@ -5302,27 +5652,37 @@ float C_BaseEntity::GetInterpolationAmount( int flags ) return TICK_INTERVAL * serverTickMultiple; } - // Always fully interpolation in multiplayer or during demo playback... - if ( gpGlobals->maxClients > 1 || engine->IsPlayingDemo() ) + // Always fully interpolate during multi-player or during demo playback, if the recorded + // demo was recorded locally. + const bool bPlayingDemo = engine->IsPlayingDemo(); + const bool bPlayingMultiplayer = !bPlayingDemo && ( gpGlobals->maxClients > 1 ); + const bool bPlayingNonLocallyRecordedDemo = bPlayingDemo && !engine->IsPlayingDemoALocallyRecordedDemo(); + if ( bPlayingMultiplayer || bPlayingNonLocallyRecordedDemo ) { - return AdjustInterpolationAmount( this, TICKS_TO_TIME ( TIME_TO_TICKS( cl_interp.GetFloat() ) + serverTickMultiple ) ); + return AdjustInterpolationAmount( this, TICKS_TO_TIME( TIME_TO_TICKS( GetClientInterpAmount() ) + serverTickMultiple ) ); + } + + int expandedServerTickMultiple = serverTickMultiple; + if ( IsEngineThreaded() ) + { + expandedServerTickMultiple += cl_interp_threadmodeticks.GetInt(); } if ( IsAnimatedEveryTick() && IsSimulatedEveryTick() ) { - return TICK_INTERVAL * serverTickMultiple; + return TICK_INTERVAL * expandedServerTickMultiple; } if ( ( flags & LATCH_ANIMATION_VAR ) && IsAnimatedEveryTick() ) { - return TICK_INTERVAL * serverTickMultiple; + return TICK_INTERVAL * expandedServerTickMultiple; } if ( ( flags & LATCH_SIMULATION_VAR ) && IsSimulatedEveryTick() ) { - return TICK_INTERVAL * serverTickMultiple; + return TICK_INTERVAL * expandedServerTickMultiple; } - return AdjustInterpolationAmount( this, TICK_INTERVAL * ( TIME_TO_TICKS( cl_interp.GetFloat() ) + serverTickMultiple ) ); + return AdjustInterpolationAmount( this, TICKS_TO_TIME( TIME_TO_TICKS( GetClientInterpAmount() ) + serverTickMultiple ) ); } @@ -5570,12 +5930,30 @@ void C_BaseEntity::GetToolRecordingState( KeyValues *msg ) static BaseEntityRecordingState_t state; state.m_flTime = gpGlobals->curtime; state.m_pModelName = modelinfo->GetModelName( GetModel() ); - state.m_nOwner = pOwner ? pOwner->entindex() : 0; + state.m_nOwner = pOwner ? pOwner->entindex() : -1; state.m_nEffects = m_fEffects; - state.m_bVisible = ShouldDraw(); + state.m_bVisible = ShouldDraw() && !IsDormant(); + state.m_bRecordFinalVisibleSample = false; state.m_vecRenderOrigin = GetRenderOrigin(); state.m_vecRenderAngles = GetRenderAngles(); + // use EF_NOINTERP if the owner or a hierarchical parent has NO_INTERP + if ( pOwner && pOwner->IsEffectActive( EF_NOINTERP ) ) + { + state.m_nEffects |= EF_NOINTERP; + } + C_BaseEntity *pParent = GetMoveParent(); + while ( pParent ) + { + if ( pParent->IsEffectActive( EF_NOINTERP ) ) + { + state.m_nEffects |= EF_NOINTERP; + break; + } + + pParent = pParent->GetMoveParent(); + } + msg->SetPtr( "baseentity", &state ); } @@ -5605,8 +5983,6 @@ void C_BaseEntity::RecordToolMessage() m_nLastRecordedFrame = gpGlobals->framecount; } -void PostToolMessage( HTOOLHANDLE hEntity, KeyValues *msg ); - // (static function) void C_BaseEntity::ToolRecordEntities() { @@ -5619,11 +5995,11 @@ void C_BaseEntity::ToolRecordEntities() int c = recordinglist->Count(); for ( int i = 0 ; i < c ; i++ ) { - C_BaseEntity *pEnt = recordinglist->Get( i ); - if ( !pEnt ) + IClientRenderable *pRenderable = recordinglist->Get( i ); + if ( !pRenderable ) continue; - pEnt->RecordToolMessage(); + pRenderable->RecordToolMessage(); } } @@ -5733,4 +6109,99 @@ void C_BaseEntity::RemoveVar( void *data, bool bAssert ) } } +void C_BaseEntity::CheckCLInterpChanged() +{ + float flCurValue_Interp = GetClientInterpAmount(); + static float flLastValue_Interp = flCurValue_Interp; + float flCurValue_InterpNPCs = cl_interp_npcs.GetFloat(); + static float flLastValue_InterpNPCs = flCurValue_InterpNPCs; + + if ( flLastValue_Interp != flCurValue_Interp || + flLastValue_InterpNPCs != flCurValue_InterpNPCs ) + { + flLastValue_Interp = flCurValue_Interp; + flLastValue_InterpNPCs = flCurValue_InterpNPCs; + + // Tell all the existing entities to update their interpolation amounts to account for the change. + C_BaseEntityIterator iterator; + C_BaseEntity *pEnt; + while ( (pEnt = iterator.Next()) != NULL ) + { + pEnt->Interp_UpdateInterpolationAmounts( pEnt->GetVarMapping() ); + } + } +} + +void C_BaseEntity::DontRecordInTools() +{ +#ifndef NO_TOOLFRAMEWORK + m_bRecordInTools = false; +#endif +} + +int C_BaseEntity::GetCreationTick() const +{ + return m_nCreationTick; +} + +//------------------------------------------------------------------------------ +void CC_CL_Find_Ent( const CCommand& args ) +{ + if ( args.ArgC() < 2 ) + { + Msg( "Format: cl_find_ent \n" ); + return; + } + + int iCount = 0; + const char *pszSubString = args[1]; + Msg("Searching for client entities with classname containing substring: '%s'\n", pszSubString ); + + C_BaseEntity *ent = NULL; + while ( (ent = ClientEntityList().NextBaseEntity(ent)) != NULL ) + { + const char *pszClassname = ent->GetClassname(); + + bool bMatches = false; + if ( pszClassname && pszClassname[0] ) + { + if ( Q_stristr( pszClassname, pszSubString ) ) + { + bMatches = true; + } + } + + if ( bMatches ) + { + iCount++; + Msg(" '%s' (entindex %d) %s \n", pszClassname ? pszClassname : "[NO NAME]", ent->entindex(), ent->IsDormant() ? "(DORMANT)" : "" ); + } + } + + Msg("Found %d matches.\n", iCount); +} +static ConCommand cl_find_ent("cl_find_ent", CC_CL_Find_Ent, "Find and list all client entities with classnames that contain the specified substring.\nFormat: cl_find_ent \n", FCVAR_CHEAT); + +//------------------------------------------------------------------------------ +void CC_CL_Find_Ent_Index( const CCommand& args ) +{ + if ( args.ArgC() < 2 ) + { + Msg( "Format: cl_find_ent_index \n" ); + return; + } + + int iIndex = atoi(args[1]); + C_BaseEntity *ent = ClientEntityList().GetBaseEntity( iIndex ); + if ( ent ) + { + const char *pszClassname = ent->GetClassname(); + Msg(" '%s' (entindex %d) %s \n", pszClassname ? pszClassname : "[NO NAME]", iIndex, ent->IsDormant() ? "(DORMANT)" : "" ); + } + else + { + Msg("Found no entity at %d.\n", iIndex); + } +} +static ConCommand cl_find_ent_index("cl_find_ent_index", CC_CL_Find_Ent_Index, "Display data for clientside entity matching specified index.\nFormat: cl_find_ent_index \n", FCVAR_CHEAT); diff --git a/src/src/cl_dll/c_baseentity.h b/src/src/game/client/c_baseentity.h similarity index 94% rename from src/src/cl_dll/c_baseentity.h rename to src/src/game/client/c_baseentity.h index 25b5f04..e7e9f1c 100644 --- a/src/src/cl_dll/c_baseentity.h +++ b/src/src/game/client/c_baseentity.h @@ -1,4 +1,4 @@ -//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: A base class for the client-side representation of entities. // @@ -7,7 +7,7 @@ // client. // // $NoKeywords: $ -//=============================================================================// +//===========================================================================// #ifndef C_BASEENTITY_H #define C_BASEENTITY_H @@ -15,7 +15,7 @@ #pragma once #endif -#include "vector.h" +#include "mathlib/vector.h" #include "IClientEntityInternal.h" #include "engine/IVModelRender.h" #include "client_class.h" @@ -31,7 +31,9 @@ #include "networkvar.h" #include "interpolatedvar.h" #include "collisionproperty.h" +#include "particle_property.h" #include "toolframework/itoolentity.h" +#include "tier0/threadtools.h" class C_Team; class IPhysicsObject; @@ -91,7 +93,8 @@ struct VarMapping_t } CUtlVector< VarMapEntry_t > m_Entries; - int m_nInterpolatedEntries; + int m_nInterpolatedEntries; + float m_lastInterpolationTime; }; @@ -173,7 +176,7 @@ class C_BaseEntity : public IClientEntity DECLARE_CLASS_NOBASE( C_BaseEntity ); friend class CPrediction; - friend void cc_cl_interp_all_changed( ConVar *var, const char *pOldString ); + friend void cc_cl_interp_all_changed( IConVar *pConVar, const char *pOldString, float flOldValue ); public: DECLARE_DATADESC(); @@ -191,10 +194,12 @@ public: virtual bool ShouldDrawWaterImpacts( void ) { return true; } virtual bool HandleShotImpactingWater( const FireBulletsInfo_t &info, const Vector &vecEnd, ITraceFilter *pTraceFilter, Vector *pVecTracerDest ); + virtual ITraceFilter* GetBeamTraceFilter( void ); virtual void DispatchTraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr ); virtual void TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr ); virtual void DoImpactEffect( trace_t &tr, int nDamageType ); virtual void MakeTracer( const Vector &vecTracerSrc, const trace_t &tr, int iTracerType ); + virtual int GetTracerAttachment( void ); void ComputeTracerStartPosition( const Vector &vecShotSrc, Vector *pVecTracerStart ); void TraceBleed( float flDamage, const Vector &vecDir, trace_t *ptr, int bitsDamageType ); virtual int BloodColor(); @@ -208,7 +213,8 @@ public: virtual void ParseMapData( CEntityMapData *mapData ); virtual bool KeyValue( const char *szKeyName, const char *szValue ); virtual bool KeyValue( const char *szKeyName, float flValue ); - virtual bool KeyValue( const char *szKeyName, Vector vec ); + virtual bool KeyValue( const char *szKeyName, const Vector &vecValue ); + virtual bool GetKeyValue( const char *szKeyName, char *szValue, int iMaxLen ); // Entities block Line-Of-Sight for NPCs by default. // Set this to false if you want to change this behavior. @@ -263,7 +269,11 @@ public: void SetToolRecording( bool recording ); bool IsToolRecording() const; bool HasRecordedThisFrame() const; - void RecordToolMessage(); + virtual void RecordToolMessage(); + + // used to exclude entities from being recorded in the SFM tools + void DontRecordInTools(); + bool ShouldRecordInTools() const; virtual void Release(); virtual ICollideable* GetCollideable() { return &m_Collision; } @@ -279,9 +289,12 @@ public: virtual const Vector& GetRenderOrigin( void ); virtual const QAngle& GetRenderAngles( void ); + virtual Vector GetObserverCamOrigin( void ) { return GetRenderOrigin(); } // Return the origin for player observers tracking this target virtual const matrix3x4_t & RenderableToWorldTransform(); virtual bool IsTransparent( void ); - virtual bool UsesFrameBufferTexture(); + virtual bool IsTwoPass( void ); + virtual bool UsesPowerOfTwoFrameBufferTexture(); + virtual bool UsesFullFrameBufferTexture(); virtual const model_t *GetModel( void ) const; virtual int DrawModel( int flags ); virtual void ComputeFxBlend( void ); @@ -296,6 +309,7 @@ public: // Determine the color modulation amount virtual void GetColorModulation( float* color ); + virtual void OnThreadedDrawSetup() {} public: virtual bool TestCollision( const Ray_t &ray, unsigned int fContentsMask, trace_t& tr ); virtual bool TestHitboxes( const Ray_t &ray, unsigned int fContentsMask, trace_t& tr ); @@ -325,6 +339,10 @@ public: virtual void SetDormant( bool bDormant ); virtual bool IsDormant( void ); + // Tells the entity that it's about to be destroyed due to the client receiving + // an uncompressed update that's caused it to destroy all entities & recreate them. + virtual void SetDestroyedOnRecreateEntities( void ); + virtual int GetEFlags() const; virtual void SetEFlags( int iEFlags ); void AddEFlags( int nEFlagMask ); @@ -367,6 +385,8 @@ public: // An inline version the game code can use CCollisionProperty *CollisionProp(); const CCollisionProperty*CollisionProp() const; + CParticleProperty *ParticleProp(); + const CParticleProperty *ParticleProp() const; // Simply here for game shared bool IsFloating(); @@ -421,11 +441,13 @@ public: virtual void VPhysicsUpdate( IPhysicsObject *pPhysics ); inline IPhysicsObject *VPhysicsGetObject( void ) const { return m_pPhysicsObject; } virtual int VPhysicsGetObjectList( IPhysicsObject **pList, int listMax ); + virtual bool VPhysicsIsFlesh( void ); // IClientEntity implementation. public: virtual bool SetupBones( matrix3x4_t *pBoneToWorldOut, int nMaxBones, int boneMask, float currentTime ); - virtual void SetupWeights( void ); + virtual void SetupWeights( const matrix3x4_t *pBoneToWorld, int nFlexWeightCount, float *pFlexWeights, float *pFlexDelayedWeights ); + virtual bool UsesFlexDelayedWeights() { return false; } virtual void DoAnimationEvents( void ); // Add entity to visible entities list? @@ -538,11 +560,13 @@ public: // Attachments virtual int LookupAttachment( const char *pAttachmentName ) { return -1; } virtual bool GetAttachment( int number, matrix3x4_t &matrix ); + virtual bool GetAttachment( int number, Vector &origin ); virtual bool GetAttachment( int number, Vector &origin, QAngle &angles ); + virtual bool GetAttachmentVelocity( int number, Vector &originVel, Quaternion &angleVel ); // Team handling virtual C_Team *GetTeam( void ); - virtual int GetTeamNumber( void ); + virtual int GetTeamNumber( void ) const; virtual void ChangeTeam( int iTeamNum ); // Assign this entity to a team. virtual int GetRenderTeamNumber( void ); virtual bool InSameTeam( C_BaseEntity *pEntity ); // Returns true if the specified entity is on the same team as this one @@ -652,7 +676,7 @@ public: // The value returned by here determines whether or not (and how) the entity // is put into the spatial partition. - virtual CollideType_t ShouldCollide(); + virtual CollideType_t GetCollideType( void ); virtual bool ShouldDraw(); inline bool IsVisible() const { return m_hRender != INVALID_CLIENT_RENDER_HANDLE; } @@ -665,8 +689,12 @@ public: // Set appropriate flags and store off data when these fields are about to change virtual void OnLatchInterpolatedVariables( int flags ); + // For predictable entities, stores last networked value + void OnStoreLastNetworkedValue(); + // Initialize things given a new model. virtual CStudioHdr *OnNewModel(); + virtual void OnNewParticleEffect( const char *pszParticleName, CNewParticleEffect *pNewParticleEffect ); bool IsSimulatedEveryTick() const; bool IsAnimatedEveryTick() const; @@ -682,8 +710,6 @@ public: // Interpolate the position for rendering virtual bool Interpolate( float currentTime ); - // reset interpolant optimizations to force stuff to interpolate - void ForceAllInterpolate(); // Did the object move so far that it shouldn't interpolate? bool Teleported( void ); // Is this a submodel of the world ( *1 etc. in name ) ( brush models only ) @@ -697,7 +723,8 @@ public: // Reset internal fields virtual void Clear( void ); // Helper to draw raw brush models - virtual int DrawBrushModel( bool sort ); + virtual int DrawBrushModel( bool bSort, bool bShadowDepth ); + // returns the material animation start time virtual float GetTextureAnimationStartTime(); // Indicates that a texture animation has wrapped @@ -793,7 +820,9 @@ public: // interface function pointers void (C_BaseEntity::*m_pfnThink)(void); virtual void Think( void ) - { + { + AssertMsg( m_pfnThink != &C_BaseEntity::Think, "Infinite recursion is infinitely bad." ); + if ( m_pfnThink ) { ( this->*m_pfnThink )(); @@ -850,6 +879,7 @@ public: void UnsetPlayerSimulated( void ); #endif + // Sorry folks, here lies TF2-specific stuff that really has no other place to go virtual bool CanBePoweredUp( void ) { return false; } virtual bool AttemptToPowerup( int iPowerup, float flTime, float flAmount = 0, C_BaseEntity *pAttacker = NULL, CDamageModifier *pDamageModifier = NULL ) { return false; } @@ -958,12 +988,16 @@ public: ///////////////// virtual bool IsPlayer( void ) const { return false; }; + virtual bool IsBot( void ) const { return ((GetFlags() & FL_FAKECLIENT) == FL_FAKECLIENT) ? true : false; } virtual bool IsBaseCombatCharacter( void ) { return false; }; virtual C_BaseCombatCharacter *MyCombatCharacterPointer( void ) { return NULL; } virtual bool IsNPC( void ) { return false; } C_AI_BaseNPC *MyNPCPointer( void ); + // TF2 specific virtual bool IsBaseObject( void ) const { return false; } + virtual bool IsBaseTrain( void ) const { return false; } + // Returns the eye point + angles (used for viewing + shooting) virtual Vector EyePosition( void ); virtual const QAngle& EyeAngles( void ); // Direction of eyes @@ -1077,6 +1111,7 @@ public: void CheckHasGamePhysicsSimulation(); bool WillThink(); bool WillSimulateGamePhysics(); + int GetFirstThinkTick(); // get first tick thinking on any context float GetAnimTime() const; void SetAnimTime( float at ); @@ -1084,20 +1119,22 @@ public: float GetSimulationTime() const; void SetSimulationTime( float st ); + int GetCreationTick() const; + #ifdef _DEBUG - void FunctionCheck( void *pFunction, char *name ); + void FunctionCheck( void *pFunction, const char *name ); ENTITYFUNCPTR TouchSet( ENTITYFUNCPTR func, char *name ) { //COMPILE_TIME_ASSERT( sizeof(func) == 4 ); m_pfnTouch = func; - //FunctionCheck( (void *)*((int *)((char *)this + ( offsetof(C_BaseEntity,m_pfnTouch)))), name ); + //FunctionCheck( *(reinterpret_cast(&m_pfnTouch)), name ); return func; } #endif // Gets the model instance + shadow handle - ModelInstanceHandle_t GetModelInstance() { return m_ModelInstance; } + virtual ModelInstanceHandle_t GetModelInstance() { return m_ModelInstance; } void SetModelInstance( ModelInstanceHandle_t hInstance) { m_ModelInstance = hInstance; } bool SnatchModelInstance( C_BaseEntity * pToEntity ); virtual ClientShadowHandle_t GetShadowHandle() const { return m_ShadowHandle; } @@ -1152,6 +1189,7 @@ public: static void SetPredictionRandomSeed( const CUserCmd *cmd ); static C_BasePlayer *GetPredictionPlayer( void ); static void SetPredictionPlayer( C_BasePlayer *player ); + static void CheckCLInterpChanged(); // Collision group accessors int GetCollisionGroup() const; @@ -1305,10 +1343,7 @@ public: void HierarchyUpdateMoveParent(); protected: - -#ifdef _DEBUG int m_nFXComputeFrame; -#endif // FIXME: Should I move the functions handling these out of C_ClientEntity // and into C_BaseEntity? Then we could make these private. @@ -1322,6 +1357,7 @@ private: bool m_bToolRecording; HTOOLHANDLE m_ToolHandle; int m_nLastRecordedFrame; + bool m_bRecordInTools; // should this entity be recorded in the tools (we exclude some things like models for menus) #endif protected: @@ -1380,7 +1416,6 @@ private: // Computes absolute position based on hierarchy void CalcAbsolutePosition( ); void CalcAbsoluteVelocity(); - void CalcAbsoluteAngularVelocity(); // Computes new angles based on the angular velocity void SimulateAngles( float flFrameTime ); @@ -1460,8 +1495,8 @@ private: int m_iEFlags; // entity flags EFL_* // Object movetype - MoveType_t m_MoveType; - MoveCollide_t m_MoveCollide; + unsigned char m_MoveType; + unsigned char m_MoveCollide; unsigned char m_iParentAttachment; // 0 if we're relative to the parent's absorigin and absangles. unsigned char m_iOldParentAttachment; @@ -1487,6 +1522,7 @@ private: string_t m_ModelName; CNetworkVarEmbedded( CCollisionProperty, m_Collision ); + CNetworkVarEmbedded( CParticleProperty, m_Particles ); // Physics state float m_flElasticity; @@ -1531,6 +1567,7 @@ private: // For storing prediction results and pristine network state byte *m_pIntermediateData[ MULTIPLAYER_BACKUP ]; byte *m_pOriginalData; + int m_nIntermediateDataCount; bool m_bIsPlayerSimulated; #endif @@ -1571,6 +1608,7 @@ private: int m_fDataObjectTypes; AimEntsListHandle_t m_AimEntsListHandle; + int m_nCreationTick; public: @@ -1587,12 +1625,19 @@ protected: void AddToTeleportList(); void RemoveFromTeleportList(); unsigned short m_TeleportListEntry; + + CThreadFastMutex m_CalcAbsolutePositionMutex; + CThreadFastMutex m_CalcAbsoluteVelocityMutex; }; EXTERN_RECV_TABLE(DT_BaseEntity); inline bool FClassnameIs( C_BaseEntity *pEntity, const char *szClassname ) { + Assert( pEntity ); + if ( pEntity == NULL ) + return false; + return !strcmp( pEntity->GetClassname(), szClassname ) ? true : false; } @@ -1621,6 +1666,18 @@ inline const CCollisionProperty *C_BaseEntity::CollisionProp() const return &m_Collision; } +//----------------------------------------------------------------------------- +// An inline version the game code can use +//----------------------------------------------------------------------------- +inline CParticleProperty *C_BaseEntity::ParticleProp() +{ + return &m_Particles; +} + +inline const CParticleProperty *C_BaseEntity::ParticleProp() const +{ + return &m_Particles; +} //----------------------------------------------------------------------------- // Purpose: Returns whether this entity was created on the client. @@ -2022,6 +2079,20 @@ inline bool C_BaseEntity::IsEnabledInToolView() const #endif } +//----------------------------------------------------------------------------- +// Purpose: +// Input : - +// Output : inline bool +//----------------------------------------------------------------------------- +inline bool C_BaseEntity::ShouldRecordInTools() const +{ +#ifndef NO_TOOLFRAMEWORK + return m_bRecordInTools; +#else + return true; +#endif +} + C_BaseEntity *CreateEntityByName( const char *className ); #endif // C_BASEENTITY_H diff --git a/src/src/cl_dll/c_baseflex.cpp b/src/src/game/client/c_baseflex.cpp similarity index 68% rename from src/src/cl_dll/c_baseflex.cpp rename to src/src/game/client/c_baseflex.cpp index 92dcafb..eb3a4af 100644 --- a/src/src/cl_dll/c_baseflex.cpp +++ b/src/src/game/client/c_baseflex.cpp @@ -19,10 +19,13 @@ #include "choreoevent.h" #include "choreoscene.h" #include "choreoactor.h" +#include "toolframework_client.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" +bool UseHWMorphVCDs(); + ConVar g_CV_PhonemeDelay("phonemedelay", "0", 0, "Phoneme delay to account for sound system latency." ); ConVar g_CV_PhonemeFilter("phonemefilter", "0.08", 0, "Time duration of box filter to pass over phonemes." ); ConVar g_CV_FlexRules("flex_rules", "1", 0, "Allow flex animation rules to run." ); @@ -42,6 +45,9 @@ IMPLEMENT_CLIENTCLASS_DT(C_BaseFlex, DT_BaseFlex, CBaseFlex) RecvPropFloat( RECVINFO(m_vecViewOffset[0]) ), RecvPropFloat( RECVINFO(m_vecViewOffset[1]) ), RecvPropFloat( RECVINFO(m_vecViewOffset[2]) ), + + RecvPropVector(RECVINFO(m_vecLean)), + RecvPropVector(RECVINFO(m_vecShift)), #endif END_RECV_TABLE() @@ -64,7 +70,60 @@ BEGIN_PREDICTION_DATA( C_BaseFlex ) END_PREDICTION_DATA() -C_BaseFlex::C_BaseFlex() : m_iv_viewtarget( "C_BaseFlex::m_iv_viewtarget" ), m_iv_flexWeight("C_BaseFlex:m_iv_flexWeight" ), +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool GetHWMExpressionFileName( const char *pFilename, char *pHWMFilename ) +{ + // Are we even using hardware morph? + if ( !UseHWMorphVCDs() ) + return false; + + // Do we have a valid filename? + if ( !( pFilename && pFilename[0] ) ) + return false; + + // Check to see if we already have an player/hwm/* filename. + if ( ( V_strstr( pFilename, "player/hwm" ) != NULL ) || ( V_strstr( pFilename, "player\\hwm" ) != NULL ) ) + { + V_strcpy( pHWMFilename, pFilename ); + return true; + } + + // Find the hardware morph scene name and pass that along as well. + char szExpression[MAX_PATH]; + V_strcpy( szExpression, pFilename ); + + char szExpressionHWM[MAX_PATH]; + szExpressionHWM[0] = '\0'; + + char *pszToken = strtok( szExpression, "/\\" ); + while ( pszToken != NULL ) + { + V_strcat( szExpressionHWM, pszToken, sizeof( szExpressionHWM ) ); + if ( !V_stricmp( pszToken, "player" ) ) + { + V_strcat( szExpressionHWM, "\\hwm", sizeof( szExpressionHWM ) ); + } + + pszToken = strtok( NULL, "/\\" ); + if ( pszToken != NULL ) + { + V_strcat( szExpressionHWM, "\\", sizeof( szExpressionHWM ) ); + } + } + + V_strcpy( pHWMFilename, szExpressionHWM ); + return true; +} + +C_BaseFlex::C_BaseFlex() : + m_iv_viewtarget( "C_BaseFlex::m_iv_viewtarget" ), + m_iv_flexWeight("C_BaseFlex:m_iv_flexWeight" ), +#ifdef HL2_CLIENT_DLL + m_iv_vecLean("C_BaseFlex:m_iv_vecLean" ), + m_iv_vecShift("C_BaseFlex:m_iv_vecShift" ), +#endif m_LocalToGlobal( 0, 0, FlexSettingLessFunc ) { #ifdef _DEBUG @@ -75,22 +134,18 @@ C_BaseFlex::C_BaseFlex() : m_iv_viewtarget( "C_BaseFlex::m_iv_viewtarget" ), m_i AddVar( m_flexWeight, &m_iv_flexWeight, LATCH_ANIMATION_VAR ); // Fill in phoneme class lookup - memset( m_PhonemeClasses, 0, sizeof( m_PhonemeClasses ) ); - - Emphasized_Phoneme *weak = &m_PhonemeClasses[ PHONEME_CLASS_WEAK ]; - Q_strncpy( weak->classname, "phonemes_weak", sizeof( weak->classname ) ); - weak->required = false; - Emphasized_Phoneme *normal = &m_PhonemeClasses[ PHONEME_CLASS_NORMAL ]; - Q_strncpy( normal->classname, "phonemes", sizeof( normal->classname ) ); - normal->required = true; - Emphasized_Phoneme *strong = &m_PhonemeClasses[ PHONEME_CLASS_STRONG ]; - Q_strncpy( strong->classname, "phonemes_strong", sizeof( strong->classname ) ); - strong->required = false; + SetupMappings( "phonemes" ); m_flFlexDelayedWeight = NULL; /// Make sure size is correct Assert( PHONEME_CLASS_STRONG + 1 == NUM_PHONEME_CLASSES ); + +#ifdef HL2_CLIENT_DLL + // Get general lean vector + AddVar( &m_vecLean, &m_iv_vecLean, LATCH_ANIMATION_VAR ); + AddVar( &m_vecShift, &m_iv_vecShift, LATCH_ANIMATION_VAR ); +#endif } C_BaseFlex::~C_BaseFlex() @@ -100,6 +155,35 @@ C_BaseFlex::~C_BaseFlex() m_LocalToGlobal.RemoveAll(); } + +void C_BaseFlex::Spawn() +{ + BaseClass::Spawn(); + + InitPhonemeMappings(); +} + +// TF Player overrides all of these with class specific files +void C_BaseFlex::InitPhonemeMappings() +{ + SetupMappings( "phonemes" ); +} + +void C_BaseFlex::SetupMappings( char const *pchFileRoot ) +{ + // Fill in phoneme class lookup + memset( m_PhonemeClasses, 0, sizeof( m_PhonemeClasses ) ); + + Emphasized_Phoneme *normal = &m_PhonemeClasses[ PHONEME_CLASS_NORMAL ]; + Q_snprintf( normal->classname, sizeof( normal->classname ), "%s", pchFileRoot ); + normal->required = true; + + Emphasized_Phoneme *weak = &m_PhonemeClasses[ PHONEME_CLASS_WEAK ]; + Q_snprintf( weak->classname, sizeof( weak->classname ), "%s_weak", pchFileRoot ); + Emphasized_Phoneme *strong = &m_PhonemeClasses[ PHONEME_CLASS_STRONG ]; + Q_snprintf( strong->classname, sizeof( strong->classname ), "%s_strong", pchFileRoot ); +} + //----------------------------------------------------------------------------- // Purpose: initialize fast lookups when model changes //----------------------------------------------------------------------------- @@ -110,8 +194,9 @@ CStudioHdr *C_BaseFlex::OnNewModel() // init to invalid setting m_iBlink = -1; - m_iEyeUpdown = -1; - m_iEyeRightleft = -1; + m_iEyeUpdown = LocalFlexController_t(-1); + m_iEyeRightleft = LocalFlexController_t(-1); + m_bSearchedForEyeFlexes = false; m_iMouthAttachment = 0; delete[] m_flFlexDelayedWeight; @@ -138,6 +223,56 @@ CStudioHdr *C_BaseFlex::OnNewModel() } +void C_BaseFlex::StandardBlendingRules( CStudioHdr *hdr, Vector pos[], Quaternion q[], float currentTime, int boneMask ) +{ + BaseClass::StandardBlendingRules( hdr, pos, q, currentTime, boneMask ); + +#ifdef HL2_CLIENT_DLL + // shift pelvis, rotate body + if (hdr->GetNumIKChains() != 0 && (m_vecShift.x != 0.0 || m_vecShift.y != 0.0)) + { + //CIKContext auto_ik; + //auto_ik.Init( hdr, GetRenderAngles(), GetRenderOrigin(), currentTime, gpGlobals->framecount, boneMask ); + //auto_ik.AddAllLocks( pos, q ); + + matrix3x4_t rootxform; + AngleMatrix( GetRenderAngles(), GetRenderOrigin(), rootxform ); + + Vector localShift; + VectorIRotate( m_vecShift, rootxform, localShift ); + Vector localLean; + VectorIRotate( m_vecLean, rootxform, localLean ); + + Vector p0 = pos[0]; + float length = VectorNormalize( p0 ); + + // shift the root bone, but keep the height off the origin the same + Vector shiftPos = pos[0] + localShift; + VectorNormalize( shiftPos ); + Vector leanPos = pos[0] + localLean; + VectorNormalize( leanPos ); + pos[0] = shiftPos * length; + + // rotate the root bone based on how much it was "leaned" + Vector p1; + CrossProduct( p0, leanPos, p1 ); + float sinAngle = VectorNormalize( p1 ); + float cosAngle = DotProduct( p0, leanPos ); + float angle = atan2( sinAngle, cosAngle ) * 180 / M_PI; + Quaternion q1; + angle = clamp( angle, -45, 45 ); + AxisAngleQuaternion( p1, angle, q1 ); + QuaternionMult( q1, q[0], q[0] ); + QuaternionNormalize( q[0] ); + + // DevMsgRT( " (%.2f) %.2f %.2f %.2f\n", angle, p1.x, p1.y, p1.z ); + // auto_ik.SolveAllLocks( pos, q ); + } +#endif +} + + + //----------------------------------------------------------------------------- // Purpose: place "voice" sounds on mouth //----------------------------------------------------------------------------- @@ -153,7 +288,7 @@ bool C_BaseFlex::GetSoundSpatialization( SpatializationInfo_t& info ) Vector origin; QAngle angles; - C_BaseAnimating::PushAllowBoneAccess( true, false ); + C_BaseAnimating::AutoAllowBoneAccess boneaccess( true, false ); if (GetAttachment( m_iMouthAttachment, origin, angles )) { @@ -167,8 +302,6 @@ bool C_BaseFlex::GetSoundSpatialization( SpatializationInfo_t& info ) *info.pAngles = angles; } } - - C_BaseAnimating::PopBoneAccess(); } } @@ -221,6 +354,52 @@ public: FindSceneFile( NULL, "random", true ); FindSceneFile( NULL, "randomAlert", true ); #endif + +#if defined( TF_CLIENT_DLL ) + // HACK TO ALL TF TO HAVE PER CLASS OVERRIDES + char const *pTFClasses[] = + { + "scout", + "sniper", + "soldier", + "demo", + "medic", + "heavy", + "pyro", + "spy", + "engineer", + }; + + char fn[ MAX_PATH ]; + for ( int i = 0; i < ARRAYSIZE( pTFClasses ); ++i ) + { + Q_snprintf( fn, sizeof( fn ), "player/%s/phonemes/phonemes", pTFClasses[i] ); + FindSceneFile( NULL, fn, true ); + Q_snprintf( fn, sizeof( fn ), "player/%s/phonemes/phonemes_weak", pTFClasses[i] ); + FindSceneFile( NULL, fn, true ); + Q_snprintf( fn, sizeof( fn ), "player/%s/phonemes/phonemes_strong", pTFClasses[i] ); + FindSceneFile( NULL, fn, true ); + + if ( !IsX360() ) + { + Q_snprintf( fn, sizeof( fn ), "player/hwm/%s/phonemes/phonemes", pTFClasses[i] ); + FindSceneFile( NULL, fn, true ); + Q_snprintf( fn, sizeof( fn ), "player/hwm/%s/phonemes/phonemes_weak", pTFClasses[i] ); + FindSceneFile( NULL, fn, true ); + Q_snprintf( fn, sizeof( fn ), "player/hwm/%s/phonemes/phonemes_strong", pTFClasses[i] ); + FindSceneFile( NULL, fn, true ); + } + + Q_snprintf( fn, sizeof( fn ), "player/%s/emotion/emotion", pTFClasses[i] ); + FindSceneFile( NULL, fn, true ); + if ( !IsX360() ) + { + Q_snprintf( fn, sizeof( fn ), "player/hwm/%s/emotion/emotion", pTFClasses[i] ); + FindSceneFile( NULL, fn, true ); + } + } +#endif + return true; } @@ -249,12 +428,26 @@ public: void *FindSceneFile( C_BaseFlex *instance, const char *filename, bool allowBlockingIO ) { + char szFilename[MAX_PATH]; + Assert( V_strlen( filename ) < MAX_PATH ); + V_strcpy( szFilename, filename ); + +#if defined( TF_CLIENT_DLL ) + char szHWMFilename[MAX_PATH]; + if ( GetHWMExpressionFileName( szFilename, szHWMFilename ) ) + { + V_strcpy( szFilename, szHWMFilename ); + } +#endif + + Q_FixSlashes( szFilename ); + // See if it's already loaded int i; for ( i = 0; i < m_FileList.Count(); i++ ) { CFlexSceneFile *file = m_FileList[ i ]; - if ( file && !stricmp( file->filename, filename ) ) + if ( file && !Q_stricmp( file->filename, szFilename ) ) { // Make sure translations (local to global flex controller) are set up for this instance EnsureTranslations( instance, ( const flexsettinghdr_t * )file->buffer ); @@ -269,7 +462,7 @@ public: // Load file into memory void *buffer = NULL; - int len = filesystem->ReadFileEx( VarArgs( "expressions/%s.vfe", filename ), "GAME", &buffer ); + int len = filesystem->ReadFileEx( VarArgs( "expressions/%s.vfe", szFilename ), "GAME", &buffer ); if ( !len ) return NULL; @@ -277,12 +470,47 @@ public: // Create scene entry CFlexSceneFile *pfile = new CFlexSceneFile; // Remember filename - Q_strncpy( pfile->filename, filename, sizeof( pfile->filename ) ); + Q_strncpy( pfile->filename, szFilename, sizeof( pfile->filename ) ); // Remember data pointer pfile->buffer = buffer; // Add to list m_FileList.AddToTail( pfile ); + // Swap the entire file + if ( IsX360() ) + { + CByteswap swap; + swap.ActivateByteSwapping( true ); + byte *pData = (byte*)buffer; + flexsettinghdr_t *pHdr = (flexsettinghdr_t*)pData; + swap.SwapFieldsToTargetEndian( pHdr ); + + // Flex Settings + flexsetting_t *pFlexSetting = (flexsetting_t*)((byte*)pHdr + pHdr->flexsettingindex); + for ( int i = 0; i < pHdr->numflexsettings; ++i, ++pFlexSetting ) + { + swap.SwapFieldsToTargetEndian( pFlexSetting ); + + flexweight_t *pWeight = (flexweight_t*)(((byte*)pFlexSetting) + pFlexSetting->settingindex ); + for ( int j = 0; j < pFlexSetting->numsettings; ++j, ++pWeight ) + { + swap.SwapFieldsToTargetEndian( pWeight ); + } + } + + // indexes + pData = (byte*)pHdr + pHdr->indexindex; + swap.SwapBufferToTargetEndian( (int*)pData, (int*)pData, pHdr->numindexes ); + + // keymappings + pData = (byte*)pHdr + pHdr->keymappingindex; + swap.SwapBufferToTargetEndian( (int*)pData, (int*)pData, pHdr->numkeys ); + + // keyname indices + pData = (byte*)pHdr + pHdr->keynameindex; + swap.SwapBufferToTargetEndian( (int*)pData, (int*)pData, pHdr->numkeys ); + } + // Fill in translation table EnsureTranslations( instance, ( const flexsettinghdr_t * )pfile->buffer ); @@ -328,11 +556,22 @@ Vector C_BaseFlex::SetViewTarget( CStudioHdr *pStudioHdr ) // aim the eyes Vector tmp = m_viewtarget; - if (m_iEyeUpdown == -1) - m_iEyeUpdown = AddGlobalFlexController( "eyes_updown" ); + if ( !m_bSearchedForEyeFlexes ) + { + m_bSearchedForEyeFlexes = true; - if (m_iEyeRightleft == -1) - m_iEyeRightleft = AddGlobalFlexController( "eyes_rightleft" ); + m_iEyeUpdown = FindFlexController( "eyes_updown" ); + m_iEyeRightleft = FindFlexController( "eyes_rightleft" ); + + if ( m_iEyeUpdown != -1 ) + { + pStudioHdr->pFlexcontroller( m_iEyeUpdown )->localToGlobal = AddGlobalFlexController( "eyes_updown" ); + } + if ( m_iEyeRightleft != -1 ) + { + pStudioHdr->pFlexcontroller( m_iEyeRightleft )->localToGlobal = AddGlobalFlexController( "eyes_rightleft" ); + } + } if (m_iEyeAttachment > 0) { @@ -356,14 +595,16 @@ Vector C_BaseFlex::SetViewTarget( CStudioHdr *pStudioHdr ) // calculate animated eye deflection Vector eyeDeflect; QAngle eyeAng( 0, 0, 0 ); - if ( m_iEyeUpdown != -1) + if ( m_iEyeUpdown != -1 ) { - eyeAng.x = g_flexweight[ m_iEyeUpdown ]; + mstudioflexcontroller_t *pflex = pStudioHdr->pFlexcontroller( m_iEyeUpdown ); + eyeAng.x = g_flexweight[ pflex->localToGlobal ]; } - if ( m_iEyeRightleft != -1) + if ( m_iEyeRightleft != -1 ) { - eyeAng.y = g_flexweight[ m_iEyeRightleft ]; + mstudioflexcontroller_t *pflex = pStudioHdr->pFlexcontroller( m_iEyeRightleft ); + eyeAng.y = g_flexweight[ pflex->localToGlobal ]; } // debugoverlay->AddTextOverlay( GetAbsOrigin() + Vector( 0, 0, 64 ), 0, 0, "%5.3f %5.3f", eyeAng.x, eyeAng.y ); @@ -377,17 +618,18 @@ Vector C_BaseFlex::SetViewTarget( CStudioHdr *pStudioHdr ) local = local + eyeDeflect; VectorNormalize( local ); - // check to see if the eye is aiming outside a 30 degree cone - if (local.x < 0.866) // cos(30) + // check to see if the eye is aiming outside the max eye deflection + float flMaxEyeDeflection = pStudioHdr->MaxEyeDeflection(); + if ( local.x < flMaxEyeDeflection ) { // if so, clamp it to 30 degrees offset // debugoverlay->AddTextOverlay( GetAbsOrigin() + Vector( 0, 0, 64 ), 1, 0, "%5.3f %5.3f %5.3f", local.x, local.y, local.z ); local.x = 0; float d = local.LengthSqr(); - if (d > 0.0) + if ( d > 0.0f ) { - d = sqrtf( (1.0 - 0.866 * 0.866) / (local.y*local.y + local.z*local.z) ); - local.x = 0.866; + d = sqrtf( ( 1.0f - flMaxEyeDeflection * flMaxEyeDeflection ) / ( local.y*local.y + local.z*local.z ) ); + local.x = flMaxEyeDeflection; local.y = local.y * d; local.z = local.z * d; } @@ -400,7 +642,7 @@ Vector C_BaseFlex::SetViewTarget( CStudioHdr *pStudioHdr ) VectorTransform( local, attToWorld, tmp ); } - modelrender->SetViewTarget( tmp ); + modelrender->SetViewTarget( GetModelPtr(), GetBody(), tmp ); /* debugoverlay->AddTextOverlay( GetAbsOrigin() + Vector( 0, 0, 64 ), 0, 0, "%.2f %.2f %.2f : %.2f %.2f %.2f", @@ -411,32 +653,6 @@ Vector C_BaseFlex::SetViewTarget( CStudioHdr *pStudioHdr ) return tmp; } -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -static void NewMarkovIndex( flexsetting_t *pSetting ) -{ - if ( pSetting->type != FS_MARKOV ) - return; - - int weighttotal = 0; - int member = 0; - for (int i = 0; i < pSetting->numsettings; i++) - { - flexmarkovgroup_t *group = pSetting->pMarkovGroup( i ); - if ( !group ) - continue; - - weighttotal += group->weight; - if ( !weighttotal || random->RandomInt(0,weighttotal-1) < group->weight ) - { - member = i; - } - } - - pSetting->currentindex = member; -} - #define STRONG_CROSSFADE_START 0.60f #define WEAK_CROSSFADE_START 0.40f @@ -452,7 +668,7 @@ static void NewMarkovIndex( flexsetting_t *pSetting ) //----------------------------------------------------------------------------- void C_BaseFlex::ComputeBlendedSetting( Emphasized_Phoneme *classes, float emphasis_intensity ) { - // See which overrides are available for the current phoneme + // See which blends are available for the current phoneme bool has_weak = classes[ PHONEME_CLASS_WEAK ].valid; bool has_strong = classes[ PHONEME_CLASS_STRONG ].valid; @@ -528,56 +744,19 @@ void C_BaseFlex::AddViseme( Emphasized_Phoneme *classes, float emphasis_intensit if ( !info->valid || info->amount == 0.0f ) continue; - // Assume that we're not using overrieds const flexsettinghdr_t *actual_flexsetting_header = info->base; - const flexsetting_t *pSetting = actual_flexsetting_header->pIndexedSetting( phoneme ); if (!pSetting) { continue; } - if ( newexpression ) - { - if ( pSetting->type == FS_MARKOV ) - { - NewMarkovIndex( ( flexsetting_t * )pSetting ); - } - } - - // Determine its index - int i = pSetting - actual_flexsetting_header->pSetting( 0 ); - Assert( i >= 0 ); - Assert( i < actual_flexsetting_header->numflexsettings ); - - // Resolve markov chain for the returned setting, probably not an issue for visemes - pSetting = actual_flexsetting_header->pTranslatedSetting( i ); -#if !defined( NO_ENTITY_PREDICTION ) - // Check for overrides - if ( info->override ) - { - // Get name from setting - const char *resolvedName = pSetting->pszName(); - if ( resolvedName ) - { - // See if resolvedName exists in the override file - const flexsetting_t *override = FindNamedSetting( info->override, resolvedName ); - if ( override ) - { - // If so, point at the override file instead - actual_flexsetting_header = info->override; - pSetting = override; - } - } - } -#endif - flexweight_t *pWeights = NULL; int truecount = pSetting->psetting( (byte *)actual_flexsetting_header, 0, &pWeights ); if ( pWeights ) { - for (i = 0; i < truecount; i++) + for ( int i = 0; i < truecount; i++) { // Translate to global controller number int j = FlexControllerLocalToGlobal( actual_flexsetting_header, pWeights->key ); @@ -617,9 +796,6 @@ bool C_BaseFlex::SetupEmphasisBlend( Emphasized_Phoneme *classes, int phoneme ) info->basechecked = true; info->base = (flexsettinghdr_t *)FindSceneFile( info->classname ); } -#if !defined( NO_ENTITY_PREDICTION ) - info->override = NULL; -#endif info->exp = NULL; if ( info->base ) { @@ -637,38 +813,6 @@ bool C_BaseFlex::SetupEmphasisBlend( Emphasized_Phoneme *classes, int phoneme ) { info->valid = true; } - -// NOTE: We never actually used any overrides in HL2/Aftermath, so doing this disk check could lead to hitches due to calling filesystem->Open on each -// possibility. If we ever need to use these overrides, I would suggest adding a flag on the server to the keyvalues for NPCs specifying "use overrides", -// networking the flag down, and then only checking for overrides if the flag is set on the client. ALternateley, we could crawl the expressions folders -// with findfirst/next and find all override files and create a database, we'd do that at startup if we did it. However, that would add a bit of time to startup -// due to recursively crawling the directories (though we could just enumerate dirs off of the expressions dir...). -// ywb 2/8/06 -#if 0 -#if !defined( NO_ENTITY_PREDICTION ) - // Find overrides, if any exist - // Also a one-time setup - if ( !info->overridechecked ) - { - char overridefile[ 512 ]; - char shortname[ 128 ]; - char modelname[ 128 ]; - - Q_strncpy( modelname, modelinfo->GetModelName( GetModel() ), sizeof( modelname ) ); - - // Fix up the name - Q_FileBase( modelname, shortname, sizeof( shortname ) ); - - Q_snprintf( overridefile, sizeof( overridefile ), "%s/%s", shortname, info->classname ); - - info->overridechecked = true; - info->override = ( flexsettinghdr_t * )FindSceneFile( overridefile ); - } -#else - info->overridechecked = true; - info->override = 0; -#endif -#endif } return skip; @@ -682,7 +826,7 @@ bool C_BaseFlex::SetupEmphasisBlend( Emphasized_Phoneme *classes, int phoneme ) // dt - // juststarted - //----------------------------------------------------------------------------- -ConVar g_CV_PhonemeSnap("phonemesnap", "1", 0, "Don't force visemes to always consider two phonemes, regardless of duration." ); +ConVar g_CV_PhonemeSnap("phonemesnap", "2", 0, "Lod at level at which visemes stops always considering two phonemes, regardless of duration." ); void C_BaseFlex::AddVisemesForSentence( Emphasized_Phoneme *classes, float emphasis_intensity, CSentence *sentence, float t, float dt, bool juststarted ) { CStudioHdr *hdr = GetModelPtr(); @@ -696,14 +840,42 @@ void C_BaseFlex::AddVisemesForSentence( Emphasized_Phoneme *classes, float empha { const CBasePhonemeTag *phoneme = sentence->GetRuntimePhoneme( k ); - if ((!g_CV_PhonemeSnap.GetBool() || (hdr->flags() & STUDIOHDR_FLAGS_FORCE_PHONEME_CROSSFADE)) && t > phoneme->GetStartTime() && t < phoneme->GetEndTime()) + if (t > phoneme->GetStartTime() && t < phoneme->GetEndTime()) { - if (k < pcount-1) + bool bCrossfade = true; + if ((hdr->flags() & STUDIOHDR_FLAGS_FORCE_PHONEME_CROSSFADE) == 0) { - const CBasePhonemeTag *next = sentence->GetRuntimePhoneme( k + 1 ); - if ( next ) + if (m_iAccumulatedBoneMask & BONE_USED_BY_VERTEX_LOD0) { - dt = max( dt, min( next->GetEndTime() - t, phoneme->GetEndTime() - phoneme->GetStartTime() ) ); + bCrossfade = (g_CV_PhonemeSnap.GetInt() > 0); + } + else if (m_iAccumulatedBoneMask & BONE_USED_BY_VERTEX_LOD1) + { + bCrossfade = (g_CV_PhonemeSnap.GetInt() > 1); + } + else if (m_iAccumulatedBoneMask & BONE_USED_BY_VERTEX_LOD2) + { + bCrossfade = (g_CV_PhonemeSnap.GetInt() > 2); + } + else if (m_iAccumulatedBoneMask & BONE_USED_BY_VERTEX_LOD3) + { + bCrossfade = (g_CV_PhonemeSnap.GetInt() > 3); + } + else + { + bCrossfade = false; + } + } + + if (bCrossfade) + { + if (k < pcount-1) + { + const CBasePhonemeTag *next = sentence->GetRuntimePhoneme( k + 1 ); + if ( next ) + { + dt = max( dt, min( next->GetEndTime() - t, phoneme->GetEndTime() - phoneme->GetStartTime() ) ); + } } } } @@ -743,7 +915,7 @@ void C_BaseFlex::ProcessVisemes( Emphasized_Phoneme *classes ) for ( int source = 0 ; source < MouthInfo().GetNumVoiceSources(); source++ ) { CVoiceData *vd = MouthInfo().GetVoiceSource( source ); - if ( !vd ) + if ( !vd || vd->ShouldIgnorePhonemes() ) continue; CSentence *sentence = engine->GetSentence( vd->GetSource() ); @@ -777,14 +949,6 @@ void C_BaseFlex::ProcessVisemes( Emphasized_Phoneme *classes ) // Assume sound has been playing for a while... bool juststarted = false; - /* - // FIXME: Do we really want to support markov chains for the phonemes? - // If so, we'll need to uncomment out these lines. - if ( timesincestart < 0.001 ) - { - juststarted = true; - } - */ // Get intensity setting for this time (from spline) float emphasis_intensity = sentence->GetIntensity( t, sentence_length ); @@ -816,29 +980,29 @@ void C_BaseFlex::GetToolRecordingState( KeyValues *msg ) if ( hdr->numflexcontrollers() == 0 ) return; - int i, j; + LocalFlexController_t i; ProcessSceneEvents( true ); // FIXME: shouldn't this happen at runtime? // initialize the models local to global flex controller mappings - if (hdr->pFlexcontroller( 0 )->link == -1) + if (hdr->pFlexcontroller( LocalFlexController_t(0) )->localToGlobal == -1) { - for (i = 0; i < hdr->numflexcontrollers(); i++) + for (i = LocalFlexController_t(0); i < hdr->numflexcontrollers(); i++) { - j = AddGlobalFlexController( hdr->pFlexcontroller( i )->pszName() ); - hdr->pFlexcontroller( i )->link = j; + int j = AddGlobalFlexController( hdr->pFlexcontroller( i )->pszName() ); + hdr->pFlexcontroller( i )->localToGlobal = j; } } // blend weights from server - for (i = 0; i < hdr->numflexcontrollers(); i++) + for (i = LocalFlexController_t(0); i < hdr->numflexcontrollers(); i++) { mstudioflexcontroller_t *pflex = hdr->pFlexcontroller( i ); - g_flexweight[pflex->link] = m_flexWeight[i]; + g_flexweight[pflex->localToGlobal] = m_flexWeight[i]; // rescale - g_flexweight[pflex->link] = g_flexweight[pflex->link] * (pflex->max - pflex->min) + pflex->min; + g_flexweight[pflex->localToGlobal] = g_flexweight[pflex->localToGlobal] * (pflex->max - pflex->min) + pflex->min; } ProcessSceneEvents( false ); @@ -872,7 +1036,47 @@ void C_BaseFlex::GetToolRecordingState( KeyValues *msg ) // Drive the mouth from .wav file playback... ProcessVisemes( m_PhonemeClasses ); - Vector viewtarget = SetViewTarget( hdr ); + // Necessary??? + SetViewTarget( hdr ); + + Vector viewtarget = m_viewtarget; // Use the unfiltered value + + // HACK HACK: Unmap eyes right/left amounts + if (m_iEyeUpdown != -1 && m_iEyeRightleft != -1) + { + mstudioflexcontroller_t *flexupdown = hdr->pFlexcontroller( m_iEyeUpdown ); + mstudioflexcontroller_t *flexrightleft = hdr->pFlexcontroller( m_iEyeRightleft ); + + if ( flexupdown->localToGlobal != -1 && flexrightleft->localToGlobal != -1 ) + { + float updown = g_flexweight[ flexupdown->localToGlobal ]; + float rightleft = g_flexweight[ flexrightleft->localToGlobal ]; + + if ( flexupdown->min != flexupdown->max ) + { + updown = RemapVal( updown, flexupdown->min, flexupdown->max, 0.0f, 1.0f ); + } + if ( flexrightleft->min != flexrightleft->max ) + { + rightleft = RemapVal( rightleft, flexrightleft->min, flexrightleft->max, 0.0f, 1.0f ); + } + + g_flexweight[ flexupdown->localToGlobal ] = updown; + g_flexweight[ flexrightleft->localToGlobal ] = rightleft; + } + } + + // Convert back to normalized weights + for (i = LocalFlexController_t(0); i < hdr->numflexcontrollers(); i++) + { + mstudioflexcontroller_t *pflex = hdr->pFlexcontroller( i ); + + // rescale + if ( pflex->max != pflex->min ) + { + g_flexweight[pflex->localToGlobal] = ( g_flexweight[pflex->localToGlobal] - pflex->min ) / ( pflex->max - pflex->min ); + } + } static BaseFlexRecordingState_t state; state.m_nFlexCount = MAXSTUDIOFLEXCTRL; @@ -885,43 +1089,75 @@ void C_BaseFlex::GetToolRecordingState( KeyValues *msg ) //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- -void C_BaseFlex::SetupWeights( ) +void C_BaseFlex::OnThreadedDrawSetup() { + if (m_iEyeAttachment < 0) + return; + CStudioHdr *hdr = GetModelPtr(); if ( !hdr ) { return; } + CalcAttachments(); +} - memset( g_flexweight, 0, sizeof( g_flexweight ) ); - // FIXME: this should assert then, it's too complex a class for the model - if (hdr->numflexcontrollers() == 0) +//----------------------------------------------------------------------------- +// Should we use delayed flex weights? +//----------------------------------------------------------------------------- +bool C_BaseFlex::UsesFlexDelayedWeights() +{ + return ( m_flFlexDelayedWeight && g_CV_FlexSmooth.GetBool() ); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_BaseFlex::SetupWeights( const matrix3x4_t *pBoneToWorld, int nFlexWeightCount, float *pFlexWeights, float *pFlexDelayedWeights ) +{ + CStudioHdr *hdr = GetModelPtr(); + if ( !hdr ) return; - int i, j; + memset( g_flexweight, 0, sizeof(g_flexweight) ); + + // FIXME: this should assert then, it's too complex a class for the model + if ( hdr->numflexcontrollers() == 0 ) + { + int nSizeInBytes = nFlexWeightCount * sizeof( float ); + memset( pFlexWeights, 0, nSizeInBytes ); + if ( pFlexDelayedWeights ) + { + memset( pFlexDelayedWeights, 0, nSizeInBytes ); + } + return; + } + + LocalFlexController_t i; ProcessSceneEvents( true ); // FIXME: shouldn't this happen at runtime? // initialize the models local to global flex controller mappings - if (hdr->pFlexcontroller( 0 )->link == -1) + if ( hdr->pFlexcontroller( LocalFlexController_t(0) )->localToGlobal == -1 ) { - for (i = 0; i < hdr->numflexcontrollers(); i++) + for (i = LocalFlexController_t(0); i < hdr->numflexcontrollers(); i++) { - j = AddGlobalFlexController( hdr->pFlexcontroller( i )->pszName() ); - hdr->pFlexcontroller( i )->link = j; + int j = AddGlobalFlexController( hdr->pFlexcontroller( i )->pszName() ); + hdr->pFlexcontroller( i )->localToGlobal = j; } } // get the networked flexweights and convert them from 0..1 to real dynamic range - for (i = 0; i < hdr->numflexcontrollers(); i++) + for (i = LocalFlexController_t(0); i < hdr->numflexcontrollers(); i++) { mstudioflexcontroller_t *pflex = hdr->pFlexcontroller( i ); - g_flexweight[pflex->link] = m_flexWeight[i]; + g_flexweight[pflex->localToGlobal] = m_flexWeight[i]; // rescale - g_flexweight[pflex->link] = g_flexweight[pflex->link] * (pflex->max - pflex->min) + pflex->min; + g_flexweight[pflex->localToGlobal] = g_flexweight[pflex->localToGlobal] * (pflex->max - pflex->min) + pflex->min; } ProcessSceneEvents( false ); @@ -934,11 +1170,15 @@ void C_BaseFlex::SetupWeights( ) } if (m_iBlink == -1) + { m_iBlink = AddGlobalFlexController( "blink" ); + } // FIXME: this needs a better algorithm // blink the eyes - float t = (m_blinktime - gpGlobals->curtime) * M_PI * 0.5 * (1.0/g_CV_BlinkDuration.GetFloat()); + float flBlinkDuration = g_CV_BlinkDuration.GetFloat(); + float flOOBlinkDuration = ( flBlinkDuration > 0 ) ? 1.0f / flBlinkDuration : 0.0f; + float t = ( m_blinktime - gpGlobals->curtime ) * M_PI * 0.5 * flOOBlinkDuration; if (t > 0) { // do eyeblink falloff curve @@ -958,39 +1198,31 @@ void C_BaseFlex::SetupWeights( ) ProcessVisemes( m_PhonemeClasses ); // convert the flex controllers into actual flex values - float destweight[MAXSTUDIOFLEXDESC]; - RunFlexRules( hdr, destweight ); + RunFlexRules( hdr, pFlexWeights ); // aim the eyes SetViewTarget( hdr ); - if (m_flFlexDelayedWeight && g_CV_FlexSmooth.GetBool()) + if ( pFlexDelayedWeights ) { // process the delayed version of the flexweights float d = 1.0; - if (gpGlobals->frametime != 0) + if ( gpGlobals->frametime != 0 ) { d = ExponentialDecay( 0.8, 0.033, gpGlobals->frametime ); } - for ( i = 0; i < hdr->numflexdesc(); i++) + for ( i = LocalFlexController_t(0); i < hdr->numflexdesc(); i++) { - m_flFlexDelayedWeight[i] = m_flFlexDelayedWeight[i] * d + destweight[i] * (1 - d); + m_flFlexDelayedWeight[i] = m_flFlexDelayedWeight[i] * d + pFlexWeights[i] * (1 - d); + pFlexDelayedWeights[i] = m_flFlexDelayedWeight[i]; } // debugoverlay->AddTextOverlay( GetAbsOrigin() + Vector( 0, 0, 64 ), i-hdr->numflexcontrollers, 0, "%.3f", d ); - - // send the flex values to the renderer - modelrender->SetFlexWeights( hdr->numflexdesc(), destweight, m_flFlexDelayedWeight ); - } - else - { - // send the flex values to the renderer - modelrender->SetFlexWeights( hdr->numflexdesc(), destweight ); } /* for (i = 0; i < hdr->numflexdesc; i++) { - debugoverlay->AddTextOverlay( GetAbsOrigin() + Vector( 0, 0, 64 ), i-hdr->numflexcontrollers, 0, "%2d:%s : %3.2f", i, hdr->pFlexdesc( i )->pszFACS(), destweight[i] ); + debugoverlay->AddTextOverlay( GetAbsOrigin() + Vector( 0, 0, 64 ), i-hdr->numflexcontrollers, 0, "%2d:%s : %3.2f", i, hdr->pFlexdesc( i )->pszFACS(), pFlexWeights[i] ); } */ @@ -1147,7 +1379,7 @@ bool C_BaseFlex::ClearSceneEvent( CSceneEventInfo *info, bool fastKill, bool can // expression - // duration - //----------------------------------------------------------------------------- -void C_BaseFlex::AddSceneEvent( CChoreoScene *scene, CChoreoEvent *event, CBaseEntity *pTarget ) +void C_BaseFlex::AddSceneEvent( CChoreoScene *scene, CChoreoEvent *event, CBaseEntity *pTarget, bool bClientSide ) { if ( !scene || !event ) { @@ -1170,7 +1402,8 @@ void C_BaseFlex::AddSceneEvent( CChoreoScene *scene, CChoreoEvent *event, CBaseE info.m_pEvent = event; info.m_pScene = scene; info.m_hTarget = pTarget; - info.m_bStarted = false; + info.m_bStarted = false; + info.m_bClientSide = bClientSide; if (StartSceneEvent( &info, scene, event, actor, pTarget )) { @@ -1199,11 +1432,40 @@ bool C_BaseFlex::StartSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CC case CChoreoEvent::EXPRESSION: return true; + + case CChoreoEvent::SEQUENCE: + if ( info->m_bClientSide ) + { + return RequestStartSequenceSceneEvent( info, scene, event, actor, pTarget ); + } + break; + + case CChoreoEvent::SPEAK: + if ( info->m_bClientSide ) + { + return true; + } + break; } return false; } +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool C_BaseFlex::RequestStartSequenceSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event, CChoreoActor *actor, CBaseEntity *pTarget ) +{ + info->m_nSequence = LookupSequence( event->GetParameters() ); + + // make sure sequence exists + if ( info->m_nSequence < 0 ) + return false; + + info->m_pActor = actor; + return true; +} + //----------------------------------------------------------------------------- // Purpose: Remove expression // Input : scenefile - @@ -1271,7 +1533,7 @@ bool C_BaseFlex::CheckSceneEventCompletion( CSceneEventInfo *info, float current return true; } -void C_BaseFlex::SetFlexWeight( int index, float value ) +void C_BaseFlex::SetFlexWeight( LocalFlexController_t index, float value ) { if (index >= 0 && index < GetNumFlexControllers()) { @@ -1291,7 +1553,7 @@ void C_BaseFlex::SetFlexWeight( int index, float value ) } } -float C_BaseFlex::GetFlexWeight( int index ) +float C_BaseFlex::GetFlexWeight( LocalFlexController_t index ) { if (index >= 0 && index < GetNumFlexControllers()) { @@ -1311,9 +1573,9 @@ float C_BaseFlex::GetFlexWeight( int index ) return 0.0; } -int C_BaseFlex::FindFlexController( const char *szName ) +LocalFlexController_t C_BaseFlex::FindFlexController( const char *szName ) { - for (int i = 0; i < GetNumFlexControllers(); i++) + for (LocalFlexController_t i = LocalFlexController_t(0); i < GetNumFlexControllers(); i++) { if (stricmp( GetFlexControllerName( i ), szName ) == 0) { @@ -1322,7 +1584,7 @@ int C_BaseFlex::FindFlexController( const char *szName ) } // AssertMsg( 0, UTIL_VarArgs( "flexcontroller %s couldn't be mapped!!!\n", szName ) ); - return 0; + return LocalFlexController_t(-1); } //----------------------------------------------------------------------------- @@ -1337,17 +1599,17 @@ void C_BaseFlex::ProcessSceneEvents( bool bFlexEvents ) } // slowly decay to netural expression - int i; + if ( bFlexEvents ) { - for ( i = 0; i < GetNumFlexControllers(); i++) + for ( LocalFlexController_t i = LocalFlexController_t(0); i < GetNumFlexControllers(); i++) { SetFlexWeight( i, GetFlexWeight( i ) * 0.95 ); } } // Iterate SceneEvents and look for active slots - for ( i = 0; i < m_SceneEvents.Count(); i++ ) + for ( int i = 0; i < m_SceneEvents.Count(); i++ ) { CSceneEventInfo *info = &m_SceneEvents[ i ]; Assert( info ); @@ -1379,8 +1641,6 @@ bool C_BaseFlex::ProcessFlexAnimationSceneEvent( CSceneEventInfo *info, CChoreoS return true; } -#define AllowSceneOverrides() 0 - bool C_BaseFlex::ProcessFlexSettingSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event ) { // Flexanimations have to have an end time!!! @@ -1400,34 +1660,12 @@ bool C_BaseFlex::ProcessFlexSettingSceneEvent( CSceneEventInfo *info, CChoreoSce const flexsettinghdr_t *pExpHdr = ( const flexsettinghdr_t * )g_FlexSceneFileManager.FindSceneFile( this, scenefile, true ); if ( pExpHdr ) { - const flexsettinghdr_t *pOverrideHdr = NULL; - - // Find overrides, if any exist - CStudioHdr *hdr; - - if ( AllowSceneOverrides() && ( hdr = GetModelPtr() ) != NULL ) - { - char overridefile[ 512 ]; - char shortname[ 128 ]; - char modelname[ 128 ]; - - //Q_strncpy( modelname, modelinfo->GetModelName( model ) ,sizeof(modelname)); - Q_strncpy( modelname, hdr->pszName() ,sizeof(modelname)); - - // Fix up the name - Q_FileBase( modelname, shortname, sizeof( shortname ) ); - - Q_snprintf( overridefile,sizeof(overridefile), "%s/%s", shortname, scenefile ); - - pOverrideHdr = ( const flexsettinghdr_t * )g_FlexSceneFileManager.FindSceneFile( this, overridefile, true ); - } - float scenetime = scene->GetTime(); - float scale = event->GetIntensity( event, scenetime ); + float scale = event->GetIntensity( scenetime ); // Add the named expression - AddFlexSetting( name, scale, pExpHdr, pOverrideHdr, !info->m_bStarted ); + AddFlexSetting( name, scale, pExpHdr, !info->m_bStarted ); } } @@ -1507,11 +1745,10 @@ int C_BaseFlex::FlexControllerLocalToGlobal( const flexsettinghdr_t *pSettinghdr // Input : *expr - // scale - // *pSettinghdr - -// *pOverrideHdr - // newexpression - //----------------------------------------------------------------------------- void C_BaseFlex::AddFlexSetting( const char *expr, float scale, - const flexsettinghdr_t *pSettinghdr, const flexsettinghdr_t *pOverrideHdr, bool newexpression ) + const flexsettinghdr_t *pSettinghdr, bool newexpression ) { int i; const flexsetting_t *pSetting = NULL; @@ -1534,36 +1771,6 @@ void C_BaseFlex::AddFlexSetting( const char *expr, float scale, return; } - // Update markov chain if needed - if ( newexpression ) - { - if ( pSetting->type == FS_MARKOV ) - { - NewMarkovIndex( (flexsetting_t *)pSetting ); - } - } - - // Resolve markov chain for the returned setting - pSetting = pSettinghdr->pTranslatedSetting( i ); - - // Check for overrides - if ( AllowSceneOverrides() && pOverrideHdr ) - { - // Get name from setting - const char *resolvedName = pSetting->pszName(); - if ( resolvedName ) - { - // See if resolvedName exists in the override file - const flexsetting_t *override = FindNamedSetting( pOverrideHdr, resolvedName ); - if ( override ) - { - // If so, point at the override file instead - pSettinghdr = pOverrideHdr; - pSetting = override; - } - } - } - flexweight_t *pWeights = NULL; int truecount = pSetting->psetting( (byte *)pSettinghdr, 0, &pWeights ); if ( !pWeights ) @@ -1575,9 +1782,9 @@ void C_BaseFlex::AddFlexSetting( const char *expr, float scale, // this is translating from the settings's local index to the models local index int index = FlexControllerLocalToGlobal( pSettinghdr, pWeights->key ); - // Add scaled weighting in to total (post networking g_flexweight!!!!) - float value = g_flexweight[index] + scale * pWeights->weight; - g_flexweight[index] = value; + // blend scaled weighting in to total (post networking g_flexweight!!!!) + float s = clamp( scale * pWeights->influence, 0.0f, 1.0f ); + g_flexweight[index] = g_flexweight[index] * (1.0f - s) + pWeights->weight * s; } } @@ -1603,11 +1810,42 @@ bool C_BaseFlex::ProcessSceneEvent( bool bFlexEvents, CSceneEventInfo *info, CCh return ProcessFlexSettingSceneEvent( info, scene, event ); } return true; + + case CChoreoEvent::SEQUENCE: + if ( info->m_bClientSide ) + { + if ( !bFlexEvents ) + { + return ProcessSequenceSceneEvent( info, scene, event ); + } + return true; + } + break; + + case CChoreoEvent::SPEAK: + if ( info->m_bClientSide ) + { + return true; + } + break; } return false; } +//----------------------------------------------------------------------------- +// Purpose: +// Input : *actor - +// *parameters - +//----------------------------------------------------------------------------- +bool C_BaseFlex::ProcessSequenceSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event ) +{ + if ( !info || !event || !scene ) + return false; + + SetSequence( info->m_nSequence ); + return true; +} //----------------------------------------------------------------------------- // Purpose: @@ -1641,16 +1879,16 @@ void C_BaseFlex::AddFlexAnimation( CSceneEventInfo *info ) Q_strncpy( name, "right_" ,sizeof(name)); Q_strncat( name, track->GetFlexControllerName(),sizeof(name), COPY_ALL_CHARACTERS ); - track->SetFlexControllerIndex( 0, FindFlexController( name ), 0 ); + track->SetFlexControllerIndex( max( FindFlexController( name ), LocalFlexController_t(0) ), 0, 0 ); Q_strncpy( name, "left_" ,sizeof(name)); Q_strncat( name, track->GetFlexControllerName(),sizeof(name), COPY_ALL_CHARACTERS ); - track->SetFlexControllerIndex( 0, FindFlexController( name ), 1 ); + track->SetFlexControllerIndex( max( FindFlexController( name ), LocalFlexController_t(0) ), 0, 1 ); } else { - track->SetFlexControllerIndex( 0, FindFlexController( (char *)track->GetFlexControllerName() ) ); + track->SetFlexControllerIndex( max( FindFlexController( (char *)track->GetFlexControllerName() ), LocalFlexController_t(0)), 0 ); } } @@ -1662,7 +1900,7 @@ void C_BaseFlex::AddFlexAnimation( CSceneEventInfo *info ) float scenetime = scene->GetTime(); - float weight = event->GetIntensity( event, scenetime ); + float weight = event->GetIntensity( scenetime ); // decay if this is a background scene and there's other flex animations playing weight = weight * info->UpdateWeight( this ); @@ -1684,11 +1922,11 @@ void C_BaseFlex::AddFlexAnimation( CSceneEventInfo *info ) { for ( int side = 0; side < 2; side++ ) { - int controller = track->GetFlexControllerIndex( side ); + LocalFlexController_t controller = track->GetRawFlexControllerIndex( side ); // Get spline intensity for controller float flIntensity = track->GetIntensity( scenetime, side ); - if ( controller >= 0 ) + if ( controller >= LocalFlexController_t(0) ) { float orig = GetFlexWeight( controller ); float value = orig * (1 - weight) + flIntensity * weight; @@ -1698,11 +1936,11 @@ void C_BaseFlex::AddFlexAnimation( CSceneEventInfo *info ) } else { - int controller = track->GetFlexControllerIndex( 0 ); + LocalFlexController_t controller = track->GetRawFlexControllerIndex( 0 ); // Get spline intensity for controller float flIntensity = track->GetIntensity( scenetime, 0 ); - if ( controller >= 0 ) + if ( controller >= LocalFlexController_t(0) ) { float orig = GetFlexWeight( controller ); float value = orig * (1 - weight) + flIntensity * weight; @@ -1728,3 +1966,34 @@ float CSceneEventInfo::UpdateWeight( C_BaseFlex *pActor ) m_flWeight = min( m_flWeight + 0.1, 1.0 ); return m_flWeight; } + +BEGIN_BYTESWAP_DATADESC( flexsettinghdr_t ) + DEFINE_FIELD( id, FIELD_INTEGER ), + DEFINE_FIELD( version, FIELD_INTEGER ), + DEFINE_ARRAY( name, FIELD_CHARACTER, 64 ), + DEFINE_FIELD( length, FIELD_INTEGER ), + DEFINE_FIELD( numflexsettings, FIELD_INTEGER ), + DEFINE_FIELD( flexsettingindex, FIELD_INTEGER ), + DEFINE_FIELD( nameindex, FIELD_INTEGER ), + DEFINE_FIELD( numindexes, FIELD_INTEGER ), + DEFINE_FIELD( indexindex, FIELD_INTEGER ), + DEFINE_FIELD( numkeys, FIELD_INTEGER ), + DEFINE_FIELD( keynameindex, FIELD_INTEGER ), + DEFINE_FIELD( keymappingindex, FIELD_INTEGER ), +END_BYTESWAP_DATADESC() + +BEGIN_BYTESWAP_DATADESC( flexsetting_t ) + DEFINE_FIELD( nameindex, FIELD_INTEGER ), + DEFINE_FIELD( obsolete1, FIELD_INTEGER ), + DEFINE_FIELD( numsettings, FIELD_INTEGER ), + DEFINE_FIELD( index, FIELD_INTEGER ), + DEFINE_FIELD( obsolete2, FIELD_INTEGER ), + DEFINE_FIELD( settingindex, FIELD_INTEGER ), +END_BYTESWAP_DATADESC() + +BEGIN_BYTESWAP_DATADESC( flexweight_t ) + DEFINE_FIELD( key, FIELD_INTEGER ), + DEFINE_FIELD( weight, FIELD_FLOAT ), + DEFINE_FIELD( influence, FIELD_FLOAT ), +END_BYTESWAP_DATADESC() + diff --git a/src/src/cl_dll/c_baseflex.h b/src/src/game/client/c_baseflex.h similarity index 82% rename from src/src/cl_dll/c_baseflex.h rename to src/src/game/client/c_baseflex.h index f8ffa31..8fa9109 100644 --- a/src/src/cl_dll/c_baseflex.h +++ b/src/src/game/client/c_baseflex.h @@ -1,10 +1,10 @@ -//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: // // $NoKeywords: $ // -//=============================================================================// +//===========================================================================// // Client-side CBasePlayer #ifndef C_STUDIOFLEX_H @@ -51,10 +51,21 @@ public: C_BaseFlex(); virtual ~C_BaseFlex(); + virtual void Spawn(); + + virtual void InitPhonemeMappings(); + + void SetupMappings( char const *pchFileRoot ); + virtual CStudioHdr *OnNewModel( void ); + virtual void StandardBlendingRules( CStudioHdr *hdr, Vector pos[], Quaternion q[], float currentTime, int boneMask ); + + virtual void OnThreadedDrawSetup(); + // model specific - virtual void SetupWeights( ); + virtual void SetupWeights( const matrix3x4_t *pBoneToWorld, int nFlexWeightCount, float *pFlexWeights, float *pFlexDelayedWeights ); + virtual bool UsesFlexDelayedWeights(); virtual void RunFlexRules( CStudioHdr *pStudioHdr, float *dest ); @@ -67,17 +78,18 @@ public: // Called at the lowest level to actually apply a flex animation void AddFlexAnimation( CSceneEventInfo *info ); - void SetFlexWeight( int index, float value ); - float GetFlexWeight( int index ); + void SetFlexWeight( LocalFlexController_t index, float value ); + float GetFlexWeight( LocalFlexController_t index ); // Look up flex controller index by global name - int FindFlexController( const char *szName ); + LocalFlexController_t FindFlexController( const char *szName ); public: Vector m_viewtarget; CInterpolatedVar< Vector > m_iv_viewtarget; - float m_flexWeight[64]; - CInterpolatedVarArray< float, 64 > m_iv_flexWeight; + // indexed by model local flexcontroller + float m_flexWeight[MAXSTUDIOFLEXCTRL]; + CInterpolatedVarArray< float, MAXSTUDIOFLEXCTRL > m_iv_flexWeight; int m_blinktoggle; @@ -105,6 +117,8 @@ public: // expressions to the flex weights and adds other scene events as needed virtual bool ProcessSceneEvent( bool bFlexEvents, CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event ); + virtual bool ProcessSequenceSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event ); + // Remove all playing events void ClearSceneEvents( CChoreoScene *scene, bool canceled ); @@ -112,7 +126,7 @@ public: virtual bool ClearSceneEvent( CSceneEventInfo *info, bool fastKill, bool canceled ); // Add the event to the queue for this actor - void AddSceneEvent( CChoreoScene *scene, CChoreoEvent *event, C_BaseEntity *pTarget = NULL ); + void AddSceneEvent( CChoreoScene *scene, CChoreoEvent *event, C_BaseEntity *pTarget = NULL, bool bClientSide = false ); // Remove the event from the queue for this actor void RemoveSceneEvent( CChoreoScene *scene, CChoreoEvent *event, bool fastKill ); @@ -126,12 +140,17 @@ public: int FlexControllerLocalToGlobal( const flexsettinghdr_t *pSettinghdr, int key ); void EnsureTranslations( const flexsettinghdr_t *pSettinghdr ); + // For handling scene files + void *FindSceneFile( const char *filename ); + private: + bool RequestStartSequenceSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event, CChoreoActor *actor, CBaseEntity *pTarget ); + bool ProcessFlexAnimationSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event ); bool ProcessFlexSettingSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event ); void AddFlexSetting( const char *expr, float scale, - const flexsettinghdr_t *pSettinghdr, const flexsettinghdr_t *pOverrideHdr, bool newexpression ); + const flexsettinghdr_t *pSettinghdr, bool newexpression ); // Array of active SceneEvents, in order oldest to newest CUtlVector < CSceneEventInfo > m_SceneEvents; @@ -196,8 +215,9 @@ private: int m_prevblinktoggle; int m_iBlink; - int m_iEyeUpdown; - int m_iEyeRightleft; + LocalFlexController_t m_iEyeUpdown; + LocalFlexController_t m_iEyeRightleft; + bool m_bSearchedForEyeFlexes; int m_iMouthAttachment; float *m_flFlexDelayedWeight; @@ -207,8 +227,7 @@ private: static char *g_flexcontroller[MAXSTUDIOFLEXCTRL*4]; // room for global set of flexcontrollers static float g_flexweight[MAXSTUDIOFLEXDESC]; -private: - C_BaseFlex( const C_BaseFlex & ); // not defined, not accessible +protected: enum { @@ -230,10 +249,6 @@ private: // Global fields setup first time tracks played bool basechecked; const flexsettinghdr_t *base; -#if !defined( NO_ENTITY_PREDICTION ) - bool overridechecked; - const flexsettinghdr_t *override; -#endif const flexsetting_t *exp; // Local fields, processed for each sentence @@ -241,8 +256,11 @@ private: float amount; }; - // For handling scene files - void *FindSceneFile( const char *filename ); + Emphasized_Phoneme m_PhonemeClasses[ NUM_PHONEME_CLASSES ]; + +private: + + C_BaseFlex( const C_BaseFlex & ); // not defined, not accessible const flexsetting_t *FindNamedSetting( const flexsettinghdr_t *pSettinghdr, const char *expr ); @@ -252,7 +270,14 @@ private: bool SetupEmphasisBlend( Emphasized_Phoneme *classes, int phoneme ); void ComputeBlendedSetting( Emphasized_Phoneme *classes, float emphasis_intensity ); - Emphasized_Phoneme m_PhonemeClasses[ NUM_PHONEME_CLASSES ]; +#ifdef HL2_CLIENT_DLL +public: + + Vector m_vecLean; + CInterpolatedVar< Vector > m_iv_vecLean; + Vector m_vecShift; + CInterpolatedVar< Vector > m_iv_vecShift; +#endif }; diff --git a/src/src/cl_dll/c_baseplayer.cpp b/src/src/game/client/c_baseplayer.cpp similarity index 69% rename from src/src/cl_dll/c_baseplayer.cpp rename to src/src/game/client/c_baseplayer.cpp index 3653cd7..29ac38d 100644 --- a/src/src/cl_dll/c_baseplayer.cpp +++ b/src/src/game/client/c_baseplayer.cpp @@ -22,7 +22,6 @@ #include "c_playerresource.h" #include "iclientvehicle.h" #include "view_shared.h" -#include "C_VguiScreen.h" #include "movevars_shared.h" #include "prediction.h" #include "tier0/vprof.h" @@ -35,6 +34,11 @@ #include "toolframework/itoolframework.h" #include "toolframework_client.h" #include "view_scene.h" +#include "c_vguiscreen.h" +#include "datacache/imdlcache.h" +#include "vgui/isurface.h" +#include "voice_status.h" +#include "fx.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -47,7 +51,6 @@ int g_nKillCamMode = OBS_MODE_NONE; int g_nKillCamTarget1 = 0; int g_nKillCamTarget2 = 0; -int g_nUsedPrediction = 1; extern ConVar mp_forcecamera; // in gamevars_shared.h @@ -58,6 +61,8 @@ extern ConVar mp_forcecamera; // in gamevars_shared.h static Vector WALL_MIN(-WALL_OFFSET,-WALL_OFFSET,-WALL_OFFSET); static Vector WALL_MAX(WALL_OFFSET,WALL_OFFSET,WALL_OFFSET); +bool CommentaryModeShouldSwallowInput( C_BasePlayer *pPlayer ); + extern ConVar default_fov; #ifndef _XBOX extern ConVar sensitivity; @@ -77,9 +82,10 @@ static ConVar cl_smoothtime ( true, 2.0 ); -ConVar zoom_sensitivity_ratio( "zoom_sensitivity_ratio", "1.0", 0, "Additional mouse sensitivity scale factor applied when FOV is zoomed in." ); -void RecvProxy_FOV( const CRecvProxyData *pData, void *pStruct, void *pOut ); -void RecvProxy_DefaultFOV( const CRecvProxyData *pData, void *pStruct, void *pOut ); +ConVar spec_freeze_time( "spec_freeze_time", "4.0", FCVAR_CHEAT | FCVAR_REPLICATED, "Time spend frozen in observer freeze cam." ); +ConVar spec_freeze_traveltime( "spec_freeze_traveltime", "0.4", FCVAR_CHEAT | FCVAR_REPLICATED, "Time taken to zoom in to frame a target in observer freeze cam.", true, 0.01, false, 0 ); +ConVar spec_freeze_distance_min( "spec_freeze_distance_min", "96", FCVAR_CHEAT, "Minimum random distance from the target to stop when framing them in observer freeze cam." ); +ConVar spec_freeze_distance_max( "spec_freeze_distance_max", "200", FCVAR_CHEAT, "Maximum random distance from the target to stop when framing them in observer freeze cam." ); void RecvProxy_LocalVelocityX( const CRecvProxyData *pData, void *pStruct, void *pOut ); void RecvProxy_LocalVelocityY( const CRecvProxyData *pData, void *pStruct, void *pOut ); @@ -112,9 +118,19 @@ BEGIN_RECV_TABLE_NOBASE( CPlayerLocalData, DT_Local ) RecvPropFloat (RECVINFO(m_flDuckJumpTime)), RecvPropFloat (RECVINFO(m_flJumpTime)), RecvPropFloat (RECVINFO(m_flFallVelocity)), -// RecvPropInt (RECVINFO(m_nOldButtons)), + +#if PREDICTION_ERROR_CHECK_LEVEL > 1 + RecvPropFloat (RECVINFO_NAME( m_vecPunchAngle.m_Value[0], m_vecPunchAngle[0])), + RecvPropFloat (RECVINFO_NAME( m_vecPunchAngle.m_Value[1], m_vecPunchAngle[1])), + RecvPropFloat (RECVINFO_NAME( m_vecPunchAngle.m_Value[2], m_vecPunchAngle[2] )), + RecvPropFloat (RECVINFO_NAME( m_vecPunchAngleVel.m_Value[0], m_vecPunchAngleVel[0] )), + RecvPropFloat (RECVINFO_NAME( m_vecPunchAngleVel.m_Value[1], m_vecPunchAngleVel[1] )), + RecvPropFloat (RECVINFO_NAME( m_vecPunchAngleVel.m_Value[2], m_vecPunchAngleVel[2] )), +#else RecvPropVector (RECVINFO(m_vecPunchAngle)), RecvPropVector (RECVINFO(m_vecPunchAngleVel)), +#endif + RecvPropInt (RECVINFO(m_bDrawViewmodel)), RecvPropInt (RECVINFO(m_bWearingSuit)), RecvPropBool (RECVINFO(m_bPoisoned)), @@ -134,23 +150,10 @@ BEGIN_RECV_TABLE_NOBASE( CPlayerLocalData, DT_Local ) RecvPropInt( RECVINFO( m_skybox3d.fog.colorSecondary ) ), RecvPropFloat( RECVINFO( m_skybox3d.fog.start ) ), RecvPropFloat( RECVINFO( m_skybox3d.fog.end ) ), + RecvPropFloat( RECVINFO( m_skybox3d.fog.maxdensity ) ), // fog data - RecvPropInt( RECVINFO( m_fog.enable ) ), - RecvPropInt( RECVINFO( m_fog.blend ) ), - RecvPropVector( RECVINFO( m_fog.dirPrimary ) ), - RecvPropInt( RECVINFO( m_fog.colorPrimary ) ), - RecvPropInt( RECVINFO( m_fog.colorSecondary ) ), - RecvPropFloat( RECVINFO( m_fog.start ) ), - RecvPropFloat( RECVINFO( m_fog.end ) ), - RecvPropFloat( RECVINFO( m_fog.farz ) ), - - RecvPropInt( RECVINFO( m_fog.colorPrimaryLerpTo ) ), - RecvPropInt( RECVINFO( m_fog.colorSecondaryLerpTo ) ), - RecvPropFloat( RECVINFO( m_fog.startLerpTo ) ), - RecvPropFloat( RECVINFO( m_fog.endLerpTo ) ), - RecvPropFloat( RECVINFO( m_fog.lerptime ) ), - RecvPropFloat( RECVINFO( m_fog.duration ) ), + RecvPropEHandle( RECVINFO( m_PlayerFog.m_hCtrl ) ), // audio data RecvPropVector( RECVINFO( m_audio.localSound[0] ) ), @@ -164,6 +167,14 @@ BEGIN_RECV_TABLE_NOBASE( CPlayerLocalData, DT_Local ) RecvPropInt( RECVINFO( m_audio.soundscapeIndex ) ), RecvPropInt( RECVINFO( m_audio.localBits ) ), RecvPropEHandle( RECVINFO( m_audio.ent ) ), + + //Tony; tonemap stuff! -- TODO! Optimize this with bit sizes from env_tonemap_controller. + RecvPropFloat ( RECVINFO( m_TonemapParams.m_flTonemapScale ) ), + RecvPropFloat ( RECVINFO( m_TonemapParams.m_flTonemapRate ) ), + RecvPropFloat ( RECVINFO( m_TonemapParams.m_flBloomScale ) ), + + RecvPropFloat ( RECVINFO( m_TonemapParams.m_flAutoExposureMin ) ), + RecvPropFloat ( RECVINFO( m_TonemapParams.m_flAutoExposureMax ) ), END_RECV_TABLE() // -------------------------------------------------------------------------------- // @@ -219,8 +230,11 @@ END_RECV_TABLE() RecvPropDataTable(RECVINFO_DT(pl), 0, &REFERENCE_RECV_TABLE(DT_PlayerState), DataTableRecvProxy_StaticDataTable), - RecvPropInt (RECVINFO(m_iFOV), 0, RecvProxy_FOV), - RecvPropInt (RECVINFO(m_iDefaultFOV), 0, RecvProxy_DefaultFOV), + RecvPropInt (RECVINFO(m_iFOV)), + RecvPropInt (RECVINFO(m_iFOVStart)), + RecvPropFloat (RECVINFO(m_flFOVTime)), + RecvPropInt (RECVINFO(m_iDefaultFOV)), + RecvPropEHandle (RECVINFO(m_hZoomOwner)), RecvPropEHandle( RECVINFO(m_hVehicle) ), RecvPropEHandle( RECVINFO(m_hUseEntity) ), @@ -228,6 +242,9 @@ END_RECV_TABLE() RecvPropInt (RECVINFO(m_iHealth)), RecvPropInt (RECVINFO(m_lifeState)), + RecvPropInt (RECVINFO(m_iBonusProgress)), + RecvPropInt (RECVINFO(m_iBonusChallenge)), + RecvPropFloat (RECVINFO(m_flMaxspeed)), RecvPropInt (RECVINFO(m_fFlags)), @@ -239,6 +256,8 @@ END_RECV_TABLE() RecvPropString( RECVINFO(m_szLastPlaceName) ), + RecvPropInt( RECVINFO( m_ubEFNoInterpParity ) ), + END_RECV_TABLE() BEGIN_PREDICTION_DATA_NO_BASE( CPlayerState ) @@ -259,8 +278,13 @@ BEGIN_PREDICTION_DATA_NO_BASE( CPlayerLocalData ) DEFINE_FIELD( m_nStepside, FIELD_INTEGER ), DEFINE_PRED_FIELD( m_iHideHUD, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ), +#if PREDICTION_ERROR_CHECK_LEVEL > 1 + DEFINE_PRED_FIELD( m_vecPunchAngle, FIELD_VECTOR, FTYPEDESC_INSENDTABLE ), + DEFINE_PRED_FIELD( m_vecPunchAngleVel, FIELD_VECTOR, FTYPEDESC_INSENDTABLE ), +#else DEFINE_PRED_FIELD_TOL( m_vecPunchAngle, FIELD_VECTOR, FTYPEDESC_INSENDTABLE, 0.125f ), DEFINE_PRED_FIELD_TOL( m_vecPunchAngleVel, FIELD_VECTOR, FTYPEDESC_INSENDTABLE, 0.125f ), +#endif DEFINE_PRED_FIELD( m_bDrawViewmodel, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ), DEFINE_PRED_FIELD( m_bWearingSuit, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ), DEFINE_PRED_FIELD( m_bPoisoned, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ), @@ -276,6 +300,7 @@ BEGIN_PREDICTION_DATA_NO_BASE( CPlayerLocalData ) // DEFINE_PRED_FIELD( m_nOldButtons, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ), DEFINE_FIELD( m_nOldButtons, FIELD_INTEGER ), DEFINE_PRED_FIELD( m_flStepSize, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ), + DEFINE_FIELD( m_flFOVRate, FIELD_FLOAT ), END_PREDICTION_DATA() @@ -285,10 +310,15 @@ BEGIN_PREDICTION_DATA( C_BasePlayer ) DEFINE_PRED_TYPEDESCRIPTION( pl, CPlayerState ), DEFINE_PRED_FIELD( m_iFOV, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ), + DEFINE_PRED_FIELD( m_hZoomOwner, FIELD_EHANDLE, FTYPEDESC_INSENDTABLE ), + DEFINE_PRED_FIELD( m_flFOVTime, FIELD_FLOAT, 0 ), + DEFINE_PRED_FIELD( m_iFOVStart, FIELD_INTEGER, 0 ), DEFINE_PRED_FIELD( m_hVehicle, FIELD_EHANDLE, FTYPEDESC_INSENDTABLE ), DEFINE_PRED_FIELD_TOL( m_flMaxspeed, FIELD_FLOAT, FTYPEDESC_INSENDTABLE, 0.5f ), DEFINE_PRED_FIELD( m_iHealth, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ), + DEFINE_PRED_FIELD( m_iBonusProgress, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ), + DEFINE_PRED_FIELD( m_iBonusChallenge, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ), DEFINE_PRED_FIELD( m_fOnTarget, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ), DEFINE_PRED_FIELD( m_nNextThinkTick, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ), DEFINE_PRED_FIELD( m_lifeState, FIELD_CHARACTER, FTYPEDESC_INSENDTABLE ), @@ -323,9 +353,14 @@ BEGIN_PREDICTION_DATA( C_BasePlayer ) DEFINE_PRED_ARRAY( m_hViewModel, FIELD_EHANDLE, MAX_VIEWMODELS, FTYPEDESC_INSENDTABLE ), + DEFINE_FIELD( m_surfaceFriction, FIELD_FLOAT ), + END_PREDICTION_DATA() +// link this in each derived player class, like the server!! +#if 0 LINK_ENTITY_TO_CLASS( player, C_BasePlayer ); +#endif // -------------------------------------------------------------------------------- // // Functions. @@ -400,6 +435,23 @@ void C_BasePlayer::Spawn( void ) SetThink(NULL); SharedSpawn(); + + m_bWasFreezeFraming = false; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool C_BasePlayer::AudioStateIsUnderwater( Vector vecMainViewOrigin ) +{ + if ( IsObserver() ) + { + // Just check the view position + int cont = enginetrace->GetPointContents ( vecMainViewOrigin ); + return (cont & MASK_WATER); + } + + return ( GetWaterLevel() >= WL_Eyes ); } bool C_BasePlayer::IsHLTV() const @@ -441,6 +493,12 @@ void C_BasePlayer::SetObserverTarget( EHANDLE hObserverTarget ) // has a chance to become non-NULL even if it currently resolves to NULL. m_hObserverTarget.Init( hObserverTarget.GetEntryIndex(), hObserverTarget.GetSerialNumber() ); + IGameEvent *event = gameeventmanager->CreateEvent( "spec_target_updated" ); + if ( event ) + { + gameeventmanager->FireEventClientSide( event ); + } + if ( IsLocalPlayer() ) { ResetToneMapping(1.0); @@ -473,6 +531,17 @@ void C_BasePlayer::SetLocalViewAngles( const QAngle &viewAngles ) pl.v_angle = viewAngles; } +//----------------------------------------------------------------------------- +// Purpose: +// Input : ang - +//----------------------------------------------------------------------------- +void C_BasePlayer::SetViewAngles( const QAngle& ang ) +{ + SetLocalAngles( ang ); + SetNetworkAngles( ang ); +} + + surfacedata_t* C_BasePlayer::GetGroundSurface() { // @@ -544,9 +613,19 @@ void C_BasePlayer::OnPreDataChanged( DataUpdateType_t updateType ) m_iOldAmmo[i] = GetAmmoCount(i); } + m_bWasFreezeFraming = (GetObserverMode() == OBS_MODE_FREEZECAM); + m_hOldFogController = m_Local.m_PlayerFog.m_hCtrl; + BaseClass::OnPreDataChanged( updateType ); } +void C_BasePlayer::PreDataUpdate( DataUpdateType_t updateType ) +{ + BaseClass::PreDataUpdate( updateType ); + + m_ubOldEFNoInterpParity = m_ubEFNoInterpParity; +} + //----------------------------------------------------------------------------- // Purpose: // Input : updateType - @@ -570,9 +649,16 @@ void C_BasePlayer::PostDataUpdate( DataUpdateType_t updateType ) { Assert( s_pLocalPlayer == NULL ); s_pLocalPlayer = this; + + // Reset our sound mixed in case we were in a freeze cam when we + // changed level, which would cause the snd_soundmixer to be left modified. + ConVar *pVar = (ConVar *)cvar->FindVar( "snd_soundmixer" ); + pVar->Revert(); } } + bool bForceEFNoInterp = ( m_ubOldEFNoInterpParity != m_ubEFNoInterpParity ); + if ( IsLocalPlayer() ) { SetSimulatedEveryTick( true ); @@ -583,7 +669,7 @@ void C_BasePlayer::PostDataUpdate( DataUpdateType_t updateType ) // estimate velocity for non local players float flTimeDelta = m_flSimulationTime - m_flOldSimulationTime; - if ( flTimeDelta > 0 && !IsEffectActive(EF_NOINTERP) ) + if ( flTimeDelta > 0 && !( IsEffectActive(EF_NOINTERP) || bForceEFNoInterp ) ) { Vector newVelo = (GetNetworkOrigin() - GetOldOrigin() ) / flTimeDelta; SetAbsVelocity( newVelo); @@ -591,67 +677,70 @@ void C_BasePlayer::PostDataUpdate( DataUpdateType_t updateType ) } BaseClass::PostDataUpdate( updateType ); - + // Only care about this for local player if ( IsLocalPlayer() ) { - default_fov.SetValue( m_iDefaultFOV ); - - //Update our FOV, including any zooms going on - int iDefaultFOV = default_fov.GetInt(); - int localFOV = GetFOV(); - int min_fov = GetMinFOV(); - - // Don't let it go too low - localFOV = max( min_fov, localFOV ); - - gHUD.m_flFOVSensitivityAdjust = 1.0f; -#ifndef _XBOX - if ( gHUD.m_flMouseSensitivityFactor ) - { - gHUD.m_flMouseSensitivity = sensitivity.GetFloat() * gHUD.m_flMouseSensitivityFactor; - } - else -#endif - { - // No override, don't use huge sensitivity - if ( localFOV == iDefaultFOV ) - { -#ifndef _XBOX - // reset to saved sensitivity - gHUD.m_flMouseSensitivity = 0; -#endif - } - else - { - // Set a new sensitivity that is proportional to the change from the FOV default and scaled - // by a separate compensating factor - gHUD.m_flFOVSensitivityAdjust = - ((float)localFOV / (float)iDefaultFOV) * // linear fov downscale - zoom_sensitivity_ratio.GetFloat(); // sensitivity scale factor -#ifndef _XBOX - gHUD.m_flMouseSensitivity = gHUD.m_flFOVSensitivityAdjust * sensitivity.GetFloat(); // regular sensitivity -#endif - } - } - + QAngle angles; + engine->GetViewAngles( angles ); if ( updateType == DATA_UPDATE_CREATED ) { - QAngle angles; - engine->GetViewAngles( angles ); SetLocalViewAngles( angles ); m_flOldPlayerZ = GetLocalOrigin().z; } + SetLocalAngles( angles ); + + if ( !m_bWasFreezeFraming && GetObserverMode() == OBS_MODE_FREEZECAM ) + { + m_vecFreezeFrameStart = MainViewOrigin(); + m_flFreezeFrameStartTime = gpGlobals->curtime; + m_flFreezeFrameDistance = RandomFloat( spec_freeze_distance_min.GetFloat(), spec_freeze_distance_max.GetFloat() ); + m_flFreezeZOffset = RandomFloat( -30, 20 ); + m_bSentFreezeFrame = false; + + IGameEvent *pEvent = gameeventmanager->CreateEvent( "show_freezepanel" ); + if ( pEvent ) + { + pEvent->SetInt( "killer", GetObserverTarget() ? GetObserverTarget()->entindex() : 0 ); + gameeventmanager->FireEventClientSide( pEvent ); + } + + // Force the sound mixer to the freezecam mixer + ConVar *pVar = (ConVar *)cvar->FindVar( "snd_soundmixer" ); + pVar->SetValue( "FreezeCam_Only" ); + } + else if ( m_bWasFreezeFraming && GetObserverMode() != OBS_MODE_FREEZECAM ) + { + IGameEvent *pEvent = gameeventmanager->CreateEvent( "hide_freezepanel" ); + if ( pEvent ) + { + gameeventmanager->FireEventClientSide( pEvent ); + } + + view->FreezeFrame(0); + + ConVar *pVar = (ConVar *)cvar->FindVar( "snd_soundmixer" ); + pVar->Revert(); + } } // If we are updated while paused, allow the player origin to be snapped by the // server if we receive a packet from the server - if ( engine->IsPaused() ) + if ( engine->IsPaused() || bForceEFNoInterp ) { ResetLatched(); } } +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool C_BasePlayer::CanSetSoundMixer( void ) +{ + // Can't set sound mixers when we're in freezecam mode, since it has a code-enforced mixer + return (GetObserverMode() != OBS_MODE_FREEZECAM); +} + void C_BasePlayer::ReceiveMessage( int classID, bf_read &msg ) { if ( classID != GetClientClass()->m_ClassID ) @@ -731,6 +820,11 @@ void C_BasePlayer::OnDataChanged( DataUpdateType_t updateType ) } Soundscape_Update( m_Local.m_audio ); + + if ( m_hOldFogController != m_Local.m_PlayerFog.m_hCtrl ) + { + FogControllerChanged( updateType == DATA_UPDATE_CREATED ); + } } } @@ -754,6 +848,21 @@ bool C_BasePlayer::IsInVGuiInputMode() const return (m_pCurrentVguiScreen.Get() != NULL); } +//----------------------------------------------------------------------------- +// Are we inputing to a view model vgui screen +//----------------------------------------------------------------------------- +bool C_BasePlayer::IsInViewModelVGuiInputMode() const +{ + C_BaseEntity *pScreenEnt = m_pCurrentVguiScreen.Get(); + + if ( !pScreenEnt ) + return false; + + Assert( dynamic_cast(pScreenEnt) ); + C_VGuiScreen *pVguiScreen = static_cast(pScreenEnt); + + return ( pVguiScreen->IsAttachedToViewModel() && pVguiScreen->AcceptsInput() ); +} //----------------------------------------------------------------------------- // Check to see if we're in vgui input mode... @@ -814,6 +923,14 @@ void C_BasePlayer::DetermineVguiInputMode( CUserCmd *pCmd ) return; } + // Don't interact with world screens when we're in a menu + if ( vgui::surface()->IsCursorVisible() ) + { + DeactivateVguiScreen( m_pCurrentVguiScreen.Get() ); + m_pCurrentVguiScreen.Set( NULL ); + return; + } + // Not in vgui mode if there are no nearby screens C_BaseEntity *pOldScreen = m_pCurrentVguiScreen.Get(); @@ -837,7 +954,7 @@ void C_BasePlayer::DetermineVguiInputMode( CUserCmd *pCmd ) //----------------------------------------------------------------------------- // Purpose: Input handling //----------------------------------------------------------------------------- -void C_BasePlayer::CreateMove( float flInputSampleTime, CUserCmd *pCmd ) +bool C_BasePlayer::CreateMove( float flInputSampleTime, CUserCmd *pCmd ) { // Allow the vehicle to clamp the view angles if ( IsInAVehicle() ) @@ -851,7 +968,7 @@ void C_BasePlayer::CreateMove( float flInputSampleTime, CUserCmd *pCmd ) } else { -#ifndef _XBOX +#ifndef _X360 if ( joy_autosprint.GetBool() ) #endif { @@ -893,6 +1010,7 @@ void C_BasePlayer::CreateMove( float flInputSampleTime, CUserCmd *pCmd ) // Check to see if we're in vgui input mode... DetermineVguiInputMode( pCmd ); + return true; } @@ -1028,10 +1146,6 @@ void C_BasePlayer::CreateWaterEffects( void ) m_pWaterEmitter->SetSortOrigin( offset ); - PMaterialHandle hMaterial[2]; - hMaterial[0] = ParticleMgr()->GetPMaterial( "effects/fleck_cement1" ); - hMaterial[1] = ParticleMgr()->GetPMaterial( "effects/fleck_cement2" ); - SimpleParticle *pParticle; float curTime = gpGlobals->frametime; @@ -1047,7 +1161,7 @@ void C_BasePlayer::CreateWaterEffects( void ) offset.z = ( m_flWaterSurfaceZ - 8.0f ); } - pParticle = (SimpleParticle *) m_pWaterEmitter->AddParticle( sizeof(SimpleParticle), hMaterial[random->RandomInt(0,1)], offset ); + pParticle = (SimpleParticle *) m_pWaterEmitter->AddParticle( sizeof(SimpleParticle), g_Mat_Fleck_Cement[random->RandomInt(0,1)], offset ); if (pParticle == NULL) continue; @@ -1116,6 +1230,25 @@ int C_BasePlayer::DrawModel( int flags ) return BaseClass::DrawModel( flags ); } +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +Vector C_BasePlayer::GetChaseCamViewOffset( CBaseEntity *target ) +{ + C_BasePlayer *player = ToBasePlayer( target ); + + if ( player && player->IsAlive() ) + { + if( player->GetFlags() & FL_DUCKING ) + return VEC_DUCK_VIEW; + + return VEC_VIEW; + } + + // assume it's the players ragdoll + return VEC_DEAD_VIEWHEIGHT; +} + void C_BasePlayer::CalcChaseCamView(Vector& eyeOrigin, QAngle& eyeAngles, float& fov) { C_BaseEntity *target = GetObserverTarget(); @@ -1128,31 +1261,23 @@ void C_BasePlayer::CalcChaseCamView(Vector& eyeOrigin, QAngle& eyeAngles, float& return; }; + // If our target isn't visible, we're at a camera point of some kind. + // Instead of letting the player rotate around an invisible point, treat + // the point as a fixed camera. + if ( !target->GetBaseAnimating() && !target->GetModel() ) + { + CalcRoamingView( eyeOrigin, eyeAngles, fov ); + return; + } + // QAngle tmpangles; Vector forward, viewpoint; - // GetRenderOrigin() returns ragdoll pos if player is ragdolled - Vector origin = target->GetRenderOrigin(); + // GetObserverCamOrigin() returns ragdoll pos if player is ragdolled + Vector origin = target->GetObserverCamOrigin(); - C_BasePlayer *player = ToBasePlayer( target ); - - if ( player && player->IsAlive() ) - { - if( player->GetFlags() & FL_DUCKING ) - { - VectorAdd( origin, VEC_DUCK_VIEW, origin ); - } - else - { - VectorAdd( origin, VEC_VIEW, origin ); - } - } - else - { - // assume it's the players ragdoll - VectorAdd( origin, VEC_DEAD_VIEWHEIGHT, origin ); - } + VectorAdd( origin, GetChaseCamViewOffset( target ), origin ); QAngle viewangles; @@ -1170,7 +1295,14 @@ void C_BasePlayer::CalcChaseCamView(Vector& eyeOrigin, QAngle& eyeAngles, float& } m_flObserverChaseDistance += gpGlobals->frametime*48.0f; - m_flObserverChaseDistance = clamp( m_flObserverChaseDistance, 16, CHASE_CAM_DISTANCE ); + + float flMaxDistance = CHASE_CAM_DISTANCE; + if ( target && target->IsBaseTrain() ) + { + // if this is a train, we want to be back a little further so we can see more of it + flMaxDistance *= 2.5f; + } + m_flObserverChaseDistance = clamp( m_flObserverChaseDistance, 16, flMaxDistance ); AngleVectors( viewangles, &forward ); @@ -1179,8 +1311,9 @@ void C_BasePlayer::CalcChaseCamView(Vector& eyeOrigin, QAngle& eyeAngles, float& VectorMA(origin, -m_flObserverChaseDistance, forward, viewpoint ); trace_t trace; + CTraceFilterNoNPCsOrPlayer filter( target, COLLISION_GROUP_NONE ); C_BaseEntity::PushEnableAbsRecomputations( false ); // HACK don't recompute positions while doing RayTrace - UTIL_TraceHull( origin, viewpoint, WALL_MIN, WALL_MAX, MASK_SOLID, target, COLLISION_GROUP_NONE, &trace ); + UTIL_TraceHull( origin, viewpoint, WALL_MIN, WALL_MAX, MASK_SOLID, &filter, &trace ); C_BaseEntity::PopEnableAbsRecomputations(); if (trace.fraction < 1.0) @@ -1232,6 +1365,89 @@ void C_BasePlayer::CalcRoamingView(Vector& eyeOrigin, QAngle& eyeAngles, float& fov = GetFOV(); } +//----------------------------------------------------------------------------- +// Purpose: Calculate the view for the player while he's in freeze frame observer mode +//----------------------------------------------------------------------------- +void C_BasePlayer::CalcFreezeCamView( Vector& eyeOrigin, QAngle& eyeAngles, float& fov ) +{ + C_BaseEntity *pTarget = GetObserverTarget(); + if ( !pTarget ) + { + CalcDeathCamView( eyeOrigin, eyeAngles, fov ); + return; + } + + // Zoom towards our target + float flCurTime = (gpGlobals->curtime - m_flFreezeFrameStartTime); + float flBlendPerc = clamp( flCurTime / spec_freeze_traveltime.GetFloat(), 0, 1 ); + flBlendPerc = SimpleSpline( flBlendPerc ); + + Vector vecCamDesired = pTarget->GetObserverCamOrigin(); // Returns ragdoll origin if they're ragdolled + VectorAdd( vecCamDesired, GetChaseCamViewOffset( pTarget ), vecCamDesired ); + Vector vecCamTarget = vecCamDesired; + if ( pTarget->IsAlive() ) + { + // Look at their chest, not their head + Vector maxs = GameRules()->GetViewVectors()->m_vHullMax; + vecCamTarget.z -= (maxs.z * 0.5); + } + else + { + vecCamTarget.z += VEC_DEAD_VIEWHEIGHT.z; // look over ragdoll, not through + } + + // Figure out a view position in front of the target + Vector vecEyeOnPlane = eyeOrigin; + vecEyeOnPlane.z = vecCamTarget.z; + Vector vecTargetPos = vecCamTarget; + Vector vecToTarget = vecTargetPos - vecEyeOnPlane; + VectorNormalize( vecToTarget ); + + // Stop a few units away from the target, and shift up to be at the same height + vecTargetPos = vecCamTarget - (vecToTarget * m_flFreezeFrameDistance); + float flEyePosZ = pTarget->EyePosition().z; + vecTargetPos.z = flEyePosZ + m_flFreezeZOffset; + + // Now trace out from the target, so that we're put in front of any walls + trace_t trace; + C_BaseEntity::PushEnableAbsRecomputations( false ); // HACK don't recompute positions while doing RayTrace + UTIL_TraceHull( vecCamTarget, vecTargetPos, WALL_MIN, WALL_MAX, MASK_SOLID, pTarget, COLLISION_GROUP_NONE, &trace ); + C_BaseEntity::PopEnableAbsRecomputations(); + if (trace.fraction < 1.0) + { + // The camera's going to be really close to the target. So we don't end up + // looking at someone's chest, aim close freezecams at the target's eyes. + vecTargetPos = trace.endpos; + vecCamTarget = vecCamDesired; + + // To stop all close in views looking up at character's chins, move the view up. + vecTargetPos.z += fabs(vecCamTarget.z - vecTargetPos.z) * 0.85; + C_BaseEntity::PushEnableAbsRecomputations( false ); // HACK don't recompute positions while doing RayTrace + UTIL_TraceHull( vecCamTarget, vecTargetPos, WALL_MIN, WALL_MAX, MASK_SOLID, pTarget, COLLISION_GROUP_NONE, &trace ); + C_BaseEntity::PopEnableAbsRecomputations(); + vecTargetPos = trace.endpos; + } + + // Look directly at the target + vecToTarget = vecCamTarget - vecTargetPos; + VectorNormalize( vecToTarget ); + VectorAngles( vecToTarget, eyeAngles ); + + VectorLerp( m_vecFreezeFrameStart, vecTargetPos, flBlendPerc, eyeOrigin ); + + if ( flCurTime >= spec_freeze_traveltime.GetFloat() && !m_bSentFreezeFrame ) + { + IGameEvent *pEvent = gameeventmanager->CreateEvent( "freezecam_started" ); + if ( pEvent ) + { + gameeventmanager->FireEventClientSide( pEvent ); + } + + m_bSentFreezeFrame = true; + view->FreezeFrame( spec_freeze_time.GetFloat() ); + } +} + void C_BasePlayer::CalcInEyeCamView(Vector& eyeOrigin, QAngle& eyeAngles, float& fov) { C_BaseEntity *target = GetObserverTarget(); @@ -1371,6 +1587,24 @@ C_BasePlayer *C_BasePlayer::GetLocalPlayer( void ) return s_pLocalPlayer; } +//----------------------------------------------------------------------------- +// Purpose: +// Input : bThirdperson - +//----------------------------------------------------------------------------- +void C_BasePlayer::ThirdPersonSwitch( bool bThirdperson ) +{ + // We've switch from first to third, or vice versa. + UpdateVisibility(); + + CBaseCombatWeapon *pWeapon = GetActiveWeapon(); + + if ( pWeapon ) + { + pWeapon->ThirdPersonSwitch( bThirdperson ); + } + +} + //----------------------------------------------------------------------------- // Purpose: single place to decide whether the local player should draw //----------------------------------------------------------------------------- @@ -1423,6 +1657,11 @@ void C_BasePlayer::PreThink( void ) UpdateClientData(); + UpdateUnderwaterState(); + + // Update the player's fog data if necessary. + UpdateFogController(); + if (m_lifeState >= LIFE_DYING) return; @@ -1439,10 +1678,15 @@ void C_BasePlayer::PreThink( void ) void C_BasePlayer::PostThink( void ) { #if !defined( NO_ENTITY_PREDICTION ) + MDLCACHE_CRITICAL_SECTION(); + if ( IsAlive()) { - // do weapon stuff - ItemPostFrame(); + if ( !CommentaryModeShouldSwallowInput( this ) ) + { + // do weapon stuff + ItemPostFrame(); + } if ( GetFlags() & FL_ONGROUND ) { @@ -1485,6 +1729,30 @@ void C_BasePlayer::GetToolRecordingState( KeyValues *msg ) float flZNear = view->GetZNear(); float flZFar = view->GetZFar(); CalcView( state.m_vecEyePosition, state.m_vecEyeAngles, flZNear, flZFar, state.m_flFOV ); + state.m_bThirdPerson = !engine->IsPaused() && ::input->CAM_IsThirdPerson(); + + // this is a straight copy from ClientModeShared::OverrideView, + // When that method is removed in favor of rolling it into CalcView, + // then this code can (should!) be removed + if ( state.m_bThirdPerson ) + { + Vector cam_ofs; + ::input->CAM_GetCameraOffset( cam_ofs ); + + QAngle camAngles; + camAngles[ PITCH ] = cam_ofs[ PITCH ]; + camAngles[ YAW ] = cam_ofs[ YAW ]; + camAngles[ ROLL ] = 0; + + Vector camForward, camRight, camUp; + AngleVectors( camAngles, &camForward, &camRight, &camUp ); + + VectorMA( state.m_vecEyePosition, -cam_ofs[ ROLL ], camForward, state.m_vecEyePosition ); + + // Override angles from third person camera + VectorCopy( camAngles, state.m_vecEyeAngles ); + } + msg->SetPtr( "camera", &state ); } @@ -1499,6 +1767,9 @@ void C_BasePlayer::Simulate() { //Update the flashlight Flashlight(); + + // Update the player's fog data if necessary. + UpdateFogController(); } else { @@ -1525,7 +1796,8 @@ C_BaseViewModel *C_BasePlayer::GetViewModel( int index /*= 0*/ ) { C_BasePlayer *target = ToBasePlayer( GetObserverTarget() ); - if ( target && target != this ) + // get the targets viewmodel unless the target is an observer itself + if ( target && target != this && !target->IsObserver() ) { vm = target->GetViewModel( index ); } @@ -1750,92 +2022,62 @@ float C_BasePlayer::GetFOV( void ) { C_BasePlayer *pTargetPlayer = dynamic_cast( GetObserverTarget() ); - if ( pTargetPlayer ) + // get fov from observer target. Not if target is observer itself + if ( pTargetPlayer && !pTargetPlayer->IsObserver() ) { return pTargetPlayer->GetFOV(); } } - float fFOV = m_iFOV; - // Allow our vehicle to override our FOV if it's currently at the default FOV. + float flDefaultFOV; IClientVehicle *pVehicle = GetVehicle(); - if ( pVehicle && ( fFOV == 0 ) ) + if ( pVehicle ) { - pVehicle->GetVehicleFOV( fFOV ); + CacheVehicleView(); + flDefaultFOV = ( m_flVehicleViewFOV == 0 ) ? GetDefaultFOV() : m_flVehicleViewFOV; } - - if ( fFOV == 0 ) + else { - fFOV = default_fov.GetInt(); + flDefaultFOV = GetDefaultFOV(); } + + float fFOV = ( m_iFOV == 0 ) ? flDefaultFOV : m_iFOV; - //See if we need to lerp the values for local player - if ( IsLocalPlayer() && ( fFOV != m_iFOVStart ) && (m_Local.m_flFOVRate > 0.0f ) ) + // Don't do lerping during prediction. It's only necessary when actually rendering, + // and it'll cause problems due to prediction timing messiness. + if ( !prediction->InPrediction() ) { - float deltaTime = (float)( gpGlobals->curtime - m_flFOVTime ) / m_Local.m_flFOVRate; + // See if we need to lerp the values for local player + if ( IsLocalPlayer() && ( fFOV != m_iFOVStart ) && (m_Local.m_flFOVRate > 0.0f ) ) + { + float deltaTime = (float)( gpGlobals->curtime - m_flFOVTime ) / m_Local.m_flFOVRate; - if ( deltaTime >= 1.0f ) - { - //If we're past the zoom time, just take the new value and stop lerping - m_iFOVStart = fFOV; - } - else - { - fFOV = SimpleSplineRemapVal( deltaTime, 0.0f, 1.0f, m_iFOVStart, fFOV ); +#if !defined( NO_ENTITY_PREDICTION ) + if ( GetPredictable() ) + { + // m_flFOVTime was set to a predicted time in the future, because the FOV change was predicted. + deltaTime = (float)( GetFinalPredictedTime() - m_flFOVTime ); + deltaTime += ( gpGlobals->interpolation_amount * TICK_INTERVAL ); + deltaTime /= m_Local.m_flFOVRate; + } +#endif + + if ( deltaTime >= 1.0f ) + { + //If we're past the zoom time, just take the new value and stop lerping + m_iFOVStart = fFOV; + } + else + { + fFOV = SimpleSplineRemapValClamped( deltaTime, 0.0f, 1.0f, (float) m_iFOVStart, fFOV ); + } } } return fFOV; } - -//----------------------------------------------------------------------------- -// Purpose: Called when the FOV changes from the server-side -// Input : *pData - -// *pStruct - -// *pOut - -//----------------------------------------------------------------------------- -void RecvProxy_FOV( const CRecvProxyData *pData, void *pStruct, void *pOut ) -{ - C_BasePlayer *pPlayer = (C_BasePlayer *) pStruct; - - //Hold onto the old FOV as our starting point - int iNewFov = pData->m_Value.m_Int; - - if ( pPlayer->m_iFOV == iNewFov ) - return; - - // Get the true current FOV of the player at this point - pPlayer->m_iFOVStart = pPlayer->GetFOV(); - - //Get our start time for the zoom - pPlayer->m_flFOVTime = gpGlobals->curtime; - pPlayer->m_iFOV = iNewFov; -} - -//----------------------------------------------------------------------------- -// Purpose: Called when the default FOV changes from the server-side -// Input : *pData - -// *pStruct - -// *pOut - -//----------------------------------------------------------------------------- -void RecvProxy_DefaultFOV( const CRecvProxyData *pData, void *pStruct, void *pOut ) -{ - C_BasePlayer *pPlayer = (C_BasePlayer *) pStruct; - - //Hold onto the old FOV as our starting point - int iNewFov = pData->m_Value.m_Int; - - if ( pPlayer->m_iDefaultFOV != iNewFov ) - { - // Don't lerp - pPlayer->m_Local.m_flFOVRate = 0.0f; - - pPlayer->m_iDefaultFOV = iNewFov; - } -} - void RecvProxy_LocalVelocityX( const CRecvProxyData *pData, void *pStruct, void *pOut ) { C_BasePlayer *pPlayer = (C_BasePlayer *) pStruct; @@ -1963,6 +2205,10 @@ float C_BasePlayer::GetFinalPredictedTime() const void C_BasePlayer::NotePredictionError( const Vector &vDelta ) { + // don't worry about prediction errors when dead + if ( !IsAlive() ) + return; + #if !defined( NO_ENTITY_PREDICTION ) Vector vOldDelta; @@ -1978,10 +2224,56 @@ void C_BasePlayer::NotePredictionError( const Vector &vDelta ) #endif } + +// offset curtime and setup bones at that time using fake interpolation +// fake interpolation means we don't have reliable interpolation history (the local player doesn't animate locally) +// so we just modify cycle and origin directly and use that as a fake guess +void C_BasePlayer::ForceSetupBonesAtTimeFakeInterpolation( matrix3x4_t *pBonesOut, float curtimeOffset ) +{ + // we don't have any interpolation data, so fake it + float cycle = m_flCycle; + Vector origin = GetLocalOrigin(); + + // blow the cached prev bones + InvalidateBoneCache(); + // reset root position to flTime + Interpolate( gpGlobals->curtime + curtimeOffset ); + + // force cycle back by boneDt + m_flCycle = fmod( 10 + cycle + m_flPlaybackRate * curtimeOffset, 1.0f ); + SetLocalOrigin( origin + curtimeOffset * GetLocalVelocity() ); + // Setup bone state to extrapolate physics velocity + SetupBones( pBonesOut, MAXSTUDIOBONES, BONE_USED_BY_ANYTHING, gpGlobals->curtime + curtimeOffset ); + + m_flCycle = cycle; + SetLocalOrigin( origin ); +} + +void C_BasePlayer::GetRagdollInitBoneArrays( matrix3x4_t *pDeltaBones0, matrix3x4_t *pDeltaBones1, matrix3x4_t *pCurrentBones, float boneDt ) +{ + if ( !IsLocalPlayer() ) + { + BaseClass::GetRagdollInitBoneArrays(pDeltaBones0, pDeltaBones1, pCurrentBones, boneDt); + return; + } + ForceSetupBonesAtTimeFakeInterpolation( pDeltaBones0, -boneDt ); + ForceSetupBonesAtTimeFakeInterpolation( pDeltaBones1, 0 ); + float ragdollCreateTime = PhysGetSyncCreateTime(); + if ( ragdollCreateTime != gpGlobals->curtime ) + { + ForceSetupBonesAtTimeFakeInterpolation( pCurrentBones, ragdollCreateTime - gpGlobals->curtime ); + } + else + { + SetupBones( pCurrentBones, MAXSTUDIOBONES, BONE_USED_BY_ANYTHING, gpGlobals->curtime ); + } +} + + void C_BasePlayer::GetPredictionErrorSmoothingVector( Vector &vOffset ) { #if !defined( NO_ENTITY_PREDICTION ) - if ( engine->IsPlayingDemo() || !cl_smooth.GetInt() || !cl_predict.GetBool() ) + if ( engine->IsPlayingDemo() || !cl_smooth.GetInt() || !cl_predict->GetInt() ) { vOffset.Init(); return; @@ -2009,3 +2301,169 @@ IRagdoll* C_BasePlayer::GetRepresentativeRagdoll() const return m_pRagdoll; } +IMaterial *C_BasePlayer::GetHeadLabelMaterial( void ) +{ + if ( GetClientVoiceMgr() == NULL ) + return NULL; + + return GetClientVoiceMgr()->GetHeadLabelMaterial(); +} + +bool IsInFreezeCam( void ) +{ + C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); + if ( pPlayer && pPlayer->GetObserverMode() == OBS_MODE_FREEZECAM ) + return true; + + return false; +} + +//----------------------------------------------------------------------------- +// Purpose: Set the fog controller data per player. +// Input : &inputdata - +//----------------------------------------------------------------------------- +void C_BasePlayer::FogControllerChanged( bool bSnap ) +{ + if ( m_Local.m_PlayerFog.m_hCtrl ) + { + fogparams_t *pFogParams = &(m_Local.m_PlayerFog.m_hCtrl->m_fog); + + /* + Msg("Updating Fog Target: (%d,%d,%d) %.0f,%.0f -> (%d,%d,%d) %.0f,%.0f (%.2f seconds)\n", + m_CurrentFog.colorPrimary.GetR(), m_CurrentFog.colorPrimary.GetB(), m_CurrentFog.colorPrimary.GetG(), + m_CurrentFog.start.Get(), m_CurrentFog.end.Get(), + pFogParams->colorPrimary.GetR(), pFogParams->colorPrimary.GetB(), pFogParams->colorPrimary.GetG(), + pFogParams->start.Get(), pFogParams->end.Get(), pFogParams->duration.Get() );*/ + + + // Setup the fog color transition. + m_Local.m_PlayerFog.m_OldColor = m_CurrentFog.colorPrimary; + m_Local.m_PlayerFog.m_flOldStart = m_CurrentFog.start; + m_Local.m_PlayerFog.m_flOldEnd = m_CurrentFog.end; + + m_Local.m_PlayerFog.m_NewColor = pFogParams->colorPrimary; + m_Local.m_PlayerFog.m_flNewStart = pFogParams->start; + m_Local.m_PlayerFog.m_flNewEnd = pFogParams->end; + + m_Local.m_PlayerFog.m_flTransitionTime = bSnap ? -1 : gpGlobals->curtime; + + m_CurrentFog = *pFogParams; + + // Update the fog player's local fog data with the fog controller's data if need be. + UpdateFogController(); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Check to see that the controllers data is up to date. +//----------------------------------------------------------------------------- +void C_BasePlayer::UpdateFogController( void ) +{ + if ( m_Local.m_PlayerFog.m_hCtrl ) + { + // Don't bother copying while we're transitioning, since it'll be stomped in UpdateFogBlend(); + if ( m_Local.m_PlayerFog.m_flTransitionTime == -1 && (m_hOldFogController == m_Local.m_PlayerFog.m_hCtrl) ) + { + fogparams_t *pFogParams = &(m_Local.m_PlayerFog.m_hCtrl->m_fog); + if ( m_CurrentFog != *pFogParams ) + { + /* + Msg("FORCING UPDATE: (%d,%d,%d) %.0f,%.0f -> (%d,%d,%d) %.0f,%.0f (%.2f seconds)\n", + m_CurrentFog.colorPrimary.GetR(), m_CurrentFog.colorPrimary.GetB(), m_CurrentFog.colorPrimary.GetG(), + m_CurrentFog.start.Get(), m_CurrentFog.end.Get(), + pFogParams->colorPrimary.GetR(), pFogParams->colorPrimary.GetB(), pFogParams->colorPrimary.GetG(), + pFogParams->start.Get(), pFogParams->end.Get(), pFogParams->duration.Get() );*/ + + + m_CurrentFog = *pFogParams; + } + } + } + else + { + if ( m_CurrentFog.farz != -1 || m_CurrentFog.enable != false ) + { + // No fog controller in this level. Use default fog parameters. + m_CurrentFog.farz = -1; + m_CurrentFog.enable = false; + } + } + + // Update the fog blending state - of necessary. + UpdateFogBlend(); +} + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +void C_BasePlayer::UpdateFogBlend( void ) +{ + // Transition. + if ( m_Local.m_PlayerFog.m_flTransitionTime != -1 ) + { + float flTimeDelta = gpGlobals->curtime - m_Local.m_PlayerFog.m_flTransitionTime; + if ( flTimeDelta < m_CurrentFog.duration ) + { + float flScale = flTimeDelta / m_CurrentFog.duration; + m_CurrentFog.colorPrimary.SetR( ( m_Local.m_PlayerFog.m_NewColor.r * flScale ) + ( m_Local.m_PlayerFog.m_OldColor.r * ( 1.0f - flScale ) ) ); + m_CurrentFog.colorPrimary.SetG( ( m_Local.m_PlayerFog.m_NewColor.g * flScale ) + ( m_Local.m_PlayerFog.m_OldColor.g * ( 1.0f - flScale ) ) ); + m_CurrentFog.colorPrimary.SetB( ( m_Local.m_PlayerFog.m_NewColor.b * flScale ) + ( m_Local.m_PlayerFog.m_OldColor.b * ( 1.0f - flScale ) ) ); + m_CurrentFog.start.Set( ( m_Local.m_PlayerFog.m_flNewStart * flScale ) + ( ( m_Local.m_PlayerFog.m_flOldStart * ( 1.0f - flScale ) ) ) ); + m_CurrentFog.end.Set( ( m_Local.m_PlayerFog.m_flNewEnd * flScale ) + ( ( m_Local.m_PlayerFog.m_flOldEnd * ( 1.0f - flScale ) ) ) ); + } + else + { + // Slam the final fog values. + m_CurrentFog.colorPrimary.SetR( m_Local.m_PlayerFog.m_NewColor.r ); + m_CurrentFog.colorPrimary.SetG( m_Local.m_PlayerFog.m_NewColor.g ); + m_CurrentFog.colorPrimary.SetB( m_Local.m_PlayerFog.m_NewColor.b ); + m_CurrentFog.start.Set( m_Local.m_PlayerFog.m_flNewStart ); + m_CurrentFog.end.Set( m_Local.m_PlayerFog.m_flNewEnd ); + m_Local.m_PlayerFog.m_flTransitionTime = -1; + + /* + Msg("Finished transition to (%d,%d,%d) %.0f,%.0f\n", + m_CurrentFog.colorPrimary.GetR(), m_CurrentFog.colorPrimary.GetB(), m_CurrentFog.colorPrimary.GetG(), + m_CurrentFog.start.Get(), m_CurrentFog.end.Get() );*/ + + } + } +} + +void CC_DumpClientSoundscapeData( const CCommand& args ) +{ + C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); + if ( !pPlayer ) + return; + + Msg("Client Soundscape data dump:\n"); + Msg(" Position: %.2f %.2f %.2f\n", pPlayer->GetAbsOrigin().x, pPlayer->GetAbsOrigin().y, pPlayer->GetAbsOrigin().z ); + Msg(" soundscape index: %d\n", pPlayer->m_Local.m_audio.soundscapeIndex ); + Msg(" entity index: %d\n", pPlayer->m_Local.m_audio.ent.Get() ? pPlayer->m_Local.m_audio.ent->entindex() : -1 ); + if ( pPlayer->m_Local.m_audio.ent.Get() ) + { + Msg(" entity pos: %.2f %.2f %.2f\n", pPlayer->m_Local.m_audio.ent.Get()->GetAbsOrigin().x, pPlayer->m_Local.m_audio.ent.Get()->GetAbsOrigin().y, pPlayer->m_Local.m_audio.ent.Get()->GetAbsOrigin().z ); + if ( pPlayer->m_Local.m_audio.ent.Get()->IsDormant() ) + { + Msg(" ENTITY IS DORMANT\n"); + } + } + bool bFoundOne = false; + for ( int i = 0; i < NUM_AUDIO_LOCAL_SOUNDS; i++ ) + { + if ( pPlayer->m_Local.m_audio.localBits & (1<m_Local.m_audio.localSound[i]; + Msg(" %d: %.2f %.2f %.2f\n", i, vecPos.x,vecPos.y, vecPos.z ); + } + } + + Msg("End dump.\n"); +} +static ConCommand soundscape_dumpclient("soundscape_dumpclient", CC_DumpClientSoundscapeData, "Dumps the client's soundscape data.\n", FCVAR_CHEAT); diff --git a/src/src/cl_dll/c_baseplayer.h b/src/src/game/client/c_baseplayer.h similarity index 74% rename from src/src/cl_dll/c_baseplayer.h rename to src/src/game/client/c_baseplayer.h index 31268e8..5e5e4d8 100644 --- a/src/src/cl_dll/c_baseplayer.h +++ b/src/src/game/client/c_baseplayer.h @@ -20,6 +20,9 @@ #include "timedevent.h" #include "smartptr.h" #include "fx_water.h" +#include "hintsystem.h" +#include "soundemittersystem/isoundemittersystembase.h" +#include "c_env_fog_controller.h" class C_BaseCombatWeapon; class C_BaseViewModel; @@ -29,7 +32,6 @@ class CFlashlightEffect; extern int g_nKillCamMode; extern int g_nKillCamTarget1; extern int g_nKillCamTarget2; -extern int g_nUsedPrediction; class C_CommandContext { @@ -50,6 +52,9 @@ public: #define CHASE_CAM_DISTANCE 96.0f #define WALL_OFFSET 6.0f + +bool IsInFreezeCam( void ); + //----------------------------------------------------------------------------- // Purpose: Base Player class //----------------------------------------------------------------------------- @@ -71,6 +76,7 @@ public: virtual void OnPreDataChanged( DataUpdateType_t updateType ); virtual void OnDataChanged( DataUpdateType_t updateType ); + virtual void PreDataUpdate( DataUpdateType_t updateType ); virtual void PostDataUpdate( DataUpdateType_t updateType ); virtual void ReceiveMessage( int classID, bf_read &msg ); @@ -87,6 +93,7 @@ public: C_BaseViewModel *GetViewModel( int viewmodelindex = 0 ); C_BaseCombatWeapon *GetActiveWeapon( void ) const; + const char *GetTracerType( void ); // View model prediction setup virtual void CalcView( Vector &eyeOrigin, QAngle &eyeAngles, float &zNear, float &zFar, float &fov ); @@ -99,6 +106,10 @@ public: void CalcViewRoll( QAngle& eyeAngles ); void CreateWaterEffects( void ); + virtual void SetPlayerUnderwater( bool state ); + void UpdateUnderwaterState( void ); + bool IsPlayerUnderwater( void ) { return m_bPlayerUnderwater; } + virtual Vector Weapon_ShootPosition(); virtual void Weapon_DropPrimary( void ) {} @@ -106,7 +117,7 @@ public: void SetSuitUpdate(char *name, int fgroup, int iNoRepeat); // Input handling - virtual void CreateMove( float flInputSampleTime, CUserCmd *pCmd ); + virtual bool CreateMove( float flInputSampleTime, CUserCmd *pCmd ); virtual void AvoidPhysicsProps( CUserCmd *pCmd ); virtual void PlayerUse( void ); @@ -114,14 +125,18 @@ public: virtual bool IsUseableEntity( CBaseEntity *pEntity, unsigned int requiredCaps ); // Data handlers - virtual bool IsPlayer( void ) const { return true; }; - virtual int GetHealth() const { return m_iHealth; }; + virtual bool IsPlayer( void ) const { return true; } + virtual int GetHealth() const { return m_iHealth; } + + int GetBonusProgress() const { return m_iBonusProgress; } + int GetBonusChallenge() const { return m_iBonusChallenge; } // observer mode virtual int GetObserverMode() const; virtual CBaseEntity *GetObserverTarget() const; void SetObserverTarget( EHANDLE hObserverTarget ); - + + bool AudioStateIsUnderwater( Vector vecMainViewOrigin ); bool IsObserver() const; bool IsHLTV() const; @@ -138,8 +153,13 @@ public: // entities for ragdolls. virtual IRagdoll* GetRepresentativeRagdoll() const; + // override the initial bone position for ragdolls + virtual void GetRagdollInitBoneArrays( matrix3x4_t *pDeltaBones0, matrix3x4_t *pDeltaBones1, matrix3x4_t *pCurrentBones, float boneDt ); + // Returns eye vectors void EyeVectors( Vector *pForward, Vector *pRight = NULL, Vector *pUp = NULL ); + void CacheVehicleView( void ); // Calculate and cache the position of the player in the vehicle + bool IsSuitEquipped( void ) { return m_Local.m_bWearingSuit; }; @@ -148,7 +168,7 @@ public: // Flashlight void Flashlight( void ); - void UpdateFlashlight( void ); + virtual void UpdateFlashlight( void ); // Weapon selection code virtual bool IsAllowedToSwitchWeapons( void ) { return !IsObserver(); } @@ -156,7 +176,7 @@ public: // Returns the view model if this is the local player. If you're in third person or // this is a remote player, it returns the active weapon - // + // (and its appropriate left/right weapon if this is TF2). virtual C_BaseAnimating* GetRenderedWeaponModel(); virtual bool IsOverridingViewmodel( void ) { return false; }; @@ -170,7 +190,7 @@ public: // Should this object cast shadows? virtual ShadowType_t ShadowCastType() { return SHADOWS_NONE; } - bool ShouldReceiveProjectedTextures( int flags ) + virtual bool ShouldReceiveProjectedTextures( int flags ) { return false; } @@ -179,9 +199,11 @@ public: bool IsLocalPlayer( void ) const; // Global/static methods + virtual void ThirdPersonSwitch( bool bThirdperson ); static bool ShouldDrawLocalPlayer(); static C_BasePlayer *GetLocalPlayer( void ); int GetUserID( void ); + virtual bool CanSetSoundMixer( void ); // Called by the view model if its rendering is being overridden. virtual bool ViewModel_IsTransparent( void ); @@ -220,6 +242,8 @@ public: virtual float GetFOV( void ); int GetDefaultFOV( void ) const; virtual bool IsZoomed( void ) { return false; } + bool SetFOV( CBaseEntity *pRequester, int FOV, float zoomRate, int iZoomStart = 0 ); + void ClearZoomOwner( void ); float GetFOVDistanceAdjustFactor(); @@ -248,6 +272,8 @@ public: bool IsPlayerDead(); bool IsPoisoned( void ) { return m_Local.m_bPoisoned; } + C_BaseEntity *GetUseEntity(); + // Vehicles... IClientVehicle *GetVehicle(); @@ -263,6 +289,7 @@ public: float GetFinalPredictedTime() const; bool IsInVGuiInputMode() const; + bool IsInViewModelVGuiInputMode() const; C_CommandContext *GetCommandContext(); @@ -278,6 +305,11 @@ public: float GetSwimSoundTime( void ) const; void SetSwimSoundTime( float flSwimSoundTime ); + float GetDeathTime( void ) { return m_flDeathTime; } + + void SetPreviouslyPredictedOrigin( const Vector &vecAbsOrigin ); + const Vector &GetPreviouslyPredictedOrigin() const; + // CS wants to allow small FOVs for zoomed-in AWPs. virtual float GetMinFOV() const; @@ -287,6 +319,8 @@ public: virtual void UpdateStepSound( surfacedata_t *psurface, const Vector &vecOrigin, const Vector &vecVelocity ); virtual void PlayStepSound( Vector &vecOrigin, surfacedata_t *psurface, float fvol, bool force ); virtual surfacedata_t * GetFootstepSurface( const Vector &origin, const char *surfaceName ); + virtual void GetStepSoundVelocities( float *velwalk, float *velrun ); + virtual void SetStepSoundTime( stepsoundtimes_t iStepSoundTime, bool bWalking ); // Called by prediction when it detects a prediction correction. // vDelta is the line from where the client had predicted the player to at the usercmd in question, @@ -297,11 +331,37 @@ public: void GetPredictionErrorSmoothingVector( Vector &vOffset ); virtual void ExitLadder() {} + surfacedata_t *GetLadderSurface( const Vector &origin ); surfacedata_t *GetSurfaceData( void ) { return m_pSurfaceData; } void SetLadderNormal( Vector vecLadderNormal ) { m_vecLadderNormal = vecLadderNormal; } + // Hints + virtual CHintSystem *Hints( void ) { return NULL; } + bool ShouldShowHints( void ) { return Hints() ? Hints()->ShouldShowHints() : false; } + bool HintMessage( int hint, bool bForce = false, bool bOnlyIfClear = false ) { return Hints() ? Hints()->HintMessage( hint, bForce, bOnlyIfClear ) : false; } + void HintMessage( const char *pMessage ) { if (Hints()) Hints()->HintMessage( pMessage ); } + + virtual IMaterial *GetHeadLabelMaterial( void ); + + // Fog + fogparams_t *GetFogParams( void ) { return &m_CurrentFog; } + void FogControllerChanged( bool bSnap ); + void UpdateFogController( void ); + void UpdateFogBlend( void ); + + void IncrementEFNoInterpParity(); + int GetEFNoInterpParity() const; + + float GetFOVTime( void ){ return m_flFOVTime; } + + virtual void OnAchievementAchieved( int iAchievement ) {} + +protected: + fogparams_t m_CurrentFog; + EHANDLE m_hOldFogController; + public: int m_StuckLast; @@ -316,6 +376,8 @@ public: int m_iFOVStart; // starting value of the FOV changing over time (client only) float m_flFOVTime; // starting time of the FOV zoom int m_iDefaultFOV; // default FOV if no other zooms are occurring + EHANDLE m_hZoomOwner; // This is a pointer to the entity currently controlling the player's zoom + // Only this entity can change the zoom state once it has ownership // For weapon prediction bool m_fOnTarget; //Is the crosshair on a target? @@ -339,20 +401,24 @@ public: protected: - void CalcPlayerView( Vector& eyeOrigin, QAngle& eyeAngles, float& fov ); - void CalcVehicleView(IClientVehicle *pVehicle, Vector& eyeOrigin, QAngle& eyeAngles, + //Tony; made all of these virtual so mods can override. + virtual void CalcPlayerView( Vector& eyeOrigin, QAngle& eyeAngles, float& fov ); + virtual void CalcVehicleView(IClientVehicle *pVehicle, Vector& eyeOrigin, QAngle& eyeAngles, float& zNear, float& zFar, float& fov ); virtual void CalcObserverView( Vector& eyeOrigin, QAngle& eyeAngles, float& fov ); - void CalcChaseCamView( Vector& eyeOrigin, QAngle& eyeAngles, float& fov ); - void CalcInEyeCamView( Vector& eyeOrigin, QAngle& eyeAngles, float& fov ); - void CalcDeathCamView( Vector& eyeOrigin, QAngle& eyeAngles, float& fov ); - void CalcRoamingView(Vector& eyeOrigin, QAngle& eyeAngles, float& fov); + virtual Vector GetChaseCamViewOffset( CBaseEntity *target ); + virtual void CalcChaseCamView( Vector& eyeOrigin, QAngle& eyeAngles, float& fov ); + virtual void CalcInEyeCamView( Vector& eyeOrigin, QAngle& eyeAngles, float& fov ); + virtual void CalcDeathCamView( Vector& eyeOrigin, QAngle& eyeAngles, float& fov ); + virtual void CalcRoamingView(Vector& eyeOrigin, QAngle& eyeAngles, float& fov); + virtual void CalcFreezeCamView( Vector& eyeOrigin, QAngle& eyeAngles, float& fov ); // Check to see if we're in vgui input mode... void DetermineVguiInputMode( CUserCmd *pCmd ); // Used by prediction, sets the view angles for the player - void SetLocalViewAngles( const QAngle &viewAngles ); + virtual void SetLocalViewAngles( const QAngle &viewAngles ); + virtual void SetViewAngles( const QAngle& ang ); // used by client side player footsteps surfacedata_t* GetGroundSurface(); @@ -365,6 +431,10 @@ protected: int m_iObserverMode; // if in spectator mode != 0 EHANDLE m_hObserverTarget; // current observer target float m_flObserverChaseDistance; // last distance to observer traget + Vector m_vecFreezeFrameStart; + float m_flFreezeFrameStartTime; // Time at which we entered freeze frame observer mode + float m_flFreezeFrameDistance; + bool m_bWasFreezeFraming; float m_flDeathTime; // last time player died float m_flStepSoundTime; @@ -380,7 +450,9 @@ private: EHANDLE m_hUseEntity; float m_flMaxspeed; - int m_iHealth; + + int m_iBonusProgress; + int m_iBonusChallenge; CInterpolatedVar< Vector > m_iv_vecViewOffset; @@ -402,6 +474,7 @@ private: EHANDLE m_pCurrentVguiScreen; + // Player flashlight dynamic light pointers CFlashlightEffect *m_pFlashlight; @@ -418,6 +491,11 @@ private: float m_flOldPlayerZ; float m_flOldPlayerViewOffsetZ; + Vector m_vecVehicleViewOrigin; // Used to store the calculated view of the player while riding in a vehicle + QAngle m_vecVehicleViewAngles; // Vehicle angles + float m_flVehicleViewFOV; + int m_nVehicleViewSavedFrame; // Used to mark which frame was the last one the view was calculated for + // For UI purposes... int m_iOldAmmo[ MAX_AMMO_TYPES ]; @@ -429,8 +507,11 @@ private: TimedEvent m_tWaterParticleTimer; CSmartPtr m_pWaterEmitter; + bool m_bPlayerUnderwater; + friend class CPrediction; + // HACK FOR TF2 Prediction friend class CTFGameMovementRecon; friend class CGameMovement; friend class CTFGameMovement; @@ -438,7 +519,11 @@ private: friend class CCSGameMovement; friend class CHL2GameMovement; friend class CDODGameMovement; - + friend class CPortalGameMovement; +#if defined ( SDK_DLL ) + friend class CSDKGameMovement; +#endif + // Accessors for gamemovement float GetStepSize( void ) const { return m_Local.m_flStepSize; } @@ -452,6 +537,7 @@ protected: virtual bool IsDucked( void ) const { return m_Local.m_bDucked; } virtual bool IsDucking( void ) const { return m_Local.m_bDucking; } virtual float GetFallVelocity( void ) { return m_Local.m_flFallVelocity; } + void ForceSetupBonesAtTimeFakeInterpolation( matrix3x4_t *pBonesOut, float curtimeOffset ); float m_flLaggedMovementValue; @@ -461,6 +547,8 @@ protected: Vector m_vecPredictionError; float m_flPredictionErrorTime; + Vector m_vecPreviouslyPredictedOrigin; // Used to determine if non-gamemovement game code has teleported, or tweaked the player's origin + char m_szLastPlaceName[MAX_PLACE_NAME_LENGTH]; // received from the server // Texture names and surface data, used by CGameMovement @@ -469,6 +557,22 @@ protected: float m_surfaceFriction; char m_chTextureType; + bool m_bSentFreezeFrame; + float m_flFreezeZOffset; + byte m_ubEFNoInterpParity; + byte m_ubOldEFNoInterpParity; + +private: + + struct StepSoundCache_t + { + StepSoundCache_t() : m_usSoundNameIndex( 0 ) {} + CSoundParameters m_SoundParameters; + unsigned short m_usSoundNameIndex; + }; + // One for left and one for right side of step + StepSoundCache_t m_StepSoundCache[ 2 ]; + public: const char *GetLastKnownPlaceName( void ) const { return m_szLastPlaceName; } // return the last nav place name the player occupied @@ -496,6 +600,12 @@ inline C_BasePlayer *ToBasePlayer( C_BaseEntity *pEntity ) return static_cast( pEntity ); } +inline C_BaseEntity *C_BasePlayer::GetUseEntity() +{ + return m_hUseEntity; +} + + inline IClientVehicle *C_BasePlayer::GetVehicle() { C_BaseEntity *pVehicleEnt = m_hVehicle.Get(); diff --git a/src/src/cl_dll/c_basetempentity.cpp b/src/src/game/client/c_basetempentity.cpp similarity index 98% rename from src/src/cl_dll/c_basetempentity.cpp rename to src/src/game/client/c_basetempentity.cpp index fd0ec7f..754f9cf 100644 --- a/src/src/cl_dll/c_basetempentity.cpp +++ b/src/src/game/client/c_basetempentity.cpp @@ -192,6 +192,7 @@ void C_BaseTempEntity::OnDataChanged( DataUpdateType_t updateType ) { Assert( 0 void C_BaseTempEntity::SetDormant( bool bDormant ) { Assert( 0 ); } bool C_BaseTempEntity::IsDormant( void ) { Assert( 0 ); return false; }; void C_BaseTempEntity::ReceiveMessage( int classID, bf_read &msg ) { Assert( 0 ); } +void C_BaseTempEntity::SetDestroyedOnRecreateEntities( void ) { Assert(0); } void* C_BaseTempEntity::GetDataTableBasePtr() { diff --git a/src/src/cl_dll/c_basetempentity.h b/src/src/game/client/c_basetempentity.h similarity index 98% rename from src/src/cl_dll/c_basetempentity.h rename to src/src/game/client/c_basetempentity.h index a6eb5d5..e0a7548 100644 --- a/src/src/cl_dll/c_basetempentity.h +++ b/src/src/game/client/c_basetempentity.h @@ -62,7 +62,7 @@ public: virtual int entindex( void ) const; virtual void ReceiveMessage( int classID, bf_read &msg ); virtual void* GetDataTableBasePtr(); - + virtual void SetDestroyedOnRecreateEntities( void ); public: diff --git a/src/src/cl_dll/c_baseviewmodel.cpp b/src/src/game/client/c_baseviewmodel.cpp similarity index 89% rename from src/src/cl_dll/c_baseviewmodel.cpp rename to src/src/game/client/c_baseviewmodel.cpp index 81a0fe6..27b0ff3 100644 --- a/src/src/cl_dll/c_baseviewmodel.cpp +++ b/src/src/game/client/c_baseviewmodel.cpp @@ -12,7 +12,7 @@ #include "view_shared.h" #include "iviewrender.h" #include "view.h" -#include "vmatrix.h" +#include "mathlib/vmatrix.h" #include "cl_animevent.h" #include "eventlist.h" #include "tools/bonelist.h" @@ -22,7 +22,8 @@ // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" -#ifdef CSTRIKE_DLL +//Tony; modified so that the sdk view models are right handed out of the box. +#if defined( CSTRIKE_DLL ) || defined( SDK_DLL ) ConVar cl_righthand( "cl_righthand", "1", FCVAR_ARCHIVE, "Use right-handed view models." ); #endif @@ -75,9 +76,12 @@ void FormatViewModelAttachment( Vector &vOrigin, bool bInverse ) } -void C_BaseViewModel::FormatViewModelAttachment( int nAttachment, Vector &vecOrigin, QAngle &angle ) +void C_BaseViewModel::FormatViewModelAttachment( int nAttachment, matrix3x4_t &attachmentToWorld ) { + Vector vecOrigin; + MatrixPosition( attachmentToWorld, vecOrigin ); ::FormatViewModelAttachment( vecOrigin, false ); + PositionMatrix( vecOrigin, attachmentToWorld ); } @@ -170,13 +174,22 @@ bool C_BaseViewModel::Interpolate( float currentTime ) inline bool C_BaseViewModel::ShouldFlipViewModel() { -#ifdef CSTRIKE_DLL +//Tony; changed for SDK so that the CSS models can be flipped out of the box. +#if defined( CSTRIKE_DLL ) || defined ( SDK_DLL ) + //Tony; move this up here. + if (!cl_righthand.GetBool()) + return false; + // If cl_righthand is set, then we want them all right-handed. CBaseCombatWeapon *pWeapon = m_hWeapon.Get(); if ( pWeapon ) { const FileWeaponInfo_t *pInfo = &pWeapon->GetWpnData(); - return pInfo->m_bAllowFlipping && pInfo->m_bBuiltRightHanded != cl_righthand.GetBool(); + //Tony; if they're already built right handed (default) then we can get out. + if (pInfo->m_bBuiltRightHanded) + return false; + + return pInfo->m_bAllowFlipping; } #endif @@ -261,22 +274,29 @@ int C_BaseViewModel::DrawModel( int flags ) render->SetColorModulation( color ); } + CMatRenderContextPtr pRenderContext( materials ); + if ( ShouldFlipViewModel() ) - materials->CullMode( MATERIAL_CULLMODE_CW ); + pRenderContext->CullMode( MATERIAL_CULLMODE_CW ); C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); + C_BaseCombatWeapon *pWeapon = GetOwningWeapon(); int ret; // If the local player's overriding the viewmodel rendering, let him do it if ( pPlayer && pPlayer->IsOverridingViewmodel() ) { ret = pPlayer->DrawOverriddenViewmodel( this, flags ); } + else if ( pWeapon && pWeapon->IsOverridingViewmodel() ) + { + ret = pWeapon->DrawOverriddenViewmodel( this, flags ); + } else { ret = BaseClass::DrawModel( flags ); } - materials->CullMode( MATERIAL_CULLMODE_CCW ); + pRenderContext->CullMode( MATERIAL_CULLMODE_CCW ); // Now that we've rendered, reset the animation restart flag if ( flags & STUDIO_RENDER ) @@ -286,7 +306,6 @@ int C_BaseViewModel::DrawModel( int flags ) m_nOldAnimationParity = m_nAnimationParity; } // Tell the weapon itself that we've rendered, in case it wants to do something - C_BaseCombatWeapon *pWeapon = GetActiveWeapon(); if ( pWeapon ) { pWeapon->ViewModelDrawn( this ); @@ -314,9 +333,17 @@ int C_BaseViewModel::GetFxBlend( void ) C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); if ( pPlayer && pPlayer->IsOverridingViewmodel() ) { + pPlayer->ComputeFxBlend(); return pPlayer->GetFxBlend(); } + C_BaseCombatWeapon *pWeapon = GetOwningWeapon(); + if ( pWeapon && pWeapon->IsOverridingViewmodel() ) + { + pWeapon->ComputeFxBlend(); + return pWeapon->GetFxBlend(); + } + return BaseClass::GetFxBlend(); } @@ -333,6 +360,10 @@ bool C_BaseViewModel::IsTransparent( void ) return pPlayer->ViewModel_IsTransparent(); } + C_BaseCombatWeapon *pWeapon = GetOwningWeapon(); + if ( pWeapon && pWeapon->IsOverridingViewmodel() ) + return pWeapon->ViewModel_IsTransparent(); + return BaseClass::IsTransparent(); } diff --git a/src/src/cl_dll/c_baseviewmodel.h b/src/src/game/client/c_baseviewmodel.h similarity index 100% rename from src/src/cl_dll/c_baseviewmodel.h rename to src/src/game/client/c_baseviewmodel.h diff --git a/src/src/cl_dll/c_breakableprop.cpp b/src/src/game/client/c_breakableprop.cpp similarity index 100% rename from src/src/cl_dll/c_breakableprop.cpp rename to src/src/game/client/c_breakableprop.cpp diff --git a/src/src/cl_dll/c_breakableprop.h b/src/src/game/client/c_breakableprop.h similarity index 100% rename from src/src/cl_dll/c_breakableprop.h rename to src/src/game/client/c_breakableprop.h diff --git a/src/src/cl_dll/c_colorcorrection.cpp b/src/src/game/client/c_colorcorrection.cpp similarity index 53% rename from src/src/cl_dll/c_colorcorrection.cpp rename to src/src/game/client/c_colorcorrection.cpp index 77b813d..f86440f 100644 --- a/src/src/cl_dll/c_colorcorrection.cpp +++ b/src/src/game/client/c_colorcorrection.cpp @@ -1,26 +1,23 @@ -//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: Color correction entity with simple radial falloff // // $NoKeywords: $ -//=============================================================================// +//===========================================================================// #include "cbase.h" -#include "cbase.h" #include "filesystem.h" #include "cdll_client_int.h" - +#include "colorcorrectionmgr.h" #include "materialsystem/materialsystemutil.h" -#include "materialsystem/icolorcorrection.h" - -#include "utlvector.h" - -#include "generichash.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" +static ConVar mat_colcorrection_disableentities( "mat_colcorrection_disableentities", "0", FCVAR_NONE, "Disable map color-correction entities" ); + + //------------------------------------------------------------------------------ // Purpose : Color correction entity with radial falloff //------------------------------------------------------------------------------ @@ -31,6 +28,9 @@ public: DECLARE_CLIENTCLASS(); + C_ColorCorrection(); + virtual ~C_ColorCorrection(); + void OnDataChanged(DataUpdateType_t updateType); bool ShouldDraw(); @@ -41,24 +41,39 @@ private: float m_minFalloff; float m_maxFalloff; - float m_maxWeight; + float m_flCurWeight; char m_netLookupFilename[MAX_PATH]; bool m_bEnabled; - ColorCorrectionHandle_t m_CCHandle; + ClientCCHandle_t m_CCHandle; }; IMPLEMENT_CLIENTCLASS_DT(C_ColorCorrection, DT_ColorCorrection, CColorCorrection) RecvPropVector( RECVINFO(m_vecOrigin) ), RecvPropFloat( RECVINFO(m_minFalloff) ), RecvPropFloat( RECVINFO(m_maxFalloff) ), - RecvPropFloat( RECVINFO(m_maxWeight) ), + RecvPropFloat( RECVINFO(m_flCurWeight) ), RecvPropString( RECVINFO(m_netLookupFilename) ), RecvPropBool( RECVINFO(m_bEnabled) ), END_RECV_TABLE() + +//------------------------------------------------------------------------------ +// Constructor, destructor +//------------------------------------------------------------------------------ +C_ColorCorrection::C_ColorCorrection() +{ + m_CCHandle = INVALID_CLIENT_CCHANDLE; +} + +C_ColorCorrection::~C_ColorCorrection() +{ + g_pColorCorrectionMgr->RemoveColorCorrection( m_CCHandle ); +} + + //------------------------------------------------------------------------------ // Purpose : // Input : @@ -68,24 +83,16 @@ void C_ColorCorrection::OnDataChanged(DataUpdateType_t updateType) { BaseClass::OnDataChanged( updateType ); - // We're releasing the CS:S client before the engine with this interface, so we need to fail gracefully - if ( !colorcorrection ) - { - return; - } - if ( updateType == DATA_UPDATE_CREATED ) { - SetNextClientThink( CLIENT_THINK_ALWAYS ); + if ( m_CCHandle == INVALID_CLIENT_CCHANDLE ) + { + char filename[MAX_PATH]; + Q_strncpy( filename, m_netLookupFilename, MAX_PATH ); - char filename[MAX_PATH]; - Q_strncpy( filename, m_netLookupFilename, MAX_PATH ); - - m_CCHandle = colorcorrection->AddLookup( filename ); - - colorcorrection->LockLookup( m_CCHandle ); - colorcorrection->LoadLookup( m_CCHandle, filename ); - colorcorrection->UnlockLookup( m_CCHandle ); + m_CCHandle = g_pColorCorrectionMgr->AddColorCorrection( filename ); + SetNextClientThink( ( m_CCHandle != INVALID_CLIENT_CCHANDLE ) ? CLIENT_THINK_ALWAYS : CLIENT_THINK_NEVER ); + } } } @@ -99,32 +106,38 @@ bool C_ColorCorrection::ShouldDraw() void C_ColorCorrection::ClientThink() { - // We're releasing the CS:S client before the engine with this interface, so we need to fail gracefully - if ( !colorcorrection ) + if ( m_CCHandle == INVALID_CLIENT_CCHANDLE ) + return; + + if ( mat_colcorrection_disableentities.GetInt() ) { + // Allow the colorcorrectionui panel (or user) to turn off color-correction entities + g_pColorCorrectionMgr->SetColorCorrectionWeight( m_CCHandle, 0.0f ); return; } - if( !m_bEnabled ) + if( !m_bEnabled && m_flCurWeight == 0.0f ) { - colorcorrection->SetLookupWeight( m_CCHandle, 0.0f ); + g_pColorCorrectionMgr->SetColorCorrectionWeight( m_CCHandle, 0.0f ); return; } CBaseEntity *pPlayer = UTIL_PlayerByIndex(1); if( !pPlayer ) - { return; - } Vector playerOrigin = pPlayer->GetAbsOrigin(); - float dist = (playerOrigin - m_vecOrigin).Length(); - float weight = (dist-m_minFalloff) / (m_maxFalloff-m_minFalloff); - if( weight<0.0f ) weight = 0.0f; - if( weight>1.0f ) weight = 1.0f; + float weight = 0; + if ( ( m_minFalloff != -1 ) && ( m_maxFalloff != -1 ) && m_minFalloff != m_maxFalloff ) + { + float dist = (playerOrigin - m_vecOrigin).Length(); + weight = (dist-m_minFalloff) / (m_maxFalloff-m_minFalloff); + if ( weight<0.0f ) weight = 0.0f; + if ( weight>1.0f ) weight = 1.0f; + } - colorcorrection->SetLookupWeight( m_CCHandle, m_maxWeight * (1.0f - weight) ); + g_pColorCorrectionMgr->SetColorCorrectionWeight( m_CCHandle, m_flCurWeight * ( 1.0 - weight ) ); BaseClass::ClientThink(); } diff --git a/src/src/cl_dll/c_colorcorrectionvolume.cpp b/src/src/game/client/c_colorcorrectionvolume.cpp similarity index 67% rename from src/src/cl_dll/c_colorcorrectionvolume.cpp rename to src/src/game/client/c_colorcorrectionvolume.cpp index 3b47938..3b9223c 100644 --- a/src/src/cl_dll/c_colorcorrectionvolume.cpp +++ b/src/src/game/client/c_colorcorrectionvolume.cpp @@ -1,24 +1,15 @@ -//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: Color correction entity. // // $NoKeywords: $ -//=============================================================================// +//===========================================================================// #include "cbase.h" -#include "cbase.h" #include "filesystem.h" -//#include "triggers.h" #include "cdll_client_int.h" - #include "materialsystem/materialsystemutil.h" -#include "materialsystem/icolorcorrection.h" - -#include "utlvector.h" - -#include "generichash.h" - -//#include "engine/conprint.h" +#include "colorcorrectionmgr.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -39,17 +30,19 @@ public: DECLARE_CLIENTCLASS(); DECLARE_PREDICTABLE(); + C_ColorCorrectionVolume(); + virtual ~C_ColorCorrectionVolume(); + void OnDataChanged(DataUpdateType_t updateType); bool ShouldDraw(); void ClientThink(); private: - float m_Weight; char m_lookupFilename[MAX_PATH]; - ColorCorrectionHandle_t m_CCHandle; + ClientCCHandle_t m_CCHandle; }; IMPLEMENT_CLIENTCLASS_DT(C_ColorCorrectionVolume, DT_ColorCorrectionVolume, CColorCorrectionVolume) @@ -61,6 +54,21 @@ BEGIN_PREDICTION_DATA( C_ColorCorrectionVolume ) DEFINE_PRED_FIELD( m_Weight, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ), END_PREDICTION_DATA() + +//------------------------------------------------------------------------------ +// Constructor, destructor +//------------------------------------------------------------------------------ +C_ColorCorrectionVolume::C_ColorCorrectionVolume() +{ + m_CCHandle = INVALID_CLIENT_CCHANDLE; +} + +C_ColorCorrectionVolume::~C_ColorCorrectionVolume() +{ + g_pColorCorrectionMgr->RemoveColorCorrection( m_CCHandle ); +} + + //------------------------------------------------------------------------------ // Purpose : // Input : @@ -70,24 +78,16 @@ void C_ColorCorrectionVolume::OnDataChanged(DataUpdateType_t updateType) { BaseClass::OnDataChanged( updateType ); - // We're releasing the CS:S client before the engine with this interface, so we need to fail gracefully - if ( !colorcorrection ) - { - return; - } - if ( updateType == DATA_UPDATE_CREATED ) { - SetNextClientThink( CLIENT_THINK_ALWAYS ); + if ( m_CCHandle == INVALID_CLIENT_CCHANDLE ) + { + char filename[MAX_PATH]; + Q_strncpy( filename, m_lookupFilename, MAX_PATH ); - char filename[MAX_PATH]; - Q_strncpy( filename, m_lookupFilename, MAX_PATH ); - - m_CCHandle = colorcorrection->AddLookup( filename ); - - colorcorrection->LockLookup( m_CCHandle ); - colorcorrection->LoadLookup( m_CCHandle, filename ); - colorcorrection->UnlockLookup( m_CCHandle ); + m_CCHandle = g_pColorCorrectionMgr->AddColorCorrection( filename ); + SetNextClientThink( ( m_CCHandle != INVALID_CLIENT_CCHANDLE ) ? CLIENT_THINK_ALWAYS : CLIENT_THINK_NEVER ); + } } } @@ -101,15 +101,8 @@ bool C_ColorCorrectionVolume::ShouldDraw() void C_ColorCorrectionVolume::ClientThink() { - // We're releasing the CS:S client before the engine with this interface, so we need to fail gracefully - if ( !colorcorrection ) - { - return; - } - Vector entityPosition = GetAbsOrigin(); - - colorcorrection->SetLookupWeight( m_CCHandle, m_Weight ); + g_pColorCorrectionMgr->SetColorCorrectionWeight( m_CCHandle, m_Weight ); } diff --git a/src/src/cl_dll/c_dynamiclight.cpp b/src/src/game/client/c_dynamiclight.cpp similarity index 80% rename from src/src/cl_dll/c_dynamiclight.cpp rename to src/src/game/client/c_dynamiclight.cpp index ad153e5..ed5b100 100644 --- a/src/src/cl_dll/c_dynamiclight.cpp +++ b/src/src/game/client/c_dynamiclight.cpp @@ -14,6 +14,19 @@ // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" + +#if HL2_EPISODIC +// In Episodic we unify the NO_WORLD_ILLUMINATION lights to use +// the more efficient elight structure instead. This should theoretically +// be extended to other projects but may have unintended consequences +// and bears more thorough testing. +// +// For an earlier iteration on this technique see changelist 214433, +// which had a specific flag for use of elights. +#define DLIGHT_NO_WORLD_USES_ELIGHT 1 +#endif + + //----------------------------------------------------------------------------- // A dynamic light, with the goofy hack needed for spotlights //----------------------------------------------------------------------------- @@ -29,6 +42,7 @@ public: void OnDataChanged(DataUpdateType_t updateType); bool ShouldDraw(); void ClientThink( void ); + void Release( void ); unsigned char m_Flags; unsigned char m_LightStyle; @@ -42,6 +56,9 @@ public: private: dlight_t* m_pDynamicLight; dlight_t* m_pSpotlightEnd; + + + inline bool ShouldBeElight() { return (m_Flags & DLIGHT_NO_WORLD_ILLUMINATION); } }; IMPLEMENT_CLIENTCLASS_DT(C_DynamicLight, DT_DynamicLight, CDynamicLight) @@ -85,6 +102,26 @@ bool C_DynamicLight::ShouldDraw() return false; } +//------------------------------------------------------------------------------ +// Purpose : Disable drawing of this light when entity perishes +//------------------------------------------------------------------------------ +void C_DynamicLight::Release() +{ + if (m_pDynamicLight) + { + m_pDynamicLight->die = gpGlobals->curtime; + m_pDynamicLight = 0; + } + + if (m_pSpotlightEnd) + { + m_pSpotlightEnd->die = gpGlobals->curtime; + m_pSpotlightEnd = 0; + } + + BaseClass::Release(); +} + //------------------------------------------------------------------------------ // Purpose : @@ -99,8 +136,15 @@ void C_DynamicLight::ClientThink(void) // Deal with the model light if ( !m_pDynamicLight || (m_pDynamicLight->key != index) ) { +#if DLIGHT_NO_WORLD_USES_ELIGHT + m_pDynamicLight = ShouldBeElight() != 0 + ? effects->CL_AllocElight( index ) + : effects->CL_AllocDlight( index ); +#else m_pDynamicLight = effects->CL_AllocDlight( index ); +#endif Assert (m_pDynamicLight); + m_pDynamicLight->minlight = 0; } m_pDynamicLight->style = m_LightStyle; @@ -128,7 +172,11 @@ void C_DynamicLight::ClientThink(void) } } - if (( m_OuterAngle > 0 ) && ((m_Flags & DLIGHT_NO_WORLD_ILLUMINATION) == 0) ) +#if DLIGHT_NO_WORLD_USES_ELIGHT + if (( m_OuterAngle > 0 ) && !ShouldBeElight()) +#else + if (( m_OuterAngle > 0 ) && ((m_Flags & DLIGHT_NO_WORLD_ILLUMINATION) == 0)) +#endif { // Raycast to where the endpoint goes // Deal with the environment light diff --git a/src/src/cl_dll/c_effects.cpp b/src/src/game/client/c_effects.cpp similarity index 97% rename from src/src/cl_dll/c_effects.cpp rename to src/src/game/client/c_effects.cpp index 7cc6ba0..aa4a255 100644 --- a/src/src/cl_dll/c_effects.cpp +++ b/src/src/game/client/c_effects.cpp @@ -21,18 +21,19 @@ #include "ClientEffectPrecacheSystem.h" #include "collisionutils.h" #include "tier0/vprof.h" +#include "viewrender.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" -ConVar cl_winddir ( "cl_winddir", "0", 0, "Weather effects wind direction angle" ); -ConVar cl_windspeed ( "cl_windspeed", "0", 0, "Weather effects wind speed scalar" ); +ConVar cl_winddir ( "cl_winddir", "0", FCVAR_CHEAT, "Weather effects wind direction angle" ); +ConVar cl_windspeed ( "cl_windspeed", "0", FCVAR_CHEAT, "Weather effects wind speed scalar" ); Vector g_vSplashColor( 0.5, 0.5, 0.5 ); float g_flSplashScale = 0.15; float g_flSplashLifetime = 0.5f; float g_flSplashAlpha = 0.3f; -ConVar r_RainSplashPercentage( "r_RainSplashPercentage", "20" ); // N% chance of a rain particle making a splash. +ConVar r_RainSplashPercentage( "r_RainSplashPercentage", "20", FCVAR_CHEAT ); // N% chance of a rain particle making a splash. float GUST_INTERVAL_MIN = 1; @@ -44,23 +45,17 @@ float GUST_LIFETIME_MAX = 3; float MIN_SCREENSPACE_RAIN_WIDTH = 1; #ifndef _XBOX -ConVar r_RainHack( "r_RainHack", "0" ); -ConVar r_RainRadius( "r_RainRadius", "1500" ); -ConVar r_RainSideVel( "r_RainSideVel", "130", 0, "How much sideways velocity rain gets." ); +ConVar r_RainHack( "r_RainHack", "0", FCVAR_CHEAT ); +ConVar r_RainRadius( "r_RainRadius", "1500", FCVAR_CHEAT ); +ConVar r_RainSideVel( "r_RainSideVel", "130", FCVAR_CHEAT, "How much sideways velocity rain gets." ); -ConVar r_RainSimulate( "r_RainSimulate", "1", 0, "Enable/disable rain simulation." ); +ConVar r_RainSimulate( "r_RainSimulate", "1", FCVAR_CHEAT, "Enable/disable rain simulation." ); ConVar r_DrawRain( "r_DrawRain", "1", FCVAR_CHEAT, "Enable/disable rain rendering." ); -ConVar r_RainProfile( "r_RainProfile", "0", 0, "Enable/disable rain profiling." ); +ConVar r_RainProfile( "r_RainProfile", "0", FCVAR_CHEAT, "Enable/disable rain profiling." ); //Precahce the effects CLIENTEFFECT_REGISTER_BEGIN( PrecachePrecipitation ) -#ifdef HL2_EPISODIC -CLIENTEFFECT_MATERIAL( "effects/fleck_ash1" ) -CLIENTEFFECT_MATERIAL( "effects/fleck_ash2" ) -CLIENTEFFECT_MATERIAL( "effects/fleck_ash3" ) -CLIENTEFFECT_MATERIAL( "effects/ember_swirling001" ) -#endif CLIENTEFFECT_MATERIAL( "particle/rain" ) CLIENTEFFECT_MATERIAL( "particle/snow" ) CLIENTEFFECT_REGISTER_END() @@ -212,7 +207,7 @@ IMPLEMENT_CLIENTCLASS_DT(CClient_Precipitation, DT_Precipitation, CPrecipitation RecvPropInt( RECVINFO( m_nPrecipType ) ) END_RECV_TABLE() -static ConVar r_SnowEnable( "r_SnowEnable", "1", 0, "Snow Enable" ); +static ConVar r_SnowEnable( "r_SnowEnable", "1", FCVAR_CHEAT, "Snow Enable" ); static ConVar r_SnowParticles( "r_SnowParticles", "500", FCVAR_CHEAT, "Snow." ); static ConVar r_SnowInsideRadius( "r_SnowInsideRadius", "256", FCVAR_CHEAT, "Snow." ); static ConVar r_SnowOutsideRadius( "r_SnowOutsideRadius", "1024", FCVAR_CHEAT, "Snow." ); @@ -257,12 +252,12 @@ static bool IsInAir( const Vector& position ) // Globals //----------------------------------------------------------------------------- -ConVar CClient_Precipitation::s_raindensity( "r_raindensity","0.001"); -ConVar CClient_Precipitation::s_rainwidth( "r_rainwidth", "0.5" ); -ConVar CClient_Precipitation::s_rainlength( "r_rainlength", "0.1f" ); -ConVar CClient_Precipitation::s_rainspeed( "r_rainspeed", "600.0f" ); -ConVar r_rainalpha( "r_rainalpha", "0.4" ); -ConVar r_rainalphapow( "r_rainalphapow", "0.8" ); +ConVar CClient_Precipitation::s_raindensity( "r_raindensity","0.001", FCVAR_CHEAT); +ConVar CClient_Precipitation::s_rainwidth( "r_rainwidth", "0.5", FCVAR_CHEAT ); +ConVar CClient_Precipitation::s_rainlength( "r_rainlength", "0.1f", FCVAR_CHEAT ); +ConVar CClient_Precipitation::s_rainspeed( "r_rainspeed", "600.0f", FCVAR_CHEAT ); +ConVar r_rainalpha( "r_rainalpha", "0.4", FCVAR_CHEAT ); +ConVar r_rainalphapow( "r_rainalphapow", "0.8", FCVAR_CHEAT ); Vector CClient_Precipitation::s_WindVector; // Stores the wind speed vector @@ -568,7 +563,10 @@ void CClient_Precipitation::Render() return; // Don't render in monitors or in reflections or refractions. - if ( view->GetDrawFlags() & (DF_MONITOR | DF_RENDER_REFLECTION | DF_RENDER_REFRACTION) ) + if ( CurrentViewID() == VIEW_MONITOR ) + return; + + if ( view->GetDrawFlags() & (DF_RENDER_REFLECTION | DF_RENDER_REFRACTION) ) return; if ( m_nPrecipType == PRECIPITATION_TYPE_ASH ) @@ -584,19 +582,21 @@ void CClient_Precipitation::Render() CFastTimer timer; timer.Start(); + CMatRenderContextPtr pRenderContext( materials ); + // We want to do our calculations in view space. VMatrix tempView; - materials->GetMatrix( MATERIAL_VIEW, &tempView ); - materials->MatrixMode( MATERIAL_VIEW ); - materials->LoadIdentity(); + pRenderContext->GetMatrix( MATERIAL_VIEW, &tempView ); + pRenderContext->MatrixMode( MATERIAL_VIEW ); + pRenderContext->LoadIdentity(); // Force the user clip planes to use the old view matrix - materials->EnableUserClipTransformOverride( true ); - materials->UserClipTransform( tempView ); + pRenderContext->EnableUserClipTransformOverride( true ); + pRenderContext->UserClipTransform( tempView ); // Draw all the rain tracers. - materials->Bind( m_MatHandle ); - IMesh *pMesh = materials->GetDynamicMesh(); + pRenderContext->Bind( m_MatHandle ); + IMesh *pMesh = pRenderContext->GetDynamicMesh(); if ( pMesh ) { CMeshBuilder mb; @@ -611,9 +611,9 @@ void CClient_Precipitation::Render() mb.End( false, true ); } - materials->EnableUserClipTransformOverride( false ); - materials->MatrixMode( MATERIAL_VIEW ); - materials->LoadMatrix( tempView ); + pRenderContext->EnableUserClipTransformOverride( false ); + pRenderContext->MatrixMode( MATERIAL_VIEW ); + pRenderContext->LoadMatrix( tempView ); if ( r_RainProfile.GetInt() ) { diff --git a/src/src/cl_dll/c_effects.h b/src/src/game/client/c_effects.h similarity index 100% rename from src/src/cl_dll/c_effects.h rename to src/src/game/client/c_effects.h diff --git a/src/src/cl_dll/c_entitydissolve.cpp b/src/src/game/client/c_entitydissolve.cpp similarity index 99% rename from src/src/cl_dll/c_entitydissolve.cpp rename to src/src/game/client/c_entitydissolve.cpp index 37c4c4d..1909db6 100644 --- a/src/src/cl_dll/c_entitydissolve.cpp +++ b/src/src/game/client/c_entitydissolve.cpp @@ -510,8 +510,8 @@ void C_EntityDissolve::ClientThink( void ) // the server ragdoll (or any server physics) on the client if (( !m_pController ) && ( m_nDissolveType == ENTITY_DISSOLVE_NORMAL ) && pAnimating->IsRagdoll()) { - IPhysicsObject *ppList[32]; - int nCount = pAnimating->VPhysicsGetObjectList( ppList, 32 ); + IPhysicsObject *ppList[VPHYSICS_MAX_OBJECT_LIST_COUNT]; + int nCount = pAnimating->VPhysicsGetObjectList( ppList, ARRAYSIZE(ppList) ); if ( nCount > 0 ) { m_pController = physenv->CreateMotionController( this ); diff --git a/src/src/cl_dll/c_entitydissolve.h b/src/src/game/client/c_entitydissolve.h similarity index 100% rename from src/src/cl_dll/c_entitydissolve.h rename to src/src/game/client/c_entitydissolve.h diff --git a/src/src/cl_dll/c_entityparticletrail.cpp b/src/src/game/client/c_entityparticletrail.cpp similarity index 100% rename from src/src/cl_dll/c_entityparticletrail.cpp rename to src/src/game/client/c_entityparticletrail.cpp diff --git a/src/src/game/client/c_env_fog_controller.cpp b/src/src/game/client/c_env_fog_controller.cpp new file mode 100644 index 0000000..0a4043a --- /dev/null +++ b/src/src/game/client/c_env_fog_controller.cpp @@ -0,0 +1,46 @@ +//========= Copyright © 1996-2007, Valve Corporation, All rights reserved. ==== +// +// An entity that allows level designer control over the fog parameters. +// +//============================================================================= + +#include "cbase.h" +#include "c_env_fog_controller.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +IMPLEMENT_NETWORKCLASS_ALIASED( FogController, DT_FogController ) + +//----------------------------------------------------------------------------- +// Datatable +//----------------------------------------------------------------------------- +BEGIN_NETWORK_TABLE_NOBASE( CFogController, DT_FogController ) + // fog data + RecvPropInt( RECVINFO( m_fog.enable ) ), + RecvPropInt( RECVINFO( m_fog.blend ) ), + RecvPropVector( RECVINFO( m_fog.dirPrimary ) ), + RecvPropInt( RECVINFO( m_fog.colorPrimary ) ), + RecvPropInt( RECVINFO( m_fog.colorSecondary ) ), + RecvPropFloat( RECVINFO( m_fog.start ) ), + RecvPropFloat( RECVINFO( m_fog.end ) ), + RecvPropFloat( RECVINFO( m_fog.farz ) ), + RecvPropFloat( RECVINFO( m_fog.maxdensity ) ), + + RecvPropInt( RECVINFO( m_fog.colorPrimaryLerpTo ) ), + RecvPropInt( RECVINFO( m_fog.colorSecondaryLerpTo ) ), + RecvPropFloat( RECVINFO( m_fog.startLerpTo ) ), + RecvPropFloat( RECVINFO( m_fog.endLerpTo ) ), + RecvPropFloat( RECVINFO( m_fog.lerptime ) ), + RecvPropFloat( RECVINFO( m_fog.duration ) ), +END_NETWORK_TABLE() + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_FogController::C_FogController() +{ + // Make sure that old maps without fog fields don't get wacked out fog values. + m_fog.enable = false; + m_fog.maxdensity = 1.0f; +} diff --git a/src/src/game/client/c_env_fog_controller.h b/src/src/game/client/c_env_fog_controller.h new file mode 100644 index 0000000..6fc7331 --- /dev/null +++ b/src/src/game/client/c_env_fog_controller.h @@ -0,0 +1,33 @@ +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef C_ENV_FOG_CONTROLLER_H +#define C_ENV_FOG_CONTROLLER_H + +#define CFogController C_FogController + +//============================================================================= +// +// Class Fog Controller: +// Compares a set of integer inputs to the one main input +// Outputs true if they are all equivalant, false otherwise +// +class C_FogController : public C_BaseEntity +{ +public: + DECLARE_NETWORKCLASS(); + DECLARE_CLASS( C_FogController, C_BaseEntity ); + + C_FogController(); + +public: + + fogparams_t m_fog; +}; + + +#endif // C_ENV_FOG_CONTROLLER_H \ No newline at end of file diff --git a/src/src/cl_dll/c_env_particlescript.cpp b/src/src/game/client/c_env_particlescript.cpp similarity index 100% rename from src/src/cl_dll/c_env_particlescript.cpp rename to src/src/game/client/c_env_particlescript.cpp diff --git a/src/src/game/client/c_env_projected_texture.h b/src/src/game/client/c_env_projected_texture.h new file mode 100644 index 0000000..1aa36b6 --- /dev/null +++ b/src/src/game/client/c_env_projected_texture.h @@ -0,0 +1,65 @@ +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef C_ENVPROJECTEDTEXTURE_H +#define C_ENVPROJECTEDTEXTURE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "c_baseentity.h" +#include "basetypes.h" + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class C_EnvProjectedTexture : public C_BaseEntity +{ + DECLARE_CLASS( C_EnvProjectedTexture, C_BaseEntity ); +public: + DECLARE_CLIENTCLASS(); + + C_EnvProjectedTexture(); + ~C_EnvProjectedTexture(); + + virtual void OnDataChanged( DataUpdateType_t updateType ); + void ShutDownLightHandle( void ); + + virtual void Simulate(); + + void UpdateLight( bool bForceUpdate ); + + bool ShadowsEnabled(); + + float GetFOV(); + +private: + + ClientShadowHandle_t m_LightHandle; + + EHANDLE m_hTargetEntity; + + bool m_bState; + float m_flLightFOV; + bool m_bEnableShadows; + bool m_bLightOnlyTarget; + bool m_bLightWorld; + bool m_bCameraSpace; + color32 m_cLightColor; + float m_flAmbient; + char m_SpotlightTextureName[ MAX_PATH ]; + int m_nSpotlightTextureFrame; + int m_nShadowQuality; + bool m_bCurrentShadow; + +public: + C_EnvProjectedTexture *m_pNext; +}; + +C_EnvProjectedTexture* GetEnvProjectedTextureList(); + +#endif // C_ENVPROJECTEDTEXTURE_H diff --git a/src/src/cl_dll/c_env_projectedtexture.cpp b/src/src/game/client/c_env_projectedtexture.cpp similarity index 66% rename from src/src/cl_dll/c_env_projectedtexture.cpp rename to src/src/game/client/c_env_projectedtexture.cpp index c8a2f18..818393f 100644 --- a/src/src/cl_dll/c_env_projectedtexture.cpp +++ b/src/src/game/client/c_env_projectedtexture.cpp @@ -12,11 +12,14 @@ #include "iviewrender.h" #include "view_shared.h" #include "texture_group_names.h" -#include "vstdlib/icommandline.h" +#include "tier0/icommandline.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" +static ConVar mat_slopescaledepthbias_shadowmap( "mat_slopescaledepthbias_shadowmap", "16", FCVAR_CHEAT ); +static ConVar mat_depthbias_shadowmap( "mat_depthbias_shadowmap", "0.0005", FCVAR_CHEAT ); + //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- @@ -48,7 +51,13 @@ private: bool m_bLightOnlyTarget; bool m_bLightWorld; bool m_bCameraSpace; - color32 m_cLightColor; + Vector m_LinearFloatLightColor; + float m_flAmbient; + float m_flNearZ; + float m_flFarZ; + char m_SpotlightTextureName[ MAX_PATH ]; + int m_nSpotlightTextureFrame; + int m_nShadowQuality; }; IMPLEMENT_CLIENTCLASS_DT( C_EnvProjectedTexture, DT_EnvProjectedTexture, CEnvProjectedTexture ) @@ -59,7 +68,13 @@ IMPLEMENT_CLIENTCLASS_DT( C_EnvProjectedTexture, DT_EnvProjectedTexture, CEnvPro RecvPropBool( RECVINFO( m_bLightOnlyTarget ) ), RecvPropBool( RECVINFO( m_bLightWorld ) ), RecvPropBool( RECVINFO( m_bCameraSpace ) ), - RecvPropInt( RECVINFO( m_cLightColor ) ), + RecvPropVector( RECVINFO( m_LinearFloatLightColor ) ), + RecvPropFloat( RECVINFO( m_flAmbient ) ), + RecvPropString( RECVINFO( m_SpotlightTextureName ) ), + RecvPropInt( RECVINFO( m_nSpotlightTextureFrame ) ), + RecvPropFloat( RECVINFO( m_flNearZ ) ), + RecvPropFloat( RECVINFO( m_flFarZ ) ), + RecvPropInt( RECVINFO( m_nShadowQuality ) ), END_RECV_TABLE() C_EnvProjectedTexture::C_EnvProjectedTexture( void ) @@ -104,8 +119,7 @@ void C_EnvProjectedTexture::UpdateLight( bool bForceUpdate ) return; } - Vector vPos = GetAbsOrigin(); - Vector vForward; + Vector vForward, vRight, vUp, vPos = GetAbsOrigin(); FlashlightState_t state; if ( m_hTargetEntity != NULL ) @@ -119,45 +133,70 @@ void C_EnvProjectedTexture::UpdateLight( bool bForceUpdate ) { const QAngle playerAngles = pPlayer->GetAbsAngles(); - Vector vPlayerForward; - AngleVectors( playerAngles, &vPlayerForward ); + Vector vPlayerForward, vPlayerRight, vPlayerUp; + AngleVectors( playerAngles, &vPlayerForward, &vPlayerRight, &vPlayerUp ); matrix3x4_t mRotMatrix; AngleMatrix( angles, mRotMatrix ); - VectorTransform( vPlayerForward, mRotMatrix, vForward ); + VectorITransform( vPlayerForward, mRotMatrix, vForward ); + VectorITransform( vPlayerRight, mRotMatrix, vRight ); + VectorITransform( vPlayerUp, mRotMatrix, vUp ); float dist = (m_hTargetEntity->GetAbsOrigin() - GetAbsOrigin()).Length(); vPos = m_hTargetEntity->GetAbsOrigin() - vForward*dist; VectorNormalize( vForward ); + VectorNormalize( vRight ); + VectorNormalize( vUp ); } } else { vForward = m_hTargetEntity->GetAbsOrigin() - GetAbsOrigin(); VectorNormalize( vForward ); + + // JasonM - unimplemented + Assert (0); + + //Quaternion q = DirectionToOrientation( dir ); + + + // + // JasonM - set up vRight, vUp + // + +// VectorNormalize( vRight ); +// VectorNormalize( vUp ); } } else { - AngleVectors( GetAbsAngles(), &vForward ); + AngleVectors( GetAbsAngles(), &vForward, &vRight, &vUp ); } state.m_fHorizontalFOVDegrees = m_flLightFOV; state.m_fVerticalFOVDegrees = m_flLightFOV; state.m_vecLightOrigin = vPos; - state.m_vecLightDirection = vForward; + BasisToQuaternion( vForward, vRight, vUp, state.m_quatOrientation ); state.m_fQuadraticAtten = 0.0; state.m_fLinearAtten = 100; state.m_fConstantAtten = 0.0f; - state.m_Color.Init( (float)m_cLightColor.r/255.0f, (float)m_cLightColor.g/255.0f, (float)m_cLightColor.b/255.0f ); - state.m_NearZ = 1.0f; - state.m_FarZ = 750; - + state.m_Color[0] = m_LinearFloatLightColor.x; + state.m_Color[1] = m_LinearFloatLightColor.y; + state.m_Color[2] = m_LinearFloatLightColor.z; + state.m_Color[3] = 0.0f; // fixme: need to make ambient work m_flAmbient; + state.m_NearZ = m_flNearZ; + state.m_FarZ = m_flFarZ; + state.m_flShadowSlopeScaleDepthBias = mat_slopescaledepthbias_shadowmap.GetFloat(); + state.m_flShadowDepthBias = mat_depthbias_shadowmap.GetFloat(); state.m_bEnableShadows = m_bEnableShadows; + state.m_pSpotlightTexture = materials->FindTexture( m_SpotlightTextureName, TEXTURE_GROUP_OTHER, false ); + state.m_nSpotlightTextureFrame = m_nSpotlightTextureFrame; + + state.m_nShadowQuality = m_nShadowQuality; // Allow entity to affect shadow quality if( m_LightHandle == CLIENTSHADOW_INVALID_HANDLE ) { diff --git a/src/src/cl_dll/c_env_screenoverlay.cpp b/src/src/game/client/c_env_screenoverlay.cpp similarity index 90% rename from src/src/cl_dll/c_env_screenoverlay.cpp rename to src/src/game/client/c_env_screenoverlay.cpp index 04c5ba9..33f83f5 100644 --- a/src/src/cl_dll/c_env_screenoverlay.cpp +++ b/src/src/game/client/c_env_screenoverlay.cpp @@ -12,7 +12,7 @@ #include "iviewrender.h" #include "view_shared.h" #include "texture_group_names.h" -#include "vstdlib/icommandline.h" +#include "tier0/icommandline.h" #include "keyvalues.h" #include "ScreenSpaceEffects.h" #include "materialsystem/imaterialsystemhardwareconfig.h" @@ -190,6 +190,7 @@ enum { SCREENEFFECT_EP2_ADVISOR_STUN, SCREENEFFECT_EP1_INTRO, + SCREENEFFECT_EP2_GROGGY, }; // ============================================================================ @@ -262,6 +263,18 @@ void C_EnvScreenEffect::ReceiveMessage( int classID, bf_read &msg ) g_pScreenSpaceEffects->SetScreenSpaceEffectParams( "episodic_stun", pKeys ); g_pScreenSpaceEffects->EnableScreenSpaceEffect( "episodic_stun" ); } + else if ( m_nType == SCREENEFFECT_EP2_GROGGY ) + { + if( g_pMaterialSystemHardwareConfig->GetDXSupportLevel() < 80 ) + return; + + // Set our keys + pKeys->SetFloat( "duration", m_flDuration ); + pKeys->SetInt( "fadeout", 0 ); + + g_pScreenSpaceEffects->SetScreenSpaceEffectParams( "ep2_groggy", pKeys ); + g_pScreenSpaceEffects->EnableScreenSpaceEffect( "ep2_groggy" ); + } pKeys->deleteThis(); } @@ -291,6 +304,23 @@ void C_EnvScreenEffect::ReceiveMessage( int classID, bf_read &msg ) { g_pScreenSpaceEffects->DisableScreenSpaceEffect( "episodic_stun" ); } + else if ( m_nType == SCREENEFFECT_EP2_GROGGY ) + { + if( g_pMaterialSystemHardwareConfig->GetDXSupportLevel() < 80 ) + { + return; + } + // Create a keyvalue block to set these params + KeyValues *pKeys = new KeyValues( "keys" ); + if ( pKeys == NULL ) + return; + + // Set our keys + pKeys->SetFloat( "duration", m_flDuration ); + pKeys->SetInt( "fadeout", 1 ); + + g_pScreenSpaceEffects->SetScreenSpaceEffectParams( "ep2_groggy", pKeys ); + } break; } diff --git a/src/src/cl_dll/c_env_tonemap_controller.cpp b/src/src/game/client/c_env_tonemap_controller.cpp similarity index 92% rename from src/src/cl_dll/c_env_tonemap_controller.cpp rename to src/src/game/client/c_env_tonemap_controller.cpp index 29fcfe8..aeca3f8 100644 --- a/src/src/cl_dll/c_env_tonemap_controller.cpp +++ b/src/src/game/client/c_env_tonemap_controller.cpp @@ -13,6 +13,8 @@ extern float g_flCustomAutoExposureMax; extern float g_flCustomBloomScale; extern float g_flCustomBloomScaleMinimum; +EHANDLE g_hTonemapControllerInUse = NULL; + //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- @@ -67,9 +69,12 @@ C_EnvTonemapController::C_EnvTonemapController( void ) //----------------------------------------------------------------------------- C_EnvTonemapController::~C_EnvTonemapController( void ) { - g_bUseCustomAutoExposureMin = false; - g_bUseCustomAutoExposureMax = false; - g_bUseCustomBloomScale = false; + if ( g_hTonemapControllerInUse == this ) + { + g_bUseCustomAutoExposureMin = false; + g_bUseCustomAutoExposureMax = false; + g_bUseCustomBloomScale = false; + } } //----------------------------------------------------------------------------- @@ -86,5 +91,7 @@ void C_EnvTonemapController::OnDataChanged( DataUpdateType_t updateType ) g_flCustomAutoExposureMax = m_flCustomAutoExposureMax; g_flCustomBloomScale = m_flCustomBloomScale; g_flCustomBloomScaleMinimum = m_flCustomBloomScaleMinimum; + + g_hTonemapControllerInUse = this; } diff --git a/src/src/game/client/c_fire_smoke.cpp b/src/src/game/client/c_fire_smoke.cpp new file mode 100644 index 0000000..cbf0f10 --- /dev/null +++ b/src/src/game/client/c_fire_smoke.cpp @@ -0,0 +1,404 @@ +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "IViewRender.h" +#include "ClientEffectPrecacheSystem.h" +#include "studio.h" +#include "bone_setup.h" +#include "engine/ivmodelinfo.h" +#include "c_fire_smoke.h" +#include "engine/IEngineSound.h" +#include "iefx.h" +#include "dlight.h" +#include "tier0/ICommandLine.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + + +CLIENTEFFECT_REGISTER_BEGIN( SmokeStackMaterials ) + CLIENTEFFECT_MATERIAL( "particle/SmokeStack" ) +CLIENTEFFECT_REGISTER_END() + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *pRecvProp - +// *pStruct - +// *pVarData - +// *pIn - +// objectID - +//----------------------------------------------------------------------------- +void RecvProxy_Scale( const CRecvProxyData *pData, void *pStruct, void *pOut ) +{ + C_FireSmoke *pFireSmoke = (C_FireSmoke *) pStruct; + float scale = pData->m_Value.m_Float; + + //If changed, update our internal information + if ( ( pFireSmoke->m_flScale != scale ) && ( pFireSmoke->m_flScaleEnd != scale ) ) + { + pFireSmoke->m_flScaleStart = pFireSmoke->m_flScaleRegister; + pFireSmoke->m_flScaleEnd = scale; + } + + pFireSmoke->m_flScale = scale; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *pRecvProp - +// *pStruct - +// *pVarData - +// *pIn - +// objectID - +//----------------------------------------------------------------------------- +void RecvProxy_ScaleTime( const CRecvProxyData *pData, void *pStruct, void *pOut ) +{ + C_FireSmoke *pFireSmoke = (C_FireSmoke *) pStruct; + float time = pData->m_Value.m_Float; + + //If changed, update our internal information + //if ( pFireSmoke->m_flScaleTime != time ) + { + if ( time == -1.0f ) + { + pFireSmoke->m_flScaleTimeStart = Helper_GetTime()-1.0f; + pFireSmoke->m_flScaleTimeEnd = pFireSmoke->m_flScaleTimeStart; + } + else + { + pFireSmoke->m_flScaleTimeStart = Helper_GetTime(); + pFireSmoke->m_flScaleTimeEnd = Helper_GetTime() + time; + } + } + + pFireSmoke->m_flScaleTime = time; +} + +//Receive datatable +IMPLEMENT_CLIENTCLASS_DT( C_FireSmoke, DT_FireSmoke, CFireSmoke ) + RecvPropFloat( RECVINFO( m_flStartScale )), + RecvPropFloat( RECVINFO( m_flScale ), 0, RecvProxy_Scale ), + RecvPropFloat( RECVINFO( m_flScaleTime ), 0, RecvProxy_ScaleTime ), + RecvPropInt( RECVINFO( m_nFlags ) ), + RecvPropInt( RECVINFO( m_nFlameModelIndex ) ), + RecvPropInt( RECVINFO( m_nFlameFromAboveModelIndex ) ), +END_RECV_TABLE() + +//================================================== +// C_FireSmoke +//================================================== + +C_FireSmoke::C_FireSmoke() +{ +} + +C_FireSmoke::~C_FireSmoke() +{ + + // Shut down our effect if we have it + if ( m_hEffect ) + { + m_hEffect->StopEmission(false, false , true); + m_hEffect = NULL; + } + +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_FireSmoke::Simulate( void ) +{ +} + +#define FLAME_ALPHA_START 0.9f +#define FLAME_ALPHA_END 1.0f + +#define FLAME_TRANS_START 0.75f + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_FireSmoke::AddFlames( void ) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : bnewentity - +//----------------------------------------------------------------------------- +void C_FireSmoke::OnDataChanged( DataUpdateType_t updateType ) +{ + BaseClass::OnDataChanged( updateType ); + + + if ( updateType == DATA_UPDATE_CREATED ) + { + Start(); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_FireSmoke::UpdateEffects( void ) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool C_FireSmoke::ShouldDraw() +{ + + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_FireSmoke::Start( void ) +{ + const char *lpszEffectName; + int nSize = (int) floor( m_flStartScale / 36.0f ); + switch ( nSize ) + { + case 0: + lpszEffectName = ( m_nFlags & bitsFIRESMOKE_SMOKE ) ? "env_fire_tiny_smoke" : "env_fire_tiny"; + break; + + case 1: + lpszEffectName = ( m_nFlags & bitsFIRESMOKE_SMOKE ) ? "env_fire_small_smoke" : "env_fire_small"; + break; + + case 2: + lpszEffectName = ( m_nFlags & bitsFIRESMOKE_SMOKE ) ? "env_fire_medium_smoke" : "env_fire_medium"; + break; + + case 3: + default: + lpszEffectName = ( m_nFlags & bitsFIRESMOKE_SMOKE ) ? "env_fire_large_smoke" : "env_fire_large"; + break; + } + + // Create the effect of the correct size + m_hEffect = ParticleProp()->Create( lpszEffectName, PATTACH_ABSORIGIN ); + +} + + +//----------------------------------------------------------------------------- +// Purpose: FIXME: what's the right way to do this? +//----------------------------------------------------------------------------- +void C_FireSmoke::StartClientOnly( void ) +{ + Start(); + + ClientEntityList().AddNonNetworkableEntity( this ); + CollisionProp()->CreatePartitionHandle(); + AddEffects( EF_NORECEIVESHADOW | EF_NOSHADOW ); + AddToLeafSystem(); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_FireSmoke::RemoveClientOnly(void) +{ + ClientThinkList()->RemoveThinkable( GetClientHandle() ); + + // Remove from the client entity list. + ClientEntityList().RemoveEntity( GetClientHandle() ); + + partition->Remove( PARTITION_CLIENT_SOLID_EDICTS | PARTITION_CLIENT_RESPONSIVE_EDICTS | PARTITION_CLIENT_NON_STATIC_EDICTS, CollisionProp()->GetPartitionHandle() ); + + RemoveFromLeafSystem(); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_FireSmoke::UpdateAnimation( void ) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_FireSmoke::UpdateFlames( void ) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_FireSmoke::UpdateScale( void ) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_FireSmoke::Update( void ) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_FireSmoke::FindClipPlane( void ) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: Spawn smoke (...duh) +//----------------------------------------------------------------------------- + +void C_FireSmoke::SpawnSmoke( void ) +{ +} + + +IMPLEMENT_CLIENTCLASS_DT( C_EntityFlame, DT_EntityFlame, CEntityFlame ) + RecvPropEHandle(RECVINFO(m_hEntAttached)), +END_RECV_TABLE() + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_EntityFlame::C_EntityFlame( void ) : +m_hEffect( NULL ) +{ + m_hOldAttached = NULL; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_EntityFlame::~C_EntityFlame( void ) +{ + StopEffect(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_EntityFlame::StopEffect( void ) +{ + if ( m_hEffect ) + { + ParticleProp()->StopEmission( m_hEffect, true ); + m_hEffect->SetControlPointEntity( 0, NULL ); + m_hEffect->SetControlPointEntity( 1, NULL ); + m_hEffect = NULL; + } + + if ( m_hEntAttached ) + { + m_hEntAttached->RemoveFlag( FL_ONFIRE ); + m_hEntAttached->SetEffectEntity( NULL ); + m_hEntAttached->StopSound( "General.BurningFlesh" ); + m_hEntAttached->StopSound( "General.BurningObject" ); + + + m_hEntAttached = NULL; + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_EntityFlame::UpdateOnRemove( void ) +{ + StopEffect(); + BaseClass::UpdateOnRemove(); +} + +void C_EntityFlame::CreateEffect( void ) +{ + if ( m_hEffect ) + { + ParticleProp()->StopEmission( m_hEffect, true ); + m_hEffect->SetControlPointEntity( 0, NULL ); + m_hEffect->SetControlPointEntity( 1, NULL ); + m_hEffect = NULL; + } + + m_hEffect = ParticleProp()->Create( "burning_character", PATTACH_ABSORIGIN_FOLLOW ); + if ( m_hEffect ) + { + C_BaseEntity *pEntity = m_hEntAttached; + m_hOldAttached = m_hEntAttached; + + ParticleProp()->AddControlPoint( m_hEffect, 1, pEntity, PATTACH_ABSORIGIN_FOLLOW ); + m_hEffect->SetControlPoint( 0, GetAbsOrigin() ); + m_hEffect->SetControlPoint( 1, GetAbsOrigin() ); + m_hEffect->SetControlPointEntity( 0, pEntity ); + m_hEffect->SetControlPointEntity( 1, pEntity ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_EntityFlame::OnDataChanged( DataUpdateType_t updateType ) +{ + if ( updateType == DATA_UPDATE_CREATED ) + { + CreateEffect(); + } + + // FIXME: This is a bit of a shady path + if ( updateType == DATA_UPDATE_DATATABLE_CHANGED ) + { + // If our owner changed, then recreate the effect + if ( m_hEntAttached != m_hOldAttached ) + { + CreateEffect(); + } + } + + BaseClass::OnDataChanged( updateType ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_EntityFlame::Simulate( void ) +{ + if ( gpGlobals->frametime <= 0.0f ) + return; + +#ifdef HL2_EPISODIC + + if ( IsEffectActive(EF_BRIGHTLIGHT) || IsEffectActive(EF_DIMLIGHT) ) + { + dlight_t *dl = effects->CL_AllocDlight ( index ); + dl->origin = GetAbsOrigin(); + dl->origin[2] += 16; + dl->color.r = 254; + dl->color.g = 174; + dl->color.b = 10; + dl->radius = random->RandomFloat(400,431); + dl->die = gpGlobals->curtime + 0.001; + } + +#endif // HL2_EPISODIC +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_EntityFlame::ClientThink( void ) +{ + StopEffect(); + Release(); +} diff --git a/src/src/cl_dll/c_fire_smoke.h b/src/src/game/client/c_fire_smoke.h similarity index 87% rename from src/src/cl_dll/c_fire_smoke.h rename to src/src/game/client/c_fire_smoke.h index cde65ab..13f694e 100644 --- a/src/src/cl_dll/c_fire_smoke.h +++ b/src/src/game/client/c_fire_smoke.h @@ -183,6 +183,8 @@ protected: CFireOverlay *m_pFireOverlay; + // New Particle Fire Effect + CNewParticleEffect *m_hEffect; private: C_FireSmoke( const C_FireSmoke & ); }; @@ -282,41 +284,19 @@ public: C_EntityFlame( void ); ~C_EntityFlame( void ); - void UpdateOnRemove( void ); - void CleanUpRagdollOnRemove( void ); - void OnDataChanged( DataUpdateType_t updateType ); - RenderGroup_t GetRenderGroup(); - void Simulate( void ); - - EHANDLE m_hEntAttached; // The entity that we are burning (attached to). - bool m_bUseHitboxes; - bool m_bCreatedClientside; + virtual void Simulate( void ); + virtual void UpdateOnRemove( void ); + virtual void OnDataChanged( DataUpdateType_t updateType ); virtual void ClientThink( void ); - C_FireSmoke *m_pFireSmoke[NUM_HITBOX_FIRES]; + CNewParticleEffect *m_hEffect; + EHANDLE m_hEntAttached; // The entity that we are burning (attached to). + EHANDLE m_hOldAttached; protected: - void AttachToHitBoxes( void ); - void UpdateHitBoxFlames( void ); - void DeleteHitBoxFlames( void ); - - float m_flSize; - CSmartPtr m_pEmitter; - TimedEvent m_ParticleSpawn; - bool m_bAttachedToHitboxes; - float m_flLifetime; - bool m_bStartedFading; - - const model_t *m_pCachedModel; // Holds the model pointer to detect when it changes - - Vector m_vecLastPosition; - - PMaterialHandle m_MaterialHandle[NUM_FLAMELETS]; - - // For attaching to the hitboxes of an animating model. - Vector m_vecFireOrigin[NUM_HITBOX_FIRES]; - int m_nHitbox[NUM_HITBOX_FIRES]; + void CreateEffect( void ); + void StopEffect( void ); }; #endif //C_FIRE_SMOKE_H \ No newline at end of file diff --git a/src/src/cl_dll/c_fish.cpp b/src/src/game/client/c_fish.cpp similarity index 100% rename from src/src/cl_dll/c_fish.cpp rename to src/src/game/client/c_fish.cpp diff --git a/src/src/cl_dll/c_forcefeedback.cpp b/src/src/game/client/c_forcefeedback.cpp similarity index 100% rename from src/src/cl_dll/c_forcefeedback.cpp rename to src/src/game/client/c_forcefeedback.cpp diff --git a/src/src/cl_dll/c_func_areaportalwindow.cpp b/src/src/game/client/c_func_areaportalwindow.cpp similarity index 94% rename from src/src/cl_dll/c_func_areaportalwindow.cpp rename to src/src/game/client/c_func_areaportalwindow.cpp index 9699d65..bc397e2 100644 --- a/src/src/cl_dll/c_func_areaportalwindow.cpp +++ b/src/src/game/client/c_func_areaportalwindow.cpp @@ -14,6 +14,8 @@ // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" +#define VIEWER_PADDING 80.0f + class C_FuncAreaPortalWindow : public C_BaseEntity { public: @@ -126,9 +128,8 @@ float C_FuncAreaPortalWindow::GetDistanceBlend() { flDist *= local->GetFOVDistanceAdjustFactor(); } - float flAlpha = RemapVal( flDist, m_flFadeStartDist, m_flFadeDist, m_flTranslucencyLimit, 1 ); - flAlpha = clamp( flAlpha, m_flTranslucencyLimit, 1 ); - return flAlpha; + + return RemapValClamped( flDist, m_flFadeStartDist, m_flFadeDist, m_flTranslucencyLimit, 1 ); } bool C_FuncAreaPortalWindow::ShouldReceiveProjectedTextures( int flags ) diff --git a/src/src/cl_dll/c_func_breakablesurf.cpp b/src/src/game/client/c_func_breakablesurf.cpp similarity index 98% rename from src/src/cl_dll/c_func_breakablesurf.cpp rename to src/src/game/client/c_func_breakablesurf.cpp index 7e40b6c..2328f41 100644 --- a/src/src/cl_dll/c_func_breakablesurf.cpp +++ b/src/src/game/client/c_func_breakablesurf.cpp @@ -560,6 +560,7 @@ void C_BreakableSurface::DrawRenderList(IBrushSurface* pBrushSurface) IMesh* pMesh = NULL; int nCurStyle = -1; int nCurEdgeType = -1; + CMatRenderContextPtr pRenderContext( materials ); for( unsigned short i = m_RenderList.Head(); i != m_RenderList.InvalidIndex(); i = m_RenderList.Next(i) ) { @@ -570,9 +571,9 @@ void C_BreakableSurface::DrawRenderList(IBrushSurface* pBrushSurface) nCurEdgeType = m_RenderList[i].m_nEdgeType; m_pCurrentDetailTexture = m_pEdge[nCurEdgeType][nCurStyle].m_pMaterialEdgeTexture; - materials->Flush(false); - materials->Bind(m_pCrackedMaterial, (IClientRenderable*)this); - pMesh = materials->GetDynamicMesh( ); + pRenderContext->Flush(false); + pRenderContext->Bind(m_pCrackedMaterial, (IClientRenderable*)this); + pMesh = pRenderContext->GetDynamicMesh( ); } Vector vRenderPos = m_vCorner + @@ -604,6 +605,7 @@ void C_BreakableSurface::DrawRenderListHighlights(IBrushSurface* pBrushSurface) IMesh* pMesh = NULL; int nCurStyle = -1; int nCurEdgeType = -1; + CMatRenderContextPtr pRenderContext( materials ); for( unsigned short i = m_RenderList.Head(); i != m_RenderList.InvalidIndex(); i = m_RenderList.Next(i) ) { @@ -614,7 +616,7 @@ void C_BreakableSurface::DrawRenderListHighlights(IBrushSurface* pBrushSurface) nCurEdgeType = m_RenderList[i].m_nEdgeType; IMaterial *pMat = m_pEdge[nCurEdgeType][nCurStyle].m_pMaterialEdge; - pMesh = materials->GetDynamicMesh( true, NULL, NULL, pMat ); + pMesh = pRenderContext->GetDynamicMesh( true, NULL, NULL, pMat ); } Vector vRenderPos = m_vCorner + @@ -908,13 +910,15 @@ void C_BreakableSurface::AddToRenderList(int nWidth, int nHeight, WinSide_t nSid //------------------------------------------------------------------------------ void C_BreakableSurface::DrawSolidBlocks(IBrushSurface* pBrushSurface) { + CMatRenderContextPtr pRenderContext( materials ); + m_pCurrentDetailTexture = m_pMaterialBoxTexture; // Gotta flush (in a non-stalling way) because we effectively // have a new material due to the new base texture - materials->Flush(false); - materials->Bind(m_pCrackedMaterial, (IClientRenderable*)this); - IMesh* pMesh = materials->GetDynamicMesh( ); + pRenderContext->Flush(false); + pRenderContext->Bind(m_pCrackedMaterial, (IClientRenderable*)this); + IMesh* pMesh = pRenderContext->GetDynamicMesh( ); CMeshBuilder pMeshBuilder; // --------------- @@ -1283,6 +1287,7 @@ public: virtual ~CBreakableSurfaceProxy(); virtual bool Init( IMaterial *pMaterial, KeyValues *pKeyValues ); virtual void OnBind( C_BaseEntity *pC_BaseEntity ); + virtual IMaterial *CBreakableSurfaceProxy::GetMaterial(); private: // get at the material whose texture we're going to steal @@ -1320,4 +1325,12 @@ void CBreakableSurfaceProxy::OnBind( C_BaseEntity *pC_BaseEntity ) m_BaseTextureVar->SetTextureValue( pEnt->m_pCurrentDetailTexture ); } +IMaterial *CBreakableSurfaceProxy::GetMaterial() +{ + if ( !m_BaseTextureVar ) + return NULL; + + return m_BaseTextureVar->GetOwningMaterial(); +} + EXPOSE_INTERFACE( CBreakableSurfaceProxy, IMaterialProxy, "BreakableSurface" IMATERIAL_PROXY_INTERFACE_VERSION ); diff --git a/src/src/cl_dll/c_func_conveyor.cpp b/src/src/game/client/c_func_conveyor.cpp similarity index 86% rename from src/src/cl_dll/c_func_conveyor.cpp rename to src/src/game/client/c_func_conveyor.cpp index 5b2448b..782326e 100644 --- a/src/src/cl_dll/c_func_conveyor.cpp +++ b/src/src/game/client/c_func_conveyor.cpp @@ -1,8 +1,8 @@ -//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: // -//=============================================================================// +//===========================================================================// #include "cbase.h" #include "materialsystem/IMaterialProxy.h" @@ -10,12 +10,15 @@ #include "materialsystem/IMaterialVar.h" #include "FunctionProxy.h" #include -#include "VMatrix.h" -#include "FunctionProxy.h" +#include "mathlib/VMatrix.h" +#include "toolframework_client.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" +// forward declarations +void ToolFramework_RecordMaterialParams( IMaterial *pMaterial ); + class C_FuncConveyor : public C_BaseEntity { public: @@ -51,6 +54,7 @@ public: virtual bool Init( IMaterial *pMaterial, KeyValues *pKeyValues ); virtual void OnBind( void *pC_BaseEntity ); virtual void Release( void ) { delete this; } + virtual IMaterial *GetMaterial(); private: C_BaseEntity *BindArgToEntity( void *pArg ); @@ -139,6 +143,16 @@ void CConveyorMaterialProxy::OnBind( void *pC_BaseEntity ) { m_pTextureScrollVar->SetVecValue( sOffset, tOffset, 0.0f ); } + + if ( ToolsEnabled() ) + { + ToolFramework_RecordMaterialParams( GetMaterial() ); + } +} + +IMaterial *CConveyorMaterialProxy::GetMaterial() +{ + return m_pTextureScrollVar ? m_pTextureScrollVar->GetOwningMaterial() : NULL; } EXPOSE_INTERFACE( CConveyorMaterialProxy, IMaterialProxy, "ConveyorScroll" IMATERIAL_PROXY_INTERFACE_VERSION ); diff --git a/src/src/cl_dll/c_func_dust.cpp b/src/src/game/client/c_func_dust.cpp similarity index 79% rename from src/src/cl_dll/c_func_dust.cpp rename to src/src/game/client/c_func_dust.cpp index 0c76ffe..718c796 100644 --- a/src/src/cl_dll/c_func_dust.cpp +++ b/src/src/game/client/c_func_dust.cpp @@ -5,6 +5,7 @@ // $NoKeywords: $ //=============================================================================// #include "cbase.h" +#include "fx.h" #include "c_func_dust.h" #include "func_dust_shared.h" #include "c_te_particlesystem.h" @@ -12,10 +13,7 @@ #include "engine/IEngineTrace.h" #include "tier0/vprof.h" #include "ClientEffectPrecacheSystem.h" - -#ifdef _XBOX #include "particles_ez.h" -#endif // XBOX // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -152,10 +150,6 @@ C_Func_Dust::~C_Func_Dust() { } -CLIENTEFFECT_REGISTER_BEGIN( PrecacheFuncDust ) -CLIENTEFFECT_MATERIAL( "particle/sparkles" ) -CLIENTEFFECT_REGISTER_END() - void C_Func_Dust::OnDataChanged( DataUpdateType_t updateType ) { BaseClass::OnDataChanged( updateType ); @@ -258,12 +252,6 @@ void C_Func_Dust::AttemptSpawnNewParticle() //----------------------------------------------------------------------------- void FX_Dust( const Vector &vecOrigin, const Vector &vecDirection, float flSize, float flSpeed ) { -#ifdef _XBOX - - // - // XBox Version - // - VPROF_BUDGET( "FX_Dust", VPROF_BUDGETGROUP_PARTICLE_RENDERING ); int numPuffs = (flSize*0.5f); @@ -286,11 +274,6 @@ void FX_Dust( const Vector &vecOrigin, const Vector &vecDirection, float flSize, //Find area ambient light color and use it to tint smoke Vector worldLight = WorldGetLightForPoint( offset, true ); - // FIXME: Reduce - PMaterialHandle hMaterial[2]; - hMaterial[0] = ParticleMgr()->GetPMaterial("particle/particle_smokegrenade"); - hMaterial[1] = ParticleMgr()->GetPMaterial("particle/particle_noisesphere"); - // Throw puffs SimpleParticle particle; for ( int i = 0; i < numPuffs; i++ ) @@ -318,81 +301,8 @@ void FX_Dust( const Vector &vecOrigin, const Vector &vecDirection, float flSize, particle.m_flRoll = random->RandomInt( 0, 360 ); particle.m_flRollDelta = random->RandomFloat( -0.5f, 0.5f ); - AddSimpleParticle( &particle, hMaterial[random->RandomInt(0,1)] ); + AddSimpleParticle( &particle, g_Mat_DustPuff[random->RandomInt(0,1)] ); } -#else - - // - // PC Version - // - - VPROF_BUDGET( "FX_Dust", VPROF_BUDGETGROUP_PARTICLE_RENDERING ); - CSmartPtr pSimple = CSimpleEmitter::Create( "dust" ); - pSimple->SetSortOrigin( vecOrigin ); - pSimple->SetNearClip( 32, 64 ); - - SimpleParticle *pParticle; - - Vector offset; - - int numPuffs = (flSize*0.5f); - - if ( numPuffs < 1 ) - numPuffs = 1; - if ( numPuffs > 32 ) - numPuffs = 32; - - float speed = flSpeed * 0.1f; - - if ( speed < 0 ) - speed = 1.0f; - - if (speed > 48.0f ) - speed = 48.0f; - - //FIXME: Better sampling area - offset = vecOrigin + ( vecDirection * flSize ); - - //Find area ambient light color and use it to tint smoke - Vector worldLight = WorldGetLightForPoint( offset, true ); - - PMaterialHandle hMaterial[2]; - - hMaterial[0] = pSimple->GetPMaterial("particle/particle_smokegrenade"); - hMaterial[1] = pSimple->GetPMaterial("particle/particle_noisesphere"); - - //Throw puffs - for ( int i = 0; i < numPuffs; i++ ) - { - offset.Random( -(flSize*0.25f), flSize*0.25f ); - offset += vecOrigin + ( vecDirection * flSize ); - - pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof(SimpleParticle), hMaterial[random->RandomInt(0,1)], offset ); - - if ( pParticle != NULL ) - { - pParticle->m_flLifetime = 0.0f; - pParticle->m_flDieTime = random->RandomFloat( 0.4f, 1.5f ); - - pParticle->m_vecVelocity = vecDirection * random->RandomFloat( speed*0.5f, speed ) * i; - - pParticle->m_vecVelocity[2] = 0.0f; - - int color = random->RandomInt( 48, 64 ); - - pParticle->m_uchColor[0] = (color+16) + ( worldLight[0] * (float) color ); - pParticle->m_uchColor[1] = (color+8) + ( worldLight[1] * (float) color ); - pParticle->m_uchColor[2] = color + ( worldLight[2] * (float) color ); - - pParticle->m_uchStartAlpha = random->RandomInt( 32, 128 ); - pParticle->m_uchEndAlpha = 0; - pParticle->m_uchStartSize = random->RandomInt( 2, 8 ); - pParticle->m_uchEndSize = random->RandomInt( 24, 48 ); - pParticle->m_flRoll = random->RandomInt( 0, 360 ); - pParticle->m_flRollDelta = random->RandomFloat( -1.0f, 1.0f ); - } - } -#endif // _XBOX } diff --git a/src/src/cl_dll/c_func_dust.h b/src/src/game/client/c_func_dust.h similarity index 100% rename from src/src/cl_dll/c_func_dust.h rename to src/src/game/client/c_func_dust.h diff --git a/src/src/cl_dll/c_func_lod.cpp b/src/src/game/client/c_func_lod.cpp similarity index 93% rename from src/src/cl_dll/c_func_lod.cpp rename to src/src/game/client/c_func_lod.cpp index a2f4939..9339c0c 100644 --- a/src/src/cl_dll/c_func_lod.cpp +++ b/src/src/game/client/c_func_lod.cpp @@ -12,10 +12,6 @@ // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" -extern Vector g_vecRenderOrigin; -extern ConVar r_DoCovertTransitions; - - class C_Func_LOD : public C_BaseEntity { public: @@ -38,7 +34,6 @@ public: ConVar lod_TransitionDist("lod_TransitionDist", "800"); -ConVar lod_Enable("lod_Enable", "0"); // ------------------------------------------------------------------------- // diff --git a/src/src/cl_dll/c_func_occluder.cpp b/src/src/game/client/c_func_occluder.cpp similarity index 100% rename from src/src/cl_dll/c_func_occluder.cpp rename to src/src/game/client/c_func_occluder.cpp diff --git a/src/src/game/client/c_func_reflective_glass.cpp b/src/src/game/client/c_func_reflective_glass.cpp new file mode 100644 index 0000000..c88f1db --- /dev/null +++ b/src/src/game/client/c_func_reflective_glass.cpp @@ -0,0 +1,118 @@ +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// +// +// Purpose: +// +// $NoKeywords: $ +//===========================================================================// +#include "cbase.h" +#include "view_shared.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +class C_FuncReflectiveGlass : public C_BaseEntity +{ +public: + DECLARE_CLASS( C_FuncReflectiveGlass, C_BaseEntity ); + DECLARE_CLIENTCLASS(); + +// C_BaseEntity. +public: + C_FuncReflectiveGlass(); + virtual ~C_FuncReflectiveGlass(); + + virtual bool ShouldDraw(); + + C_FuncReflectiveGlass *m_pNext; +}; + +IMPLEMENT_CLIENTCLASS_DT( C_FuncReflectiveGlass, DT_FuncReflectiveGlass, CFuncReflectiveGlass ) +END_RECV_TABLE() + + +//----------------------------------------------------------------------------- +// Globals +//----------------------------------------------------------------------------- +C_EntityClassList g_ReflectiveGlassList; +C_FuncReflectiveGlass *C_EntityClassList::m_pClassList = NULL; + +C_FuncReflectiveGlass* GetReflectiveGlassList() +{ + return g_ReflectiveGlassList.m_pClassList; +} + + +//----------------------------------------------------------------------------- +// Constructor, destructor +//----------------------------------------------------------------------------- +C_FuncReflectiveGlass::C_FuncReflectiveGlass() +{ + g_ReflectiveGlassList.Insert( this ); +} + +C_FuncReflectiveGlass::~C_FuncReflectiveGlass() +{ + g_ReflectiveGlassList.Remove( this ); +} + + +bool C_FuncReflectiveGlass::ShouldDraw() +{ + return true; +} + + +//----------------------------------------------------------------------------- +// Do we have reflective glass in view? +//----------------------------------------------------------------------------- +bool IsReflectiveGlassInView( const CViewSetup& view, cplane_t &plane ) +{ + // Early out if no cameras + C_FuncReflectiveGlass *pReflectiveGlass = GetReflectiveGlassList(); + if ( !pReflectiveGlass ) + return false; + + Frustum_t frustum; + GeneratePerspectiveFrustum( view.origin, view.angles, view.zNear, view.zFar, view.fov, view.m_flAspectRatio, frustum ); + + cplane_t localPlane; + Vector vecOrigin, vecWorld, vecDelta, vecForward; + AngleVectors( view.angles, &vecForward, NULL, NULL ); + + for ( ; pReflectiveGlass != NULL; pReflectiveGlass = pReflectiveGlass->m_pNext ) + { + if ( pReflectiveGlass->IsDormant() ) + continue; + + Vector vecMins, vecMaxs; + pReflectiveGlass->GetRenderBoundsWorldspace( vecMins, vecMaxs ); + if ( R_CullBox( vecMins, vecMaxs, frustum ) ) + continue; + + const model_t *pModel = pReflectiveGlass->GetModel(); + const matrix3x4_t& mat = pReflectiveGlass->EntityToWorldTransform(); + + int nCount = modelinfo->GetBrushModelPlaneCount( pModel ); + for ( int i = 0; i < nCount; ++i ) + { + modelinfo->GetBrushModelPlane( pModel, i, localPlane, &vecOrigin ); + + MatrixTransformPlane( mat, localPlane, plane ); // Transform to world space + VectorTransform( vecOrigin, mat, vecWorld ); + + if ( view.origin.Dot( plane.normal ) <= plane.dist ) // Check for view behind plane + continue; + + VectorSubtract( vecWorld, view.origin, vecDelta ); // Backface cull + if ( vecDelta.Dot( plane.normal ) >= 0 ) + continue; + + return true; + } + } + + return false; +} + + + diff --git a/src/src/game/client/c_func_reflective_glass.h b/src/src/game/client/c_func_reflective_glass.h new file mode 100644 index 0000000..69c8ad8 --- /dev/null +++ b/src/src/game/client/c_func_reflective_glass.h @@ -0,0 +1,27 @@ +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// +// +// Purpose: +// +// $NoKeywords: $ +//===========================================================================// + +#ifndef C_FUNC_REFLECTIVE_GLASS +#define C_FUNC_REFLECTIVE_GLASS + +#ifdef _WIN32 +#pragma once +#endif + +struct cplane_t; +class CViewSetup; + + +//----------------------------------------------------------------------------- +// Do we have reflective glass in view? If so, what's the reflection plane? +//----------------------------------------------------------------------------- +bool IsReflectiveGlassInView( const CViewSetup& view, cplane_t &plane ); + + +#endif // C_FUNC_REFLECTIVE_GLASS + + diff --git a/src/src/game/client/c_func_rotating.cpp b/src/src/game/client/c_func_rotating.cpp new file mode 100644 index 0000000..53a9be3 --- /dev/null +++ b/src/src/game/client/c_func_rotating.cpp @@ -0,0 +1,41 @@ +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// +// +// Purpose: +// +//===========================================================================// + +#include "cbase.h" +#include + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class C_FuncRotating : public C_BaseEntity +{ +public: + DECLARE_CLASS( C_FuncRotating, C_BaseEntity ); + DECLARE_CLIENTCLASS(); + + C_FuncRotating(); + +private: +}; + +extern void RecvProxy_SimulationTime( const CRecvProxyData *pData, void *pStruct, void *pOut ); + +IMPLEMENT_CLIENTCLASS_DT( C_FuncRotating, DT_FuncRotating, CFuncRotating ) + RecvPropVector( RECVINFO_NAME( m_vecNetworkOrigin, m_vecOrigin ) ), + RecvPropQAngles( RECVINFO_NAME( m_angNetworkAngles, m_angRotation ) ), + RecvPropInt( RECVINFO(m_flSimulationTime), 0, RecvProxy_SimulationTime ), +END_RECV_TABLE() + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_FuncRotating::C_FuncRotating() +{ +} diff --git a/src/src/cl_dll/c_func_smokevolume.cpp b/src/src/game/client/c_func_smokevolume.cpp similarity index 100% rename from src/src/cl_dll/c_func_smokevolume.cpp rename to src/src/game/client/c_func_smokevolume.cpp diff --git a/src/src/cl_dll/c_func_tracktrain.cpp b/src/src/game/client/c_func_tracktrain.cpp similarity index 98% rename from src/src/cl_dll/c_func_tracktrain.cpp rename to src/src/game/client/c_func_tracktrain.cpp index 9c1720b..a55b6eb 100644 --- a/src/src/cl_dll/c_func_tracktrain.cpp +++ b/src/src/game/client/c_func_tracktrain.cpp @@ -25,6 +25,9 @@ public: virtual void OnDataChanged( DataUpdateType_t updateType ); virtual bool GetSoundSpatialization( SpatializationInfo_t& info ); + virtual bool IsBaseTrain( void ) const { return true; } + + private: int m_nLongAxis; float m_flRadius; diff --git a/src/src/cl_dll/c_gib.cpp b/src/src/game/client/c_gib.cpp similarity index 100% rename from src/src/cl_dll/c_gib.cpp rename to src/src/game/client/c_gib.cpp diff --git a/src/src/cl_dll/c_gib.h b/src/src/game/client/c_gib.h similarity index 100% rename from src/src/cl_dll/c_gib.h rename to src/src/game/client/c_gib.h diff --git a/src/src/cl_dll/c_hairball.cpp b/src/src/game/client/c_hairball.cpp similarity index 97% rename from src/src/cl_dll/c_hairball.cpp rename to src/src/game/client/c_hairball.cpp index c988204..ce995b2 100644 --- a/src/src/cl_dll/c_hairball.cpp +++ b/src/src/game/client/c_hairball.cpp @@ -6,7 +6,7 @@ //=============================================================================// #include "cbase.h" #include "simple_physics.h" -#include "vmatrix.h" +#include "mathlib/vmatrix.h" #include "beamdraw.h" // memdbgon must be the last include file in a .cpp file!!! @@ -299,16 +299,17 @@ int C_Hairball::DrawModel( int flags ) if ( !m_pMaterial ) return 0; + CMatRenderContextPtr pRenderContext( g_pMaterialSystem ); for ( int iHair=0; iHair < m_nHairs; iHair++ ) { CSimplePhysics::CNode *pBase = &m_Nodes[iHair * m_nNodesPerHair]; CBeamSegDraw beamDraw; - beamDraw.Start( m_nNodesPerHair-1, m_pMaterial ); + beamDraw.Start( pRenderContext, m_nNodesPerHair-1, m_pMaterial ); for ( int i=0; i < m_nNodesPerHair; i++ ) { - CBeamSeg seg; + BeamSeg_t seg; seg.m_vPos = pBase[i].m_vPredicted; seg.m_vColor.Init( 0, 0, 0 ); seg.m_flTexCoord = 0; diff --git a/src/src/cl_dll/c_impact_effects.cpp b/src/src/game/client/c_impact_effects.cpp similarity index 90% rename from src/src/cl_dll/c_impact_effects.cpp rename to src/src/game/client/c_impact_effects.cpp index 252bb6b..080988d 100644 --- a/src/src/cl_dll/c_impact_effects.cpp +++ b/src/src/game/client/c_impact_effects.cpp @@ -34,15 +34,58 @@ CLIENTEFFECT_MATERIAL( "effects/blood" ) CLIENTEFFECT_MATERIAL( "effects/blood2" ) CLIENTEFFECT_MATERIAL( "sprites/bloodspray" ) CLIENTEFFECT_MATERIAL( "particle/particle_noisesphere" ) -CLIENTEFFECT_MATERIAL( "particle/particle_sphere" ) CLIENTEFFECT_REGISTER_END() -#ifdef _XBOX -PMaterialHandle g_Fleck_Wood[2] = { NULL, NULL }; -PMaterialHandle g_Fleck_Cement[2] = { NULL, NULL }; -PMaterialHandle g_DustPuff = NULL; -PMaterialHandle g_DustPuff2 = NULL; -#endif // _XBOX +// Cached handles to commonly used materials +PMaterialHandle g_Mat_Fleck_Wood[2] = { NULL, NULL }; +PMaterialHandle g_Mat_Fleck_Cement[2] = { NULL, NULL }; +PMaterialHandle g_Mat_Fleck_Antlion[2] = { NULL, NULL }; +PMaterialHandle g_Mat_Fleck_Glass[2] = { NULL, NULL }; +PMaterialHandle g_Mat_Fleck_Tile[2] = { NULL, NULL }; +PMaterialHandle g_Mat_DustPuff[2] = { NULL, NULL }; +PMaterialHandle g_Mat_BloodPuff[2] = { NULL, NULL }; +PMaterialHandle g_Mat_SMG_Muzzleflash[4] = { NULL, NULL, NULL, NULL }; +PMaterialHandle g_Mat_Combine_Muzzleflash[3] = { NULL, NULL, NULL }; + +static ConVar fx_drawimpactdebris( "fx_drawimpactdebris", "1", FCVAR_DEVELOPMENTONLY, "Draw impact debris effects." ); +static ConVar fx_drawimpactdust( "fx_drawimpactdust", "1", FCVAR_DEVELOPMENTONLY, "Draw impact dust effects." ); + +void FX_CacheMaterialHandles( void ) +{ + g_Mat_Fleck_Wood[0] = ParticleMgr()->GetPMaterial( "effects/fleck_wood1" ); + g_Mat_Fleck_Wood[1] = ParticleMgr()->GetPMaterial( "effects/fleck_wood2" ); + + g_Mat_Fleck_Cement[0] = ParticleMgr()->GetPMaterial( "effects/fleck_cement1"); + g_Mat_Fleck_Cement[1] = ParticleMgr()->GetPMaterial( "effects/fleck_cement2" ); + + g_Mat_Fleck_Antlion[0] = ParticleMgr()->GetPMaterial( "effects/fleck_antlion1" ); + g_Mat_Fleck_Antlion[1] = ParticleMgr()->GetPMaterial( "effects/fleck_antlion2" ); + + g_Mat_Fleck_Glass[0] = ParticleMgr()->GetPMaterial( "effects/fleck_glass1" ); + g_Mat_Fleck_Glass[1] = ParticleMgr()->GetPMaterial( "effects/fleck_glass2" ); + + g_Mat_Fleck_Tile[0] = ParticleMgr()->GetPMaterial( "effects/fleck_tile1" ); + g_Mat_Fleck_Tile[1] = ParticleMgr()->GetPMaterial( "effects/fleck_tile2" ); + + g_Mat_DustPuff[0] = ParticleMgr()->GetPMaterial( "particle/particle_smokegrenade" ); + g_Mat_DustPuff[1] = ParticleMgr()->GetPMaterial( "particle/particle_noisesphere" ); + + g_Mat_BloodPuff[0] = ParticleMgr()->GetPMaterial( "effects/blood" ); + g_Mat_BloodPuff[1] = ParticleMgr()->GetPMaterial( "effects/blood2" ); + +#ifndef TF_CLIENT_DLL + g_Mat_SMG_Muzzleflash[0] = ParticleMgr()->GetPMaterial( "effects/muzzleflash1" ); + g_Mat_SMG_Muzzleflash[1] = ParticleMgr()->GetPMaterial( "effects/muzzleflash2" ); + g_Mat_SMG_Muzzleflash[2] = ParticleMgr()->GetPMaterial( "effects/muzzleflash3" ); + g_Mat_SMG_Muzzleflash[3] = ParticleMgr()->GetPMaterial( "effects/muzzleflash4" ); + + g_Mat_Combine_Muzzleflash[0] = ParticleMgr()->GetPMaterial( "effects/combinemuzzle1" ); + g_Mat_Combine_Muzzleflash[1] = ParticleMgr()->GetPMaterial( "effects/combinemuzzle2" ); + g_Mat_Combine_Muzzleflash[2] = ParticleMgr()->GetPMaterial( "effects/strider_muzzle" ); +#endif +} + +extern PMaterialHandle g_Material_Spark; //----------------------------------------------------------------------------- // Purpose: Returns the color given trace information @@ -115,34 +158,28 @@ static void CreateFleckParticles( const Vector& origin, const Vector &color, tra { Vector spawnOffset = trace->endpos + ( trace->plane.normal * 1.0f ); - CSmartPtr fleckEmitter = CFleckParticles::Create( "FX_DebrisFlecks", spawnOffset ); + CSmartPtr fleckEmitter = CFleckParticles::Create( "FX_DebrisFlecks", spawnOffset, Vector(5,5,5) ); if ( !fleckEmitter ) return; - fleckEmitter->SetSortOrigin( spawnOffset ); - // Handle increased scale float flMaxSpeed = FLECK_MAX_SPEED * iScale; float flAngularSpray = max( 0.2, FLECK_ANGULAR_SPRAY - ( (float)iScale * 0.2f) ); // More power makes the spray more controlled - // Setup our collision information fleckEmitter->m_ParticleCollision.Setup( spawnOffset, &trace->plane.normal, flAngularSpray, FLECK_MIN_SPEED, flMaxSpeed, FLECK_GRAVITY, FLECK_DAMPEN ); - PMaterialHandle hMaterial[2]; - + PMaterialHandle *hMaterial; switch ( materialType ) { case CHAR_TEX_WOOD: - hMaterial[0] = fleckEmitter->GetPMaterial( "effects/fleck_wood1" ); - hMaterial[1] = fleckEmitter->GetPMaterial( "effects/fleck_wood2" ); + hMaterial = g_Mat_Fleck_Wood; break; case CHAR_TEX_CONCRETE: case CHAR_TEX_TILE: default: - hMaterial[0] = fleckEmitter->GetPMaterial( "effects/fleck_cement1" ); - hMaterial[1] = fleckEmitter->GetPMaterial( "effects/fleck_cement2" ); + hMaterial = g_Mat_Fleck_Cement; break; } @@ -198,6 +235,9 @@ void FX_DebrisFlecks( const Vector& origin, trace_t *tr, char materialType, int { VPROF_BUDGET( "FX_DebrisFlecks", VPROF_BUDGETGROUP_PARTICLE_RENDERING ); + if ( !fx_drawimpactdebris.GetBool() ) + return; + #ifdef _XBOX // @@ -218,27 +258,17 @@ void FX_DebrisFlecks( const Vector& origin, trace_t *tr, char materialType, int float colorRamp; GetColorForSurface( tr, &color ); - if ( g_DustPuff == NULL ) - { - g_DustPuff = ParticleMgr()->GetPMaterial( "particle/particle_smokegrenade" ); - } - - if ( g_DustPuff2 == NULL ) - { - g_DustPuff2 = ParticleMgr()->GetPMaterial( "effects/blood" ); - } - int i; SimpleParticle *pParticle; for ( i = 0; i < 4; i++ ) { if ( i == 3 ) { - pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_DustPuff2, origin ); + pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Mat_BloodPuff[0], origin ); } else { - pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_DustPuff, origin ); + pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Mat_DustPuff[0], origin ); } if ( pParticle != NULL ) @@ -328,7 +358,6 @@ void FX_DebrisFlecks( const Vector& origin, trace_t *tr, char materialType, int Vector offset = tr->endpos + ( tr->plane.normal * 2.0f ); SimpleParticle newParticle; - PMaterialHandle smokeMaterial = ParticleMgr()->GetPMaterial( "particle/particle_smokegrenade" ); int i; for ( i = 0; i < 2; i++ ) @@ -361,10 +390,9 @@ void FX_DebrisFlecks( const Vector& origin, trace_t *tr, char materialType, int newParticle.m_uchColor[1] = min( 1.0f, color[1]*colorRamp )*255.0f; newParticle.m_uchColor[2] = min( 1.0f, color[2]*colorRamp )*255.0f; - AddSimpleParticle( &newParticle, smokeMaterial ); + AddSimpleParticle( &newParticle, g_Mat_DustPuff[0] ); } - PMaterialHandle bloodMaterial = ParticleMgr()->GetPMaterial( "effects/blood" ); for ( i = 0; i < 4; i++ ) { @@ -396,7 +424,7 @@ void FX_DebrisFlecks( const Vector& origin, trace_t *tr, char materialType, int newParticle.m_uchColor[1] = min( 1.0f, color[1]*colorRamp )*255.0f; newParticle.m_uchColor[2] = min( 1.0f, color[2]*colorRamp )*255.0f; - AddSimpleParticle( &newParticle, bloodMaterial ); + AddSimpleParticle( &newParticle, g_Mat_BloodPuff[0] ); } // @@ -430,7 +458,7 @@ void FX_DebrisFlecks( const Vector& origin, trace_t *tr, char materialType, int newParticle.m_uchColor[1] = min( 1.0f, color[1]*colorRamp )*255.0f; newParticle.m_uchColor[2] = min( 1.0f, color[2]*colorRamp )*255.0f; - AddSimpleParticle( &newParticle, smokeMaterial ); + AddSimpleParticle( &newParticle, g_Mat_DustPuff[0] ); #endif } @@ -458,9 +486,6 @@ void FX_GlassImpact( const Vector &pos, const Vector &normal ) // HACK: Blend a little toward white to match the materials... VectorLerp( vecColor, Vector( 1, 1, 1 ), 0.3, vecColor ); - PMaterialHandle hMaterial1 = pGlassEmitter->GetPMaterial( "effects/fleck_glass1" ); - PMaterialHandle hMaterial2 = pGlassEmitter->GetPMaterial( "effects/fleck_glass2" ); - float flShardSize = random->RandomFloat( 2.0f, 6.0f ); unsigned char color[3] = { 200, 200, 210 }; @@ -475,14 +500,7 @@ void FX_GlassImpact( const Vector &pos, const Vector &normal ) { Particle3D *pParticle; - if ( random->RandomInt( 0 , 1 ) ) - { - pParticle = (Particle3D *) pGlassEmitter->AddParticle( sizeof(Particle3D), hMaterial1, pos ); - } - else - { - pParticle = (Particle3D *) pGlassEmitter->AddParticle( sizeof(Particle3D), hMaterial2, pos ); - } + pParticle = (Particle3D *) pGlassEmitter->AddParticle( sizeof(Particle3D), g_Mat_Fleck_Glass[random->RandomInt(0,1)], pos ); if ( pParticle ) { @@ -520,7 +538,6 @@ void FX_GlassImpact( const Vector &pos, const Vector &normal ) float colorRamp; SimpleParticle newParticle; - PMaterialHandle bloodMaterial = ParticleMgr()->GetPMaterial( "effects/blood" ); for ( int i = 0; i < 4; i++ ) { @@ -551,7 +568,7 @@ void FX_GlassImpact( const Vector &pos, const Vector &normal ) newParticle.m_uchColor[1] = min( 1.0f, color[1]*colorRamp )*255.0f; newParticle.m_uchColor[2] = min( 1.0f, color[2]*colorRamp )*255.0f; - AddSimpleParticle( &newParticle, bloodMaterial ); + AddSimpleParticle( &newParticle, g_Mat_BloodPuff[0] ); } // @@ -584,7 +601,7 @@ void FX_GlassImpact( const Vector &pos, const Vector &normal ) newParticle.m_uchColor[1] = min( 1.0f, color[1]*colorRamp )*255.0f; newParticle.m_uchColor[2] = min( 1.0f, color[2]*colorRamp )*255.0f; - AddSimpleParticle( &newParticle, ParticleMgr()->GetPMaterial( "particle/particle_smokegrenade" ) ); + AddSimpleParticle( &newParticle, g_Mat_DustPuff[0] ); } void GlassImpactCallback( const CEffectData &data ) @@ -601,6 +618,10 @@ DECLARE_CLIENT_EFFECT( "GlassImpact", GlassImpactCallback ); //----------------------------------------------------------------------------- void FX_AntlionImpact( const Vector &pos, trace_t *trace ) { +#if defined( _X360 ) + return; +#endif // _X360 + VPROF_BUDGET( "FX_AntlionImpact", VPROF_BUDGETGROUP_PARTICLE_RENDERING ); CSmartPtr fleckEmitter = CSimple3DEmitter::Create( "FX_DebrisFlecks" ); @@ -638,10 +659,6 @@ void FX_AntlionImpact( const Vector &pos, trace_t *trace ) // Setup our collision information fleckEmitter->m_ParticleCollision.Setup( spawnOffset, &shotDir, flAngularSpray, 8.0f, flMaxSpeed, FLECK_GRAVITY, FLECK_DAMPEN ); - PMaterialHandle antlionFleckMaterial[2]; - antlionFleckMaterial[0] = fleckEmitter->GetPMaterial( "effects/fleck_antlion1" ); - antlionFleckMaterial[1] = fleckEmitter->GetPMaterial( "effects/fleck_antlion2" ); - Vector dir, end; Vector color = Vector( 1, 0.9, 0.75 ); float colorRamp; @@ -654,7 +671,7 @@ void FX_AntlionImpact( const Vector &pos, trace_t *trace ) int i; for ( i = 0; i < numFlecks; i++ ) { - pFleckParticle = (Particle3D *) fleckEmitter->AddParticle( sizeof(Particle3D), antlionFleckMaterial[random->RandomInt(0,1)], spawnOffset ); + pFleckParticle = (Particle3D *) fleckEmitter->AddParticle( sizeof(Particle3D), g_Mat_Fleck_Antlion[random->RandomInt(0,1)], spawnOffset ); if ( pFleckParticle == NULL ) break; @@ -694,11 +711,9 @@ void FX_AntlionImpact( const Vector &pos, trace_t *trace ) dustEmitter->SetSortOrigin( offset ); dustEmitter->GetBinding().SetBBox( spawnOffset-Vector(32,32,32), spawnOffset+Vector(32,32,32), true ); - PMaterialHandle smokeMaterial = dustEmitter->GetPMaterial( "particle/particle_smokegrenade" ); - for ( i = 0; i < 4; i++ ) { - pParticle = (SimpleParticle *) dustEmitter->AddParticle( sizeof(SimpleParticle), smokeMaterial, offset ); + pParticle = (SimpleParticle *) dustEmitter->AddParticle( sizeof(SimpleParticle), g_Mat_DustPuff[0], offset ); if ( pParticle == NULL ) break; @@ -728,8 +743,6 @@ void FX_AntlionImpact( const Vector &pos, trace_t *trace ) pParticle->m_uchColor[2] = min( 1.0f, color[2]*colorRamp )*255.0f; } - // Blood spurt - FX_BugBlood( spawnOffset, shotDir, vWorldMins, vWorldMaxs ); CLocalPlayerFilter filter; C_BaseEntity::EmitSound( filter, 0, "FX_AntlionImpact.ShellImpact", &trace->endpos ); @@ -768,12 +781,10 @@ void FX_BugBlood( Vector &pos, Vector &dir, Vector &vWorldMins, Vector &vWorldMa VectorNormalize( vDir ); - PMaterialHandle bloodMaterial = pSimple->GetPMaterial( "effects/blood" ); - int i; for ( i = 0; i < NUM_BUG_BLOOD; i++ ) { - SimpleParticle *sParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), bloodMaterial, pos ); + SimpleParticle *sParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Mat_BloodPuff[0], pos ); if ( sParticle == NULL ) return; @@ -797,11 +808,9 @@ void FX_BugBlood( Vector &pos, Vector &dir, Vector &vWorldMins, Vector &vWorldMa sParticle->m_flRollDelta = random->RandomFloat( -2.0f, 2.0f ); } - bloodMaterial = pSimple->GetPMaterial( "effects/blood2" ); - for ( i = 0; i < NUM_BUG_BLOOD2; i++ ) { - SimpleParticle *sParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), bloodMaterial, pos ); + SimpleParticle *sParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Mat_BloodPuff[1], pos ); if ( sParticle == NULL ) { @@ -834,7 +843,7 @@ void FX_BugBlood( Vector &pos, Vector &dir, Vector &vWorldMins, Vector &vWorldMa offset.Random( -2, 2 ); offset += pos; - SimpleParticle *sParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), bloodMaterial, offset ); + SimpleParticle *sParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Mat_BloodPuff[1], offset ); if ( sParticle == NULL ) { @@ -884,12 +893,10 @@ void FX_Blood( Vector &pos, Vector &dir, float r, float g, float b, float a ) VectorNormalize( vDir ); - PMaterialHandle bloodMaterial = pSimple->GetPMaterial( "effects/blood" ); - int i; for ( i = 0; i < 2; i++ ) { - SimpleParticle *sParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), bloodMaterial, pos ); + SimpleParticle *sParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Mat_BloodPuff[0], pos ); if ( sParticle == NULL ) { @@ -915,11 +922,9 @@ void FX_Blood( Vector &pos, Vector &dir, float r, float g, float b, float a ) sParticle->m_flRollDelta = random->RandomFloat( -2.0f, 2.0f ); } - bloodMaterial = pSimple->GetPMaterial( "effects/blood2" ); - for ( i = 0; i < 2; i++ ) { - SimpleParticle *sParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), bloodMaterial, pos ); + SimpleParticle *sParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Mat_BloodPuff[1], pos ); if ( sParticle == NULL ) { @@ -952,6 +957,9 @@ void FX_Blood( Vector &pos, Vector &dir, float r, float g, float b, float a ) //----------------------------------------------------------------------------- void FX_DustImpact( const Vector &origin, trace_t *tr, int iScale ) { + if ( !fx_drawimpactdust.GetBool() ) + return; + #ifdef _XBOX // @@ -961,7 +969,7 @@ void FX_DustImpact( const Vector &origin, trace_t *tr, int iScale ) VPROF_BUDGET( "FX_DustImpact", VPROF_BUDGETGROUP_PARTICLE_RENDERING ); Vector offset; float spread = 0.2f; - + CSmartPtr pSimple = CDustParticle::Create( "dust" ); pSimple->SetSortOrigin( origin ); pSimple->GetBinding().SetBBox( origin - ( Vector( 32, 32, 32 ) * iScale ), origin + ( Vector( 32, 32, 32 ) * iScale ) ); @@ -970,16 +978,6 @@ void FX_DustImpact( const Vector &origin, trace_t *tr, int iScale ) float colorRamp; GetColorForSurface( tr, &color ); - if ( g_DustPuff == NULL ) - { - g_DustPuff = ParticleMgr()->GetPMaterial( "particle/particle_smokegrenade" ); - } - - if ( g_DustPuff2 == NULL ) - { - g_DustPuff2 = ParticleMgr()->GetPMaterial( "effects/blood" ); - } - int i; SimpleParticle *pParticle; for ( i = 0; i < 4; i++ ) @@ -987,11 +985,11 @@ void FX_DustImpact( const Vector &origin, trace_t *tr, int iScale ) // Last puff is gritty (hides end) if ( i == 3 ) { - pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_DustPuff2, origin ); + pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Mat_BloodPuff[0], origin ); } else { - pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_DustPuff, origin ); + pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Mat_DustPuff[0], origin ); } if ( pParticle != NULL ) @@ -1000,31 +998,31 @@ void FX_DustImpact( const Vector &origin, trace_t *tr, int iScale ) pParticle->m_vecVelocity.Random( -spread, spread ); pParticle->m_vecVelocity += ( tr->plane.normal * random->RandomFloat( 1.0f, 6.0f ) ); - + VectorNormalize( pParticle->m_vecVelocity ); float fForce = random->RandomFloat( 250, 500 ) * i; // scaled pParticle->m_vecVelocity *= fForce * iScale; - + 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; - + // scaled pParticle->m_uchStartSize = iScale * random->RandomInt( 3, 4 ) * (i+1); // scaled pParticle->m_uchEndSize = iScale * pParticle->m_uchStartSize * 4; - + pParticle->m_uchStartAlpha = random->RandomInt( 32, 255 ); pParticle->m_uchEndAlpha = 0; - + pParticle->m_flRoll = random->RandomInt( 0, 360 ); - + if ( i == 3 ) { pParticle->m_flRollDelta = random->RandomFloat( -0.1f, 0.1f ); @@ -1051,24 +1049,29 @@ void FX_DustImpact( const Vector &origin, trace_t *tr, int iScale ) pParticle->m_flDieTime = random->RandomFloat( 0.5f, 1.0f ); pParticle->m_vecVelocity.Init(); - + 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->RandomInt( 4, 8 ); pParticle->m_uchEndSize = pParticle->m_uchStartSize * 4; - + pParticle->m_uchStartAlpha = random->RandomInt( 32, 64 ); pParticle->m_uchEndAlpha = 0; - + pParticle->m_flRoll = random->RandomInt( 0, 360 ); pParticle->m_flRollDelta = random->RandomFloat( -1.0f, 1.0f ); } #else + FX_DustImpact( origin, tr, (float)iScale ); +#endif // _XBOX +} +void FX_DustImpact( const Vector &origin, trace_t *tr, float flScale ) +{ // // PC version // @@ -1087,12 +1090,10 @@ void FX_DustImpact( const Vector &origin, trace_t *tr, int iScale ) GetColorForSurface( tr, &color ); - PMaterialHandle smokeMaterial = pSimple->GetPMaterial( "particle/particle_smokegrenade" ); - int i; for ( i = 0; i < 4; i++ ) { - pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), smokeMaterial, origin ); + pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Mat_DustPuff[0], origin ); if ( pParticle != NULL ) { @@ -1107,7 +1108,7 @@ void FX_DustImpact( const Vector &origin, trace_t *tr, int iScale ) float fForce = random->RandomFloat( 250, 500 ) * i; // scaled - pParticle->m_vecVelocity *= fForce * iScale; + pParticle->m_vecVelocity *= fForce * flScale; colorRamp = random->RandomFloat( 0.75f, 1.25f ); @@ -1116,10 +1117,10 @@ void FX_DustImpact( const Vector &origin, trace_t *tr, int iScale ) pParticle->m_uchColor[2] = min( 1.0f, color[2] * colorRamp ) * 255.0f; // scaled - pParticle->m_uchStartSize = iScale * random->RandomInt( 3, 4 ) * (i+1); + pParticle->m_uchStartSize = ( unsigned char )( flScale * random->RandomInt( 3, 4 ) * (i+1) ); // scaled - pParticle->m_uchEndSize = iScale * pParticle->m_uchStartSize * 4; + pParticle->m_uchEndSize = ( unsigned char )( flScale * pParticle->m_uchStartSize * 4 ); pParticle->m_uchStartAlpha = random->RandomInt( 32, 255 ); pParticle->m_uchEndAlpha = 0; @@ -1129,12 +1130,10 @@ void FX_DustImpact( const Vector &origin, trace_t *tr, int iScale ) } } - PMaterialHandle bloodMaterial = pSimple->GetPMaterial( "effects/blood" ); - //Dust specs for ( i = 0; i < 4; i++ ) { - pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), bloodMaterial, origin ); + pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Mat_BloodPuff[0], origin ); if ( pParticle != NULL ) { @@ -1170,7 +1169,7 @@ void FX_DustImpact( const Vector &origin, trace_t *tr, int iScale ) //Impact hit for ( i = 0; i < 4; i++ ) { - pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), smokeMaterial, origin ); + pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Mat_DustPuff[0], origin ); if ( pParticle != NULL ) { @@ -1208,7 +1207,6 @@ void FX_DustImpact( const Vector &origin, trace_t *tr, int iScale ) pParticle->m_flRollDelta = random->RandomFloat( -16.0f, 16.0f ); } } -#endif // _XBOX } #ifdef _XBOX @@ -1233,7 +1231,7 @@ void FX_GaussExplosion( const Vector &pos, const Vector &dir, int type ) int i; -#ifdef _XBOX +#if defined(_XBOX) || defined(_X360) // // XBox version diff --git a/src/src/cl_dll/c_impact_effects.h b/src/src/game/client/c_impact_effects.h similarity index 100% rename from src/src/cl_dll/c_impact_effects.h rename to src/src/game/client/c_impact_effects.h diff --git a/src/src/game/client/c_info_overlay_accessor.cpp b/src/src/game/client/c_info_overlay_accessor.cpp new file mode 100644 index 0000000..f6ecd4d --- /dev/null +++ b/src/src/game/client/c_info_overlay_accessor.cpp @@ -0,0 +1,57 @@ +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#include "cbase.h" +#include "materialsystem/IMesh.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +// -------------------------------------------------------------------------------- // +// An entity used to access overlays (and change their texture) +// -------------------------------------------------------------------------------- // +class C_InfoOverlayAccessor : public C_BaseEntity +{ +public: + + DECLARE_CLASS( C_InfoOverlayAccessor, C_BaseEntity ); + DECLARE_CLIENTCLASS(); + + C_InfoOverlayAccessor(); + + virtual void OnDataChanged( DataUpdateType_t updateType ); + +private: + + int m_iOverlayID; +}; + +// Expose it to the engine. +IMPLEMENT_CLIENTCLASS(C_InfoOverlayAccessor, DT_InfoOverlayAccessor, CInfoOverlayAccessor); + +BEGIN_RECV_TABLE_NOBASE(C_InfoOverlayAccessor, DT_InfoOverlayAccessor) + RecvPropInt(RECVINFO(m_iTextureFrameIndex)), + RecvPropInt(RECVINFO(m_iOverlayID)), +END_RECV_TABLE() + + +// -------------------------------------------------------------------------------- // +// Functions. +// -------------------------------------------------------------------------------- // + +C_InfoOverlayAccessor::C_InfoOverlayAccessor() +{ +} + +void C_InfoOverlayAccessor::OnDataChanged( DataUpdateType_t updateType ) +{ + if ( updateType == DATA_UPDATE_CREATED ) + { + // Update overlay's bind proxy + engine->SetOverlayBindProxy( m_iOverlayID, GetClientRenderable() ); + } +} diff --git a/src/src/cl_dll/c_lightglow.cpp b/src/src/game/client/c_lightglow.cpp similarity index 92% rename from src/src/cl_dll/c_lightglow.cpp rename to src/src/game/client/c_lightglow.cpp index f723daa..f7811cf 100644 --- a/src/src/cl_dll/c_lightglow.cpp +++ b/src/src/game/client/c_lightglow.cpp @@ -73,6 +73,9 @@ protected: bool m_bModulateByDot; }; +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- class C_LightGlow : public C_BaseEntity { public: @@ -85,8 +88,8 @@ public: public: virtual void OnDataChanged( DataUpdateType_t updateType ); - virtual void NotifyShouldTransmit( ShouldTransmitState_t state ); virtual void Simulate( void ); + virtual void ClientThink( void ); public: @@ -173,7 +176,7 @@ void C_LightGlow::OnDataChanged( DataUpdateType_t updateType ) m_Glow.SetOneSided(); } - m_Glow.Activate(); + SetNextClientThink( gpGlobals->curtime + RandomFloat(0,3.0) ); } else if ( updateType == DATA_UPDATE_DATATABLE_CHANGED ) //Right now only color should change. { @@ -196,19 +199,17 @@ void C_LightGlow::OnDataChanged( DataUpdateType_t updateType ) //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- -void C_LightGlow::NotifyShouldTransmit( ShouldTransmitState_t state ) +void C_LightGlow::ClientThink( void ) { - BaseClass::NotifyShouldTransmit( state ); - - // Turn off - if ( state == SHOULDTRANSMIT_END ) + Vector mins = GetAbsOrigin(); + if ( engine->IsBoxVisible( mins, mins ) ) + { + m_Glow.Activate(); + } + else { m_Glow.Deactivate(); } - // Turn on - if ( state == SHOULDTRANSMIT_START ) - { - m_Glow.Activate(); - } + SetNextClientThink( gpGlobals->curtime + RandomFloat(1.0,3.0) ); } diff --git a/src/src/cl_dll/c_materialmodifycontrol.cpp b/src/src/game/client/c_materialmodifycontrol.cpp similarity index 98% rename from src/src/cl_dll/c_materialmodifycontrol.cpp rename to src/src/game/client/c_materialmodifycontrol.cpp index 7c72081..f903adf 100644 --- a/src/src/cl_dll/c_materialmodifycontrol.cpp +++ b/src/src/game/client/c_materialmodifycontrol.cpp @@ -12,6 +12,7 @@ #include "iviewrender.h" #include "texture_group_names.h" #include "BaseAnimatedTextureProxy.h" +#include "toolframework_client.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -28,6 +29,9 @@ enum MaterialModifyMode_t MATERIAL_MODIFY_MODE_FLOAT_LERP = 3, }; +// forward declarations +void ToolFramework_RecordMaterialParams( IMaterial *pMaterial ); + ConVar debug_materialmodifycontrol_client( "debug_materialmodifycontrol_client", "0" ); struct materialanimcommands_t @@ -212,6 +216,7 @@ public: virtual ~CMaterialModifyProxy(); virtual bool Init( IMaterial *pMaterial, KeyValues *pKeyValues ); virtual void OnBind( void *pEntity ); + virtual IMaterial *GetMaterial(); private: void OnBindSetVar( C_MaterialModifyControl *pControl ); @@ -323,6 +328,16 @@ void CMaterialModifyProxy::OnBind( void *pEntity ) } } } + + if ( ToolsEnabled() ) + { + ToolFramework_RecordMaterialParams( GetMaterial() ); + } +} + +IMaterial *CMaterialModifyProxy::GetMaterial() +{ + return m_pMaterial; } //----------------------------------------------------------------------------- @@ -738,6 +753,11 @@ void CMaterialModifyAnimatedProxy::OnBind( void *pEntity ) } m_AnimatedTextureFrameNumVar->SetIntValue( intFrame ); + + if ( ToolsEnabled() ) + { + ToolFramework_RecordMaterialParams( GetMaterial() ); + } } //----------------------------------------------------------------------------- diff --git a/src/src/cl_dll/c_movie_explosion.cpp b/src/src/game/client/c_movie_explosion.cpp similarity index 100% rename from src/src/cl_dll/c_movie_explosion.cpp rename to src/src/game/client/c_movie_explosion.cpp diff --git a/src/src/cl_dll/c_particle_fire.cpp b/src/src/game/client/c_particle_fire.cpp similarity index 100% rename from src/src/cl_dll/c_particle_fire.cpp rename to src/src/game/client/c_particle_fire.cpp diff --git a/src/src/cl_dll/c_particle_smokegrenade.cpp b/src/src/game/client/c_particle_smokegrenade.cpp similarity index 99% rename from src/src/cl_dll/c_particle_smokegrenade.cpp rename to src/src/game/client/c_particle_smokegrenade.cpp index 7367ef2..ea64b68 100644 --- a/src/src/cl_dll/c_particle_smokegrenade.cpp +++ b/src/src/game/client/c_particle_smokegrenade.cpp @@ -584,7 +584,7 @@ void C_ParticleSmokeGrenade::Update(float fTimeDelta) if(m_CurrentStage == 1) { // Update the expanding sphere. - m_ExpandTimeCounter += fTimeDelta; + m_ExpandTimeCounter = flLifetime; if(m_ExpandTimeCounter > SMOKESPHERE_EXPAND_TIME) m_ExpandTimeCounter = SMOKESPHERE_EXPAND_TIME; @@ -930,7 +930,7 @@ void C_ParticleSmokeGrenade::CleanupToolRecordingState( KeyValues *msg ) int nId = AllocateToolParticleEffectId(); - KeyValues *msg = new KeyValues( "ParticleSystem_Create" ); + KeyValues *msg = new KeyValues( "OldParticleSystem_Create" ); msg->SetString( "name", "C_ParticleSmokeGrenade" ); msg->SetInt( "id", nId ); msg->SetFloat( "time", gpGlobals->curtime ); diff --git a/src/src/game/client/c_particle_system.cpp b/src/src/game/client/c_particle_system.cpp new file mode 100644 index 0000000..db971e3 --- /dev/null +++ b/src/src/game/client/c_particle_system.cpp @@ -0,0 +1,235 @@ +//====== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======= +// +// Purpose: +// +//============================================================================= + +#include "cbase.h" +#include "particles/particles.h" +#include "c_te_effect_dispatch.h" +#include "particles_new.h" +#include "networkstringtable_clientdll.h" +#include "tier0/vprof.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +//----------------------------------------------------------------------------- +// Purpose: An entity that spawns and controls a particle system +//----------------------------------------------------------------------------- +class C_ParticleSystem : public C_BaseEntity +{ + DECLARE_CLASS( C_ParticleSystem, C_BaseEntity ); +public: + DECLARE_CLIENTCLASS(); + + void PreDataUpdate( DataUpdateType_t updateType ); + void PostDataUpdate( DataUpdateType_t updateType ); + void ClientThink( void ); + +protected: + int m_iEffectIndex; + bool m_bActive; + bool m_bOldActive; + float m_flStartTime; // Time at which the effect started + + enum { kMAXCONTROLPOINTS = 63 }; ///< actually one less than the total number of cpoints since 0 is assumed to be me + + + EHANDLE m_hControlPointEnts[kMAXCONTROLPOINTS]; + // SendPropArray3( SENDINFO_ARRAY3(m_iControlPointParents), SendPropInt( SENDINFO_ARRAY(m_iControlPointParents), 3, SPROP_UNSIGNED ) ), + unsigned char m_iControlPointParents[kMAXCONTROLPOINTS]; +}; + +IMPLEMENT_CLIENTCLASS(C_ParticleSystem, DT_ParticleSystem, CParticleSystem); + +BEGIN_RECV_TABLE_NOBASE( C_ParticleSystem, DT_ParticleSystem ) + RecvPropVector( RECVINFO_NAME( m_vecNetworkOrigin, m_vecOrigin ) ), + RecvPropEHandle( RECVINFO(m_hOwnerEntity) ), + RecvPropInt( RECVINFO_NAME(m_hNetworkMoveParent, moveparent), 0, RecvProxy_IntToMoveParent ), + RecvPropInt( RECVINFO( m_iParentAttachment ) ), + RecvPropQAngles( RECVINFO_NAME( m_angNetworkAngles, m_angRotation ) ), + + RecvPropInt( RECVINFO( m_iEffectIndex ) ), + RecvPropBool( RECVINFO( m_bActive ) ), + RecvPropFloat( RECVINFO( m_flStartTime ) ), + + RecvPropArray3( RECVINFO_ARRAY(m_hControlPointEnts), RecvPropEHandle( RECVINFO( m_hControlPointEnts[0] ) ) ), + RecvPropArray3( RECVINFO_ARRAY(m_iControlPointParents), RecvPropInt( RECVINFO(m_iControlPointParents[0]))), +END_RECV_TABLE(); + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_ParticleSystem::PreDataUpdate( DataUpdateType_t updateType ) +{ + m_bOldActive = m_bActive; + + BaseClass::PreDataUpdate( updateType ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_ParticleSystem::PostDataUpdate( DataUpdateType_t updateType ) +{ + BaseClass::PostDataUpdate( updateType ); + + // Always restart if just created and updated + // FIXME: Does this play fairly with PVS? + if ( updateType == DATA_UPDATE_CREATED ) + { + if ( m_bActive ) + { + // Delayed here so that we don't get invalid abs queries on level init with active particle systems + SetNextClientThink( gpGlobals->curtime ); + } + } + else + { + if ( m_bOldActive != m_bActive ) + { + if ( m_bActive ) + { + // Delayed here so that we don't get invalid abs queries on level init with active particle systems + SetNextClientThink( gpGlobals->curtime ); + } + else + { + ParticleProp()->StopEmission(); + } + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_ParticleSystem::ClientThink( void ) +{ + if ( m_bActive ) + { + const char *pszName = GetParticleSystemNameFromIndex( m_iEffectIndex ); + if ( pszName && pszName[0] ) + { + CNewParticleEffect *pEffect = ParticleProp()->Create( pszName, PATTACH_ABSORIGIN_FOLLOW ); + AssertMsg1( pEffect, "Particle system couldn't make %s", pszName ); + if (pEffect) + { + for ( int i = 0 ; i < kMAXCONTROLPOINTS ; ++i ) + { + CBaseEntity *pOnEntity = m_hControlPointEnts[i].Get(); + if ( pOnEntity ) + { + ParticleProp()->AddControlPoint( pEffect, i + 1, pOnEntity, PATTACH_ABSORIGIN_FOLLOW ); + } + + AssertMsg2( m_iControlPointParents[i] >= 0 && m_iControlPointParents[i] <= kMAXCONTROLPOINTS , + "Particle system specified bogus control point parent (%d) for point %d.", + m_iControlPointParents[i], i ); + + if (m_iControlPointParents[i] != 0) + { + pEffect->SetControlPointParent(i+1, m_iControlPointParents[i]); + } + } + + // NOTE: What we really want here is to compare our lifetime and that of our children and see if this delta is + // already past the end of it, denoting that we're finished. In that case, just destroy us and be done. -- jdw + + // TODO: This can go when the SkipToTime code below goes + ParticleProp()->OnParticleSystemUpdated( pEffect, 0.0f ); + + // Skip the effect ahead if we're restarting it + float flTimeDelta = gpGlobals->curtime - m_flStartTime; + if ( flTimeDelta > 0.01f ) + { + VPROF_BUDGET( "C_ParticleSystem::ClientThink SkipToTime", "Particle Simulation" ); + pEffect->SkipToTime( flTimeDelta ); + } + } + } + } +} + + +//====================================================================================================================== +// PARTICLE SYSTEM DISPATCH EFFECT +//====================================================================================================================== +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void ParticleEffectCallback( const CEffectData &data ) +{ + if ( SuppressingParticleEffects() ) + return; // this needs to be before using data.m_nHitBox, since that may be a serialized value that's past the end of the current particle system string table + + const char *pszName = GetParticleSystemNameFromIndex( data.m_nHitBox ); + + if ( data.m_fFlags & PARTICLE_DISPATCH_FROM_ENTITY ) + { + if ( data.m_hEntity.Get() ) + { + C_BaseEntity *pEnt = C_BaseEntity::Instance( data.m_hEntity ); + if ( pEnt && !pEnt->IsDormant() ) + { + if ( data.m_fFlags & PARTICLE_DISPATCH_RESET_PARTICLES ) + { + pEnt->ParticleProp()->StopEmission(); + } + + CSmartPtr pEffect = pEnt->ParticleProp()->Create( pszName, (ParticleAttachment_t)data.m_nDamageType, data.m_nAttachmentIndex ); + AssertMsg2( pEffect.IsValid() && pEffect->IsValid(), "%s could not create particle effect %s", + C_BaseEntity::Instance( data.m_hEntity )->GetDebugName(), pszName ); + if ( pEffect.IsValid() && pEffect->IsValid() ) + { + if ( (ParticleAttachment_t)data.m_nDamageType == PATTACH_CUSTOMORIGIN ) + { + pEffect->SetSortOrigin( data.m_vOrigin ); + pEffect->SetControlPoint( 0, data.m_vOrigin ); + pEffect->SetControlPoint( 1, data.m_vStart ); + Vector vecForward, vecRight, vecUp; + AngleVectors( data.m_vAngles, &vecForward, &vecRight, &vecUp ); + pEffect->SetControlPointOrientation( 0, vecForward, vecRight, vecUp ); + } + } + } + } + } + else + { + CSmartPtr pEffect = CNewParticleEffect::Create( NULL, pszName ); + if ( pEffect->IsValid() ) + { + pEffect->SetSortOrigin( data.m_vOrigin ); + pEffect->SetControlPoint( 0, data.m_vOrigin ); + pEffect->SetControlPoint( 1, data.m_vStart ); + Vector vecForward, vecRight, vecUp; + AngleVectors( data.m_vAngles, &vecForward, &vecRight, &vecUp ); + pEffect->SetControlPointOrientation( 0, vecForward, vecRight, vecUp ); + } + } +} + +DECLARE_CLIENT_EFFECT( "ParticleEffect", ParticleEffectCallback ); + + +//====================================================================================================================== +// PARTICLE SYSTEM STOP EFFECT +//====================================================================================================================== +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void ParticleEffectStopCallback( const CEffectData &data ) +{ + if ( data.m_hEntity.Get() ) + { + C_BaseEntity *pEnt = C_BaseEntity::Instance( data.m_hEntity ); + if ( pEnt ) + { + pEnt->ParticleProp()->StopEmission(); + } + } +} + +DECLARE_CLIENT_EFFECT( "ParticleEffectStop", ParticleEffectStopCallback ); diff --git a/src/src/cl_dll/c_physbox.cpp b/src/src/game/client/c_physbox.cpp similarity index 100% rename from src/src/cl_dll/c_physbox.cpp rename to src/src/game/client/c_physbox.cpp diff --git a/src/src/cl_dll/c_physbox.h b/src/src/game/client/c_physbox.h similarity index 100% rename from src/src/cl_dll/c_physbox.h rename to src/src/game/client/c_physbox.h diff --git a/src/src/cl_dll/c_physicsprop.cpp b/src/src/game/client/c_physicsprop.cpp similarity index 57% rename from src/src/cl_dll/c_physicsprop.cpp rename to src/src/game/client/c_physicsprop.cpp index 190dde7..7ab9c8a 100644 --- a/src/src/cl_dll/c_physicsprop.cpp +++ b/src/src/game/client/c_physicsprop.cpp @@ -47,45 +47,15 @@ C_PhysicsProp::~C_PhysicsProp( void ) } +// @MULTICORE (toml 9/18/2006): this visualization will need to be implemented elsewhere ConVar r_visualizeproplightcaching( "r_visualizeproplightcaching", "0" ); //----------------------------------------------------------------------------- // Purpose: Draws the object // Input : flags - //----------------------------------------------------------------------------- -// FIXME!!!! I hate the fact that InternalDrawModel is always such a huge cut-and-paste job. -int C_PhysicsProp::InternalDrawModel( int flags ) +bool C_PhysicsProp::OnInternalDrawModel( ClientModelRenderInfo_t *pInfo ) { - VPROF( "C_PhysicsProp::InternalDrawModel" ); - - //----------------------------------------------------------------------------- - // Overriding C_BaseAnimating::InternalDrawModel so that we can detect when the - // prop is asleep. This allows us to bake the lighting for the model. - //----------------------------------------------------------------------------- - if ( !GetModel() ) - { - return 0; - } - - if ( IsEffectActive( EF_ITEM_BLINK ) ) - { - flags |= STUDIO_ITEM_BLINK; - } - - // This should never happen, but if the server class hierarchy has bmodel entities derived from CBaseAnimating or does a - // SetModel with the wrong type of model, this could occur. - if ( modelinfo->GetModelType( GetModel() ) != mod_studio ) - { - return BaseClass::DrawModel( flags ); - } - - // Make sure hdr is valid for drawing - if ( !GetModelPtr() ) - { - // inhibit drawing and state setting until all data available - return 0; - } - CreateModelInstance(); if ( r_PhysPropStaticLighting.GetBool() && m_bAwakeLastTime != m_bAwake ) @@ -96,7 +66,7 @@ int C_PhysicsProp::InternalDrawModel( int flags ) if ( !modelrender->RecomputeStaticLighting( GetModelInstance() ) ) { // not valid for drawing - return 0; + return false; } if ( r_visualizeproplightcaching.GetBool() ) @@ -115,44 +85,11 @@ int C_PhysicsProp::InternalDrawModel( int flags ) if ( !m_bAwake && r_PhysPropStaticLighting.GetBool() ) { // going to sleep, have static lighting - flags |= STUDIO_STATIC_LIGHTING; + pInfo->flags |= STUDIO_STATIC_LIGHTING; } - Vector tmpOrigin = GetRenderOrigin(); - - int drawn = modelrender->DrawModel( - flags, - this, - GetModelInstance(), - index, - GetModel(), - GetRenderOrigin(), - GetRenderAngles(), - m_nSkin, - m_nBody, - m_nHitboxSet ); - - if ( vcollide_wireframe.GetBool() ) - { - if ( IsRagdoll() ) - { - m_pRagdoll->DrawWireframe(); - } - else - { - vcollide_t *pCollide = modelinfo->GetVCollide( GetModelIndex() ); - if ( pCollide && pCollide->solidCount == 1 ) - { - static color32 debugColor = {0,255,255,0}; - matrix3x4_t matrix; - AngleMatrix( GetAbsAngles(), GetAbsOrigin(), matrix ); - engine->DebugDrawPhysCollide( pCollide->solids[0], NULL, matrix, debugColor ); - } - } - } - // track state m_bAwakeLastTime = m_bAwake; - - return drawn; + + return true; } diff --git a/src/src/cl_dll/c_physicsprop.h b/src/src/game/client/c_physicsprop.h similarity index 91% rename from src/src/cl_dll/c_physicsprop.h rename to src/src/game/client/c_physicsprop.h index ae9f7f2..2537f45 100644 --- a/src/src/cl_dll/c_physicsprop.h +++ b/src/src/game/client/c_physicsprop.h @@ -23,7 +23,7 @@ public: C_PhysicsProp(); ~C_PhysicsProp(); - int InternalDrawModel( int flags ); + virtual bool OnInternalDrawModel( ClientModelRenderInfo_t *pInfo ); protected: // Networked vars. diff --git a/src/src/cl_dll/c_physmagnet.cpp b/src/src/game/client/c_physmagnet.cpp similarity index 100% rename from src/src/cl_dll/c_physmagnet.cpp rename to src/src/game/client/c_physmagnet.cpp diff --git a/src/src/cl_dll/c_pixel_visibility.cpp b/src/src/game/client/c_pixel_visibility.cpp similarity index 73% rename from src/src/cl_dll/c_pixel_visibility.cpp rename to src/src/game/client/c_pixel_visibility.cpp index 92cd9fa..5be9e20 100644 --- a/src/src/cl_dll/c_pixel_visibility.cpp +++ b/src/src/game/client/c_pixel_visibility.cpp @@ -1,10 +1,10 @@ -//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: // // $NoKeywords: $ // -//=============================================================================// +//===========================================================================// #include "cbase.h" #include "c_pixel_visibility.h" #include "materialsystem/imesh.h" @@ -12,8 +12,9 @@ #include "ClientEffectPrecacheSystem.h" #include "view.h" #include "utlmultilist.h" +#include "vprof.h" -static void PixelvisDrawChanged( ConVar *pPixelvisVar, const char *pOld ); +static void PixelvisDrawChanged( IConVar *pPixelvisVar, const char *pOld, float flOldValue ); ConVar r_pixelvisibility_partial( "r_pixelvisibility_partial", "1" ); ConVar r_dopixelvisibility( "r_dopixelvisibility", "1" ); @@ -22,9 +23,13 @@ ConVar r_pixelvisibility_spew( "r_pixelvisibility_spew", "0" ); extern ConVar building_cubemaps; +#ifndef _X360 const float MIN_PROXY_PIXELS = 5.0f; +#else +const float MIN_PROXY_PIXELS = 25.0f; +#endif -float PixelVisibility_DrawProxy( OcclusionQueryObjectHandle_t queryHandle, Vector origin, float scale, float proxyAspect, IMaterial *pMaterial, bool screenspace ) +float PixelVisibility_DrawProxy( IMatRenderContext *pRenderContext, OcclusionQueryObjectHandle_t queryHandle, Vector origin, float scale, float proxyAspect, IMaterial *pMaterial, bool screenspace ) { Vector point; @@ -32,12 +37,12 @@ float PixelVisibility_DrawProxy( OcclusionQueryObjectHandle_t queryHandle, Vecto // only expand the parts perpendicular to the view float forwardScale = scale; // draw a pyramid of points touching a sphere of radius "scale" at origin - float pixelsPerUnit = materials->ComputePixelWidthOfSphere( origin, 1.0f ); + float pixelsPerUnit = pRenderContext->ComputePixelDiameterOfSphere( origin, 1.0f ); pixelsPerUnit = max( pixelsPerUnit, 1e-4f ); if ( screenspace ) { // Force this to be the size of a sphere of diameter "scale" at some reference distance (1.0 unit) - float pixelsPerUnit2 = materials->ComputePixelWidthOfSphere( CurrentViewOrigin() + CurrentViewForward()*1.0f, scale*0.5f ); + float pixelsPerUnit2 = pRenderContext->ComputePixelDiameterOfSphere( CurrentViewOrigin() + CurrentViewForward()*1.0f, scale*0.5f ); // force drawing of "scale" pixels scale = pixelsPerUnit2 / pixelsPerUnit; } @@ -76,7 +81,7 @@ float PixelVisibility_DrawProxy( OcclusionQueryObjectHandle_t queryHandle, Vecto { extern int ScreenTransform( const Vector& point, Vector& screen ); if ( ScreenTransform( verts[i+1], screen[i] ) ) - return 0; + return -1; } // compute area and screen-clipped area @@ -94,10 +99,9 @@ float PixelVisibility_DrawProxy( OcclusionQueryObjectHandle_t queryHandle, Vecto ratio = clamp(ratio, 0.0f, 1.0f); } - IMesh* pMesh = materials->GetDynamicMesh( true, NULL, NULL, pMaterial ); - + pRenderContext->BeginOcclusionQueryDrawing( queryHandle ); CMeshBuilder meshBuilder; - materials->BeginOcclusionQueryDrawing( queryHandle ); + IMesh* pMesh = pRenderContext->GetDynamicMesh( false, NULL, NULL, pMaterial ); meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, 4 ); // draw a pyramid for ( int i = 0; i < 4; i++ ) @@ -141,7 +145,7 @@ float PixelVisibility_DrawProxy( OcclusionQueryObjectHandle_t queryHandle, Vecto meshBuilder.End(); pMesh->Draw(); #endif - materials->EndOcclusionQueryDrawing( queryHandle ); + pRenderContext->EndOcclusionQueryDrawing( queryHandle ); // fraction clipped by frustum return ratio; @@ -201,7 +205,6 @@ bool CPixelVisSet::IsActive() return (gpGlobals->framecount - frameIssued) > 1 ? false : true; } - class CPixelVisibilityQuery { public: @@ -211,8 +214,9 @@ public: bool IsForView( int viewID ); bool IsActive(); float GetFractionVisible( float fadeTimeInv ); - void IssueQuery( float proxySize, float proxyAspect, IMaterial *pMaterial, bool sizeIsScreenSpace ); - void IssueCountingQuery( float proxySize, float proxyAspect, IMaterial *pMaterial, bool sizeIsScreenSpace ); + void IssueQuery( IMatRenderContext *pRenderContext, float proxySize, float proxyAspect, IMaterial *pMaterial, bool sizeIsScreenSpace ); + void IssueCountingQuery( IMatRenderContext *pRenderContext, float proxySize, float proxyAspect, IMaterial *pMaterial, bool sizeIsScreenSpace ); + void ResetOcclusionQueries(); void SetView( int viewID ) { m_viewID = viewID; @@ -237,24 +241,52 @@ private: unsigned short m_hasValidQueryResults : 1; unsigned short m_pad : 13; unsigned short m_viewID; + + friend void PixelVisibility_ShiftVisibilityViews( int iSourceViewID, int iDestViewID ); //need direct access to private data to make shifting smooth }; CPixelVisibilityQuery::CPixelVisibilityQuery() { + CMatRenderContextPtr pRenderContext( materials ); SetView( 0xFFFF ); - m_queryHandle = materials->CreateOcclusionQueryObject(); - m_queryHandleCount = materials->CreateOcclusionQueryObject(); + m_queryHandle = pRenderContext->CreateOcclusionQueryObject(); + m_queryHandleCount = pRenderContext->CreateOcclusionQueryObject(); } CPixelVisibilityQuery::~CPixelVisibilityQuery() { + CMatRenderContextPtr pRenderContext( materials ); if ( m_queryHandle != INVALID_OCCLUSION_QUERY_OBJECT_HANDLE ) { - materials->DestroyOcclusionQueryObject( m_queryHandle ); + pRenderContext->DestroyOcclusionQueryObject( m_queryHandle ); } if ( m_queryHandleCount != INVALID_OCCLUSION_QUERY_OBJECT_HANDLE ) { - materials->DestroyOcclusionQueryObject( m_queryHandleCount ); + pRenderContext->DestroyOcclusionQueryObject( m_queryHandleCount ); + } +} + +void CPixelVisibilityQuery::ResetOcclusionQueries() +{ + // NOTE: Since we're keeping the CPixelVisibilityQuery objects around in a pool + // and not actually deleting them, this means that our material system occlusion queries are + // not being deleted either. Which means that if a CPixelVisibilityQuery is + // put into the free list and then immediately re-used, then we have an opportunity for + // a bug: What can happen on the first frame of the material system query + // is that if the query isn't done yet, it will use the last queried value + // which will happen to be set to the value of the last query done + // for the previous CPixelVisSet the CPixelVisibilityQuery happened to be associated with + // which makes queries have an invalid value for the first frame + + // This will mark the occlusion query objects as not ever having been read from before + CMatRenderContextPtr pRenderContext( materials ); + if ( m_queryHandle != INVALID_OCCLUSION_QUERY_OBJECT_HANDLE ) + { + pRenderContext->ResetOcclusionQueryObject( m_queryHandle ); + } + if ( m_queryHandleCount != INVALID_OCCLUSION_QUERY_OBJECT_HANDLE ) + { + pRenderContext->ResetOcclusionQueryObject( m_queryHandleCount ); } } @@ -279,6 +311,7 @@ float CPixelVisibilityQuery::GetFractionVisible( float fadeTimeInv ) if ( !m_wasQueriedThisFrame ) { + CMatRenderContextPtr pRenderContext( materials ); m_wasQueriedThisFrame = true; int pixels = -1; int pixelsPossible = -1; @@ -286,8 +319,8 @@ float CPixelVisibilityQuery::GetFractionVisible( float fadeTimeInv ) { if ( m_frameIssued != -1 ) { - pixelsPossible = materials->OcclusionQuery_GetNumPixelsRendered( m_queryHandleCount ); - pixels = materials->OcclusionQuery_GetNumPixelsRendered( m_queryHandle ); + pixelsPossible = pRenderContext->OcclusionQuery_GetNumPixelsRendered( m_queryHandleCount ); + pixels = pRenderContext->OcclusionQuery_GetNumPixelsRendered( m_queryHandle ); } if ( r_pixelvisibility_spew.GetBool() && CurrentViewID() == 0 ) @@ -297,7 +330,7 @@ float CPixelVisibilityQuery::GetFractionVisible( float fadeTimeInv ) if ( pixels < 0 || pixelsPossible < 0 ) { - m_failed = m_frameIssued != -1 ? true : false; + m_failed = ( m_frameIssued >= 0 ) ? true : false; return m_brightnessTarget * m_clipFraction; } m_hasValidQueryResults = true; @@ -318,7 +351,7 @@ float CPixelVisibilityQuery::GetFractionVisible( float fadeTimeInv ) { if ( m_frameIssued != -1 ) { - pixels = materials->OcclusionQuery_GetNumPixelsRendered( m_queryHandle ); + pixels = pRenderContext->OcclusionQuery_GetNumPixelsRendered( m_queryHandle ); } if ( r_pixelvisibility_spew.GetBool() && CurrentViewID() == 0 ) @@ -328,7 +361,7 @@ float CPixelVisibilityQuery::GetFractionVisible( float fadeTimeInv ) if ( pixels < 0 ) { - m_failed = m_frameIssued != -1 ? true : false; + m_failed = ( m_frameIssued >= 0 ) ? true : false; return m_brightnessTarget * m_clipFraction; } m_hasValidQueryResults = true; @@ -354,7 +387,7 @@ float CPixelVisibilityQuery::GetFractionVisible( float fadeTimeInv ) return m_brightnessTarget * m_clipFraction; } -void CPixelVisibilityQuery::IssueQuery( float proxySize, float proxyAspect, IMaterial *pMaterial, bool sizeIsScreenSpace ) +void CPixelVisibilityQuery::IssueQuery( IMatRenderContext *pRenderContext, float proxySize, float proxyAspect, IMaterial *pMaterial, bool sizeIsScreenSpace ) { if ( !m_failed ) { @@ -365,16 +398,27 @@ void CPixelVisibilityQuery::IssueQuery( float proxySize, float proxyAspect, IMat DevMsg( 1, "Draw Proxy: qh:%d org:<%d,%d,%d> (frame:%d)\n", m_queryHandle, (int)m_origin[0], (int)m_origin[1], (int)m_origin[2], gpGlobals->framecount ); } - m_clipFraction = PixelVisibility_DrawProxy( m_queryHandle, m_origin, proxySize, proxyAspect, pMaterial, sizeIsScreenSpace ); - - + m_clipFraction = PixelVisibility_DrawProxy( pRenderContext, m_queryHandle, m_origin, proxySize, proxyAspect, pMaterial, sizeIsScreenSpace ); + if ( m_clipFraction < 0 ) + { + // NOTE: In this case, the proxy wasn't issued cause it was offscreen + // can't set the m_frameissued field since that would cause it to get marked as failed + m_clipFraction = 0; + m_wasQueriedThisFrame = false; + m_failed = false; + return; + } } +#ifndef PORTAL // FIXME: In portal we query visibility multiple times per frame because of portal renders! + Assert(m_frameIssued != gpGlobals->framecount); +#endif + m_frameIssued = gpGlobals->framecount; m_wasQueriedThisFrame = false; m_failed = false; } -void CPixelVisibilityQuery::IssueCountingQuery( float proxySize, float proxyAspect, IMaterial *pMaterial, bool sizeIsScreenSpace ) +void CPixelVisibilityQuery::IssueCountingQuery( IMatRenderContext *pRenderContext, float proxySize, float proxyAspect, IMaterial *pMaterial, bool sizeIsScreenSpace ) { if ( !m_failed ) { @@ -389,12 +433,11 @@ void CPixelVisibilityQuery::IssueCountingQuery( float proxySize, float proxyAspe float dot = DotProduct(CurrentViewForward(), origin); origin = CurrentViewOrigin() + dot * CurrentViewForward(); #endif - PixelVisibility_DrawProxy( m_queryHandleCount, m_origin, proxySize, proxyAspect, pMaterial, sizeIsScreenSpace ); + PixelVisibility_DrawProxy( pRenderContext, m_queryHandleCount, m_origin, proxySize, proxyAspect, pMaterial, sizeIsScreenSpace ); } } - -//Precahce the effects +//Precache the effects CLIENTEFFECT_REGISTER_BEGIN( PrecacheOcclusionProxy ) CLIENTEFFECT_MATERIAL( "engine/occlusionproxy" ) CLIENTEFFECT_MATERIAL( "engine/occlusionproxy_countdraw" ) @@ -429,6 +472,7 @@ public: Msg("Pixel vis system using %d sets total (%d in free list), %d queries total (%d in free list)\n", m_setList.TotalCount(), m_setList.Count(m_freeSetsList), m_queryList.TotalCount(), m_queryList.Count( m_freeQueriesList ) ); } + private: CUtlMultiList< CPixelVisSet, unsigned short > m_setList; CUtlMultiList m_queryList; @@ -441,6 +485,9 @@ private: IMaterial *m_pDrawMaterial; bool m_hwCanTestGlows; bool m_drawQueries; + + + friend void PixelVisibility_ShiftVisibilityViews( int iSourceViewID, int iDestViewID ); //need direct access to private data to make shifting smooth }; static CPixelVisibilitySystem g_PixelVisibilitySystem; @@ -456,10 +503,12 @@ void CPixelVisibilitySystem::LevelInitPreEntity() m_hwCanTestGlows = r_dopixelvisibility.GetBool() && engine->GetDXSupportLevel() >= 80; if ( m_hwCanTestGlows ) { - unsigned short query = materials->CreateOcclusionQueryObject(); + CMatRenderContextPtr pRenderContext( materials ); + + OcclusionQueryObjectHandle_t query = pRenderContext->CreateOcclusionQueryObject(); if ( query != INVALID_OCCLUSION_QUERY_OBJECT_HANDLE ) { - materials->DestroyOcclusionQueryObject( query ); + pRenderContext->DestroyOcclusionQueryObject( query ); } else { @@ -505,8 +554,6 @@ float CPixelVisibilitySystem::GetFractionVisible( const pixelvis_queryparams_t & m_queryList[node].m_origin = params.position; float fraction = m_queryList[node].GetFractionVisible( pSet->fadeTimeInv ); pSet->MarkActive(); - - return fraction; } @@ -518,13 +565,15 @@ void CPixelVisibilitySystem::EndView() if ( m_setList.Head( m_activeSetsList ) == m_setList.InvalidIndex() ) return; + CMatRenderContextPtr pRenderContext( materials ); + IMaterial *pProxy = m_drawQueries ? m_pDrawMaterial : m_pProxyMaterial; - materials->Bind( pProxy ); + pRenderContext->Bind( pProxy ); // BUGBUG: If you draw both queries, the measure query fails for some reason. if ( r_pixelvisibility_partial.GetBool() && !m_drawQueries ) { - materials->DepthRange( 0.0f, 0.01f ); + pRenderContext->DepthRange( 0.0f, 0.01f ); unsigned short node = m_setList.Head( m_activeSetsList ); while( node != m_setList.InvalidIndex() ) { @@ -532,11 +581,11 @@ void CPixelVisibilitySystem::EndView() unsigned short queryNode = FindQueryForView( pSet, CurrentViewID() ); if ( queryNode != m_queryList.InvalidIndex() ) { - m_queryList[queryNode].IssueCountingQuery( pSet->proxySize, pSet->proxyAspect, pProxy, pSet->sizeIsScreenSpace ); + m_queryList[queryNode].IssueCountingQuery( pRenderContext, pSet->proxySize, pSet->proxyAspect, pProxy, pSet->sizeIsScreenSpace ); } node = m_setList.Next( node ); } - materials->DepthRange( 0.0f, 1.0f ); + pRenderContext->DepthRange( 0.0f, 1.0f ); } { @@ -547,7 +596,7 @@ void CPixelVisibilitySystem::EndView() unsigned short queryNode = FindQueryForView( pSet, CurrentViewID() ); if ( queryNode != m_queryList.InvalidIndex() ) { - m_queryList[queryNode].IssueQuery( pSet->proxySize, pSet->proxyAspect, pProxy, pSet->sizeIsScreenSpace ); + m_queryList[queryNode].IssueQuery( pRenderContext, pSet->proxySize, pSet->proxyAspect, pProxy, pSet->sizeIsScreenSpace ); } node = m_setList.Next( node ); } @@ -631,6 +680,7 @@ unsigned short CPixelVisibilitySystem::AllocQuery() if ( node != m_queryList.InvalidIndex() ) { m_queryList.Unlink( m_freeQueriesList, node ); + m_queryList[node].ResetOcclusionQueries(); } else { @@ -686,9 +736,10 @@ CPixelVisSet *CPixelVisibilitySystem::FindOrCreatePixelVisSet( const pixelvis_qu } -void PixelvisDrawChanged( ConVar *pPixelvisVar, const char *pOld ) +void PixelvisDrawChanged( IConVar *pPixelvisVar, const char *pOld, float flOldValue ) { - g_PixelVisibilitySystem.ShowQueries( pPixelvisVar->GetBool() ); + ConVarRef var( pPixelvisVar ); + g_PixelVisibilitySystem.ShowQueries( var.GetBool() ); } class CTraceFilterGlow : public CTraceFilterSimple @@ -763,6 +814,41 @@ bool PixelVisibility_IsAvailable() return r_dopixelvisibility.GetBool() && g_PixelVisibilitySystem.SupportsOcclusion(); } +//this originally called a class function of CPixelVisibiltySystem to keep the work clean, but that function needed friend access to CPixelVisibilityQuery +//and I didn't want to make the whole class a friend or shift all the functions and class declarations around in this file +void PixelVisibility_ShiftVisibilityViews( int iSourceViewID, int iDestViewID ) +{ + unsigned short node = g_PixelVisibilitySystem.m_setList.Head( g_PixelVisibilitySystem.m_activeSetsList ); + while ( node != g_PixelVisibilitySystem.m_setList.InvalidIndex() ) + { + unsigned short next = g_PixelVisibilitySystem.m_setList.Next( node ); + CPixelVisSet *pSet = &g_PixelVisibilitySystem.m_setList[node]; + + unsigned short iSourceQueryNode = g_PixelVisibilitySystem.FindQueryForView( pSet, iSourceViewID ); + unsigned short iDestQueryNode = g_PixelVisibilitySystem.FindQueryForView( pSet, iDestViewID ); + + if( iDestQueryNode != g_PixelVisibilitySystem.m_queryList.InvalidIndex() ) + { + //delete the destination if found + g_PixelVisibilitySystem.m_queryList.Unlink( pSet->queryList, iDestQueryNode ); + g_PixelVisibilitySystem.m_queryList.LinkToHead( g_PixelVisibilitySystem.m_freeQueriesList, iDestQueryNode ); + + if ( g_PixelVisibilitySystem.m_queryList.Head(pSet->queryList) == g_PixelVisibilitySystem.m_queryList.InvalidIndex() ) + { + g_PixelVisibilitySystem.FreeSet( node ); + } + } + + if( iSourceQueryNode != g_PixelVisibilitySystem.m_queryList.InvalidIndex() ) + { + //make the source believe it's the destination + g_PixelVisibilitySystem.m_queryList[iSourceQueryNode].m_viewID = iDestViewID; + } + + node = next; + } +} + CON_COMMAND( pixelvis_debug, "Dump debug info" ) { g_PixelVisibilitySystem.DebugInfo(); diff --git a/src/src/cl_dll/c_pixel_visibility.h b/src/src/game/client/c_pixel_visibility.h similarity index 89% rename from src/src/cl_dll/c_pixel_visibility.h rename to src/src/game/client/c_pixel_visibility.h index 4d79ed0..4a90dec 100644 --- a/src/src/cl_dll/c_pixel_visibility.h +++ b/src/src/game/client/c_pixel_visibility.h @@ -43,6 +43,8 @@ struct pixelvis_queryparams_t float PixelVisibility_FractionVisible( const pixelvis_queryparams_t ¶ms, pixelvis_handle_t *queryHandle ); float StandardGlowBlend( const pixelvis_queryparams_t ¶ms, pixelvis_handle_t *queryHandle, int rendermode, int renderfx, int alpha, float *pscale ); +void PixelVisibility_ShiftVisibilityViews( int iSourceViewID, int iDestViewID ); //mainly needed by portal mod to avoid a pop in visibility when teleporting the player + void PixelVisibility_EndCurrentView(); void PixelVisibility_EndScene(); float GlowSightDistance( const Vector &glowOrigin, bool bShouldTrace ); diff --git a/src/src/cl_dll/c_plasma.cpp b/src/src/game/client/c_plasma.cpp similarity index 100% rename from src/src/cl_dll/c_plasma.cpp rename to src/src/game/client/c_plasma.cpp diff --git a/src/src/cl_dll/c_playerlocaldata.h b/src/src/game/client/c_playerlocaldata.h similarity index 82% rename from src/src/cl_dll/c_playerlocaldata.h rename to src/src/game/client/c_playerlocaldata.h index 1b52d15..6998927 100644 --- a/src/src/cl_dll/c_playerlocaldata.h +++ b/src/src/game/client/c_playerlocaldata.h @@ -13,7 +13,7 @@ #endif #include "basetypes.h" -#include "vector.h" +#include "mathlib/vector.h" #include "playernet_vars.h" //----------------------------------------------------------------------------- @@ -27,9 +27,11 @@ public: DECLARE_EMBEDDED_NETWORKVAR(); CPlayerLocalData() : - m_iv_vecPunchAngle( "CPlayerLocalData::m_iv_vecPunchAngle" ) + m_iv_vecPunchAngle( "CPlayerLocalData::m_iv_vecPunchAngle" ), + m_iv_vecPunchAngleVel( "CPlayerLocalData::m_iv_vecPunchAngleVel" ) { m_iv_vecPunchAngle.Setup( &m_vecPunchAngle.m_Value, LATCH_SIMULATION_VAR ); + m_iv_vecPunchAngleVel.Setup( &m_vecPunchAngleVel.m_Value, LATCH_SIMULATION_VAR ); m_flFOVRate = 0; } @@ -57,6 +59,7 @@ public: CInterpolatedVar< QAngle > m_iv_vecPunchAngle; CNetworkQAngle( m_vecPunchAngleVel ); // velocity of auto-decaying view angle adjustment + CInterpolatedVar< QAngle > m_iv_vecPunchAngleVel; bool m_bDrawViewmodel; bool m_bWearingSuit; bool m_bPoisoned; @@ -65,13 +68,16 @@ public: // 3d skybox sky3dparams_t m_skybox3d; - // wold fog - fogparams_t m_fog; + // fog params + fogplayerparams_t m_PlayerFog; // audio environment audioparams_t m_audio; bool m_bSlowMovement; + //Tony; added so tonemap controller can work in multiplayer with inputs. + tonemap_params_t m_TonemapParams; + }; #endif // C_PLAYERLOCALDATA_H diff --git a/src/src/cl_dll/c_playerresource.cpp b/src/src/game/client/c_playerresource.cpp similarity index 73% rename from src/src/cl_dll/c_playerresource.cpp rename to src/src/game/client/c_playerresource.cpp index ccd571d..06b6be5 100644 --- a/src/src/cl_dll/c_playerresource.cpp +++ b/src/src/game/client/c_playerresource.cpp @@ -7,6 +7,7 @@ #include "cbase.h" #include "c_playerresource.h" #include "c_team.h" +#include "gamestringpool.h" #ifdef HL2MP #include "hl2mp_gamerules.h" @@ -15,6 +16,9 @@ // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" +const float PLAYER_RESOURCE_THINK_INTERVAL = 0.2f; +#define PLAYER_UNCONNECTED_NAME "unconnected" + IMPLEMENT_CLIENTCLASS_DT_NOBASE(C_PlayerResource, DT_PlayerResource, CPlayerResource) RecvPropArray3( RECVINFO_ARRAY(m_iPing), RecvPropInt( RECVINFO(m_iPing[0]))), RecvPropArray3( RECVINFO_ARRAY(m_iScore), RecvPropInt( RECVINFO(m_iScore[0]))), @@ -25,6 +29,19 @@ IMPLEMENT_CLIENTCLASS_DT_NOBASE(C_PlayerResource, DT_PlayerResource, CPlayerReso RecvPropArray3( RECVINFO_ARRAY(m_iHealth), RecvPropInt( RECVINFO(m_iHealth[0]))), END_RECV_TABLE() +BEGIN_PREDICTION_DATA( C_PlayerResource ) + + DEFINE_PRED_ARRAY( m_szName, FIELD_STRING, MAX_PLAYERS+1, FTYPEDESC_PRIVATE ), + DEFINE_PRED_ARRAY( m_iPing, FIELD_INTEGER, MAX_PLAYERS+1, FTYPEDESC_PRIVATE ), + DEFINE_PRED_ARRAY( m_iScore, FIELD_INTEGER, MAX_PLAYERS+1, FTYPEDESC_PRIVATE ), + DEFINE_PRED_ARRAY( m_iDeaths, FIELD_INTEGER, MAX_PLAYERS+1, FTYPEDESC_PRIVATE ), + DEFINE_PRED_ARRAY( m_bConnected, FIELD_BOOLEAN, MAX_PLAYERS+1, FTYPEDESC_PRIVATE ), + DEFINE_PRED_ARRAY( m_iTeam, FIELD_INTEGER, MAX_PLAYERS+1, FTYPEDESC_PRIVATE ), + DEFINE_PRED_ARRAY( m_bAlive, FIELD_BOOLEAN, MAX_PLAYERS+1, FTYPEDESC_PRIVATE ), + DEFINE_PRED_ARRAY( m_iHealth, FIELD_INTEGER, MAX_PLAYERS+1, FTYPEDESC_PRIVATE ), + +END_PREDICTION_DATA() + C_PlayerResource *g_PR; IGameResources * GameResources( void ) { return g_PR; } @@ -34,7 +51,6 @@ IGameResources * GameResources( void ) { return g_PR; } //----------------------------------------------------------------------------- C_PlayerResource::C_PlayerResource() { - memset( m_szName, 0, sizeof( m_szName ) ); memset( m_iPing, 0, sizeof( m_iPing ) ); // memset( m_iPacketloss, 0, sizeof( m_iPacketloss ) ); memset( m_iScore, 0, sizeof( m_iScore ) ); @@ -66,31 +82,67 @@ C_PlayerResource::~C_PlayerResource() g_PR = NULL; } +void C_PlayerResource::OnDataChanged(DataUpdateType_t updateType) +{ + BaseClass::OnDataChanged( updateType ); + if ( updateType == DATA_UPDATE_CREATED ) + { + SetNextClientThink( gpGlobals->curtime + PLAYER_RESOURCE_THINK_INTERVAL ); + } +} + +void C_PlayerResource::UpdatePlayerName( int slot ) +{ + if ( slot < 1 || slot > MAX_PLAYERS ) + { + Error( "UpdatePlayerName with bogus slot %d\n", slot ); + return; + } + player_info_t sPlayerInfo; + if ( IsConnected( slot ) && engine->GetPlayerInfo( slot, &sPlayerInfo ) ) + { + m_szName[slot] = AllocPooledString( sPlayerInfo.name ); + } + else + { + m_szName[slot] = AllocPooledString( PLAYER_UNCONNECTED_NAME ); + } +} + +void C_PlayerResource::ClientThink() +{ + BaseClass::ClientThink(); + + for ( int i = 1; i <= gpGlobals->maxClients; ++i ) + { + UpdatePlayerName( i ); + } + + SetNextClientThink( gpGlobals->curtime + PLAYER_RESOURCE_THINK_INTERVAL ); +} + //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- const char *C_PlayerResource::GetPlayerName( int iIndex ) { - if ( iIndex < 0 || iIndex > MAX_PLAYERS ) + if ( iIndex < 1 || iIndex > MAX_PLAYERS ) { Assert( false ); return "ERRORNAME"; } if ( !IsConnected( iIndex ) ) - return "unconnected"; + return PLAYER_UNCONNECTED_NAME; - // Yuck, make sure it's up to date - player_info_t sPlayerInfo; - if ( engine->GetPlayerInfo( iIndex, &sPlayerInfo ) ) + // X360TBD: Network - figure out why the name isn't set + if ( !m_szName[ iIndex ] || !Q_stricmp( m_szName[ iIndex ], PLAYER_UNCONNECTED_NAME ) ) { - Q_strncpy( m_szName[iIndex], sPlayerInfo.name, MAX_PLAYER_NAME_LENGTH ); + // If you get a full "reset" uncompressed update from server, then you can have NULLNAME show up in the scoreboard + UpdatePlayerName( iIndex ); } - else - { - return "unconnected"; - } - + + // This gets updated in ClientThink, so it could be up to 1 second out of date, oh well. return m_szName[iIndex]; } @@ -101,7 +153,7 @@ bool C_PlayerResource::IsAlive(int iIndex ) int C_PlayerResource::GetTeam(int iIndex ) { - if ( iIndex < 0 || iIndex > MAX_PLAYERS ) + if ( iIndex < 1 || iIndex > MAX_PLAYERS ) { Assert( false ); return 0; @@ -255,7 +307,7 @@ const Color &C_PlayerResource::GetTeamColor(int index ) //----------------------------------------------------------------------------- bool C_PlayerResource::IsConnected( int iIndex ) { - if ( iIndex < 0 || iIndex > MAX_PLAYERS ) + if ( iIndex < 1 || iIndex > MAX_PLAYERS ) return false; else return m_bConnected[iIndex]; diff --git a/src/src/cl_dll/c_playerresource.h b/src/src/game/client/c_playerresource.h similarity index 91% rename from src/src/cl_dll/c_playerresource.h rename to src/src/game/client/c_playerresource.h index e527dff..77a10bc 100644 --- a/src/src/cl_dll/c_playerresource.h +++ b/src/src/game/client/c_playerresource.h @@ -21,6 +21,7 @@ class C_PlayerResource : public C_BaseEntity, public IGameResources DECLARE_CLASS( C_PlayerResource, C_BaseEntity ); public: DECLARE_CLIENTCLASS(); + DECLARE_PREDICTABLE(); C_PlayerResource(); virtual ~C_PlayerResource(); @@ -48,10 +49,15 @@ public : // IGameResources intreface virtual int GetFrags( int index ); virtual int GetHealth( int index ); + virtual void ClientThink(); + virtual void OnDataChanged(DataUpdateType_t updateType); + protected: + void UpdatePlayerName( int slot ); + // Data for each player that's propagated to all clients // Stored in individual arrays so they can be sent down via datatables - char m_szName[MAX_PLAYERS+1][ MAX_PLAYER_NAME_LENGTH ]; + string_t m_szName[MAX_PLAYERS+1]; int m_iPing[MAX_PLAYERS+1]; int m_iScore[MAX_PLAYERS+1]; int m_iDeaths[MAX_PLAYERS+1]; diff --git a/src/src/cl_dll/c_point_camera.cpp b/src/src/game/client/c_point_camera.cpp similarity index 67% rename from src/src/cl_dll/c_point_camera.cpp rename to src/src/game/client/c_point_camera.cpp index 204ac37..d87630b 100644 --- a/src/src/cl_dll/c_point_camera.cpp +++ b/src/src/game/client/c_point_camera.cpp @@ -1,11 +1,16 @@ -//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: // // $NoKeywords: $ -//=============================================================================// +//===========================================================================// + #include "cbase.h" #include "C_Point_Camera.h" +#include "toolframework/itoolframework.h" +#include "toolframework_client.h" +#include "tier1/keyvalues.h" + // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -17,6 +22,7 @@ IMPLEMENT_CLIENTCLASS_DT( C_PointCamera, DT_PointCamera, CPointCamera ) RecvPropInt( RECVINFO( m_FogColor ) ), RecvPropFloat( RECVINFO( m_flFogStart ) ), RecvPropFloat( RECVINFO( m_flFogEnd ) ), + RecvPropFloat( RECVINFO( m_flFogMaxDensity ) ), RecvPropInt( RECVINFO( m_bActive ) ), RecvPropInt( RECVINFO( m_bUseScreenAspectRatio ) ), END_RECV_TABLE() @@ -79,8 +85,32 @@ float C_PointCamera::GetFogEnd() return m_flFogEnd; } +float C_PointCamera::GetFogMaxDensity() +{ + return m_flFogMaxDensity; +} + bool C_PointCamera::IsActive() { return m_bActive; } + +void C_PointCamera::GetToolRecordingState( KeyValues *msg ) +{ + BaseClass::GetToolRecordingState( msg ); + + unsigned char r, g, b; + static MonitorRecordingState_t state; + state.m_bActive = IsActive() && !IsDormant(); + state.m_flFOV = GetFOV(); + state.m_bFogEnabled = IsFogEnabled(); + state.m_flFogStart = GetFogStart(); + state.m_flFogEnd = GetFogEnd(); + GetFogColor( r, g, b ); + state.m_FogColor.SetColor( r, g, b, 255 ); + + msg->SetPtr( "monitor", &state ); +} + + diff --git a/src/src/cl_dll/c_point_camera.h b/src/src/game/client/c_point_camera.h similarity index 90% rename from src/src/cl_dll/c_point_camera.h rename to src/src/game/client/c_point_camera.h index b3e29f8..bc946ac 100644 --- a/src/src/cl_dll/c_point_camera.h +++ b/src/src/game/client/c_point_camera.h @@ -34,9 +34,12 @@ public: bool IsFogEnabled(); void GetFogColor( unsigned char &r, unsigned char &g, unsigned char &b ); float GetFogStart(); + float GetFogMaxDensity(); float GetFogEnd(); bool UseScreenAspectRatio() const { return m_bUseScreenAspectRatio; } + virtual void GetToolRecordingState( KeyValues *msg ); + private: float m_FOV; float m_Resolution; @@ -44,6 +47,7 @@ private: color32 m_FogColor; float m_flFogStart; float m_flFogEnd; + float m_flFogMaxDensity; bool m_bActive; bool m_bUseScreenAspectRatio; diff --git a/src/src/cl_dll/c_point_commentary_node.cpp b/src/src/game/client/c_point_commentary_node.cpp similarity index 78% rename from src/src/cl_dll/c_point_commentary_node.cpp rename to src/src/game/client/c_point_commentary_node.cpp index f9f1c7d..90d329b 100644 --- a/src/src/cl_dll/c_point_commentary_node.cpp +++ b/src/src/game/client/c_point_commentary_node.cpp @@ -17,6 +17,7 @@ #include "soundenvelope.h" #include "convar.h" #include "hud_closecaption.h" +#include "in_buttons.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -28,6 +29,14 @@ extern ConVar english; extern ConVar closecaption; class C_PointCommentaryNode; +CUtlVector< CHandle > g_CommentaryNodes; +bool IsInCommentaryMode( void ) +{ + return (g_CommentaryNodes.Count() > 0); +} + +static bool g_bTracingVsCommentaryNodes = false; + //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- @@ -39,6 +48,7 @@ public: virtual void Init( void ); virtual void VidInit( void ); + virtual void LevelInit( void ) { g_CommentaryNodes.Purge(); } virtual void ApplySchemeSettings( vgui::IScheme *pScheme ); void StartCommentary( C_PointCommentaryNode *pNode, char *pszSpeakers, int iNode, int iNodeMax, float flStartTime, float flEndTime ); @@ -76,7 +86,7 @@ private: CPanelAnimationVar( bool, m_bUseScriptBGColor, "use_script_bgcolor", "0" ); CPanelAnimationVar( Color, m_BackgroundColor, "BackgroundColor", "0 0 0 0" ); - CPanelAnimationVar( Color, m_BGOverrideColor, "BackgroundColor", "Panel.BgColor" ); + CPanelAnimationVar( Color, m_BGOverrideColor, "BackgroundOverrideColor", "Panel.BgColor" ); }; //----------------------------------------------------------------------------- @@ -101,6 +111,21 @@ public: StopLoopingSounds(); m_bRestartAfterRestore = true; } + + AddAndLockCommentaryHudGroup(); + } + + //----------------------------------------------------------------------------- + // Purpose: + //----------------------------------------------------------------------------- + virtual void SetDormant( bool bDormant ) + { + if ( !IsDormant() && bDormant ) + { + RemoveAndUnlockCommentaryHudGroup(); + } + + BaseClass::SetDormant( bDormant ); } //----------------------------------------------------------------------------- @@ -108,6 +133,8 @@ public: //----------------------------------------------------------------------------- void UpdateOnRemove( void ) { + RemoveAndUnlockCommentaryHudGroup(); + StopLoopingSounds(); BaseClass::UpdateOnRemove(); } @@ -116,6 +143,31 @@ public: virtual bool TestCollision( const Ray_t &ray, unsigned int mask, trace_t& trace ); + void AddAndLockCommentaryHudGroup( void ) + { + if ( !g_CommentaryNodes.Count() ) + { + int iRenderGroup = gHUD.LookupRenderGroupIndexByName( "commentary" ); + gHUD.LockRenderGroup( iRenderGroup ); + } + + if ( g_CommentaryNodes.Find(this) == g_CommentaryNodes.InvalidIndex() ) + { + g_CommentaryNodes.AddToTail( this ); + } + } + + void RemoveAndUnlockCommentaryHudGroup( void ) + { + g_CommentaryNodes.FindAndRemove( this ); + + if ( !g_CommentaryNodes.Count() ) + { + int iRenderGroup = gHUD.LookupRenderGroupIndexByName( "commentary" ); + gHUD.UnlockRenderGroup( iRenderGroup ); + } + } + public: // Data received from the server bool m_bActive; @@ -166,6 +218,11 @@ void C_PointCommentaryNode::OnDataChanged( DataUpdateType_t updateType ) { BaseClass::OnDataChanged( updateType ); + if ( updateType == DATA_UPDATE_CREATED ) + { + AddAndLockCommentaryHudGroup(); + } + if ( m_bWasActive == m_bActive && !m_bRestartAfterRestore ) return; @@ -272,7 +329,31 @@ void C_PointCommentaryNode::StopLoopingSounds( void ) //----------------------------------------------------------------------------- bool C_PointCommentaryNode::TestCollision( const Ray_t &ray, unsigned int mask, trace_t& trace ) { - return false; + if ( !g_bTracingVsCommentaryNodes ) + return false; + + return BaseClass::TestCollision( ray, mask, trace ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool IsNodeUnderCrosshair( C_BasePlayer *pPlayer ) +{ + // See if the player's looking at a commentary node + trace_t tr; + Vector vecSrc = pPlayer->EyePosition(); + Vector vecForward; + AngleVectors( pPlayer->EyeAngles(), &vecForward ); + + g_bTracingVsCommentaryNodes = true; + UTIL_TraceLine( vecSrc, vecSrc + vecForward * MAX_TRACE_LENGTH, MASK_SOLID, pPlayer, COLLISION_GROUP_NONE, &tr ); + g_bTracingVsCommentaryNodes = false; + + if ( !tr.m_pEnt ) + return false; + + return dynamic_cast(tr.m_pEnt); } //=================================================================================================================== @@ -360,12 +441,40 @@ void CHudCommentary::Paint() // Draw the speaker names // Get our scheme and font information vgui::HScheme scheme = vgui::scheme()->GetScheme( "ClientScheme" ); - vgui::HFont hFont = vgui::scheme()->GetIScheme(scheme)->GetFont( "Default" ); + vgui::HFont hFont = vgui::scheme()->GetIScheme(scheme)->GetFont( "CommentaryDefault" ); + if ( !hFont ) + { + hFont = vgui::scheme()->GetIScheme(scheme)->GetFont( "Default" ); + } vgui::surface()->DrawSetTextFont( hFont ); vgui::surface()->DrawSetTextColor( clr ); vgui::surface()->DrawSetTextPos( m_iSpeakersX, m_iSpeakersY ); vgui::surface()->DrawPrintText( m_szSpeakers, wcslen(m_szSpeakers) ); + if ( COMMENTARY_BUTTONS & IN_ATTACK ) + { + int iY = m_iBarY + m_iBarTall + YRES(4); + wchar_t wzFinal[512] = L""; + + wchar_t *pszText = g_pVGuiLocalize->Find( "#Commentary_PrimaryAttack" ); + if ( pszText ) + { + UTIL_ReplaceKeyBindings( pszText, 0, wzFinal, sizeof( wzFinal ) ); + vgui::surface()->DrawSetTextPos( m_iSpeakersX, iY ); + vgui::surface()->DrawPrintText( wzFinal, wcslen(wzFinal) ); + } + + pszText = g_pVGuiLocalize->Find( "#Commentary_SecondaryAttack" ); + if ( pszText ) + { + int w, h; + UTIL_ReplaceKeyBindings( pszText, 0, wzFinal, sizeof( wzFinal ) ); + vgui::surface()->GetTextSize( hFont, wzFinal, w, h ); + vgui::surface()->DrawSetTextPos( m_iBarX + m_iBarWide - w, iY ); + vgui::surface()->DrawPrintText( wzFinal, wcslen(wzFinal) ); + } + } + // Draw the commentary count // Determine our text size, and move that far in from the right hand size (plus the offset) int iCountWide, iCountTall; @@ -392,7 +501,7 @@ bool CHudCommentary::ShouldDraw() //----------------------------------------------------------------------------- void CHudCommentary::Init( void ) { - m_matIcon.Init( "vgui/icon_commentary", TEXTURE_GROUP_VGUI ); + m_matIcon.Init( "vgui/hud/icon_commentary", TEXTURE_GROUP_VGUI ); } //----------------------------------------------------------------------------- @@ -416,13 +525,13 @@ void CHudCommentary::StartCommentary( C_PointCommentaryNode *pNode, char *pszSpe m_flStartTime = flStartTime; m_flEndTime = flEndTime; m_bHiding = false; - vgui::localize()->ConvertANSIToUnicode( pszSpeakers, m_szSpeakers, sizeof(m_szSpeakers) ); + g_pVGuiLocalize->ConvertANSIToUnicode( pszSpeakers, m_szSpeakers, sizeof(m_szSpeakers) ); // Don't draw the element itself if closecaptions are on (and captions are always on in non-english mode) - ConVar *pCVar = cvar->FindVar("closecaption"); - if ( pCVar ) + ConVarRef pCVar( "closecaption" ); + if ( pCVar.IsValid() ) { - m_bShouldPaint = (!pCVar->GetBool() && english.GetBool()); + m_bShouldPaint = ( !pCVar.GetBool() && english.GetBool() ); } else { @@ -432,7 +541,7 @@ void CHudCommentary::StartCommentary( C_PointCommentaryNode *pNode, char *pszSpe char sz[MAX_COUNT_STRING]; Q_snprintf( sz, sizeof(sz), "%d \\ %d", iNode, iNodeMax ); - vgui::localize()->ConvertANSIToUnicode( sz, m_szCount, sizeof(m_szCount) ); + g_pVGuiLocalize->ConvertANSIToUnicode( sz, m_szCount, sizeof(m_szCount) ); // If the commentary just started, play the commentary fade in. if ( fabs(flStartTime - gpGlobals->curtime) < 1.0 ) @@ -454,3 +563,24 @@ void CHudCommentary::StopCommentary( void ) m_hActiveNode = NULL; } +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CommentaryModeShouldSwallowInput( C_BasePlayer *pPlayer ) +{ + if ( !IsInCommentaryMode() ) + return false; + + if ( pPlayer->m_nButtons & COMMENTARY_BUTTONS ) + { + // Always steal the secondary attack + if ( pPlayer->m_nButtons & IN_ATTACK2 ) + return true; + + // See if there's any nodes ahead of us. + if ( IsNodeUnderCrosshair( pPlayer ) ) + return true; + } + + return false; +} \ No newline at end of file diff --git a/src/src/game/client/c_prop_vehicle.cpp b/src/src/game/client/c_prop_vehicle.cpp new file mode 100644 index 0000000..1425d98 --- /dev/null +++ b/src/src/game/client/c_prop_vehicle.cpp @@ -0,0 +1,372 @@ +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + + +#include "cbase.h" +#include "c_prop_vehicle.h" +#include "hud.h" +#include +#include +#include "view.h" +#include "engine/IVDebugOverlay.h" +#include "movevars_shared.h" +#include "iviewrender.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +int ScreenTransform( const Vector& point, Vector& screen ); + +extern ConVar default_fov; +extern ConVar joy_response_move_vehicle; + + +IMPLEMENT_CLIENTCLASS_DT(C_PropVehicleDriveable, DT_PropVehicleDriveable, CPropVehicleDriveable) + RecvPropEHandle( RECVINFO(m_hPlayer) ), + RecvPropInt( RECVINFO( m_nSpeed ) ), + RecvPropInt( RECVINFO( m_nRPM ) ), + RecvPropFloat( RECVINFO( m_flThrottle ) ), + RecvPropInt( RECVINFO( m_nBoostTimeLeft ) ), + RecvPropInt( RECVINFO( m_nHasBoost ) ), + RecvPropInt( RECVINFO( m_nScannerDisabledWeapons ) ), + RecvPropInt( RECVINFO( m_nScannerDisabledVehicle ) ), + RecvPropInt( RECVINFO( m_bEnterAnimOn ) ), + RecvPropInt( RECVINFO( m_bExitAnimOn ) ), + RecvPropInt( RECVINFO( m_bUnableToFire ) ), + RecvPropVector( RECVINFO( m_vecEyeExitEndpoint ) ), + RecvPropBool( RECVINFO( m_bHasGun ) ), + RecvPropVector( RECVINFO( m_vecGunCrosshair ) ), +END_RECV_TABLE() + + +BEGIN_DATADESC( C_PropVehicleDriveable ) + DEFINE_EMBEDDED( m_ViewSmoothingData ), +END_DATADESC() + +ConVar r_VehicleViewClamp( "r_VehicleViewClamp", "1", FCVAR_CHEAT ); + +#define ROLL_CURVE_ZERO 20 // roll less than this is clamped to zero +#define ROLL_CURVE_LINEAR 90 // 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: Constructor +//----------------------------------------------------------------------------- +C_PropVehicleDriveable::C_PropVehicleDriveable() : + m_iv_vecGunCrosshair( "C_PropVehicleDriveable::m_iv_vecGunCrosshair" ) + +{ + m_hPrevPlayer = NULL; + + memset( &m_ViewSmoothingData, 0, sizeof( m_ViewSmoothingData ) ); + + m_ViewSmoothingData.pVehicle = this; + m_ViewSmoothingData.bClampEyeAngles = true; + m_ViewSmoothingData.bDampenEyePosition = 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 = m_flFOV = default_fov.GetFloat(); + + AddVar( &m_vecGunCrosshair, &m_iv_vecGunCrosshair, LATCH_SIMULATION_VAR ); +} + +//----------------------------------------------------------------------------- +// Purpose: De-constructor +//----------------------------------------------------------------------------- +C_PropVehicleDriveable::~C_PropVehicleDriveable() +{ +} + + +//----------------------------------------------------------------------------- +// By default all driveable vehicles use the curve defined by the convar. +//----------------------------------------------------------------------------- +int C_PropVehicleDriveable::GetJoystickResponseCurve() const +{ + return joy_response_move_vehicle.GetInt(); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_BaseCombatCharacter *C_PropVehicleDriveable::GetPassenger( int nRole ) +{ + if ( nRole == VEHICLE_ROLE_DRIVER ) + return m_hPlayer.Get(); + + return NULL; +} + +//----------------------------------------------------------------------------- +// Returns the role of the passenger +//----------------------------------------------------------------------------- +int C_PropVehicleDriveable::GetPassengerRole( C_BaseCombatCharacter *pPassenger ) +{ + if ( m_hPlayer.Get() == pPassenger ) + return VEHICLE_ROLE_DRIVER; + + return VEHICLE_ROLE_NONE; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : updateType - +//----------------------------------------------------------------------------- +void C_PropVehicleDriveable::OnPreDataChanged( DataUpdateType_t updateType ) +{ + BaseClass::OnPreDataChanged( updateType ); + + m_hPrevPlayer = m_hPlayer; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_PropVehicleDriveable::OnDataChanged( DataUpdateType_t updateType ) +{ + BaseClass::OnDataChanged( updateType ); + + if ( m_hPlayer && !m_hPrevPlayer ) + { + OnEnteredVehicle( m_hPlayer ); + SetNextClientThink( CLIENT_THINK_ALWAYS ); + } + else 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; + SetNextClientThink( CLIENT_THINK_NEVER ); + } +} + +//----------------------------------------------------------------------------- +// Should this object cast render-to-texture shadows? +//----------------------------------------------------------------------------- +ShadowType_t C_PropVehicleDriveable::ShadowCastType() +{ + CStudioHdr *pStudioHdr = GetModelPtr(); + if ( !pStudioHdr ) + return SHADOWS_NONE; + + if ( IsEffectActive(EF_NODRAW | EF_NOSHADOW) ) + return SHADOWS_NONE; + + // Always use render-to-texture. We'll always the dirty bits in our think function + return SHADOWS_RENDER_TO_TEXTURE; +} + + +//----------------------------------------------------------------------------- +// Mark the shadow as dirty while the vehicle is being driven +//----------------------------------------------------------------------------- +void C_PropVehicleDriveable::ClientThink( void ) +{ + // The vehicle is always dirty owing to pose parameters while it's being driven. + g_pClientShadowMgr->MarkRenderToTextureShadowDirty( GetShadowHandle() ); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_PropVehicleDriveable::DampenEyePosition( Vector &vecVehicleEyePos, QAngle &vecVehicleEyeAngles ) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: Modify the player view/camera while in a vehicle +//----------------------------------------------------------------------------- +void C_PropVehicleDriveable::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_PropVehicleDriveable::GetVehicleClipPlanes( float &flZNear, float &flZFar ) const +{ + // FIXME: Need something a better long-term, this fixes the buggy. + flZNear = 6; +} + + +//----------------------------------------------------------------------------- +// Renders hud elements +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// Simply used to return intensity value based upon current timer passed in +//----------------------------------------------------------------------------- +int GetFlashColorIntensity( int LowIntensity, int HighIntensity, bool Dimming, int Increment, int Timer ) +{ + if ( Dimming ) + return ( HighIntensity - Timer * Increment ); + else + return ( LowIntensity + Timer * Increment ); +} + +#define TRIANGULATED_CROSSHAIR 1 + +void C_PropVehicleDriveable::DrawHudElements( ) +{ + CHudTexture *pIcon; + int iIconX, iIconY; + + if (m_bHasGun) + { + // draw crosshairs for vehicle gun + pIcon = gHUD.GetIcon( "gunhair" ); + + if ( pIcon != NULL ) + { + float x, y; + Vector screen; + + x = ScreenWidth()/2; + y = ScreenHeight()/2; + + #if TRIANGULATED_CROSSHAIR + ScreenTransform( m_vecGunCrosshair, screen ); + x += 0.5 * screen[0] * ScreenWidth() + 0.5; + y -= 0.5 * screen[1] * ScreenHeight() + 0.5; + #endif + + x -= pIcon->Width() / 2; + y -= pIcon->Height() / 2; + + Color clr = ( m_bUnableToFire ) ? gHUD.m_clrCaution : gHUD.m_clrNormal; + pIcon->DrawSelf( x, y, clr ); + } + + if ( m_nScannerDisabledWeapons ) + { + // Draw icons for scanners "weps disabled" + pIcon = gHUD.GetIcon( "dmg_bio" ); + if ( pIcon ) + { + iIconY = 467 - pIcon->Height() / 2; + iIconX = 385; + if ( !m_bScannerWepIcon ) + { + pIcon->DrawSelf( XRES(iIconX), YRES(iIconY), Color( 0, 0, 255, 255 ) ); + m_bScannerWepIcon = true; + m_iScannerWepFlashTimer = 0; + m_bScannerWepDim = true; + } + else + { + pIcon->DrawSelf( XRES(iIconX), YRES(iIconY), Color( 0, 0, GetFlashColorIntensity(55, 255, m_bScannerWepDim, 10, m_iScannerWepFlashTimer), 255 ) ); + m_iScannerWepFlashTimer++; + m_iScannerWepFlashTimer %= 20; + if(!m_iScannerWepFlashTimer) + m_bScannerWepDim ^= 1; + } + } + } + } + + if ( m_nScannerDisabledVehicle ) + { + // Draw icons for scanners "vehicle disabled" + pIcon = gHUD.GetIcon( "dmg_bio" ); + if ( pIcon ) + { + iIconY = 467 - pIcon->Height() / 2; + iIconX = 410; + if ( !m_bScannerVehicleIcon ) + { + pIcon->DrawSelf( XRES(iIconX), YRES(iIconY), Color( 0, 0, 255, 255 ) ); + m_bScannerVehicleIcon = true; + m_iScannerVehicleFlashTimer = 0; + m_bScannerVehicleDim = true; + } + else + { + pIcon->DrawSelf( XRES(iIconX), YRES(iIconY), Color( 0, 0, GetFlashColorIntensity(55, 255, m_bScannerVehicleDim, 10, m_iScannerVehicleFlashTimer), 255 ) ); + m_iScannerVehicleFlashTimer++; + m_iScannerVehicleFlashTimer %= 20; + if(!m_iScannerVehicleFlashTimer) + m_bScannerVehicleDim ^= 1; + } + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_PropVehicleDriveable::RestrictView( float *pYawBounds, float *pPitchBounds, + float *pRollBounds, QAngle &vecViewAngles ) +{ + int eyeAttachmentIndex = LookupAttachment( "vehicle_driver_eyes" ); + Vector vehicleEyeOrigin; + QAngle vehicleEyeAngles; + GetAttachmentLocal( eyeAttachmentIndex, vehicleEyeOrigin, vehicleEyeAngles ); + + // Limit the yaw. + if ( pYawBounds ) + { + float flAngleDiff = AngleDiff( vecViewAngles.y, vehicleEyeAngles.y ); + flAngleDiff = clamp( flAngleDiff, pYawBounds[0], pYawBounds[1] ); + vecViewAngles.y = vehicleEyeAngles.y + flAngleDiff; + } + + // Limit the pitch. + if ( pPitchBounds ) + { + float flAngleDiff = AngleDiff( vecViewAngles.x, vehicleEyeAngles.x ); + flAngleDiff = clamp( flAngleDiff, pPitchBounds[0], pPitchBounds[1] ); + vecViewAngles.x = vehicleEyeAngles.x + flAngleDiff; + } + + // Limit the roll. + if ( pRollBounds ) + { + float flAngleDiff = AngleDiff( vecViewAngles.z, vehicleEyeAngles.z ); + flAngleDiff = clamp( flAngleDiff, pRollBounds[0], pRollBounds[1] ); + vecViewAngles.z = vehicleEyeAngles.z + flAngleDiff; + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_PropVehicleDriveable::UpdateViewAngles( C_BasePlayer *pLocalPlayer, CUserCmd *pCmd ) +{ + if ( r_VehicleViewClamp.GetInt() ) + { + float pitchBounds[2] = { -85.0f, 25.0f }; + RestrictView( NULL, pitchBounds, NULL, pCmd->viewangles ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_PropVehicleDriveable::OnEnteredVehicle( C_BaseCombatCharacter *pPassenger ) +{ +} + diff --git a/src/src/cl_dll/c_prop_vehicle.h b/src/src/game/client/c_prop_vehicle.h similarity index 92% rename from src/src/cl_dll/c_prop_vehicle.h rename to src/src/game/client/c_prop_vehicle.h index 85aa4ca..e117953 100644 --- a/src/src/cl_dll/c_prop_vehicle.h +++ b/src/src/game/client/c_prop_vehicle.h @@ -9,7 +9,7 @@ #pragma once #include "IClientVehicle.h" - +#include "vehicle_viewblend_shared.h" class C_PropVehicleDriveable : public C_BaseAnimating, public IClientVehicle { @@ -30,7 +30,7 @@ public: virtual C_BaseCombatCharacter* GetPassenger( int nRole ); virtual int GetPassengerRole( C_BaseCombatCharacter *pEnt ); virtual bool IsPassengerUsingStandardWeapons( int nRole = VEHICLE_ROLE_DRIVER ) { return false; } - virtual void GetVehicleViewPosition( int nRole, Vector *pOrigin, QAngle *pAngles ); + virtual void GetVehicleViewPosition( int nRole, Vector *pOrigin, QAngle *pAngles, float *pFOV = NULL ); virtual void SetupMove( C_BasePlayer *player, CUserCmd *ucmd, IMoveHelper *pHelper, CMoveData *move ) {} virtual void ProcessMovement( C_BasePlayer *pPlayer, CMoveData *pMoveData ) {} @@ -55,6 +55,7 @@ public: #endif virtual bool IsPredicted() const { return false; } + virtual int GetJoystickResponseCurve() const; // C_BaseEntity overrides. public: @@ -125,15 +126,4 @@ protected: }; -enum RemapAngleRange_CurvePart_t -{ - RemapAngleRange_CurvePart_Zero = 0, - RemapAngleRange_CurvePart_Spline, - RemapAngleRange_CurvePart_Linear, -}; - - -float RemapAngleRange( float startInterval, float endInterval, float value, RemapAngleRange_CurvePart_t *peCurvePart ); - - #endif // C_PROP_VEHICLE_H diff --git a/src/src/cl_dll/c_props.cpp b/src/src/game/client/c_props.cpp similarity index 81% rename from src/src/cl_dll/c_props.cpp rename to src/src/game/client/c_props.cpp index 06b8ce5..e62e656 100644 --- a/src/src/cl_dll/c_props.cpp +++ b/src/src/game/client/c_props.cpp @@ -7,10 +7,9 @@ #include "cbase.h" -#include "c_breakableprop.h" #include "c_physicsprop.h" #include "c_physbox.h" -#include "props_shared.h" +#include "c_props.h" #define CPhysBox C_PhysBox #define CPhysicsProp C_PhysicsProp @@ -19,31 +18,11 @@ // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" -class C_DynamicProp : public C_BreakableProp -{ - DECLARE_CLASS( C_DynamicProp, C_BreakableProp ); -public: - DECLARE_CLIENTCLASS(); +IMPLEMENT_NETWORKCLASS_ALIASED( DynamicProp, DT_DynamicProp ) - // constructor, destructor - C_DynamicProp( void ); - ~C_DynamicProp( void ); - - void GetRenderBounds( Vector& theMins, Vector& theMaxs ); - unsigned int ComputeClientSideAnimationFlags(); - -private: - C_DynamicProp( const C_DynamicProp & ); - - bool m_bUseHitboxesForRenderBox; - int m_iCachedFrameCount; - Vector m_vecCachedRenderMins; - Vector m_vecCachedRenderMaxs; -}; - -IMPLEMENT_CLIENTCLASS_DT(C_DynamicProp, DT_DynamicProp, CDynamicProp) +BEGIN_NETWORK_TABLE( CDynamicProp, DT_DynamicProp ) RecvPropBool(RECVINFO(m_bUseHitboxesForRenderBox)), -END_RECV_TABLE() +END_NETWORK_TABLE() C_DynamicProp::C_DynamicProp( void ) { @@ -54,6 +33,41 @@ C_DynamicProp::~C_DynamicProp( void ) { } +bool C_DynamicProp::TestBoneFollowers( const Ray_t &ray, unsigned int fContentsMask, trace_t& tr ) +{ + // UNDONE: There is no list of the bone followers that is networked to the client + // so instead we do a search for solid stuff here. This is not really great - a list would be + // preferable. + CBaseEntity *pList[128]; + Vector mins, maxs; + CollisionProp()->WorldSpaceAABB( &mins, &maxs ); + int count = UTIL_EntitiesInBox( pList, ARRAYSIZE(pList), mins, maxs, 0, PARTITION_CLIENT_SOLID_EDICTS ); + for ( int i = 0; i < count; i++ ) + { + if ( pList[i]->GetOwnerEntity() == this ) + { + if ( pList[i]->TestCollision(ray, fContentsMask, tr) ) + { + return true; + } + } + } + return false; +} + +bool C_DynamicProp::TestCollision( const Ray_t &ray, unsigned int fContentsMask, trace_t& tr ) +{ + if ( IsSolidFlagSet(FSOLID_NOT_SOLID) ) + { + // if this entity is marked non-solid and custom test it must have bone followers + if ( IsSolidFlagSet( FSOLID_CUSTOMBOXTEST ) && IsSolidFlagSet( FSOLID_CUSTOMRAYTEST )) + { + return TestBoneFollowers( ray, fContentsMask, tr ); + } + } + return BaseClass::TestCollision( ray, fContentsMask, tr ); +} + //----------------------------------------------------------------------------- // implements these so ragdolls can handle frustum culling & leaf visibility //----------------------------------------------------------------------------- diff --git a/src/src/game/client/c_props.h b/src/src/game/client/c_props.h new file mode 100644 index 0000000..9eccad8 --- /dev/null +++ b/src/src/game/client/c_props.h @@ -0,0 +1,45 @@ +//====== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======= +// +// Purpose: +// +//============================================================================= + +#ifndef C_PROPS_H +#define C_PROPS_H +#ifdef _WIN32 +#pragma once +#endif + +#include "c_breakableprop.h" +#include "props_shared.h" + +#define CDynamicProp C_DynamicProp + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class C_DynamicProp : public C_BreakableProp +{ + DECLARE_CLASS( C_DynamicProp, C_BreakableProp ); +public: + DECLARE_NETWORKCLASS(); + + // constructor, destructor + C_DynamicProp( void ); + ~C_DynamicProp( void ); + + void GetRenderBounds( Vector& theMins, Vector& theMaxs ); + unsigned int ComputeClientSideAnimationFlags(); + bool TestBoneFollowers( const Ray_t &ray, unsigned int fContentsMask, trace_t& tr ); + bool TestCollision( const Ray_t &ray, unsigned int fContentsMask, trace_t& tr ); + +private: + C_DynamicProp( const C_DynamicProp & ); + + bool m_bUseHitboxesForRenderBox; + int m_iCachedFrameCount; + Vector m_vecCachedRenderMins; + Vector m_vecCachedRenderMaxs; +}; + +#endif // C_PROPS_H diff --git a/src/src/cl_dll/c_ragdoll_manager.cpp b/src/src/game/client/c_ragdoll_manager.cpp similarity index 86% rename from src/src/cl_dll/c_ragdoll_manager.cpp rename to src/src/game/client/c_ragdoll_manager.cpp index 625642a..cbb1deb 100644 --- a/src/src/cl_dll/c_ragdoll_manager.cpp +++ b/src/src/game/client/c_ragdoll_manager.cpp @@ -2,7 +2,6 @@ // // Purpose: // -// $NoKeywords: $ //=============================================================================// #include "cbase.h" #include "ragdoll_shared.h" @@ -25,11 +24,11 @@ public: public: - int m_iMaxRagdollCount; + int m_iCurrentMaxRagdollCount; }; IMPLEMENT_CLIENTCLASS_DT_NOBASE( C_RagdollManager, DT_RagdollManager, CRagdollManager ) - RecvPropInt( RECVINFO( m_iMaxRagdollCount ) ), + RecvPropInt( RECVINFO( m_iCurrentMaxRagdollCount ) ), END_RECV_TABLE() //----------------------------------------------------------------------------- @@ -37,7 +36,7 @@ END_RECV_TABLE() //----------------------------------------------------------------------------- C_RagdollManager::C_RagdollManager() { - m_iMaxRagdollCount = -1; + m_iCurrentMaxRagdollCount = -1; } //----------------------------------------------------------------------------- @@ -48,5 +47,5 @@ void C_RagdollManager::OnDataChanged( DataUpdateType_t updateType ) { BaseClass::OnDataChanged( updateType ); - s_RagdollLRU.SetMaxRagdollCount( m_iMaxRagdollCount ); + s_RagdollLRU.SetMaxRagdollCount( m_iCurrentMaxRagdollCount ); } diff --git a/src/src/cl_dll/c_recipientfilter.cpp b/src/src/game/client/c_recipientfilter.cpp similarity index 100% rename from src/src/cl_dll/c_recipientfilter.cpp rename to src/src/game/client/c_recipientfilter.cpp diff --git a/src/src/cl_dll/c_recipientfilter.h b/src/src/game/client/c_recipientfilter.h similarity index 100% rename from src/src/cl_dll/c_recipientfilter.h rename to src/src/game/client/c_recipientfilter.h diff --git a/src/src/cl_dll/c_rope.cpp b/src/src/game/client/c_rope.cpp similarity index 66% rename from src/src/cl_dll/c_rope.cpp rename to src/src/game/client/c_rope.cpp index 51ce298..d584e28 100644 --- a/src/src/cl_dll/c_rope.cpp +++ b/src/src/game/client/c_rope.cpp @@ -1,9 +1,9 @@ -//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2007, Valve Corporation, All rights reserved. ============// // // Purpose: // // $NoKeywords: $ -//=============================================================================// +//=====================================================================================// #include "cbase.h" #include "c_rope.h" #include "beamdraw.h" @@ -17,8 +17,10 @@ #include "collisionutils.h" #include #include -#include "utlfixedlinkedlist.h" +#include "utllinkedlist.h" #include "materialsystem/imaterialsystemhardwareconfig.h" +#include "tier1/callqueue.h" +#include "tier1/memstack.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -34,7 +36,7 @@ void RecvProxy_RecomputeSprings( const CRecvProxyData *pData, void *pStruct, voi IMPLEMENT_CLIENTCLASS_DT_NOBASE( C_RopeKeyframe, DT_RopeKeyframe, CRopeKeyframe ) - RecvPropInt( RECVINFO(m_iRopeMaterialModel) ), + RecvPropInt( RECVINFO(m_iRopeMaterialModelIndex) ), RecvPropEHandle( RECVINFO(m_hStartPoint) ), RecvPropEHandle( RECVINFO(m_hEndPoint) ), RecvPropInt( RECVINFO(m_iStartAttachment) ), @@ -46,6 +48,7 @@ IMPLEMENT_CLIENTCLASS_DT_NOBASE( C_RopeKeyframe, DT_RopeKeyframe, CRopeKeyframe RecvPropInt( RECVINFO(m_RopeFlags) ), RecvPropFloat( RECVINFO(m_TextureScale) ), RecvPropInt( RECVINFO(m_nSegments) ), + RecvPropBool( RECVINFO(m_bConstrainBetweenEndpoints) ), RecvPropInt( RECVINFO(m_Subdiv) ), RecvPropFloat( RECVINFO(m_Width) ), @@ -82,7 +85,7 @@ static ConVar rope_averagelight( "rope_averagelight", "1", 0, "Makes ropes use a static ConVar rope_rendersolid( "rope_rendersolid", "1" ); -static ConVar rope_solid_minwidth( "rope_solid_minwidth", "0.6" ); +static ConVar rope_solid_minwidth( "rope_solid_minwidth", "0.3" ); static ConVar rope_solid_maxwidth( "rope_solid_maxwidth", "1" ); static ConVar rope_solid_minalpha( "rope_solid_minalpha", "0.0" ); @@ -110,7 +113,7 @@ public: } g_FullBrightLightValuesInit; // Precalculated info for rope subdivision. -static float g_RopeSubdivs[MAX_ROPE_SUBDIVS][MAX_ROPE_SUBDIVS]; +static Vector g_RopeSubdivs[MAX_ROPE_SUBDIVS][MAX_ROPE_SUBDIVS]; class CSubdivInit { public: @@ -118,20 +121,84 @@ public: { for ( int iSubdiv=0; iSubdiv < MAX_ROPE_SUBDIVS; iSubdiv++ ) { - for( int i=0; i < iSubdiv; i++ ) - g_RopeSubdivs[iSubdiv][i] = (float)(i+1) / (iSubdiv+1); + for( int i=0; i <= iSubdiv; i++ ) + { + float t = (float)(i+1) / (iSubdiv+1); + g_RopeSubdivs[iSubdiv][i].Init( t, t*t, t*t*t ); + } } } } g_SubdivInit; //interesting barbed-wire-looking effect static int g_nBarbedSubdivs = 3; -static float g_BarbedSubdivs[MAX_ROPE_SUBDIVS] = {1.5, -0.5, 0.5}; +static Vector g_BarbedSubdivs[MAX_ROPE_SUBDIVS] = { Vector(1.5, 1.5*1.5, 1.5*1.5*1.5), + Vector(-0.5, -0.5 * -0.5, -0.5*-0.5*-0.5), + Vector(0.5, 0.5*0.5, 0.5*0.5*0.5) }; // This can be exposed through the entity if we ever care. static float g_flLockAmount = 0.1; static float g_flLockFalloff = 0.3; + + + +class CQueuedRopeMemoryManager +{ +public: + CQueuedRopeMemoryManager( void ) + { + m_nCurrentStack = 0; + MEM_ALLOC_CREDIT(); + m_QueuedRopeMemory[0].Init( 131072, 0, 16384 ); + m_QueuedRopeMemory[1].Init( 131072, 0, 16384 ); + } + ~CQueuedRopeMemoryManager( void ) + { + m_QueuedRopeMemory[0].FreeAll( true ); + m_QueuedRopeMemory[1].FreeAll( true ); + for( int i = 0; i != 2; ++i ) + { + for( int j = m_DeleteOnSwitch[i].Count(); --j >= 0; ) + { + delete []m_DeleteOnSwitch[i].Element(j); + } + + m_DeleteOnSwitch[i].RemoveAll(); + } + } + + void SwitchStack( void ) + { + m_nCurrentStack = 1 - m_nCurrentStack; + m_QueuedRopeMemory[m_nCurrentStack].FreeAll( false ); + + for( int i = m_DeleteOnSwitch[m_nCurrentStack].Count(); --i >= 0; ) + { + delete []m_DeleteOnSwitch[m_nCurrentStack].Element(i); + } + m_DeleteOnSwitch[m_nCurrentStack].RemoveAll(); + } + + inline void *Alloc( size_t bytes ) + { + MEM_ALLOC_CREDIT(); + void *pReturn = m_QueuedRopeMemory[m_nCurrentStack].Alloc( bytes, false ); + if( pReturn == NULL ) + { + int iMaxSize = m_QueuedRopeMemory[m_nCurrentStack].GetMaxSize(); + Warning( "Overflowed rope queued rendering memory stack. Needed %d, have %d/%d\n", bytes, iMaxSize - m_QueuedRopeMemory[m_nCurrentStack].GetUsed(), iMaxSize ); + pReturn = new uint8 [bytes]; + m_DeleteOnSwitch[m_nCurrentStack].AddToTail( pReturn ); + } + return pReturn; + } + + CMemoryStack m_QueuedRopeMemory[2]; + int m_nCurrentStack; + CUtlVector m_DeleteOnSwitch[2]; //when we overflow the stack, we do new/delete +}; + //============================================================================= // // Rope mananger. @@ -139,7 +206,7 @@ static float g_flLockFalloff = 0.3; struct RopeSegData_t { int m_nSegmentCount; - CBeamSeg m_Segments[MAX_ROPE_SEGMENTS]; + BeamSeg_t m_Segments[MAX_ROPE_SEGMENTS]; float m_BackWidths[MAX_ROPE_SEGMENTS]; // If this is less than rope_solid_minwidth and rope_solid_minalpha is 0, then we can avoid drawing.. @@ -155,17 +222,28 @@ public: void ResetRenderCache( void ); void AddToRenderCache( C_RopeKeyframe *pRope ); - void DrawRenderCache( void ); - + void DrawRenderCache( bool bShadowDepth ); + void OnRenderStart( void ) + { + m_QueuedModeMemory.SwitchStack(); + } + +private: + struct RopeRenderData_t; +public: + void DrawRenderCache_NonQueued( bool bShadowDepth, RopeRenderData_t *pRenderCache, int nRenderCacheCount, const Vector &vCurrentViewForward, const Vector &vCurrentViewOrigin, C_RopeKeyframe::BuildRopeQueuedData_t *pBuildRopeQueuedData ); + void ResetSegmentCache( int nMaxSegments ); RopeSegData_t *GetNextSegmentFromCache( void ); enum { MAX_ROPE_RENDERCACHE = 128 }; + + void RemoveRopeFromQueuedRenderCaches( C_RopeKeyframe *pRope ); private: - void RenderNonSolidRopes( IMaterial *pMaterial, int nVertCount, int nIndexCount ); - void RenderSolidRopes( IMaterial *pMaterial, int nVertCount, int nIndexCount, bool bRenderNonSolid ); + void RenderNonSolidRopes( IMatRenderContext *pRenderContext, IMaterial *pMaterial, int nVertCount, int nIndexCount ); + void RenderSolidRopes( IMatRenderContext *pRenderContext, IMaterial *pMaterial, int nVertCount, int nIndexCount, bool bRenderNonSolid ); private: @@ -180,6 +258,22 @@ private: CUtlVector m_aRenderCache; int m_nSegmentCacheCount; CUtlVector m_aSegmentCache; + CThreadFastMutex m_RenderCacheMutex; //there's only any contention during the switch from r_queued_ropes on to off + + //in queued material system mode we need to store off data for later use. + CQueuedRopeMemoryManager m_QueuedModeMemory; + + IMaterial* m_pDepthWriteMaterial; + + + struct RopeQueuedRenderCache_t + { + RopeRenderData_t *pCaches; + int iCacheCount; + RopeQueuedRenderCache_t( void ) : pCaches(NULL), iCacheCount(0) { }; + }; + + CUtlLinkedList m_RopeQueuedRenderCaches; }; static CRopeManager s_RopeManager; @@ -204,6 +298,7 @@ CRopeManager::CRopeManager() m_aRenderCache.Purge(); m_aSegmentCache.Purge(); m_nSegmentCacheCount = 0; + m_pDepthWriteMaterial = NULL; } //----------------------------------------------------------------------------- @@ -267,34 +362,74 @@ void CRopeManager::AddToRenderCache( C_RopeKeyframe *pRope ) ++m_aRenderCache[iRenderCache].m_nCacheCount; } -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CRopeManager::DrawRenderCache( void ) +void CRopeManager::DrawRenderCache_NonQueued( bool bShadowDepth, RopeRenderData_t *pRenderCache, int nRenderCacheCount, const Vector &vCurrentViewForward, const Vector &vCurrentViewOrigin, C_RopeKeyframe::BuildRopeQueuedData_t *pBuildRopeQueuedData ) { VPROF_BUDGET( "CRopeManager::DrawRenderCache", VPROF_BUDGETGROUP_ROPES ); + AUTO_LOCK( m_RenderCacheMutex ); //contention cases: Toggling from queued mode on to off. Rope deletion from the cache. // Check to see if we want to render the ropes. if( !r_drawropes.GetBool() ) return; - int nRenderCacheCount = m_aRenderCache.Count(); + if ( bShadowDepth && !m_pDepthWriteMaterial && g_pMaterialSystem ) + { + KeyValues *pVMTKeyValues = new KeyValues( "DepthWrite" ); + pVMTKeyValues->SetInt( "$no_fullbright", 1 ); + pVMTKeyValues->SetInt( "$alphatest", 0 ); + pVMTKeyValues->SetInt( "$nocull", 1 ); + m_pDepthWriteMaterial = g_pMaterialSystem->FindProceduralMaterial( "__DepthWrite01", TEXTURE_GROUP_OTHER, pVMTKeyValues ); + } + + CMatRenderContextPtr pRenderContext( materials ); + + C_RopeKeyframe::BuildRopeQueuedData_t stackQueuedData; + Vector vStackPredictedPositions[MAX_ROPE_SEGMENTS]; + for ( int iRenderCache = 0; iRenderCache < nRenderCacheCount; ++iRenderCache ) { - if ( m_aRenderCache[iRenderCache].m_nCacheCount == 0 ) - continue; + int nCacheCount = pRenderCache[iRenderCache].m_nCacheCount; - int nCacheCount = m_aRenderCache[iRenderCache].m_nCacheCount; + if ( nCacheCount == 0 ) + continue; ResetSegmentCache( nCacheCount ); for ( int iCache = 0; iCache < nCacheCount; ++iCache ) { - C_RopeKeyframe *pRope = m_aRenderCache[iRenderCache].m_aCache[iCache]; + C_RopeKeyframe *pRope = pRenderCache[iRenderCache].m_aCache[iCache]; if ( pRope ) { RopeSegData_t *pRopeSegment = GetNextSegmentFromCache(); - pRope->BuildRope( pRopeSegment ); + + if( pBuildRopeQueuedData ) + { + pRope->BuildRope( pRopeSegment, vCurrentViewForward, vCurrentViewOrigin, pBuildRopeQueuedData ); + ++pBuildRopeQueuedData; + } + else + { + //to unify the BuildRope code, emulate the queued data + stackQueuedData.m_iNodeCount = pRope->m_RopePhysics.NumNodes(); + stackQueuedData.m_pLightValues = pRope->m_LightValues; + stackQueuedData.m_vColorMod = pRope->m_vColorMod; + stackQueuedData.m_pPredictedPositions = vStackPredictedPositions; + stackQueuedData.m_RopeLength = pRope->m_RopeLength; + stackQueuedData.m_Slack = pRope->m_Slack; + for( int i = 0; i != stackQueuedData.m_iNodeCount; ++i ) + { + vStackPredictedPositions[i] = pRope->m_RopePhysics.GetNode( i )->m_vPredicted; + } + + pRope->BuildRope( pRopeSegment, vCurrentViewForward, vCurrentViewOrigin, &stackQueuedData ); + } + } + else + { + if( pBuildRopeQueuedData ) + { + //we should only be here if a rope was in the queue and then deleted. We still have it's relevant data (and need to skip over it). + ++pBuildRopeQueuedData; + } } } @@ -307,29 +442,145 @@ void CRopeManager::DrawRenderCache( void ) } // Render the non-solid portion of the ropes. - bool bRenderNonSolid = ShouldUseFakeAA( m_aRenderCache[iRenderCache].m_pBackMaterial ); + bool bRenderNonSolid = !bShadowDepth && ShouldUseFakeAA( pRenderCache[iRenderCache].m_pBackMaterial ); if ( bRenderNonSolid ) { - RenderNonSolidRopes( m_aRenderCache[iRenderCache].m_pBackMaterial, nVertCount, nIndexCount ); + RenderNonSolidRopes( pRenderContext, pRenderCache[iRenderCache].m_pBackMaterial, nVertCount, nIndexCount ); } // Render the solid portion of the ropes. if ( rope_rendersolid.GetInt() ) { - RenderSolidRopes( m_aRenderCache[iRenderCache].m_pSolidMaterial, nVertCount, nIndexCount, bRenderNonSolid ); + if ( bShadowDepth ) + RenderSolidRopes( pRenderContext, m_pDepthWriteMaterial, nVertCount, nIndexCount, bRenderNonSolid ); + else + RenderSolidRopes( pRenderContext, pRenderCache[iRenderCache].m_pSolidMaterial, nVertCount, nIndexCount, bRenderNonSolid ); } } ResetSegmentCache( 0 ); + + if( pBuildRopeQueuedData && (m_RopeQueuedRenderCaches.Count() != 0) ) + m_RopeQueuedRenderCaches.Remove( m_RopeQueuedRenderCaches.Head() ); +} + +ConVar r_queued_ropes( "r_queued_ropes", "1" ); + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CRopeManager::DrawRenderCache( bool bShadowDepth ) +{ + int iRenderCacheCount = m_aRenderCache.Count(); + + if( iRenderCacheCount == 0 ) + return; + + Vector vForward = CurrentViewForward(); + Vector vOrigin = CurrentViewOrigin(); + + ICallQueue *pCallQueue; + if( r_queued_ropes.GetBool() && (pCallQueue = materials->GetRenderContext()->GetCallQueue()) != NULL ) + { + //material queue available and desired + CRopeManager::RopeRenderData_t *pRenderCache = m_aRenderCache.Base(); + AUTO_LOCK( m_RenderCacheMutex ); + + int iRopeCount = 0; + int iNodeCount = 0; + for( int i = 0; i != iRenderCacheCount; ++i ) + { + CRopeManager::RopeRenderData_t *pCache = &pRenderCache[i]; + int iCacheCount = pCache->m_nCacheCount; + iRopeCount += iCacheCount; + for( int j = 0; j != iCacheCount; ++j ) + { + C_RopeKeyframe *pRope = pCache->m_aCache[j]; + if( pRope ) + iNodeCount += pRope->m_RopePhysics.NumNodes(); + else + --iRopeCount; + } + } + + if( iRopeCount == 0 ) + return; //nothing to draw + + size_t iMemoryNeeded = (iRenderCacheCount * sizeof(CRopeManager::RopeRenderData_t)) + + (iRopeCount * sizeof(C_RopeKeyframe::BuildRopeQueuedData_t)) + + (iNodeCount * (sizeof(Vector) * 2)); + + void *pMemory = m_QueuedModeMemory.Alloc( iMemoryNeeded ); + + CRopeManager::RopeRenderData_t *pRenderCachesStart = (CRopeManager::RopeRenderData_t *)pMemory; + C_RopeKeyframe::BuildRopeQueuedData_t *pBuildRopeQueuedDataStart = (C_RopeKeyframe::BuildRopeQueuedData_t *)(pRenderCachesStart + iRenderCacheCount); + Vector *pVectorDataStart = (Vector *)(pBuildRopeQueuedDataStart + iRopeCount); + + //memcpy( pRenderCachesStart, m_aRenderCache.Base(), iRenderCacheCount * sizeof( CRopeManager::RopeRenderData_t ) ); + + RopeQueuedRenderCache_t cache; + cache.pCaches = pRenderCachesStart; + cache.iCacheCount = iRenderCacheCount; + m_RopeQueuedRenderCaches.AddToTail( cache ); + + C_RopeKeyframe::BuildRopeQueuedData_t *pWriteRopeQueuedData = pBuildRopeQueuedDataStart; + Vector *pVectorWrite = (Vector *)pVectorDataStart; + + //Setup the rest of our data. This writes to two separate areas of memory at the same time. One area for the C_RopeKeyframe::BuildRopeQueuedData_t array, the other for mini-arrays of vector data + for( int i = 0; i != iRenderCacheCount; ++i ) + { + CRopeManager::RopeRenderData_t *pReadCache = &pRenderCache[i]; + CRopeManager::RopeRenderData_t *pWriteCache = &pRenderCachesStart[i]; + int iCacheCount = pReadCache->m_nCacheCount; + pWriteCache->m_nCacheCount = 0; + pWriteCache->m_pSolidMaterial = pReadCache->m_pSolidMaterial; + pWriteCache->m_pBackMaterial = pReadCache->m_pBackMaterial; + for( int j = 0; j != iCacheCount; ++j ) + { + C_RopeKeyframe *pRope = pReadCache->m_aCache[j]; + if( pRope == NULL ) + continue; + + pWriteCache->m_aCache[pWriteCache->m_nCacheCount] = pRope; + ++pWriteCache->m_nCacheCount; + + int iNodes = pRope->m_RopePhysics.NumNodes(); + + //setup the C_RopeKeyframe::BuildRopeQueuedData_t struct + pWriteRopeQueuedData->m_iNodeCount = pRope->m_RopePhysics.NumNodes(); + pWriteRopeQueuedData->m_vColorMod = pRope->m_vColorMod; + pWriteRopeQueuedData->m_RopeLength = pRope->m_RopeLength; + pWriteRopeQueuedData->m_Slack = pRope->m_Slack; + pWriteRopeQueuedData->m_pPredictedPositions = pVectorWrite; + pWriteRopeQueuedData->m_pLightValues = pVectorWrite + iNodes; + ++pWriteRopeQueuedData; + + //make two arrays, one of predicted positions followed immediately by light values + for( int k = 0; k != iNodes; ++k ) + { + pVectorWrite[0] = pRope->m_RopePhysics.GetNode( k )->m_vPredicted; + pVectorWrite[iNodes] = pRope->m_LightValues[k]; + ++pVectorWrite; + } + pVectorWrite += iNodes; //so we don't overwrite the light values with the next rope's predicted positions + } + } + Assert( ((void *)pVectorWrite == (void *)(((uint8 *)pMemory) + iMemoryNeeded)) && ((void *)pWriteRopeQueuedData == (void *)pVectorDataStart)); + pCallQueue->QueueCall( this, &CRopeManager::DrawRenderCache_NonQueued, bShadowDepth, pRenderCachesStart, iRenderCacheCount, vForward, vOrigin, pBuildRopeQueuedDataStart ); + } + else + { + DrawRenderCache_NonQueued( bShadowDepth, m_aRenderCache.Base(), iRenderCacheCount, vForward, vOrigin, NULL ); + } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- -void CRopeManager::RenderNonSolidRopes( IMaterial *pMaterial, int nVertCount, int nIndexCount ) +void CRopeManager::RenderNonSolidRopes( IMatRenderContext *pRenderContext, IMaterial *pMaterial, int nVertCount, int nIndexCount ) { // Render the solid portion of the ropes. CMeshBuilder meshBuilder; - IMesh *pMesh = materials->GetDynamicMesh( true, NULL, NULL, pMaterial ); + IMesh *pMesh = pRenderContext->GetDynamicMesh( true, NULL, NULL, pMaterial ); meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, nVertCount, nIndexCount ); CBeamSegDraw beamSegment; @@ -338,7 +589,7 @@ void CRopeManager::RenderNonSolidRopes( IMaterial *pMaterial, int nVertCount, in for ( int iSegmentCache = 0; iSegmentCache < m_nSegmentCacheCount; ++iSegmentCache ) { int nSegmentCount = m_aSegmentCache[iSegmentCache].m_nSegmentCount; - beamSegment.Start( nSegmentCount, pMaterial, &meshBuilder, nVerts ); + beamSegment.Start( pRenderContext, nSegmentCount, pMaterial, &meshBuilder, nVerts ); for ( int iSegment = 0; iSegment < nSegmentCount; ++iSegment ) { beamSegment.NextSeg( &m_aSegmentCache[iSegmentCache].m_Segments[iSegment] ); @@ -354,11 +605,11 @@ void CRopeManager::RenderNonSolidRopes( IMaterial *pMaterial, int nVertCount, in //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- -void CRopeManager::RenderSolidRopes( IMaterial *pMaterial, int nVertCount, int nIndexCount, bool bRenderNonSolid ) +void CRopeManager::RenderSolidRopes( IMatRenderContext *pRenderContext, IMaterial *pMaterial, int nVertCount, int nIndexCount, bool bRenderNonSolid ) { // Render the solid portion of the ropes. CMeshBuilder meshBuilder; - IMesh *pMesh = materials->GetDynamicMesh( true, NULL, NULL, pMaterial ); + IMesh *pMesh = pRenderContext->GetDynamicMesh( true, NULL, NULL, pMaterial ); meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, nVertCount, nIndexCount ); CBeamSegDraw beamSegment; @@ -375,10 +626,10 @@ void CRopeManager::RenderSolidRopes( IMaterial *pMaterial, int nVertCount, int n continue; int nSegmentCount = m_aSegmentCache[iSegmentCache].m_nSegmentCount; - beamSegment.Start( nSegmentCount, pMaterial, &meshBuilder, nVerts ); + beamSegment.Start( pRenderContext, nSegmentCount, pMaterial, &meshBuilder, nVerts ); for ( int iSegment = 0; iSegment < nSegmentCount; ++iSegment ) { - CBeamSeg *pSeg = &m_aSegmentCache[iSegmentCache].m_Segments[iSegment]; + BeamSeg_t *pSeg = &m_aSegmentCache[iSegmentCache].m_Segments[iSegment]; pSeg->m_flWidth = m_aSegmentCache[iSegmentCache].m_BackWidths[iSegment]; // To avoid aliasing, the "solid" version of the rope on xbox is just "more solid", @@ -403,7 +654,7 @@ void CRopeManager::RenderSolidRopes( IMaterial *pMaterial, int nVertCount, int n for ( int iSegmentCache = 0; iSegmentCache < m_nSegmentCacheCount; ++iSegmentCache ) { int nSegmentCount = m_aSegmentCache[iSegmentCache].m_nSegmentCount; - beamSegment.Start( nSegmentCount, pMaterial, &meshBuilder, nVerts ); + beamSegment.Start( pRenderContext, nSegmentCount, pMaterial, &meshBuilder, nVerts ); for ( int iSegment = 0; iSegment < nSegmentCount; ++iSegment ) { beamSegment.NextSeg( &m_aSegmentCache[iSegmentCache].m_Segments[iSegment] ); @@ -446,6 +697,32 @@ RopeSegData_t *CRopeManager::GetNextSegmentFromCache( void ) return &m_aSegmentCache[m_nSegmentCacheCount-1]; } + + +void CRopeManager::RemoveRopeFromQueuedRenderCaches( C_RopeKeyframe *pRope ) +{ + //remove this rope from queued render caches + AUTO_LOCK( m_RenderCacheMutex ); + int index = m_RopeQueuedRenderCaches.Head(); + while( m_RopeQueuedRenderCaches.IsValidIndex( index ) ) + { + RopeQueuedRenderCache_t &RenderCacheData = m_RopeQueuedRenderCaches[index]; + for( int i = 0; i != RenderCacheData.iCacheCount; ++i ) + { + RopeRenderData_t *pCache = &RenderCacheData.pCaches[i]; + for( int j = 0; j != pCache->m_nCacheCount; ++j ) + { + if( pCache->m_aCache[j] == pRope ) + { + pCache->m_aCache[j] = NULL; + } + } + } + + index = m_RopeQueuedRenderCaches.Next( index ); + } +} + //============================================================================= // ------------------------------------------------------------------------------------ // @@ -649,7 +926,8 @@ void C_RopeKeyframe::CPhysicsDelegate::ApplyConstraints( CSimplePhysics::CNode * C_RopeKeyframe::C_RopeKeyframe() { - m_bEndPointAttachmentsDirty = true; + m_bEndPointAttachmentPositionsDirty = true; + m_bEndPointAttachmentAnglesDirty = true; m_PhysicsDelegate.m_pKeyframe = this; m_pMaterial = NULL; m_bPhysicsInitted = false; @@ -675,6 +953,7 @@ C_RopeKeyframe::C_RopeKeyframe() C_RopeKeyframe::~C_RopeKeyframe() { + s_RopeManager.RemoveRopeFromQueuedRenderCaches( this ); g_Ropes.FindAndRemove( this ); } @@ -891,7 +1170,7 @@ void C_RopeKeyframe::OnDataChanged( DataUpdateType_t updateType ) // Figure out the material name. char str[512]; - const model_t *pModel = modelinfo->GetModel( m_iRopeMaterialModel ); + const model_t *pModel = modelinfo->GetModel( m_iRopeMaterialModelIndex ); if ( pModel ) { Q_strncpy( str, modelinfo->GetModelName( pModel ), sizeof( str ) ); @@ -928,7 +1207,6 @@ void C_RopeKeyframe::FinishInit( const char *pMaterialName ) if ( m_pBackMaterial ) m_pBackMaterial->GetMappingWidth(); - // Init rope physics. m_nSegments = clamp( m_nSegments, 2, ROPE_MAX_SEGMENTS ); @@ -958,10 +1236,48 @@ void C_RopeKeyframe::RunRopeSimulation( float flSeconds ) } } +Vector C_RopeKeyframe::ConstrainNode( const Vector &vNormal, const Vector &vNodePosition, const Vector &vMidpiont, float fNormalLength ) +{ + // Get triangle edges formed + Vector vMidpointToNode = vNodePosition - vMidpiont; + Vector vMidpointToNodeProjected = vMidpointToNode.Dot( vNormal ) * vNormal; + float fMidpointToNodeLengh = VectorNormalize( vMidpointToNode ); + float fMidpointToNodeProjectedLengh = VectorNormalize( vMidpointToNodeProjected ); + + // See if it's past an endpoint + if ( fMidpointToNodeProjectedLengh < fNormalLength + 1.0f ) + return vNodePosition; + + // Apply the ratio between the triangles + return vMidpiont + vMidpointToNode * fMidpointToNodeLengh * ( fNormalLength / fMidpointToNodeProjectedLengh ); +} + +void C_RopeKeyframe::ConstrainNodesBetweenEndpoints( void ) +{ + if ( !m_bConstrainBetweenEndpoints ) + return; + + // Get midpoint and normals + Vector vMidpiont = ( m_vCachedEndPointAttachmentPos[ 0 ] + m_vCachedEndPointAttachmentPos[ 1 ] ) / 2.0f; + Vector vNormal = vMidpiont - m_vCachedEndPointAttachmentPos[ 0 ]; + float fNormalLength = VectorNormalize( vNormal ); + + // Loop through all the middle segments and ensure their positions are constrained between the endpoints + for ( int i = 1; i < m_RopePhysics.NumNodes() - 1; ++i ) + { + // Fix the current position + m_RopePhysics.GetNode( i )->m_vPos = ConstrainNode( vNormal, m_RopePhysics.GetNode( i )->m_vPos, vMidpiont, fNormalLength ); + + // Fix the predicted position + m_RopePhysics.GetNode( i )->m_vPredicted = ConstrainNode( vNormal, m_RopePhysics.GetNode( i )->m_vPredicted, vMidpiont, fNormalLength ); + } +} + void C_RopeKeyframe::ClientThink() { // Only recalculate the endpoint attachments once per frame. - m_bEndPointAttachmentsDirty = true; + m_bEndPointAttachmentPositionsDirty = true; + m_bEndPointAttachmentAnglesDirty = true; if( !r_drawropes.GetBool() ) return; @@ -1026,6 +1342,8 @@ int C_RopeKeyframe::DrawModel( int flags ) return 0; } + ConstrainNodesBetweenEndpoints(); + RopeManager()->AddToRenderCache( this ); return 1; } @@ -1046,6 +1364,53 @@ const Vector& C_RopeKeyframe::WorldSpaceCenter( ) const return GetAbsOrigin(); } +bool C_RopeKeyframe::GetAttachment( int number, matrix3x4_t &matrix ) +{ + int nNodes = m_RopePhysics.NumNodes(); + if ( (number != ROPE_ATTACHMENT_START_POINT && number != ROPE_ATTACHMENT_END_POINT) || nNodes < 2 ) + return false; + + // Now setup the orientation based on the last segment. + Vector vForward, origin; + if ( number == ROPE_ATTACHMENT_START_POINT ) + { + origin = m_RopePhysics.GetNode( 0 )->m_vPredicted; + vForward = m_RopePhysics.GetNode( 0 )->m_vPredicted - m_RopePhysics.GetNode( 1 )->m_vPredicted; + } + else + { + origin = m_RopePhysics.GetNode( nNodes-1 )->m_vPredicted; + vForward = m_RopePhysics.GetNode( nNodes-1 )->m_vPredicted - m_RopePhysics.GetNode( nNodes-2 )->m_vPredicted; + } + VectorMatrix( vForward, matrix ); + PositionMatrix( origin, matrix ); + return true; +} + +bool C_RopeKeyframe::GetAttachment( int number, Vector &origin ) +{ + int nNodes = m_RopePhysics.NumNodes(); + if ( (number != ROPE_ATTACHMENT_START_POINT && number != ROPE_ATTACHMENT_END_POINT) || nNodes < 2 ) + return false; + + // Now setup the orientation based on the last segment. + if ( number == ROPE_ATTACHMENT_START_POINT ) + { + origin = m_RopePhysics.GetNode( 0 )->m_vPredicted; + } + else + { + origin = m_RopePhysics.GetNode( nNodes-1 )->m_vPredicted; + } + return true; +} + +bool C_RopeKeyframe::GetAttachmentVelocity( int number, Vector &originVel, Quaternion &angleVel ) +{ + Assert(0); + return false; +} + bool C_RopeKeyframe::GetAttachment( int number, Vector &origin, QAngle &angles ) { int nNodes = m_RopePhysics.NumNodes(); @@ -1156,53 +1521,90 @@ bool C_RopeKeyframe::DetectRestingState( bool &bApplyWind ) return !AnyPointsMoved() && !bApplyWind && !rope_shake.GetInt(); } +// simple struct to precompute basis for catmull rom splines for faster evaluation +struct catmull_t +{ + Vector t3; + Vector t2; + Vector t; + Vector c; +}; + +// bake out the terms of the catmull rom spline +void Catmull_Rom_Spline_Matrix( const Vector &p1, const Vector &p2, const Vector &p3, const Vector &p4, catmull_t &output ) +{ + output.t3 = 0.5f * ((-1*p1) + (3*p2) + (-3*p3) + p4); // 0.5 t^3 * [ (-1*p1) + ( 3*p2) + (-3*p3) + p4 ] + output.t2 = 0.5f * ((2*p1) + (-5*p2) + (4*p3) - p4); // 0.5 t^2 * [ ( 2*p1) + (-5*p2) + ( 4*p3) - p4 ] + output.t = 0.5f * ((-1*p1) + p3); // 0.5 t * [ (-1*p1) + p3 ] + output.c = p2; // p2 +} + +// evaluate one point on the spline, t is a vector of (t, t^2, t^3) +inline void Catmull_Rom_Eval( const catmull_t &spline, const Vector &t, Vector &output ) +{ + Assert(spline.c.IsValid()); + Assert(spline.t.IsValid()); + Assert(spline.t2.IsValid()); + Assert(spline.t3.IsValid()); + output = spline.c + (t.x * spline.t) + (t.y*spline.t2) + (t.z * spline.t3); +} + + //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- -void C_RopeKeyframe::BuildRope( RopeSegData_t *pSegmentData ) +void C_RopeKeyframe::BuildRope( RopeSegData_t *pSegmentData, const Vector &vCurrentViewForward, const Vector &vCurrentViewOrigin, C_RopeKeyframe::BuildRopeQueuedData_t *pQueuedData ) { if ( !pSegmentData ) return; // Get the lighting values. - Vector *pLightValues = mat_fullbright.GetInt() ? g_FullBright_LightValues : m_LightValues; + Vector *pLightValues = ( mat_fullbright.GetInt() == 1 ) ? g_FullBright_LightValues : pQueuedData->m_pLightValues; // Update the rope subdivisions if necessary. int nSubdivCount; - float *pSubdivList; - UpdateRopeSubdivs( &pSubdivList, &nSubdivCount ); + Vector *pSubdivVecList = GetRopeSubdivVectors( &nSubdivCount ); int nSegmentCount = 0; int iPrevNode = 0; - for( int iNode = 0; iNode < m_RopePhysics.NumNodes(); ++iNode ) + const float subdivScale = 1.0f / (nSubdivCount+1); + const int nodeCount = pQueuedData->m_iNodeCount; + const int lastNode = nodeCount-1; + catmull_t spline; + + Vector *pPredictedPositions = pQueuedData->m_pPredictedPositions; + Vector vColorMod = pQueuedData->m_vColorMod; + + for( int iNode = 0; iNode < nodeCount; ++iNode ) { - Vector &vecCurrent = m_RopePhysics.GetNode( iNode )->m_vPredicted; - - pSegmentData->m_Segments[nSegmentCount].m_vPos = vecCurrent; - pSegmentData->m_Segments[nSegmentCount].m_vColor = pLightValues[iNode] * m_vColorMod; + pSegmentData->m_Segments[nSegmentCount].m_vPos = pPredictedPositions[iNode]; + pSegmentData->m_Segments[nSegmentCount].m_vColor = pLightValues[iNode] * vColorMod; ++nSegmentCount; - if ( ( iNode + 1 ) < m_RopePhysics.NumNodes() ) + if ( iNode < lastNode ) { // Draw a midpoint to the next segment. int iNext = iNode + 1; int iNextNext = iNode + 2; - if ( iNext >= m_RopePhysics.NumNodes() ) + if ( iNext >= nodeCount ) { - iNext = iNextNext = m_RopePhysics.NumNodes() - 1; + iNext = iNextNext = lastNode; } - else if ( iNextNext >= m_RopePhysics.NumNodes() ) + else if ( iNextNext >= nodeCount ) { - iNextNext = m_RopePhysics.NumNodes() - 1; + iNextNext = lastNode; } - Vector vecColorInc = ( ( pLightValues[iNode+1] - pLightValues[iNode] ) * m_vColorMod ) / ( nSubdivCount + 1 ); + Vector vecColorInc = subdivScale * ( ( pLightValues[iNode+1] - pLightValues[iNode] ) * vColorMod ); + // precompute spline basis + Catmull_Rom_Spline_Matrix( pPredictedPositions[iPrevNode], pPredictedPositions[iNode], + pPredictedPositions[iNext], pPredictedPositions[iNextNext], spline ); for( int iSubdiv = 0; iSubdiv < nSubdivCount; ++iSubdiv ) { pSegmentData->m_Segments[nSegmentCount].m_vColor = pSegmentData->m_Segments[nSegmentCount-1].m_vColor + vecColorInc; - Catmull_Rom_Spline( m_RopePhysics.GetNode( iPrevNode )->m_vPredicted, m_RopePhysics.GetNode( iNode )->m_vPredicted, - m_RopePhysics.GetNode( iNext )->m_vPredicted, m_RopePhysics.GetNode( iNextNext )->m_vPredicted, - pSubdivList[iSubdiv], pSegmentData->m_Segments[nSegmentCount].m_vPos ); + // simple eval using precomputed basis + Catmull_Rom_Eval( spline, pSubdivVecList[iSubdiv], pSegmentData->m_Segments[nSegmentCount].m_vPos ); + ++nSegmentCount; Assert( nSegmentCount <= MAX_ROPE_SEGMENTS ); } @@ -1210,14 +1612,13 @@ void C_RopeKeyframe::BuildRope( RopeSegData_t *pSegmentData ) iPrevNode = iNode; } } - pSegmentData->m_nSegmentCount = nSegmentCount; pSegmentData->m_flMaxBackWidth = 0; // Figure out texture scale. float flPixelsPerInch = 4.0f / m_TextureScale; - float flTotalTexCoord = flPixelsPerInch * ( m_RopeLength + m_Slack + ROPESLACK_FUDGEFACTOR ); - int nTotalPoints = ( m_RopePhysics.NumNodes() - 1 ) * nSubdivCount + 1; + float flTotalTexCoord = flPixelsPerInch * ( pQueuedData->m_RopeLength + pQueuedData->m_Slack + ROPESLACK_FUDGEFACTOR ); + int nTotalPoints = ( nodeCount - 1 ) * nSubdivCount + 1; float flActualInc = ( flTotalTexCoord / nTotalPoints ) / ( float )m_TextureHeight; // First draw a translucent rope underneath the solid rope for an antialiasing effect. @@ -1241,7 +1642,7 @@ void C_RopeKeyframe::BuildRope( RopeSegData_t *pSegmentData ) pSegmentData->m_Segments[iSegment].m_flTexCoord = flTexCoord; // Right here, we need to specify a width that will be 1 pixel larger in screen space. - float zCoord = CurrentViewForward().Dot( pSegmentData->m_Segments[iSegment].m_vPos - CurrentViewOrigin() ); + float zCoord = vCurrentViewForward.Dot( pSegmentData->m_Segments[iSegment].m_vPos - vCurrentViewOrigin ); zCoord = max( zCoord, 0.1f ); float flScreenSpaceWidth = m_Width * flHalfScreenWidth / zCoord; @@ -1373,16 +1774,13 @@ bool C_RopeKeyframe::InitRopePhysics() } -bool C_RopeKeyframe::CalculateEndPointAttachment( C_BaseEntity *pEnt, int iAttachment, Vector &vPos, QAngle &angles ) +bool C_RopeKeyframe::CalculateEndPointAttachment( C_BaseEntity *pEnt, int iAttachment, Vector &vPos, QAngle *pAngles ) { VPROF_BUDGET( "C_RopeKeyframe::CalculateEndPointAttachment", VPROF_BUDGETGROUP_ROPES ); if( !pEnt ) return false; - vPos = pEnt->WorldSpaceCenter( ); - angles = pEnt->GetAbsAngles(); - if ( m_RopeFlags & ROPE_PLAYER_WPN_ATTACH ) { C_BasePlayer *pPlayer = dynamic_cast< C_BasePlayer* >( pEnt ); @@ -1393,33 +1791,59 @@ bool C_RopeKeyframe::CalculateEndPointAttachment( C_BaseEntity *pEnt, int iAttac return false; int iAttachment = pModel->LookupAttachment( "buff_attach" ); - return pModel->GetAttachment( iAttachment, vPos, angles ); + if ( pAngles ) + return pModel->GetAttachment( iAttachment, vPos, *pAngles ); + return pModel->GetAttachment( iAttachment, vPos ); } } if( iAttachment > 0 ) { - if( !pEnt->GetAttachment( iAttachment, vPos, angles ) ) - return false; + bool bOk; + if ( pAngles ) + { + bOk = pEnt->GetAttachment( iAttachment, vPos, *pAngles ); + } + else + { + bOk = pEnt->GetAttachment( iAttachment, vPos ); + } + if ( bOk ) + return true; } + vPos = pEnt->WorldSpaceCenter( ); + if ( pAngles ) + { + *pAngles = pEnt->GetAbsAngles(); + } return true; } bool C_RopeKeyframe::GetEndPointPos( int iPt, Vector &vPos ) { - QAngle angle; - return GetEndPointAttachment( iPt, vPos, angle ); + // By caching the results here, we avoid doing this a bunch of times per frame. + if ( m_bEndPointAttachmentPositionsDirty ) + { + CalculateEndPointAttachment( m_hStartPoint, m_iStartAttachment, m_vCachedEndPointAttachmentPos[0], NULL ); + CalculateEndPointAttachment( m_hEndPoint, m_iEndAttachment, m_vCachedEndPointAttachmentPos[1], NULL ); + m_bEndPointAttachmentPositionsDirty = false; + } + + Assert( iPt == 0 || iPt == 1 ); + vPos = m_vCachedEndPointAttachmentPos[iPt]; + return true; } bool C_RopeKeyframe::GetEndPointAttachment( int iPt, Vector &vPos, QAngle &angle ) { // By caching the results here, we avoid doing this a bunch of times per frame. - if ( m_bEndPointAttachmentsDirty ) + if ( m_bEndPointAttachmentPositionsDirty || m_bEndPointAttachmentAnglesDirty ) { - CalculateEndPointAttachment( m_hStartPoint, m_iStartAttachment, m_vCachedEndPointAttachmentPos[0], m_vCachedEndPointAttachmentAngle[0] ); - CalculateEndPointAttachment( m_hEndPoint, m_iEndAttachment, m_vCachedEndPointAttachmentPos[1], m_vCachedEndPointAttachmentAngle[1] ); - m_bEndPointAttachmentsDirty = false; + CalculateEndPointAttachment( m_hStartPoint, m_iStartAttachment, m_vCachedEndPointAttachmentPos[0], &m_vCachedEndPointAttachmentAngle[0] ); + CalculateEndPointAttachment( m_hEndPoint, m_iEndAttachment, m_vCachedEndPointAttachmentPos[1], &m_vCachedEndPointAttachmentAngle[1] ); + m_bEndPointAttachmentPositionsDirty = false; + m_bEndPointAttachmentAnglesDirty = false; } Assert( iPt == 0 || iPt == 1 ); @@ -1428,13 +1852,14 @@ bool C_RopeKeyframe::GetEndPointAttachment( int iPt, Vector &vPos, QAngle &angle return true; } + // Look at the global cvar and recalculate rope subdivision data if necessary. -void C_RopeKeyframe::UpdateRopeSubdivs( float **pSubdivs, int *nSubdivs ) +Vector *C_RopeKeyframe::GetRopeSubdivVectors( int *nSubdivs ) { if( m_RopeFlags & ROPE_BARBED ) { - *pSubdivs = g_BarbedSubdivs; *nSubdivs = g_nBarbedSubdivs; + return g_BarbedSubdivs; } else { @@ -1444,11 +1869,11 @@ void C_RopeKeyframe::UpdateRopeSubdivs( float **pSubdivs, int *nSubdivs ) subdiv = rope_subdiv.GetInt(); } - if ( subdiv > MAX_ROPE_SUBDIVS ) - subdiv = MAX_ROPE_SUBDIVS; + if ( subdiv >= MAX_ROPE_SUBDIVS ) + subdiv = MAX_ROPE_SUBDIVS-1; - *pSubdivs = g_RopeSubdivs[subdiv]; *nSubdivs = subdiv; + return g_RopeSubdivs[subdiv]; } } diff --git a/src/src/cl_dll/c_rope.h b/src/src/game/client/c_rope.h similarity index 80% rename from src/src/cl_dll/c_rope.h rename to src/src/game/client/c_rope.h index 1c98f3e..c1c9bef 100644 --- a/src/src/cl_dll/c_rope.h +++ b/src/src/game/client/c_rope.h @@ -109,7 +109,17 @@ public: IMaterial *GetSolidMaterial( void ) { return m_pMaterial; } IMaterial *GetBackMaterial( void ) { return m_pBackMaterial; } - void BuildRope( RopeSegData_t *pRopeSegment ); + struct BuildRopeQueuedData_t + { + Vector *m_pPredictedPositions; + Vector *m_pLightValues; + int m_iNodeCount; + Vector m_vColorMod; + float m_RopeLength; + float m_Slack; + }; + + void BuildRope( RopeSegData_t *pRopeSegment, const Vector &vCurrentViewForward, const Vector &vCurrentViewOrigin, BuildRopeQueuedData_t *pQueuedData ); // C_BaseEntity overrides. public: @@ -122,12 +132,17 @@ public: // Specify ROPE_ATTACHMENT_START_POINT or ROPE_ATTACHMENT_END_POINT for the attachment. virtual bool GetAttachment( int number, Vector &origin, QAngle &angles ); + virtual bool GetAttachment( int number, matrix3x4_t &matrix ); + virtual bool GetAttachment( int number, Vector &origin ); + virtual bool GetAttachmentVelocity( int number, Vector &originVel, Quaternion &angleVel ); private: void FinishInit( const char *pMaterialName ); void RunRopeSimulation( float flSeconds ); + Vector ConstrainNode( const Vector &vNormal, const Vector &vNodePosition, const Vector &vMidpiont, float fNormalLength ); + void ConstrainNodesBetweenEndpoints( void ); bool AnyPointsMoved(); @@ -139,20 +154,14 @@ private: bool GetEndPointAttachment( int iPt, Vector &vPos, QAngle &angle ); - void UpdateRopeSubdivs( float **pSubdivs, int *nSubdivs ); + Vector *GetRopeSubdivVectors( int *nSubdivs ); void CalcLightValues(); void ReceiveMessage( int classID, bf_read &msg ); - bool CalculateEndPointAttachment( C_BaseEntity *pEnt, int iAttachment, Vector &vPos, QAngle &angles ); + bool CalculateEndPointAttachment( C_BaseEntity *pEnt, int iAttachment, Vector &vPos, QAngle *pAngles ); private: - - bool m_bNewDataThisFrame; // Set to true in OnDataChanged so that we simulate that frame - - bool m_bPhysicsInitted; // It waits until all required entities are - // present to start simulating and rendering. - // Track which links touched something last frame. Used to prevent wind from gusting on them. CBitVec m_LinksTouchingSomething; int m_nLinksTouchingSomething; @@ -168,7 +177,7 @@ private: float m_flScrollSpeed; int m_RopeFlags; // Combo of ROPE_ flags. - int m_iRopeMaterialModel; // Index of sprite model with the rope's material. + int m_iRopeMaterialModelIndex; // Index of sprite model with the rope's material. CRopePhysics m_RopePhysics; Vector m_LightValues[ROPE_MAX_SEGMENTS]; // light info when the rope is created. @@ -193,7 +202,8 @@ private: CPhysicsDelegate m_PhysicsDelegate; IMaterial *m_pMaterial; - IMaterial *m_pBackMaterial; // Optional translucent background material for the rope to help reduce aliasing. + IMaterial *m_pBackMaterial; // Optional translucent background material for the rope to help reduce aliasing. + int m_TextureHeight; // Texture height, for texture scale calculations. // Instantaneous force @@ -209,9 +219,19 @@ private: Vector m_vColorMod; // Color modulation on all verts? - bool m_bEndPointAttachmentsDirty; Vector m_vCachedEndPointAttachmentPos[2]; QAngle m_vCachedEndPointAttachmentAngle[2]; + + // In network table, can't bit-compress + bool m_bConstrainBetweenEndpoints; // Simulated segment points won't stretch beyond the endpoints + + bool m_bEndPointAttachmentPositionsDirty : 1; + bool m_bEndPointAttachmentAnglesDirty : 1; + bool m_bNewDataThisFrame : 1; // Set to true in OnDataChanged so that we simulate that frame + bool m_bPhysicsInitted : 1; // It waits until all required entities are + // present to start simulating and rendering. + + friend class CRopeManager; }; @@ -229,7 +249,8 @@ public: virtual ~IRopeManager() {} virtual void ResetRenderCache( void ) = 0; virtual void AddToRenderCache( C_RopeKeyframe *pRope ) = 0; - virtual void DrawRenderCache( void ) = 0; + virtual void DrawRenderCache( bool bShadowDepth ) = 0; + virtual void OnRenderStart( void ) = 0; }; IRopeManager *RopeManager(); diff --git a/src/src/cl_dll/c_rumble.cpp b/src/src/game/client/c_rumble.cpp similarity index 93% rename from src/src/cl_dll/c_rumble.cpp rename to src/src/game/client/c_rumble.cpp index d384fd0..3c07945 100644 --- a/src/src/cl_dll/c_rumble.cpp +++ b/src/src/game/client/c_rumble.cpp @@ -6,11 +6,6 @@ // //=============================================================================// #include "cbase.h" -//#ifdef _XBOX -//#include "xbox/xbox_platform.h" -//#include "xbox/xbox_win32stubs.h" -//#include "xbox/xbox_core.h" -//#endif #include "c_rumble.h" #include "rumble_shared.h" #include "inputsystem/iinputsystem.h" @@ -361,10 +356,9 @@ void CRumbleEffects::Init() TerminateWaveform( &m_Waveforms[RUMBLE_RPG_MISSILE], 6 ); // Physcannon open forks - params.Set( 1, 1.0f, true, 0.0f, 0.1f ); + params.Set( 1, 1.0f, false, 0.0f, 0.25f ); GenerateFlatEffect( &m_Waveforms[RUMBLE_PHYSCANNON_OPEN], params ); - params.Set( 6, 1.0f, false, 0.0f, 0.12f ); - GenerateSineWaveEffect( &m_Waveforms[RUMBLE_PHYSCANNON_OPEN], params ); + TerminateWaveform( &m_Waveforms[RUMBLE_PHYSCANNON_OPEN], 4 ); // Physcannon holding something params.Set( 1, 1.0f, true, 0.0f, 0.2f ); @@ -395,6 +389,37 @@ void CRumbleEffects::Init() GenerateFlatEffect( &m_Waveforms[RUMBLE_FLAT_BOTH], params ); params.Set( 1, 1.0f, false, 0.0f, 1.0f ); GenerateFlatEffect( &m_Waveforms[RUMBLE_FLAT_BOTH], params ); + + // Impact from a long fall + params.Set( 1, 1.0f, false, 0.0f, 0.5f ); + GenerateFlatEffect( &m_Waveforms[RUMBLE_FALL_LONG], params ); + params.Set( 1, 1.0f, true, 0.0f, 0.5f ); + GenerateFlatEffect( &m_Waveforms[RUMBLE_FALL_LONG], params ); + TerminateWaveform( &m_Waveforms[RUMBLE_FALL_LONG], 3 ); + + // Impact from a short fall + params.Set( 1, 1.0f, false, 0.0f, 0.3f ); + GenerateFlatEffect( &m_Waveforms[RUMBLE_FALL_SHORT], params ); + params.Set( 1, 1.0f, true, 0.0f, 0.3f ); + GenerateFlatEffect( &m_Waveforms[RUMBLE_FALL_SHORT], params ); + TerminateWaveform( &m_Waveforms[RUMBLE_FALL_SHORT], 2 ); + + // Portalgun left (blue) shot + params.Set( 1, 1.0f, true, 0.0f, 0.3f ); + GenerateFlatEffect( &m_Waveforms[RUMBLE_PORTALGUN_LEFT], params ); + TerminateWaveform( &m_Waveforms[RUMBLE_PORTALGUN_LEFT], 2 ); + + // Portalgun right (red) shot + params.Set( 1, 1.0f, false, 0.0f, 0.3f ); + GenerateFlatEffect( &m_Waveforms[RUMBLE_PORTALGUN_RIGHT], params ); + TerminateWaveform( &m_Waveforms[RUMBLE_PORTALGUN_RIGHT], 2 ); + + // Portal failed to place feedback + params.Set( 12, 1.0f, true, 0.0f, 1.0f ); + GenerateSquareWaveEffect( &m_Waveforms[RUMBLE_PORTAL_PLACEMENT_FAILURE], params ); + params.Set( 12, 1.0f, false, 0.0f, 1.0f ); + GenerateSquareWaveEffect( &m_Waveforms[RUMBLE_PORTAL_PLACEMENT_FAILURE], params ); + TerminateWaveform( &m_Waveforms[RUMBLE_PORTAL_PLACEMENT_FAILURE], 6 ); } //--------------------------------------------------------- @@ -747,10 +772,7 @@ void CRumbleEffects::UpdateEffects( float curtime ) fRightMotor = 0.0f; } - if ( IsXbox() ) - { - inputsystem->SetRumble( fLeftMotor, fRightMotor ); - } + inputsystem->SetRumble( fLeftMotor, fRightMotor ); } //--------------------------------------------------------- diff --git a/src/src/cl_dll/c_rumble.h b/src/src/game/client/c_rumble.h similarity index 100% rename from src/src/cl_dll/c_rumble.h rename to src/src/game/client/c_rumble.h diff --git a/src/src/game/client/c_sceneentity.cpp b/src/src/game/client/c_sceneentity.cpp new file mode 100644 index 0000000..8a349e2 --- /dev/null +++ b/src/src/game/client/c_sceneentity.cpp @@ -0,0 +1,1125 @@ +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "networkstringtable_clientdll.h" +#include "dt_utlvector_recv.h" +#include "choreoevent.h" +#include "choreoactor.h" +#include "choreochannel.h" +#include "choreoscene.h" +#include "filesystem.h" +#include "ichoreoeventcallback.h" +#include "scenefilecache/ISceneFileCache.h" +#include "materialsystem/imaterialsystemhardwareconfig.h" +#include "tier2/tier2.h" +#include "hud_closecaption.h" + +#include "c_sceneentity.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +//----------------------------------------------------------------------------- +// Purpose: Decodes animtime and notes when it changes +// Input : *pStruct - ( C_BaseEntity * ) used to flag animtime is changine +// *pVarData - +// *pIn - +// objectID - +//----------------------------------------------------------------------------- +void RecvProxy_ForcedClientTime( const CRecvProxyData *pData, void *pStruct, void *pOut ) +{ + C_SceneEntity *pScene = reinterpret_cast< C_SceneEntity * >( pStruct ); + *(float *)pOut = pData->m_Value.m_Float; + pScene->OnResetClientTime(); +} + +#if defined( CSceneEntity ) +#undef CSceneEntity +#endif + +IMPLEMENT_CLIENTCLASS_DT(C_SceneEntity, DT_SceneEntity, CSceneEntity) + RecvPropInt(RECVINFO(m_nSceneStringIndex)), + RecvPropBool(RECVINFO(m_bIsPlayingBack)), + RecvPropBool(RECVINFO(m_bPaused)), + RecvPropBool(RECVINFO(m_bMultiplayer)), + RecvPropFloat(RECVINFO(m_flForceClientTime), 0, RecvProxy_ForcedClientTime ), + RecvPropUtlVector( + RECVINFO_UTLVECTOR( m_hActorList ), + MAX_ACTORS_IN_SCENE, + RecvPropEHandle(NULL, 0, 0)), +END_RECV_TABLE() + +C_SceneEntity::C_SceneEntity( void ) +{ + m_pScene = NULL; + m_bMultiplayer = false; + + m_hOwner = NULL; + m_bClientOnly = false; +} + +C_SceneEntity::~C_SceneEntity( void ) +{ + UnloadScene(); +} + +void C_SceneEntity::OnResetClientTime() +{ + m_flCurrentTime = m_flForceClientTime; +} + +char const *C_SceneEntity::GetSceneFileName() +{ + return g_pStringTableClientSideChoreoScenes->GetString( m_nSceneStringIndex ); +} + +ConVar mp_usehwmvcds( "mp_usehwmvcds", "0", NULL, "Enable the use of the hw morph vcd(s). (-1 = never, 1 = always, 0 = based upon GPU)" ); // -1 = never, 0 = if hasfastvertextextures, 1 = always +bool UseHWMorphVCDs() +{ + if ( mp_usehwmvcds.GetInt() == 0 ) + return g_pMaterialSystemHardwareConfig->HasFastVertexTextures(); + return mp_usehwmvcds.GetInt() > 0; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool C_SceneEntity::GetHWMorphSceneFileName( const char *pFilename, char *pHWMFilename ) +{ + // Are we even using hardware morph? + if ( !UseHWMorphVCDs() ) + return false; + + // Multi-player only! + if ( !m_bMultiplayer ) + return false; + + // Do we have a valid filename? + if ( !( pFilename && pFilename[0] ) ) + return false; + + // Check to see if we already have an player/hwm/* filename. + if ( ( V_strstr( pFilename, "/high" ) != NULL ) || ( V_strstr( pFilename, "\\high" ) != NULL ) ) + { + V_strcpy( pHWMFilename, pFilename ); + return true; + } + + // Find the hardware morph scene name and pass that along as well. + char szScene[MAX_PATH]; + V_strcpy( szScene, pFilename ); + + char szSceneHWM[MAX_PATH]; + szSceneHWM[0] = '\0'; + + char *pszToken = strtok( szScene, "/\\" ); + while ( pszToken != NULL ) + { + if ( !V_stricmp( pszToken, "low" ) ) + { + V_strcat( szSceneHWM, "high", sizeof( szSceneHWM ) ); + } + else + { + V_strcat( szSceneHWM, pszToken, sizeof( szSceneHWM ) ); + } + + pszToken = strtok( NULL, "/\\" ); + if ( pszToken != NULL ) + { + V_strcat( szSceneHWM, "\\", sizeof( szSceneHWM ) ); + } + } + + V_strcpy( pHWMFilename, szSceneHWM ); + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_SceneEntity::ResetActorFlexesForScene() +{ + int nActorCount = m_pScene->GetNumActors(); + for( int iActor = 0; iActor < nActorCount; ++iActor ) + { + CChoreoActor *pChoreoActor = m_pScene->GetActor( iActor ); + if ( !pChoreoActor ) + continue; + + C_BaseFlex *pFlexActor = FindNamedActor( pChoreoActor ); + if ( !pFlexActor ) + continue; + + CStudioHdr *pStudioHdr = pFlexActor->GetModelPtr(); + if ( !pStudioHdr ) + continue; + + if ( pStudioHdr->numflexdesc() == 0 ) + continue; + + // Reset the flex weights to their starting position. + LocalFlexController_t iController; + for ( iController = LocalFlexController_t(0); iController < pStudioHdr->numflexcontrollers(); ++iController ) + { + pFlexActor->SetFlexWeight( iController, 0.0f ); + } + + // Reset the prediction interpolation values. + pFlexActor->m_iv_flexWeight.Reset(); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_SceneEntity::StopClientOnlyScene() +{ + if ( m_pScene ) + { + m_pScene->ResetSimulation(); + + if ( m_hOwner.Get() ) + { + m_hOwner->RemoveChoreoScene( m_pScene ); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_SceneEntity::SetupClientOnlyScene( const char *pszFilename, C_BaseFlex *pOwner /* = NULL */, bool bMultiplayer /* = false */ ) +{ + m_bIsPlayingBack = true; + m_bMultiplayer = bMultiplayer; + m_hOwner = pOwner; + m_bClientOnly = true; + + char szFilename[128]; + Assert( V_strlen( pszFilename ) < 128 ); + V_strcpy( szFilename, pszFilename ); + + char szSceneHWM[128]; + if ( GetHWMorphSceneFileName( szFilename, szSceneHWM ) ) + { + V_strcpy( szFilename, szSceneHWM ); + } + + Assert( szFilename && szFilename[ 0 ] ); + if ( szFilename && szFilename[ 0 ] ) + { + LoadSceneFromFile( szFilename ); + Assert( m_pScene ); + + // Should handle gestures and sequences client side. + if ( m_bMultiplayer ) + { + if ( m_pScene ) + { + int types[6]; + types[0] = CChoreoEvent::FLEXANIMATION; + types[1] = CChoreoEvent::EXPRESSION; + types[2] = CChoreoEvent::GESTURE; + types[3] = CChoreoEvent::SEQUENCE; + types[4] = CChoreoEvent::SPEAK; + types[5] = CChoreoEvent::LOOP; + m_pScene->RemoveEventsExceptTypes( types, 6 ); + } + + PrefetchAnimBlocks( m_pScene ); + } + else + { + if ( m_pScene ) + { + int types[ 2 ]; + types[ 0 ] = CChoreoEvent::FLEXANIMATION; + types[ 1 ] = CChoreoEvent::EXPRESSION; + m_pScene->RemoveEventsExceptTypes( types, 2 ); + } + } + + SetNextClientThink( CLIENT_THINK_ALWAYS ); + } + + if ( m_hOwner.Get() ) + { + Assert( m_pScene ); + + if ( m_pScene ) + { + ClearSceneEvents( m_pScene, false ); + + if ( m_bIsPlayingBack ) + { + m_pScene->ResetSimulation(); + m_hOwner->StartChoreoScene( m_pScene ); + } + else + { + m_pScene->ResetSimulation(); + m_hOwner->RemoveChoreoScene( m_pScene ); + } + + // Reset the flex weights when we start a new scene. This is normally done on the player model, but since + // we don't have a player here yet - we need to do this! + ResetActorFlexesForScene(); + } + } + else + { + for( int i = 0; i < m_hActorList.Count() ; ++i ) + { + C_BaseFlex *actor = m_hActorList[ i ].Get(); + if ( !actor ) + continue; + + Assert( m_pScene ); + + if ( m_pScene ) + { + ClearSceneEvents( m_pScene, false ); + + if ( m_bIsPlayingBack ) + { + m_pScene->ResetSimulation(); + actor->StartChoreoScene( m_pScene ); + } + else + { + m_pScene->ResetSimulation(); + actor->RemoveChoreoScene( m_pScene ); + } + } + } + } +} + +void C_SceneEntity::PostDataUpdate( DataUpdateType_t updateType ) +{ + BaseClass::PostDataUpdate( updateType ); + + char const *str = GetSceneFileName(); + char szFilename[MAX_PATH]; + Assert( V_strlen( str ) < MAX_PATH ); + V_strcpy( szFilename, str ); + + char szSceneHWM[MAX_PATH]; + if ( GetHWMorphSceneFileName( szFilename, szSceneHWM ) ) + { + V_strcpy( szFilename, szSceneHWM ); + } + + if ( updateType == DATA_UPDATE_CREATED ) + { + Assert( szFilename && szFilename[ 0 ] ); + if ( szFilename && szFilename[ 0 ] ) + { + LoadSceneFromFile( szFilename ); + + // Kill everything except flex events + Assert( m_pScene ); + + // Should handle gestures and sequences clientside. + if ( m_bMultiplayer ) + { + if ( m_pScene ) + { + int types[6]; + types[0] = CChoreoEvent::FLEXANIMATION; + types[1] = CChoreoEvent::EXPRESSION; + types[2] = CChoreoEvent::GESTURE; + types[3] = CChoreoEvent::SEQUENCE; + types[4] = CChoreoEvent::SPEAK; + types[5] = CChoreoEvent::LOOP; + m_pScene->RemoveEventsExceptTypes( types, 6 ); + } + + PrefetchAnimBlocks( m_pScene ); + } + else + { + if ( m_pScene ) + { + int types[ 2 ]; + types[ 0 ] = CChoreoEvent::FLEXANIMATION; + types[ 1 ] = CChoreoEvent::EXPRESSION; + m_pScene->RemoveEventsExceptTypes( types, 2 ); + } + } + + SetNextClientThink( CLIENT_THINK_ALWAYS ); + } + } + + // Playback state changed... + if ( m_bWasPlaying != m_bIsPlayingBack ) + { + for(int i = 0; i < m_hActorList.Count() ; ++i ) + { + C_BaseFlex *actor = m_hActorList[ i ].Get(); + if ( !actor ) + continue; + + Assert( m_pScene ); + + if ( m_pScene ) + { + ClearSceneEvents( m_pScene, false ); + + if ( m_bIsPlayingBack ) + { + m_pScene->ResetSimulation(); + actor->StartChoreoScene( m_pScene ); + } + else + { + m_pScene->ResetSimulation(); + actor->RemoveChoreoScene( m_pScene ); + } + } + } + } +} + +void C_SceneEntity::PreDataUpdate( DataUpdateType_t updateType ) +{ + BaseClass::PreDataUpdate( updateType ); + + m_bWasPlaying = m_bIsPlayingBack; +} + +//----------------------------------------------------------------------------- +// Purpose: Called every frame that an event is active (Start/EndEvent as also +// called) +// Input : *event - +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +void C_SceneEntity::ProcessEvent( float currenttime, CChoreoScene *scene, CChoreoEvent *event ) +{ + return; +} + + + +//----------------------------------------------------------------------------- +// Purpose: Called for events that are part of a pause condition +// Input : *event - +// Output : Returns true on event completed, false on non-completion. +//----------------------------------------------------------------------------- +bool C_SceneEntity::CheckEvent( float currenttime, CChoreoScene *scene, CChoreoEvent *event ) +{ + return true; +} + +C_BaseFlex *C_SceneEntity::FindNamedActor( CChoreoActor *pChoreoActor ) +{ + if ( !m_pScene ) + return NULL; + + if ( m_hOwner.Get() != NULL ) + { + return m_hOwner.Get(); + } + + int idx = m_pScene->FindActorIndex( pChoreoActor ); + if ( idx < 0 || idx >= m_hActorList.Count() ) + return NULL; + + return m_hActorList[ idx ].Get(); +} + +//----------------------------------------------------------------------------- +// Purpose: All events are leading edge triggered +// Input : currenttime - +// *event - +//----------------------------------------------------------------------------- +void C_SceneEntity::StartEvent( float currenttime, CChoreoScene *scene, CChoreoEvent *event ) +{ + Assert( event ); + + if ( !Q_stricmp( event->GetName(), "NULL" ) ) + { + Scene_Printf( "%s : %8.2f: ignored %s\n", GetSceneFileName(), currenttime, event->GetDescription() ); + return; + } + + + C_BaseFlex *pActor = NULL; + CChoreoActor *actor = event->GetActor(); + if ( actor ) + { + pActor = FindNamedActor( actor ); + if ( NULL == pActor ) + { + // This can occur if we haven't been networked an actor yet... we need to queue it so that we can + // fire off the start event as soon as we have the actor resident on the client. + QueueStartEvent( currenttime, scene, event ); + return; + } + } + + Scene_Printf( "%s : %8.2f: start %s\n", GetSceneFileName(), currenttime, event->GetDescription() ); + + switch ( event->GetType() ) + { + case CChoreoEvent::FLEXANIMATION: + { + if ( pActor ) + { + DispatchStartFlexAnimation( scene, pActor, event ); + } + } + break; + case CChoreoEvent::EXPRESSION: + { + if ( pActor ) + { + DispatchStartExpression( scene, pActor, event ); + } + } + break; + case CChoreoEvent::GESTURE: + { + // Verify data. + Assert( m_bMultiplayer ); + Assert( scene != NULL ); + Assert( event != NULL ); + + if ( pActor ) + { + DispatchStartGesture( scene, pActor, event ); + } + } + break; + case CChoreoEvent::SEQUENCE: + { + // Verify data. + Assert( m_bMultiplayer ); + Assert( scene != NULL ); + Assert( event != NULL ); + + if ( pActor ) + { + DispatchStartSequence( scene, pActor, event ); + } + } + break; + case CChoreoEvent::LOOP: + { + // Verify data. + Assert( m_bMultiplayer ); + Assert( scene != NULL ); + Assert( event != NULL ); + + DispatchProcessLoop( scene, event ); + } + case CChoreoEvent::SPEAK: + { + if ( IsClientOnly() && pActor ) + { + // FIXME: dB hack. soundlevel needs to be moved into inside of wav? + soundlevel_t iSoundlevel = SNDLVL_TALKING; + if ( event->GetParameters2() ) + { + iSoundlevel = (soundlevel_t)atoi( event->GetParameters2() ); + if ( iSoundlevel == SNDLVL_NONE ) + { + iSoundlevel = SNDLVL_TALKING; + } + } + + DispatchStartSpeak( scene, pActor, event, iSoundlevel ); + } + } + break; + default: + break; + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *scene - +// *event - +//----------------------------------------------------------------------------- +void C_SceneEntity::DispatchProcessLoop( CChoreoScene *scene, CChoreoEvent *event ) +{ + Assert( event->GetType() == CChoreoEvent::LOOP ); + + float backtime = (float)atof( event->GetParameters() ); + + bool process = true; + int counter = event->GetLoopCount(); + if ( counter != -1 ) + { + int remaining = event->GetNumLoopsRemaining(); + if ( remaining <= 0 ) + { + process = false; + } + else + { + event->SetNumLoopsRemaining( --remaining ); + } + } + + if ( !process ) + return; + + scene->LoopToTime( backtime ); + SetCurrentTime( backtime, true ); +} + +//----------------------------------------------------------------------------- +// Purpose: Playback sound file that contains phonemes +// Input : *actor - +// *parameters - +//----------------------------------------------------------------------------- +void C_SceneEntity::DispatchStartSpeak( CChoreoScene *scene, C_BaseFlex *actor, CChoreoEvent *event, soundlevel_t iSoundlevel ) +{ + // Emit sound + if ( IsClientOnly() && actor ) + { + CSingleUserRecipientFilter filter( C_BasePlayer::GetLocalPlayer() ); + + float time_in_past = m_flCurrentTime - event->GetStartTime() ; + float soundtime = gpGlobals->curtime - time_in_past; + + EmitSound_t es; + es.m_nChannel = CHAN_VOICE; + es.m_flVolume = 1; + es.m_SoundLevel = iSoundlevel; + es.m_flSoundTime = soundtime; + + // No CC since we do it manually + // FIXME: This will change + es.m_bEmitCloseCaption = false; + es.m_pSoundName = event->GetParameters(); + + EmitSound( filter, actor->entindex(), es ); + actor->AddSceneEvent( scene, event, NULL, IsClientOnly() ); + + // Close captioning only on master token no matter what... + if ( event->GetCloseCaptionType() == CChoreoEvent::CC_MASTER ) + { + char tok[ CChoreoEvent::MAX_CCTOKEN_STRING ]; + bool validtoken = event->GetPlaybackCloseCaptionToken( tok, sizeof( tok ) ); + if ( validtoken ) + { + CRC32_t tokenCRC; + CRC32_Init( &tokenCRC ); + + char lowercase[ 256 ]; + Q_strncpy( lowercase, tok, sizeof( lowercase ) ); + Q_strlower( lowercase ); + + CRC32_ProcessBuffer( &tokenCRC, lowercase, Q_strlen( lowercase ) ); + CRC32_Final( &tokenCRC ); + + float endtime = event->GetLastSlaveEndTime(); + float durationShort = event->GetDuration(); + float durationLong = endtime - event->GetStartTime(); + float duration = max( durationShort, durationLong ); + + CHudCloseCaption *hudCloseCaption = GET_HUDELEMENT( CHudCloseCaption ); + if ( hudCloseCaption ) + { + hudCloseCaption->ProcessCaption( lowercase, duration ); + } + } + + } + } +} + +void C_SceneEntity::DispatchEndSpeak( CChoreoScene *scene, C_BaseFlex *actor, CChoreoEvent *event ) +{ + if ( IsClientOnly() ) + { + actor->RemoveSceneEvent( scene, event, false ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : currenttime - +// *event - +//----------------------------------------------------------------------------- +void C_SceneEntity::EndEvent( float currenttime, CChoreoScene *scene, CChoreoEvent *event ) +{ + Assert( event ); + + if ( !Q_stricmp( event->GetName(), "NULL" ) ) + { + return; + } + + C_BaseFlex *pActor = NULL; + CChoreoActor *actor = event->GetActor(); + if ( actor ) + { + pActor = FindNamedActor( actor ); + } + + Scene_Printf( "%s : %8.2f: finish %s\n", GetSceneFileName(), currenttime, event->GetDescription() ); + + switch ( event->GetType() ) + { + case CChoreoEvent::FLEXANIMATION: + { + if ( pActor ) + { + DispatchEndFlexAnimation( scene, pActor, event ); + } + } + break; + case CChoreoEvent::EXPRESSION: + { + if ( pActor ) + { + DispatchEndExpression( scene, pActor, event ); + } + } + break; + case CChoreoEvent::GESTURE: + { + if ( pActor ) + { + DispatchEndGesture( scene, pActor, event ); + } + } + break; + case CChoreoEvent::SEQUENCE: + { + if ( pActor ) + { + DispatchEndSequence( scene, pActor, event ); + } + } + break; + case CChoreoEvent::SPEAK: + { + if ( IsClientOnly() && pActor ) + { + DispatchEndSpeak( scene, pActor, event ); + } + } + break; + default: + break; + } +} + +//----------------------------------------------------------------------------- +// Binary compiled VCDs get their strings from a pool +//----------------------------------------------------------------------------- +class CChoreoStringPool : public IChoreoStringPool +{ +public: + short FindOrAddString( const char *pString ) + { + // huh?, no compilation at run time, only fetches + Assert( 0 ); + return -1; + } + + bool GetString( short stringId, char *buff, int buffSize ) + { + // fetch from compiled pool + const char *pString = scenefilecache->GetSceneString( stringId ); + if ( !pString ) + { + V_strncpy( buff, "", buffSize ); + return false; + } + V_strncpy( buff, pString, buffSize ); + return true; + } +}; +CChoreoStringPool g_ChoreoStringPool; + +CChoreoScene *C_SceneEntity::LoadScene( const char *filename ) +{ + char loadfile[ 512 ]; + Q_strncpy( loadfile, filename, sizeof( loadfile ) ); + Q_SetExtension( loadfile, ".vcd", sizeof( loadfile ) ); + Q_FixSlashes( loadfile ); + + char *pBuffer = NULL; + size_t bufsize = scenefilecache->GetSceneBufferSize( loadfile ); + if ( bufsize <= 0 ) + return NULL; + + pBuffer = new char[ bufsize ]; + if ( !scenefilecache->GetSceneData( filename, (byte *)pBuffer, bufsize ) ) + { + delete[] pBuffer; + return NULL; + } + + CChoreoScene *pScene; + if ( IsBufferBinaryVCD( pBuffer, bufsize ) ) + { + pScene = new CChoreoScene( this ); + CUtlBuffer buf( pBuffer, bufsize, CUtlBuffer::READ_ONLY ); + if ( !pScene->RestoreFromBinaryBuffer( buf, loadfile, &g_ChoreoStringPool ) ) + { + Warning( "Unable to restore binary scene '%s'\n", loadfile ); + delete pScene; + pScene = NULL; + } + else + { + pScene->SetPrintFunc( Scene_Printf ); + pScene->SetEventCallbackInterface( this ); + } + } + else + { + g_TokenProcessor.SetBuffer( pBuffer ); + pScene = ChoreoLoadScene( loadfile, this, &g_TokenProcessor, Scene_Printf ); + } + + delete[] pBuffer; + return pScene; +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *filename - +//----------------------------------------------------------------------------- +void C_SceneEntity::LoadSceneFromFile( const char *filename ) +{ + UnloadScene(); + m_pScene = LoadScene( filename ); +} + +void C_SceneEntity::ClearSceneEvents( CChoreoScene *scene, bool canceled ) +{ + if ( !m_pScene ) + return; + + Scene_Printf( "%s : %8.2f: clearing events\n", GetSceneFileName(), m_flCurrentTime ); + + int i; + for ( i = 0 ; i < m_pScene->GetNumActors(); i++ ) + { + C_BaseFlex *pActor = FindNamedActor( m_pScene->GetActor( i ) ); + if ( !pActor ) + continue; + + // Clear any existing expressions + pActor->ClearSceneEvents( scene, canceled ); + } + + WipeQueuedEvents(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_SceneEntity::UnloadScene( void ) +{ + WipeQueuedEvents(); + + if ( m_pScene ) + { + ClearSceneEvents( m_pScene, false ); + for ( int i = 0 ; i < m_pScene->GetNumActors(); i++ ) + { + C_BaseFlex *pTestActor = FindNamedActor( m_pScene->GetActor( i ) ); + + if ( !pTestActor ) + continue; + + pTestActor->RemoveChoreoScene( m_pScene ); + } + } + delete m_pScene; + m_pScene = NULL; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *actor - +// *event - +//----------------------------------------------------------------------------- +void C_SceneEntity::DispatchStartFlexAnimation( CChoreoScene *scene, C_BaseFlex *actor, CChoreoEvent *event ) +{ + actor->AddSceneEvent( scene, event, NULL, IsClientOnly() ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *actor - +// *event - +//----------------------------------------------------------------------------- +void C_SceneEntity::DispatchEndFlexAnimation( CChoreoScene *scene, C_BaseFlex *actor, CChoreoEvent *event ) +{ + actor->RemoveSceneEvent( scene, event, false ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *actor - +// *event - +//----------------------------------------------------------------------------- +void C_SceneEntity::DispatchStartExpression( CChoreoScene *scene, C_BaseFlex *actor, CChoreoEvent *event ) +{ + actor->AddSceneEvent( scene, event, NULL, IsClientOnly() ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *actor - +// *event - +//----------------------------------------------------------------------------- +void C_SceneEntity::DispatchEndExpression( CChoreoScene *scene, C_BaseFlex *actor, CChoreoEvent *event ) +{ + actor->RemoveSceneEvent( scene, event, false ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *actor - +// *parameters - +//----------------------------------------------------------------------------- +void C_SceneEntity::DispatchStartGesture( CChoreoScene *scene, C_BaseFlex *actor, CChoreoEvent *event ) +{ + // Ingore null gestures + if ( !Q_stricmp( event->GetName(), "NULL" ) ) + return; + + actor->AddSceneEvent( scene, event, NULL, IsClientOnly() ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *actor - +//----------------------------------------------------------------------------- +void C_SceneEntity::DispatchStartSequence( CChoreoScene *scene, CBaseFlex *actor, CChoreoEvent *event ) +{ + actor->AddSceneEvent( scene, event, NULL, IsClientOnly() ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *actor - +//----------------------------------------------------------------------------- +void C_SceneEntity::DispatchEndSequence( CChoreoScene *scene, CBaseFlex *actor, CChoreoEvent *event ) +{ + actor->RemoveSceneEvent( scene, event, false ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *actor - +// *parameters - +//----------------------------------------------------------------------------- +void C_SceneEntity::DispatchEndGesture( CChoreoScene *scene, C_BaseFlex *actor, CChoreoEvent *event ) +{ + // Ingore null gestures + if ( !Q_stricmp( event->GetName(), "NULL" ) ) + return; + + actor->RemoveSceneEvent( scene, event, false ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_SceneEntity::DoThink( float frametime ) +{ + if ( !m_pScene ) + return; + + if ( !m_bIsPlayingBack ) + { + WipeQueuedEvents(); + return; + } + + CheckQueuedEvents(); + + if ( m_bPaused ) + { + return; + } + + // Msg( "CL: %d, %f for %s\n", gpGlobals->tickcount, m_flCurrentTime, m_pScene->GetFilename() ); + + // Tell scene to go + m_pScene->Think( m_flCurrentTime ); + // Drive simulation time for scene + m_flCurrentTime += gpGlobals->frametime; +} + +void C_SceneEntity::ClientThink() +{ + DoThink( gpGlobals->frametime ); +} + +void C_SceneEntity::CheckQueuedEvents() +{ +// Check for duplicates + CUtlVector< QueuedEvents_t > events; + events = m_QueuedEvents; + m_QueuedEvents.RemoveAll(); + + int c = events.Count(); + for ( int i = 0; i < c; ++i ) + { + const QueuedEvents_t& check = events[ i ]; + + // Retry starting this event + StartEvent( check.starttime, check.scene, check.event ); + } +} + +void C_SceneEntity::WipeQueuedEvents() +{ + m_QueuedEvents.Purge(); +} + +void C_SceneEntity::QueueStartEvent( float starttime, CChoreoScene *scene, CChoreoEvent *event ) +{ + // Check for duplicates + int c = m_QueuedEvents.Count(); + for ( int i = 0; i < c; ++i ) + { + const QueuedEvents_t& check = m_QueuedEvents[ i ]; + if ( check.scene == scene && + check.event == event ) + return; + } + + QueuedEvents_t qe; + qe.scene = scene; + qe.event = event; + qe.starttime = starttime; + m_QueuedEvents.AddToTail( qe ); +} + +//----------------------------------------------------------------------------- +// Purpose: Resets time such that the client version of the .vcd is also updated, if appropriate +// Input : t - +// forceClientSync - unused for now, we may want to reenable this at some point +//----------------------------------------------------------------------------- +void C_SceneEntity::SetCurrentTime( float t, bool forceClientSync ) +{ + m_flCurrentTime = t; + m_flForceClientTime = t; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_SceneEntity::PrefetchAnimBlocks( CChoreoScene *pScene ) +{ + Assert( pScene && m_bMultiplayer ); + if ( !pScene || !m_bMultiplayer ) + return; + + // Build a fast lookup, too + CUtlMap actorMap( 0, 0, DefLessFunc( CChoreoActor* ) ); + + int nSpew = 0; + int nResident = 0; + int nChecked = 0; + + // Iterate events and precache necessary resources + for ( int i = 0; i < pScene->GetNumEvents(); i++ ) + { + CChoreoEvent *pEvent = pScene->GetEvent( i ); + if ( !pEvent ) + continue; + + // load any necessary data + switch ( pEvent->GetType() ) + { + default: + break; + case CChoreoEvent::SEQUENCE: + case CChoreoEvent::GESTURE: + { + CChoreoActor *pActor = pEvent->GetActor(); + if ( pActor ) + { + CBaseFlex *pFlex = NULL; + int idx = actorMap.Find( pActor ); + if ( idx == actorMap.InvalidIndex() ) + { + pFlex = FindNamedActor( pActor ); + idx = actorMap.Insert( pActor, pFlex ); + } + else + { + pFlex = actorMap[ idx ]; + } + + if ( pFlex ) + { + int iSequence = pFlex->LookupSequence( pEvent->GetParameters() ); + if ( iSequence >= 0 ) + { + CStudioHdr *pStudioHdr = pFlex->GetModelPtr(); + if ( pStudioHdr ) + { + // Now look up the animblock + mstudioseqdesc_t &seqdesc = pStudioHdr->pSeqdesc( iSequence ); + for ( int i = 0 ; i < seqdesc.groupsize[ 0 ] ; ++i ) + { + for ( int j = 0; j < seqdesc.groupsize[ 1 ]; ++j ) + { + int iAnimation = seqdesc.anim( i, j ); + int iBaseAnimation = pStudioHdr->iRelativeAnim( iSequence, iAnimation ); + mstudioanimdesc_t &animdesc = pStudioHdr->pAnimdesc( iBaseAnimation ); + + ++nChecked; + + if ( nSpew != 0 ) + { + Msg( "%s checking block %d\n", pStudioHdr->pszName(), animdesc.animblock ); + } + + // Async load the animation + int iFrame = 0; + const mstudioanim_t *panim = animdesc.pAnim( &iFrame ); + if ( panim ) + { + ++nResident; + if ( nSpew > 1 ) + { + Msg( "%s:%s[%i:%i] was resident\n", pStudioHdr->pszName(), animdesc.pszName(), i, j ); + } + } + else + { + if ( nSpew != 0 ) + { + Msg( "%s:%s[%i:%i] async load\n", pStudioHdr->pszName(), animdesc.pszName(), i, j ); + } + } + } + } + } + } + } + } + break; + } + } + } + + if ( !nSpew || nChecked <= 0 ) + return; + + Msg( "%d of %d animations resident\n", nResident, nChecked ); +} \ No newline at end of file diff --git a/src/src/game/client/c_sceneentity.h b/src/src/game/client/c_sceneentity.h new file mode 100644 index 0000000..d2b7bbf --- /dev/null +++ b/src/src/game/client/c_sceneentity.h @@ -0,0 +1,115 @@ +//========= Copyright © 1996-2007, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef C_SCENEENTITY_H +#define C_SCENEENTITY_H +#ifdef _WIN32 +#pragma once +#endif + +#include "ichoreoeventcallback.h" + +class C_SceneEntity : public C_BaseEntity, public IChoreoEventCallback +{ + friend class CChoreoEventCallback; + +public: + DECLARE_CLASS( C_SceneEntity, C_BaseEntity ); + DECLARE_CLIENTCLASS(); + + C_SceneEntity( void ); + ~C_SceneEntity( void ); + + // From IChoreoEventCallback + virtual void StartEvent( float currenttime, CChoreoScene *scene, CChoreoEvent *event ); + virtual void EndEvent( float currenttime, CChoreoScene *scene, CChoreoEvent *event ); + virtual void ProcessEvent( float currenttime, CChoreoScene *scene, CChoreoEvent *event ); + virtual bool CheckEvent( float currenttime, CChoreoScene *scene, CChoreoEvent *event ); + + + virtual void PostDataUpdate( DataUpdateType_t updateType ); + virtual void PreDataUpdate( DataUpdateType_t updateType ); + + virtual void StopClientOnlyScene(); + virtual void SetupClientOnlyScene( const char *pszFilename, C_BaseFlex *pOwner = NULL , bool bMultiplayer = false ); + + virtual void ClientThink(); + + void OnResetClientTime(); + + CHandle< C_BaseFlex > GetActor( int i ){ return ( i < m_hActorList.Count() ) ? m_hActorList[i] : NULL; } + + virtual void DispatchStartSpeak( CChoreoScene *scene, C_BaseFlex *actor, CChoreoEvent *event, soundlevel_t iSoundlevel ); + virtual void DispatchEndSpeak( CChoreoScene *scene, C_BaseFlex *actor, CChoreoEvent *event ); + + bool IsClientOnly( void ){ return m_bClientOnly; } + +private: + + void ResetActorFlexesForScene(); + + // Scene load/unload + CChoreoScene *LoadScene( const char *filename ); + void LoadSceneFromFile( const char *filename ); + void UnloadScene( void ); + void PrefetchAnimBlocks( CChoreoScene *pScene ); + + C_BaseFlex *FindNamedActor( CChoreoActor *pChoreoActor ); + + virtual void DispatchStartFlexAnimation( CChoreoScene *scene, C_BaseFlex *actor, CChoreoEvent *event ); + virtual void DispatchEndFlexAnimation( CChoreoScene *scene, C_BaseFlex *actor, CChoreoEvent *event ); + virtual void DispatchStartExpression( CChoreoScene *scene, C_BaseFlex *actor, CChoreoEvent *event ); + virtual void DispatchEndExpression( CChoreoScene *scene, C_BaseFlex *actor, CChoreoEvent *event ); + virtual void DispatchStartGesture( CChoreoScene *scene, C_BaseFlex *actor, CChoreoEvent *event ); + virtual void DispatchEndGesture( CChoreoScene *scene, C_BaseFlex *actor, CChoreoEvent *event ); + virtual void DispatchStartSequence( CChoreoScene *scene, C_BaseFlex *actor, CChoreoEvent *event ); + virtual void DispatchEndSequence( CChoreoScene *scene, C_BaseFlex *actor, CChoreoEvent *event ); + void DispatchProcessLoop( CChoreoScene *scene, CChoreoEvent *event ); + + char const *GetSceneFileName(); + + void DoThink( float frametime ); + + void ClearSceneEvents( CChoreoScene *scene, bool canceled ); + void SetCurrentTime( float t, bool forceClientSync ); + + bool GetHWMorphSceneFileName( const char *pFilename, char *pHWMFilename ); + +private: + + void CheckQueuedEvents(); + void WipeQueuedEvents(); + void QueueStartEvent( float starttime, CChoreoScene *scene, CChoreoEvent *event ); + + bool m_bIsPlayingBack; + bool m_bPaused; + bool m_bMultiplayer; + float m_flCurrentTime; + float m_flForceClientTime; + int m_nSceneStringIndex; + bool m_bClientOnly; + + CHandle< C_BaseFlex > m_hOwner; // if set, this overrides the m_hActorList in FindNamedActor() + + CUtlVector< CHandle< C_BaseFlex > > m_hActorList; + +private: + bool m_bWasPlaying; + + CChoreoScene *m_pScene; + + struct QueuedEvents_t + { + float starttime; + CChoreoScene *scene; + CChoreoEvent *event; + }; + + CUtlVector< QueuedEvents_t > m_QueuedEvents; +}; + +#endif // C_SCENEENTITY_H diff --git a/src/src/cl_dll/c_shadowcontrol.cpp b/src/src/game/client/c_shadowcontrol.cpp similarity index 100% rename from src/src/cl_dll/c_shadowcontrol.cpp rename to src/src/game/client/c_shadowcontrol.cpp diff --git a/src/src/game/client/c_slideshow_display.cpp b/src/src/game/client/c_slideshow_display.cpp new file mode 100644 index 0000000..f7402e4 --- /dev/null +++ b/src/src/game/client/c_slideshow_display.cpp @@ -0,0 +1,377 @@ +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +#include "cbase.h" +#include "c_slideshow_display.h" +#include "c_te_legacytempents.h" +#include "tempent.h" +#include "engine/IEngineSound.h" +#include "dlight.h" +#include "iefx.h" +#include "soundemittersystem/isoundemittersystembase.h" +#include "filesystem.h" +#include "KeyValues.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + + +#define SLIDESHOW_LIST_BUFFER_MAX 8192 + + +enum SlideshowCycleTypes +{ + SLIDESHOW_CYCLE_RANDOM, + SLIDESHOW_CYCLE_FORWARD, + SLIDESHOW_CYCLE_BACKWARD, + + SLIDESHOW_CYCLE_TOTAL +}; + + +CUtlVector< C_SlideshowDisplay* > g_SlideshowDisplays; + + +IMPLEMENT_CLIENTCLASS_DT(C_SlideshowDisplay, DT_SlideshowDisplay, CSlideshowDisplay) + RecvPropBool( RECVINFO(m_bEnabled) ), + RecvPropString( RECVINFO( m_szDisplayText ) ), + RecvPropString( RECVINFO( m_szSlideshowDirectory ) ), + RecvPropArray3( RECVINFO_ARRAY(m_chCurrentSlideLists), RecvPropInt( RECVINFO(m_chCurrentSlideLists[0]) ) ), + RecvPropFloat( RECVINFO(m_fMinSlideTime) ), + RecvPropFloat( RECVINFO(m_fMaxSlideTime) ), + RecvPropInt( RECVINFO(m_iCycleType) ), + RecvPropBool( RECVINFO(m_bNoListRepeats) ), +END_RECV_TABLE() + + +C_SlideshowDisplay::C_SlideshowDisplay() +{ + g_SlideshowDisplays.AddToTail( this ); +} + +C_SlideshowDisplay::~C_SlideshowDisplay() +{ + g_SlideshowDisplays.FindAndRemove( this ); +} + +void C_SlideshowDisplay::Spawn( void ) +{ + BaseClass::Spawn(); + + m_NextSlideTime = 0; + + SetNextClientThink( CLIENT_THINK_ALWAYS ); +} + +void C_SlideshowDisplay::OnDataChanged( DataUpdateType_t updateType ) +{ + BaseClass::OnDataChanged( updateType ); + + if ( updateType == DATA_UPDATE_CREATED ) + { + BuildSlideShowImagesList(); + } + else if ( updateType == DATA_UPDATE_DATATABLE_CHANGED ) + { + m_iCurrentSlideList = 0; + m_iCurrentSlide = 0; + } +} + +int C_SlideshowDisplay::GetMaterialIndex( int iSlideIndex ) +{ + if ( !m_SlideMaterialLists[ 0 ] ) + return 0; + + return m_SlideMaterialLists[ 0 ]->iSlideMaterials[ iSlideIndex ]; +} + +int C_SlideshowDisplay::NumMaterials( void ) +{ + if ( !m_SlideMaterialLists[ 0 ] ) + return 0; + + return m_SlideMaterialLists[ 0 ]->iSlideMaterials.Count(); +} + +void C_SlideshowDisplay::ClientThink( void ) +{ + BaseClass::ClientThink(); + + if ( !m_bEnabled ) + return; + + // Check if it's time for the next slide + if ( m_NextSlideTime > gpGlobals->curtime ) + return; + + // Set the time to cycle to the next slide + m_NextSlideTime = gpGlobals->curtime + RandomFloat( m_fMinSlideTime, m_fMaxSlideTime ); + + // Get the amount of items to pick from + int iNumCurrentSlideLists; + for ( iNumCurrentSlideLists = 0; iNumCurrentSlideLists < 16; ++iNumCurrentSlideLists ) + { + if ( m_chCurrentSlideLists[ iNumCurrentSlideLists ] == (unsigned char)-1 ) + break; + } + + // Bail if no slide lists are selected + if ( iNumCurrentSlideLists == 0 ) + return; + + // Cycle the list + switch ( m_iCycleType ) + { + case SLIDESHOW_CYCLE_RANDOM: + { + int iOldSlideList = m_iCurrentSlideList; + m_iCurrentSlideList = RandomInt( 0, iNumCurrentSlideLists - 1 ); + + // Prevent repeats if we don't want them + if ( m_bNoListRepeats && iNumCurrentSlideLists > 1 && m_iCurrentSlideList == iOldSlideList ) + { + ++m_iCurrentSlideList; + + if ( m_iCurrentSlideList >= iNumCurrentSlideLists ) + m_iCurrentSlideList = 0; + } + + break; + } + + case SLIDESHOW_CYCLE_FORWARD: + if ( m_iCurrentSlideList >= iNumCurrentSlideLists ) + m_iCurrentSlideList = 0; + break; + + case SLIDESHOW_CYCLE_BACKWARD: + if ( m_iCurrentSlideList < 0 ) + m_iCurrentSlideList = iNumCurrentSlideLists - 1; + break; + } + + SlideMaterialList_t *pSlideMaterialList = m_SlideMaterialLists[ m_chCurrentSlideLists[ m_iCurrentSlideList ] ]; + + // Cycle in the list + switch ( m_iCycleType ) + { + case SLIDESHOW_CYCLE_RANDOM: + m_iCurrentSlide = RandomInt( 0, pSlideMaterialList->iSlideMaterials.Count() - 1 ); + break; + + case SLIDESHOW_CYCLE_FORWARD: + ++m_iCurrentSlide; + if ( m_iCurrentSlide >= pSlideMaterialList->iSlideMaterials.Count() ) + { + ++m_iCurrentSlideList; + if ( m_iCurrentSlideList >= iNumCurrentSlideLists ) + m_iCurrentSlideList = 0; + pSlideMaterialList = m_SlideMaterialLists[ m_chCurrentSlideLists[ m_iCurrentSlideList ] ]; + m_iCurrentSlide = 0; + } + break; + + case SLIDESHOW_CYCLE_BACKWARD: + --m_iCurrentSlide; + if ( m_iCurrentSlide < 0 ) + { + --m_iCurrentSlideList; + if ( m_iCurrentSlideList < 0 ) + m_iCurrentSlideList = iNumCurrentSlideLists - 1; + pSlideMaterialList = m_SlideMaterialLists[ m_chCurrentSlideLists[ m_iCurrentSlideList ] ]; + m_iCurrentSlide = pSlideMaterialList->iSlideMaterials.Count() - 1; + } + break; + } + + // Set the current material to what we've cycled to + m_iCurrentMaterialIndex = pSlideMaterialList->iSlideMaterials[ m_iCurrentSlide ]; + m_iCurrentSlideIndex = pSlideMaterialList->iSlideIndex[ m_iCurrentSlide ]; +} + +void C_SlideshowDisplay::BuildSlideShowImagesList( void ) +{ + FileFindHandle_t matHandle; + char szDirectory[_MAX_PATH]; + char szMatFileName[_MAX_PATH] = {'\0'}; + char szFileBuffer[ SLIDESHOW_LIST_BUFFER_MAX ]; + char *pchCurrentLine = NULL; + + if ( IsX360() ) + { + Q_snprintf( szDirectory, sizeof( szDirectory ), "materials/vgui/%s/slides.txt", m_szSlideshowDirectory ); + + FileHandle_t fh = g_pFullFileSystem->Open( szDirectory, "rt" ); + if ( !fh ) + { + DevWarning( "Couldn't read slideshow image file %s!", szDirectory ); + return; + } + + int iFileSize = min( g_pFullFileSystem->Size( fh ), SLIDESHOW_LIST_BUFFER_MAX ); + + int iBytesRead = g_pFullFileSystem->Read( szFileBuffer, iFileSize, fh ); + g_pFullFileSystem->Close( fh ); + + // Ensure we don't write outside of our buffer + if ( iBytesRead > iFileSize ) + iBytesRead = iFileSize; + szFileBuffer[ iBytesRead ] = '\0'; + + pchCurrentLine = szFileBuffer; + + // Seek to end of first line + char *pchNextLine = pchCurrentLine; + while ( *pchNextLine != '\0' && *pchNextLine != '\n' && *pchNextLine != ' ' ) + ++pchNextLine; + + if ( *pchNextLine != '\0' ) + { + // Mark end of string + *pchNextLine = '\0'; + + // Seek to start of next string + ++pchNextLine; + while ( *pchNextLine != '\0' && ( *pchNextLine == '\n' || *pchNextLine == ' ' ) ) + ++pchNextLine; + } + + Q_strncpy( szMatFileName, pchCurrentLine, sizeof(szMatFileName) ); + pchCurrentLine = pchNextLine; + } + else + { + Q_snprintf( szDirectory, sizeof( szDirectory ), "materials/vgui/%s/*.vmt", m_szSlideshowDirectory ); + const char *pMatFileName = g_pFullFileSystem->FindFirst( szDirectory, &matHandle ); + + if ( pMatFileName ) + Q_strncpy( szMatFileName, pMatFileName, sizeof(szMatFileName) ); + } + + int iSlideIndex = 0; + + while ( szMatFileName[ 0 ] ) + { + char szFileName[_MAX_PATH]; + Q_snprintf( szFileName, sizeof( szFileName ), "vgui/%s/%s", m_szSlideshowDirectory, szMatFileName ); + szFileName[ Q_strlen( szFileName ) - 4 ] = '\0'; + + int iMatIndex = ::GetMaterialIndex( szFileName ); + + // Get material keywords + char szFullFileName[_MAX_PATH]; + Q_snprintf( szFullFileName, sizeof( szFullFileName ), "materials/vgui/%s/%s", m_szSlideshowDirectory, szMatFileName ); + + KeyValues *pMaterialKeys = new KeyValues( "material" ); + bool bLoaded = pMaterialKeys->LoadFromFile( g_pFullFileSystem, szFullFileName, NULL ); + + if ( bLoaded ) + { + char szKeywords[ 256 ]; + Q_strcpy( szKeywords, pMaterialKeys->GetString( "%keywords", "" ) ); + + char *pchKeyword = szKeywords; + + while ( pchKeyword[ 0 ] != '\0' ) + { + char *pNextKeyword = pchKeyword; + + // Skip commas and spaces + while ( pNextKeyword[ 0 ] != '\0' && pNextKeyword[ 0 ] != ',' ) + ++pNextKeyword; + + if ( pNextKeyword[ 0 ] != '\0' ) + { + pNextKeyword[ 0 ] = '\0'; + ++pNextKeyword; + + while ( pNextKeyword[ 0 ] != '\0' && ( pNextKeyword[ 0 ] == ',' || pNextKeyword[ 0 ] == ' ' ) ) + ++pNextKeyword; + } + + // Find the list with the current keyword + int iList; + for ( iList = 0; iList < m_SlideMaterialLists.Count(); ++iList ) + { + if ( Q_strcmp( m_SlideMaterialLists[ iList ]->szSlideKeyword, pchKeyword ) == 0 ) + break; + } + + if ( iList >= m_SlideMaterialLists.Count() ) + { + // Couldn't find the list, so create it + iList = m_SlideMaterialLists.AddToTail( new SlideMaterialList_t ); + Q_strcpy( m_SlideMaterialLists[ iList ]->szSlideKeyword, pchKeyword ); + } + + // Add material index to this list + m_SlideMaterialLists[ iList ]->iSlideMaterials.AddToTail( iMatIndex ); + m_SlideMaterialLists[ iList ]->iSlideIndex.AddToTail( iSlideIndex ); + + pchKeyword = pNextKeyword; + } + } + + // Find the generic list + int iList; + for ( iList = 0; iList < m_SlideMaterialLists.Count(); ++iList ) + { + if ( Q_strcmp( m_SlideMaterialLists[ iList ]->szSlideKeyword, "" ) == 0 ) + break; + } + + if ( iList >= m_SlideMaterialLists.Count() ) + { + // Couldn't find the generic list, so create it + iList = m_SlideMaterialLists.AddToHead( new SlideMaterialList_t ); + Q_strcpy( m_SlideMaterialLists[ iList ]->szSlideKeyword, "" ); + } + + // Add material index to this list + m_SlideMaterialLists[ iList ]->iSlideMaterials.AddToTail( iMatIndex ); + m_SlideMaterialLists[ iList ]->iSlideIndex.AddToTail( iSlideIndex ); + + if ( IsX360() ) + { + // Seek to end of first line + char *pchNextLine = pchCurrentLine; + while ( *pchNextLine != '\0' && *pchNextLine != '\n' && *pchNextLine != ' ' ) + ++pchNextLine; + + if ( *pchNextLine != '\0' ) + { + // Mark end of string + *pchNextLine = '\0'; + + // Seek to start of next string + ++pchNextLine; + while ( *pchNextLine != '\0' && ( *pchNextLine == '\n' || *pchNextLine == ' ' ) ) + ++pchNextLine; + } + + Q_strncpy( szMatFileName, pchCurrentLine, sizeof(szMatFileName) ); + pchCurrentLine = pchNextLine; + } + else + { + const char *pMatFileName = g_pFullFileSystem->FindNext( matHandle ); + + if ( pMatFileName ) + Q_strncpy( szMatFileName, pMatFileName, sizeof(szMatFileName) ); + else + szMatFileName[ 0 ] = '\0'; + } + + ++iSlideIndex; + } + + if ( !IsX360() ) + { + g_pFullFileSystem->FindClose( matHandle ); + } +} \ No newline at end of file diff --git a/src/src/game/client/c_slideshow_display.h b/src/src/game/client/c_slideshow_display.h new file mode 100644 index 0000000..059ca44 --- /dev/null +++ b/src/src/game/client/c_slideshow_display.h @@ -0,0 +1,76 @@ +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +#ifndef C_SLIDESHOW_DISPLAY_H +#define C_SLIDESHOW_DISPLAY_H + +#include "cbase.h" +#include "utlvector.h" + + +struct SlideMaterialList_t +{ + char szSlideKeyword[64]; + CUtlVector iSlideMaterials; + CUtlVector iSlideIndex; +}; + + +class C_SlideshowDisplay : public C_BaseEntity +{ +public: + DECLARE_CLASS( C_SlideshowDisplay, CBaseEntity ); + DECLARE_CLIENTCLASS(); + + C_SlideshowDisplay(); + virtual ~C_SlideshowDisplay(); + + void Spawn( void ); + + virtual void OnDataChanged( DataUpdateType_t updateType ); + + void ClientThink( void ); + + bool IsEnabled( void ) { return m_bEnabled; } + + void GetDisplayText( char *pchText ) { Q_strcpy( pchText, m_szDisplayText ); } + int CurrentMaterialIndex( void ) { return m_iCurrentMaterialIndex; } + int GetMaterialIndex( int iSlideIndex ); + int NumMaterials( void ); + int CurrentSlideIndex( void ) { return m_iCurrentSlideIndex; } + +private: + + void BuildSlideShowImagesList( void ); + +private: + + bool m_bEnabled; + + char m_szDisplayText[ 128 ]; + + char m_szSlideshowDirectory[ 128 ]; + + CUtlVector m_SlideMaterialLists; + unsigned char m_chCurrentSlideLists[ 16 ]; + int m_iCurrentMaterialIndex; + int m_iCurrentSlideIndex; + + float m_fMinSlideTime; + float m_fMaxSlideTime; + + float m_NextSlideTime; + + int m_iCycleType; + bool m_bNoListRepeats; + int m_iCurrentSlideList; + int m_iCurrentSlide; +}; + +extern CUtlVector< C_SlideshowDisplay* > g_SlideshowDisplays; + +#endif //C_SLIDESHOW_STATS_DISPLAY_H \ No newline at end of file diff --git a/src/src/cl_dll/c_smoke_trail.cpp b/src/src/game/client/c_smoke_trail.cpp similarity index 75% rename from src/src/cl_dll/c_smoke_trail.cpp rename to src/src/game/client/c_smoke_trail.cpp index 23cb913..16ef392 100644 --- a/src/src/cl_dll/c_smoke_trail.cpp +++ b/src/src/game/client/c_smoke_trail.cpp @@ -16,6 +16,7 @@ #include "tier1/keyvalues.h" #include "toolframework_client.h" #include "view.h" +#include "ClientEffectPrecacheSystem.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -173,7 +174,7 @@ C_SmokeTrail::~C_SmokeTrail() { if ( ToolsEnabled() && clienttools->IsInRecordingMode() && m_pSmokeEmitter.IsValid() && m_pSmokeEmitter->GetToolParticleEffectId() != TOOLPARTICLESYSTEMID_INVALID ) { - KeyValues *msg = new KeyValues( "ParticleSystem_ActivateEmitter" ); + KeyValues *msg = new KeyValues( "OldParticleSystem_ActivateEmitter" ); msg->SetInt( "id", m_pSmokeEmitter->GetToolParticleEffectId() ); msg->SetInt( "emitter", 0 ); msg->SetInt( "active", false ); @@ -261,8 +262,8 @@ void C_SmokeTrail::Start( CParticleMgr *pParticleMgr, IPrototypeArgAccess *pArgs m_pSmokeEmitter->SetSortOrigin( GetAbsOrigin() ); m_pSmokeEmitter->SetNearClip( 64.0f, 128.0f ); - m_MaterialHandle[0] = m_pSmokeEmitter->GetPMaterial( "particle/particle_smokegrenade" ); - m_MaterialHandle[1] = m_pSmokeEmitter->GetPMaterial( "particle/particle_noisesphere" ); + m_MaterialHandle[0] = g_Mat_DustPuff[0]; + m_MaterialHandle[1] = g_Mat_DustPuff[1]; m_ParticleSpawn.Init( m_SpawnRate ); } @@ -315,6 +316,8 @@ void C_SmokeTrail::Update( float fTimeDelta ) pParticle->m_vecVelocity.Random( -1.0f, 1.0f ); pParticle->m_vecVelocity *= random->RandomFloat( m_MinSpeed, m_MaxSpeed ); + + pParticle->m_vecVelocity = pParticle->m_vecVelocity + GetAbsVelocity(); float flDirectedVel = random->RandomFloat( m_MinDirectedSpeed, m_MaxDirectedSpeed ); VectorMA( pParticle->m_vecVelocity, flDirectedVel, vecForward, pParticle->m_vecVelocity ); @@ -393,7 +396,7 @@ void C_SmokeTrail::CleanupToolRecordingState( KeyValues *msg ) { int nId = m_pSmokeEmitter->AllocateToolParticleEffectId(); - KeyValues *msg = new KeyValues( "ParticleSystem_Create" ); + KeyValues *msg = new KeyValues( "OldParticleSystem_Create" ); msg->SetString( "name", "C_SmokeTrail" ); msg->SetInt( "id", nId ); msg->SetFloat( "time", gpGlobals->curtime ); @@ -488,7 +491,7 @@ void C_SmokeTrail::CleanupToolRecordingState( KeyValues *msg ) } else { - KeyValues *msg = new KeyValues( "ParticleSystem_ActivateEmitter" ); + KeyValues *msg = new KeyValues( "OldParticleSystem_ActivateEmitter" ); msg->SetInt( "id", m_pSmokeEmitter->GetToolParticleEffectId() ); msg->SetInt( "emitter", 0 ); msg->SetInt( "active", bEmitterActive ); @@ -636,8 +639,8 @@ void C_RocketTrail::Start( CParticleMgr *pParticleMgr, IPrototypeArgAccess *pArg m_pRocketEmitter->SetSortOrigin( GetAbsOrigin() ); m_pRocketEmitter->SetNearClip( 64.0f, 128.0f ); - m_MaterialHandle[0] = m_pRocketEmitter->GetPMaterial( "particle/particle_smokegrenade" ); - m_MaterialHandle[1] = m_pRocketEmitter->GetPMaterial( "particle/particle_noisesphere" ); + m_MaterialHandle[0] = g_Mat_DustPuff[0]; + m_MaterialHandle[1] = g_Mat_DustPuff[1]; m_ParticleSpawn.Init( m_SpawnRate ); @@ -1014,7 +1017,7 @@ void C_SporeExplosion::AddParticles( void ) //Add smokey bits offset.Random( -(m_flSpawnRadius * 0.5), (m_flSpawnRadius * 0.5) ); - sParticle = (SimpleParticle *) m_pSporeEffect->AddParticle( sizeof(SimpleParticle), m_pSporeEffect->GetPMaterial( "particle/particle_noisesphere"), GetAbsOrigin()+offset ); + sParticle = (SimpleParticle *) m_pSporeEffect->AddParticle( sizeof(SimpleParticle), g_Mat_DustPuff[1], GetAbsOrigin()+offset ); if ( sParticle == NULL ) return; @@ -1265,7 +1268,7 @@ void C_SporeTrail::Start( CParticleMgr *pParticleMgr, IPrototypeArgAccess *pArgs if( pParticleMgr->AddEffect( &m_ParticleEffect, this ) == false ) return; - m_hMaterial = pParticleMgr->GetPMaterial( "particle/particle_noisesphere" ); + m_hMaterial = g_Mat_DustPuff[1]; m_pParticleMgr = pParticleMgr; m_teParticleSpawn.Init( 64 ); } @@ -1444,13 +1447,9 @@ void C_FireTrail::Start( CParticleMgr *pParticleMgr, IPrototypeArgAccess *pArgs m_pTrailEmitter->SetSortOrigin( GetAbsOrigin() ); // Setup our materials - m_hMaterial[FTRAIL_SMOKE1] = m_pTrailEmitter->GetPMaterial( "particle/particle_smokegrenade" ); - m_hMaterial[FTRAIL_SMOKE2] = m_pTrailEmitter->GetPMaterial( "particle/particle_noisesphere" ); + m_hMaterial[FTRAIL_SMOKE1] = g_Mat_DustPuff[0]; + m_hMaterial[FTRAIL_SMOKE2] = g_Mat_DustPuff[1]; - m_hMaterial[FTRAIL_EMBER1] = m_pTrailEmitter->GetPMaterial( "effects/fire_embers1" ); - m_hMaterial[FTRAIL_EMBER2] = m_pTrailEmitter->GetPMaterial( "effects/fire_embers2" ); - m_hMaterial[FTRAIL_EMBER3] = m_pTrailEmitter->GetPMaterial( "effects/fire_embers3" ); - m_hMaterial[FTRAIL_FLAME1] = m_pTrailEmitter->GetPMaterial( "sprites/flamelet1" ); m_hMaterial[FTRAIL_FLAME2] = m_pTrailEmitter->GetPMaterial( "sprites/flamelet2" ); m_hMaterial[FTRAIL_FLAME3] = m_pTrailEmitter->GetPMaterial( "sprites/flamelet3" ); @@ -1581,3 +1580,432 @@ void C_FireTrail::Update( float fTimeDelta ) // Save off this position m_vecLastPosition = GetAbsOrigin(); } + +//----------------------------------------------------------------------------- +// Purpose: High drag, non color changing particle +//----------------------------------------------------------------------------- + + +class CDustFollower : public CSimpleEmitter +{ +public: + + CDustFollower( const char *pDebugName ) : CSimpleEmitter( pDebugName ) {} + + //Create + static CDustFollower *Create( const char *pDebugName ) + { + return new CDustFollower( pDebugName ); + } + + //Alpha + virtual float UpdateAlpha( const SimpleParticle *pParticle ) + { + return ( ((float)pParticle->m_uchStartAlpha/255.0f) * sin( M_PI * (pParticle->m_flLifetime / pParticle->m_flDieTime) ) ); + } + + virtual void UpdateVelocity( SimpleParticle *pParticle, float timeDelta ) + { + pParticle->m_vecVelocity = pParticle->m_vecVelocity * ExponentialDecay( 0.3, timeDelta ); + } + + //Roll + virtual float UpdateRoll( SimpleParticle *pParticle, float timeDelta ) + { + pParticle->m_flRoll += pParticle->m_flRollDelta * timeDelta; + + pParticle->m_flRollDelta *= ExponentialDecay( 0.5, timeDelta ); + + return pParticle->m_flRoll; + } + +private: + CDustFollower( const CDustFollower & ); +}; + + +// Datatable.. this can have all the smoketrail parameters when we need it to. +IMPLEMENT_CLIENTCLASS_DT(C_DustTrail, DT_DustTrail, DustTrail) + RecvPropFloat(RECVINFO(m_SpawnRate)), + RecvPropVector(RECVINFO(m_Color)), + RecvPropFloat(RECVINFO(m_ParticleLifetime)), + RecvPropFloat(RECVINFO(m_StopEmitTime)), + RecvPropFloat(RECVINFO(m_MinSpeed)), + RecvPropFloat(RECVINFO(m_MaxSpeed)), + RecvPropFloat(RECVINFO(m_MinDirectedSpeed)), + RecvPropFloat(RECVINFO(m_MaxDirectedSpeed)), + RecvPropFloat(RECVINFO(m_StartSize)), + RecvPropFloat(RECVINFO(m_EndSize)), + RecvPropFloat(RECVINFO(m_SpawnRadius)), + RecvPropInt(RECVINFO(m_bEmit)), + RecvPropFloat(RECVINFO(m_Opacity)), +END_RECV_TABLE() + + +// ------------------------------------------------------------------------- // +// ParticleMovieExplosion +// ------------------------------------------------------------------------- // +C_DustTrail::C_DustTrail() +{ + for (int i = 0; i < DUSTTRAIL_MATERIALS; i++) + { + m_MaterialHandle[i] = NULL; + } + + m_SpawnRate = 10; + m_ParticleSpawn.Init(10); + m_Color.Init(0.5, 0.5, 0.5); + m_ParticleLifetime = 5; + m_StartEmitTime = gpGlobals->curtime; + m_StopEmitTime = 0; // No end time + m_MinSpeed = 2; + m_MaxSpeed = 4; + m_MinDirectedSpeed = m_MaxDirectedSpeed = 0; + m_StartSize = 35; + m_EndSize = 55; + m_SpawnRadius = 2; + m_VelocityOffset.Init(); + m_Opacity = 0.5f; + + m_bEmit = true; + + m_pDustEmitter = NULL; + m_pParticleMgr = NULL; +} + +C_DustTrail::~C_DustTrail() +{ + if ( ToolsEnabled() && clienttools->IsInRecordingMode() && m_pDustEmitter.IsValid() && m_pDustEmitter->GetToolParticleEffectId() != TOOLPARTICLESYSTEMID_INVALID ) + { + KeyValues *msg = new KeyValues( "OldParticleSystem_ActivateEmitter" ); + msg->SetInt( "id", m_pDustEmitter->GetToolParticleEffectId() ); + msg->SetInt( "emitter", 0 ); + msg->SetInt( "active", false ); + msg->SetFloat( "time", gpGlobals->curtime ); + ToolFramework_PostToolMessage( HTOOLHANDLE_INVALID, msg ); + msg->deleteThis(); + } + + if ( m_pParticleMgr ) + { + m_pParticleMgr->RemoveEffect( &m_ParticleEffect ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : bEmit - +//----------------------------------------------------------------------------- +void C_DustTrail::SetEmit(bool bEmit) +{ + m_bEmit = bEmit; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : rate - +//----------------------------------------------------------------------------- +void C_DustTrail::SetSpawnRate(float rate) +{ + m_SpawnRate = rate; + m_ParticleSpawn.Init(rate); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : bnewentity - +//----------------------------------------------------------------------------- +void C_DustTrail::OnDataChanged(DataUpdateType_t updateType) +{ + C_BaseEntity::OnDataChanged(updateType); + + if ( updateType == DATA_UPDATE_CREATED ) + { + Start( ParticleMgr(), NULL ); + } +} + + +// FIXME: These all have to be moved out of this old system and into the new to leverage art assets! +CLIENTEFFECT_REGISTER_BEGIN( PrecacheEffectDusttrail ) +CLIENTEFFECT_MATERIAL( "particle/smokesprites_0001" ) +/* +CLIENTEFFECT_MATERIAL( "particle/smokesprites_0002" ) +CLIENTEFFECT_MATERIAL( "particle/smokesprites_0003" ) +CLIENTEFFECT_MATERIAL( "particle/smokesprites_0004" ) +CLIENTEFFECT_MATERIAL( "particle/smokesprites_0005" ) +CLIENTEFFECT_MATERIAL( "particle/smokesprites_0006" ) +CLIENTEFFECT_MATERIAL( "particle/smokesprites_0007" ) +CLIENTEFFECT_MATERIAL( "particle/smokesprites_0008" ) +CLIENTEFFECT_MATERIAL( "particle/smokesprites_0009" ) +CLIENTEFFECT_MATERIAL( "particle/smokesprites_0010" ) +CLIENTEFFECT_MATERIAL( "particle/smokesprites_0011" ) +CLIENTEFFECT_MATERIAL( "particle/smokesprites_0012" ) +CLIENTEFFECT_MATERIAL( "particle/smokesprites_0013" ) +CLIENTEFFECT_MATERIAL( "particle/smokesprites_0014" ) +CLIENTEFFECT_MATERIAL( "particle/smokesprites_0015" ) +CLIENTEFFECT_MATERIAL( "particle/smokesprites_0016" ) +*/ +CLIENTEFFECT_REGISTER_END() + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *pParticleMgr - +// *pArgs - +//----------------------------------------------------------------------------- +void C_DustTrail::Start( CParticleMgr *pParticleMgr, IPrototypeArgAccess *pArgs ) +{ + if(!pParticleMgr->AddEffect( &m_ParticleEffect, this )) + return; + + m_pParticleMgr = pParticleMgr; + m_pDustEmitter = CDustFollower::Create("DustTrail"); + + if ( !m_pDustEmitter ) + { + Assert( false ); + return; + } + + m_pDustEmitter->SetSortOrigin( GetAbsOrigin() ); + m_pDustEmitter->SetNearClip( 64.0f, 128.0f ); + + for (int i = 0; i < DUSTTRAIL_MATERIALS; i++) + { + //char name[256]; + //Q_snprintf( name, sizeof( name ), "particle/smokesprites_%04d", i + 1 ); + m_MaterialHandle[i] = m_pDustEmitter->GetPMaterial( "particle/smokesprites_0001" ); + } + + m_ParticleSpawn.Init( m_SpawnRate ); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : fTimeDelta - +//----------------------------------------------------------------------------- +void C_DustTrail::Update( float fTimeDelta ) +{ + if ( !m_pDustEmitter ) + return; + + Vector offsetColor; + + // Add new particles + if ( !m_bEmit ) + return; + + if ( ( m_StopEmitTime != 0 ) && ( m_StopEmitTime <= gpGlobals->curtime ) ) + return; + + float tempDelta = fTimeDelta; + + SimpleParticle *pParticle; + Vector offset; + + Vector vecOrigin; + VectorMA( GetAbsOrigin(), -fTimeDelta, GetAbsVelocity(), vecOrigin ); + + Vector vecForward; + GetVectors( &vecForward, NULL, NULL ); + + while( m_ParticleSpawn.NextEvent( tempDelta ) ) + { + float fldt = fTimeDelta - tempDelta; + + offset.Random( -m_SpawnRadius, m_SpawnRadius ); + offset += vecOrigin; + VectorMA( offset, fldt, GetAbsVelocity(), offset ); + + //if ( random->RandomFloat( 0.f, 5.0f ) > GetAbsVelocity().Length()) + // continue; + + pParticle = (SimpleParticle *) m_pDustEmitter->AddParticle( sizeof( SimpleParticle ), m_MaterialHandle[random->RandomInt(0,0)], offset ); // FIXME: the other sprites look bad + + if ( pParticle == NULL ) + continue; + + pParticle->m_flLifetime = 0.0f; + pParticle->m_flDieTime = m_ParticleLifetime; + + pParticle->m_vecVelocity.Random( -1.0f, 1.0f ); + pParticle->m_vecVelocity *= random->RandomFloat( m_MinSpeed, m_MaxSpeed ); + + pParticle->m_vecVelocity = pParticle->m_vecVelocity + GetAbsVelocity(); + + float flDirectedVel = random->RandomFloat( m_MinDirectedSpeed, m_MaxDirectedSpeed ); + VectorMA( pParticle->m_vecVelocity, flDirectedVel, vecForward, pParticle->m_vecVelocity ); + + offsetColor = m_Color; + float flMaxVal = max( m_Color[0], m_Color[1] ); + if ( flMaxVal < m_Color[2] ) + { + flMaxVal = m_Color[2]; + } + offsetColor /= flMaxVal; + + offsetColor *= random->RandomFloat( -0.2f, 0.2f ); + offsetColor += m_Color; + + offsetColor[0] = clamp( offsetColor[0], 0.0f, 1.0f ); + offsetColor[1] = clamp( offsetColor[1], 0.0f, 1.0f ); + offsetColor[2] = clamp( offsetColor[2], 0.0f, 1.0f ); + + pParticle->m_uchColor[0] = offsetColor[0]*255.0f; + pParticle->m_uchColor[1] = offsetColor[1]*255.0f; + pParticle->m_uchColor[2] = offsetColor[2]*255.0f; + + pParticle->m_uchStartSize = m_StartSize; + pParticle->m_uchEndSize = m_EndSize; + + float alpha = random->RandomFloat( m_Opacity*0.75f, m_Opacity*1.25f ); + alpha = clamp( alpha, 0.0f, 1.0f ); + + if ( m_StopEmitTime != 0 && m_StopEmitTime > m_StartEmitTime ) + { + alpha *= sqrt( (m_StopEmitTime - gpGlobals->curtime) /(m_StopEmitTime - m_StartEmitTime) ); + } + + pParticle->m_uchStartAlpha = alpha * 255; + pParticle->m_uchEndAlpha = 0; + + pParticle->m_flRoll = random->RandomInt( 0, 360 ); + pParticle->m_flRollDelta = random->RandomFloat( -1.0f, 1.0f ); + } +} + + +void C_DustTrail::RenderParticles( CParticleRenderIterator *pIterator ) +{ +} + + +void C_DustTrail::SimulateParticles( CParticleSimulateIterator *pIterator ) +{ +} + + +//----------------------------------------------------------------------------- +// This is called after sending this entity's recording state +//----------------------------------------------------------------------------- + +void C_DustTrail::CleanupToolRecordingState( KeyValues *msg ) +{ + if ( !ToolsEnabled() ) + return; + + BaseClass::CleanupToolRecordingState( msg ); + + // Generally, this is used to allow the entity to clean up + // allocated state it put into the message, but here we're going + // to use it to send particle system messages because we + // know the grenade has been recorded at this point + if ( !clienttools->IsInRecordingMode() || !m_pDustEmitter.IsValid() ) + return; + + // For now, we can't record Dusttrails that don't have a moveparent + C_BaseEntity *pEnt = GetMoveParent(); + if ( !pEnt ) + return; + + bool bEmitterActive = m_bEmit && ( ( m_StopEmitTime == 0 ) || ( m_StopEmitTime > gpGlobals->curtime ) ); + + // NOTE: Particle system destruction message will be sent by the particle effect itself. + if ( m_pDustEmitter->GetToolParticleEffectId() == TOOLPARTICLESYSTEMID_INVALID ) + { + int nId = m_pDustEmitter->AllocateToolParticleEffectId(); + + KeyValues *msg = new KeyValues( "OldParticleSystem_Create" ); + msg->SetString( "name", "C_DustTrail" ); + msg->SetInt( "id", nId ); + msg->SetFloat( "time", gpGlobals->curtime ); + + KeyValues *pEmitter = msg->FindKey( "DmeSpriteEmitter", true ); + pEmitter->SetString( "material", "particle/smokesprites_0001" ); + pEmitter->SetInt( "count", m_SpawnRate ); // particles per second, when duration is < 0 + pEmitter->SetFloat( "duration", -1 ); // FIXME + pEmitter->SetInt( "active", bEmitterActive ); + + KeyValues *pInitializers = pEmitter->FindKey( "initializers", true ); + + // FIXME: Until we can interpolate ent logs during emission, this can't work + KeyValues *pPosition = pInitializers->FindKey( "DmePositionPointToEntityInitializer", true ); + pPosition->SetPtr( "entindex", (void*)pEnt->entindex() ); + pPosition->SetInt( "attachmentIndex", GetParentAttachment() ); + pPosition->SetFloat( "randomDist", m_SpawnRadius ); + pPosition->SetFloat( "startx", pEnt->GetAbsOrigin().x ); + pPosition->SetFloat( "starty", pEnt->GetAbsOrigin().y ); + pPosition->SetFloat( "startz", pEnt->GetAbsOrigin().z ); + + KeyValues *pVelocity = pInitializers->FindKey( "DmeDecayVelocityInitializer", true ); + pVelocity->SetFloat( "velocityX", pEnt->GetAbsVelocity().x ); + pVelocity->SetFloat( "velocityY", pEnt->GetAbsVelocity().y ); + pVelocity->SetFloat( "velocityZ", pEnt->GetAbsVelocity().z ); + pVelocity->SetFloat( "decayto", 0.5 ); + pVelocity->SetFloat( "decaytime", 0.3 ); + + KeyValues *pLifetime = pInitializers->FindKey( "DmeRandomLifetimeInitializer", true ); + pLifetime->SetFloat( "minLifetime", m_ParticleLifetime ); + pLifetime->SetFloat( "maxLifetime", m_ParticleLifetime ); + + KeyValues *pRoll = pInitializers->FindKey( "DmeRandomRollInitializer", true ); + pRoll->SetFloat( "minRoll", 0.0f ); + pRoll->SetFloat( "maxRoll", 360.0f ); + + KeyValues *pRollSpeed = pInitializers->FindKey( "DmeRandomRollSpeedInitializer", true ); + pRollSpeed->SetFloat( "minRollSpeed", -1.0f ); + pRollSpeed->SetFloat( "maxRollSpeed", 1.0f ); + + KeyValues *pColor = pInitializers->FindKey( "DmeRandomValueColorInitializer", true ); + Color c( + clamp( m_Color.x * 255.0f, 0, 255 ), + clamp( m_Color.y * 255.0f, 0, 255 ), + clamp( m_Color.z * 255.0f, 0, 255 ), 255 ); + pColor->SetColor( "startColor", c ); + pColor->SetFloat( "minStartValueDelta", 0.0f ); + pColor->SetFloat( "maxStartValueDelta", 0.0f ); + pColor->SetColor( "endColor", c ); + + KeyValues *pAlpha = pInitializers->FindKey( "DmeRandomAlphaInitializer", true ); + int nMinAlpha = 255 * m_Opacity * 0.75f; + int nMaxAlpha = 255 * m_Opacity * 1.25f; + pAlpha->SetInt( "minStartAlpha", clamp( nMinAlpha, 0, 255 ) ); + pAlpha->SetInt( "maxStartAlpha", clamp( nMaxAlpha, 0, 255 ) ); + pAlpha->SetInt( "minEndAlpha", clamp( nMinAlpha, 0, 255 ) ); + pAlpha->SetInt( "maxEndAlpha", clamp( nMaxAlpha, 0, 255 ) ); + + KeyValues *pSize = pInitializers->FindKey( "DmeRandomSizeInitializer", true ); + pSize->SetFloat( "minStartSize", m_StartSize ); + pSize->SetFloat( "maxStartSize", m_StartSize ); + pSize->SetFloat( "minEndSize", m_EndSize ); + pSize->SetFloat( "maxEndSize", m_EndSize ); + + KeyValues *pUpdaters = pEmitter->FindKey( "updaters", true ); + pUpdaters->FindKey( "DmePositionVelocityDecayUpdater", true ); + pUpdaters->FindKey( "DmeRollUpdater", true ); + + KeyValues *pRollSpeedUpdater = pUpdaters->FindKey( "DmeRollSpeedAttenuateUpdater", true ); + pRollSpeedUpdater->SetFloat( "attenuation", 1.0f - 8.0f / 30.0f ); + pRollSpeedUpdater->SetFloat( "attenuationTme", 1.0f / 30.0f ); + pRollSpeedUpdater->SetFloat( "minRollSpeed", 0.5f ); + + pUpdaters->FindKey( "DmeAlphaSineRampUpdater", true ); + pUpdaters->FindKey( "DmeColorUpdater", true ); + pUpdaters->FindKey( "DmeSizeUpdater", true ); + + ToolFramework_PostToolMessage( HTOOLHANDLE_INVALID, msg ); + msg->deleteThis(); + } + else + { + KeyValues *msg = new KeyValues( "OldParticleSystem_ActivateEmitter" ); + msg->SetInt( "id", m_pDustEmitter->GetToolParticleEffectId() ); + msg->SetInt( "emitter", 0 ); + msg->SetInt( "active", bEmitterActive ); + msg->SetFloat( "time", gpGlobals->curtime ); + ToolFramework_PostToolMessage( HTOOLHANDLE_INVALID, msg ); + msg->deleteThis(); + } +} diff --git a/src/src/cl_dll/c_smoke_trail.h b/src/src/game/client/c_smoke_trail.h similarity index 78% rename from src/src/cl_dll/c_smoke_trail.h rename to src/src/game/client/c_smoke_trail.h index 606abd4..5dc3b43 100644 --- a/src/src/cl_dll/c_smoke_trail.h +++ b/src/src/game/client/c_smoke_trail.h @@ -279,11 +279,6 @@ private: FTRAIL_SMOKE1, FTRAIL_SMOKE2, - // Smaller embers - FTRAIL_EMBER1, - FTRAIL_EMBER2, - FTRAIL_EMBER3, - // Large flame FTRAIL_FLAME1, FTRAIL_FLAME2, @@ -304,4 +299,92 @@ private: C_FireTrail( const C_FireTrail & ); }; + + + + + + + + + + + + +//================================================== +// C_DustTrail +//================================================== + +class C_DustTrail : public C_BaseParticleEntity, public IPrototypeAppEffect +{ +public: + DECLARE_CLASS( C_DustTrail, C_BaseParticleEntity ); + DECLARE_CLIENTCLASS(); + + C_DustTrail(); + virtual ~C_DustTrail(); + +public: + + // Enable/disable emission. + void SetEmit(bool bEmit); + + // Change the spawn rate. + void SetSpawnRate(float rate); + + +// C_BaseEntity. +public: + virtual void OnDataChanged(DataUpdateType_t updateType); + + virtual void CleanupToolRecordingState( KeyValues *msg ); + +// 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: + // Effect parameters. These will assume default values but you can change them. + float m_SpawnRate; // How many particles per second. + + Vector m_Color; + float m_Opacity; + + float m_ParticleLifetime; // How long do the particles live? + float m_StartEmitTime; // When did I start emitting particles? + float m_StopEmitTime; // When do I stop emitting particles? (-1 = never) + + float m_MinSpeed; // Speed range. + float m_MaxSpeed; + + float m_MinDirectedSpeed; // Directed speed range. + float m_MaxDirectedSpeed; + + float m_StartSize; // Size ramp. + float m_EndSize; + + float m_SpawnRadius; + + Vector m_VelocityOffset; // Emit the particles in a certain direction. + + bool m_bEmit; // Keep emitting particles? + +private: + C_DustTrail( const C_DustTrail & ); + +#define DUSTTRAIL_MATERIALS 16 + PMaterialHandle m_MaterialHandle[DUSTTRAIL_MATERIALS]; + TimedEvent m_ParticleSpawn; + + CParticleMgr *m_pParticleMgr; + CSmartPtr m_pDustEmitter; +}; + #endif diff --git a/src/src/cl_dll/c_smokestack.cpp b/src/src/game/client/c_smokestack.cpp similarity index 100% rename from src/src/cl_dll/c_smokestack.cpp rename to src/src/game/client/c_smokestack.cpp diff --git a/src/src/cl_dll/c_soundscape.cpp b/src/src/game/client/c_soundscape.cpp similarity index 92% rename from src/src/cl_dll/c_soundscape.cpp rename to src/src/game/client/c_soundscape.cpp index 9d3a341..859414d 100644 --- a/src/src/cl_dll/c_soundscape.cpp +++ b/src/src/game/client/c_soundscape.cpp @@ -14,7 +14,7 @@ #include "soundchars.h" #include "view.h" #include "engine/ivdebugoverlay.h" -#include "vstdlib/icommandline.h" +#include "tier0/icommandline.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -39,7 +39,7 @@ struct loopingsound_t bool isAmbient; // Ambient sounds have no spatialization - they play from everywhere }; -ConVar soundscape_fadetime( "soundscape_fadetime", "3.0", 0, "Time to crossfade sound effects between soundscapes" ); +ConVar soundscape_fadetime( "soundscape_fadetime", "3.0", FCVAR_CHEAT, "Time to crossfade sound effects between soundscapes" ); #include "interval.h" @@ -150,7 +150,11 @@ public: { Msg( "- %d: %s\n", i, m_soundscapes[i]->GetName() ); } - Msg( "- CURRENT SOUNDSCAPE: %d\n", m_params.soundscapeIndex ); + if ( m_forcedSoundscapeIndex ) + { + Msg( "- PLAYING DEBUG SOUNDSCAPE: %d [%s]\n", m_forcedSoundscapeIndex, SoundscapeNameByIndex(m_forcedSoundscapeIndex) ); + } + Msg( "- CURRENT SOUNDSCAPE: %d [%s]\n", m_params.soundscapeIndex, SoundscapeNameByIndex(m_params.soundscapeIndex) ); Msg( "----------------------------------\n\n" ); } @@ -158,7 +162,12 @@ public: // local functions void UpdateAudioParams( audioparams_t &audio ); void GetAudioParams( audioparams_t &out ) const { out = m_params; } - int GetCurrentSoundscape() { return m_params.soundscapeIndex; } + int GetCurrentSoundscape() + { + if ( m_forcedSoundscapeIndex >= 0 ) + return m_forcedSoundscapeIndex; + return m_params.soundscapeIndex; + } void DevReportSoundscapeName( int index ); void UpdateLoopingSounds( float frametime ); int AddLoopingAmbient( const char *pSoundName, float volume, int pitch ); @@ -173,8 +182,9 @@ public: void ForceSoundscape( const char *pSoundscapeName, float radius ); - KeyValues *FindSoundscapeByName( const char *pSoundscapeName ); + int FindSoundscapeByName( const char *pSoundscapeName ); const char *SoundscapeNameByIndex( int index ); + KeyValues *SoundscapeByIndex( int index ); // main-level soundscape processing, called on new soundscape void StartNewSoundscape( KeyValues *pSoundscape ); @@ -223,7 +233,7 @@ private: CUtlVector m_randomSounds; // list of random sound commands float m_nextRandomTime; // next time to play a random sound int m_loopingSoundId; // marks when the sound was issued - bool m_forcedSoundscape; // Is this a "forced" soundscape? i.e. debug mode? + int m_forcedSoundscapeIndex;// >= 0 if this a "forced" soundscape? i.e. debug mode? float m_forcedSoundscapeRadius;// distance to spatialized sounds static ConVar *m_pDSPVolumeVar; @@ -336,15 +346,22 @@ bool C_SoundscapeSystem::Init() } -KeyValues *C_SoundscapeSystem::FindSoundscapeByName( const char *pSoundscapeName ) +int C_SoundscapeSystem::FindSoundscapeByName( const char *pSoundscapeName ) { // UNDONE: Bad perf, linear search! for ( int i = m_soundscapes.Count()-1; i >= 0; --i ) { if ( !Q_stricmp( m_soundscapes[i]->GetName(), pSoundscapeName ) ) - return m_soundscapes[i]; + return i; } + return -1; +} + +KeyValues *C_SoundscapeSystem::SoundscapeByIndex( int index ) +{ + if ( m_soundscapes.IsValidIndex(index) ) + return m_soundscapes[index]; return NULL; } @@ -386,7 +403,7 @@ void C_SoundscapeSystem::Shutdown() // NOTE: This will not flush the server side so you cannot add or remove // soundscapes from the list, only change their parameters!!!! -CON_COMMAND(cl_soundscape_flush, "Flushes the client side soundscapes") +CON_COMMAND_F(cl_soundscape_flush, "Flushes the client side soundscapes", FCVAR_SERVER_CAN_EXECUTE|FCVAR_CHEAT) { // save the current soundscape audioparams_t tmp; @@ -403,19 +420,6 @@ CON_COMMAND(cl_soundscape_flush, "Flushes the client side soundscapes") } -void Playsoundscape_f() -{ - if ( engine->Cmd_Argc() < 2 ) - { - g_SoundscapeSystem.DevReportSoundscapeName( g_SoundscapeSystem.GetCurrentSoundscape() ); - return; - } - const char *pSoundscapeName = engine->Cmd_Argv(1); - float radius = engine->Cmd_Argc() > 2 ? atof(engine->Cmd_Argv(2)) : DEFAULT_SOUND_RADIUS; - g_SoundscapeSystem.ForceSoundscape( pSoundscapeName, radius ); -} - - static int SoundscapeCompletion( const char *partial, char commands[ COMMAND_COMPLETION_MAXITEMS ][ COMMAND_COMPLETION_ITEM_LENGTH ] ) { int current = 0; @@ -445,7 +449,19 @@ static int SoundscapeCompletion( const char *partial, char commands[ COMMAND_COM return current; } -static ConCommand Command_Playsoundscape( "playsoundscape", Playsoundscape_f, "Forces a soundscape to play", FCVAR_CHEAT, SoundscapeCompletion ); +CON_COMMAND_F_COMPLETION( playsoundscape, "Forces a soundscape to play", FCVAR_CHEAT, SoundscapeCompletion ) +{ + if ( args.ArgC() < 2 ) + { + g_SoundscapeSystem.DevReportSoundscapeName( g_SoundscapeSystem.GetCurrentSoundscape() ); + return; + } + const char *pSoundscapeName = args[1]; + float radius = args.ArgC() > 2 ? atof( args[2] ) : DEFAULT_SOUND_RADIUS; + g_SoundscapeSystem.ForceSoundscape( pSoundscapeName, radius ); +} + + CON_COMMAND_F( stopsoundscape, "Stops all soundscape processing and fades current looping sounds", FCVAR_CHEAT ) { g_SoundscapeSystem.StartNewSoundscape( NULL ); @@ -453,12 +469,12 @@ CON_COMMAND_F( stopsoundscape, "Stops all soundscape processing and fades curren void C_SoundscapeSystem::ForceSoundscape( const char *pSoundscapeName, float radius ) { - KeyValues *pKv = g_SoundscapeSystem.FindSoundscapeByName( pSoundscapeName ); - if ( pKv ) + int index = g_SoundscapeSystem.FindSoundscapeByName( pSoundscapeName ); + if ( index >= 0 ) { - m_forcedSoundscape = true; + m_forcedSoundscapeIndex = index; m_forcedSoundscapeRadius = radius; - g_SoundscapeSystem.StartNewSoundscape( pKv ); + g_SoundscapeSystem.StartNewSoundscape( SoundscapeByIndex(index) ); } else { @@ -513,7 +529,7 @@ void C_SoundscapeSystem::UpdateLoopingSounds( float frametime ) void C_SoundscapeSystem::Update( float frametime ) { - if ( m_forcedSoundscape ) + if ( m_forcedSoundscapeIndex >= 0 ) { // generate fake positional sources C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); @@ -542,7 +558,7 @@ void C_SoundscapeSystem::UpdateAudioParams( audioparams_t &audio ) return; m_params = audio; - m_forcedSoundscape = false; + m_forcedSoundscapeIndex = -1; if ( audio.ent.Get() && audio.soundscapeIndex >= 0 && audio.soundscapeIndex < m_soundscapes.Count() ) { DevReportSoundscapeName( audio.soundscapeIndex ); @@ -688,8 +704,12 @@ void C_SoundscapeSystem::ProcessDSPPlayer( KeyValues *pDSPPlayer ) void C_SoundscapeSystem::ProcessSoundMixer( KeyValues *pSoundMixer, subsoundscapeparams_t ¶ms ) { - m_pSoundMixerVar->SetValue( pSoundMixer->GetString() ); - params.wroteSoundMixer = true; + C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); + if ( !pPlayer || pPlayer->CanSetSoundMixer() ) + { + m_pSoundMixerVar->SetValue( pSoundMixer->GetString() ); + params.wroteSoundMixer = true; + } } void C_SoundscapeSystem::ProcessDSPVolume( KeyValues *pKey, subsoundscapeparams_t ¶ms ) @@ -1046,16 +1066,20 @@ void C_SoundscapeSystem::ProcessPlaySoundscape( KeyValues *pPlaySoundscape, subs { pSoundscapeName = pKey->GetString(); } + else if ( !Q_strcasecmp(pKey->GetName(), "soundlevel") ) + { + DevMsg(1,"soundlevel not supported on sub-soundscapes\n"); + } else { - DevMsg( 1, "Playsoundscape %s:Unknown command %s\n", pPlaySoundscape->GetName(), pKey->GetName() ); + DevMsg( 1, "Playsoundscape %s:Unknown command %s\n", pSoundscapeName ? pSoundscapeName : pPlaySoundscape->GetName(), pKey->GetName() ); } pKey = pKey->GetNextKey(); } if ( pSoundscapeName ) { - KeyValues *pSoundscapeKeys = FindSoundscapeByName( pSoundscapeName ); + KeyValues *pSoundscapeKeys = SoundscapeByIndex( FindSoundscapeByName( pSoundscapeName ) ); if ( pSoundscapeKeys ) { StartSubSoundscape( pSoundscapeKeys, subParams ); @@ -1080,6 +1104,7 @@ int C_SoundscapeSystem::AddLoopingSound( const char *pSoundName, bool isAmbient, { loopingsound_t *pSoundSlot = NULL; int soundSlot = m_loopingSounds.Count() - 1; + bool bForceSoundUpdate = false; while ( soundSlot >= 0 ) { loopingsound_t &sound = m_loopingSounds[soundSlot]; @@ -1112,8 +1137,14 @@ int C_SoundscapeSystem::AddLoopingSound( const char *pSoundName, bool isAmbient, // because it'll be sending alternating commands to the sound engine, referencing the same sound // (SOUND_FROM_WORLD, CHAN_STATIC, pSoundName). One of the alternating commands will be as // it fades the sound out, and one will be fading the sound in. - // this clicks a bit, but in the end, the correct sound is playing at the correct volume. - // UNDONE: Just stop the sound? Or use another index to get more channels? Fade position instead? + // Because this will occasionally cause the sound to vanish entirely, we stop the old sound immediately. + StopLoopingSound(sound); + pSoundSlot = &sound; + + // make a note to update the sound immediately. Otherwise, if its volume happens to be + // the same as the old sound's volume, it will never update at all. + bForceSoundUpdate = true; + break; } } } @@ -1156,6 +1187,11 @@ int C_SoundscapeSystem::AddLoopingSound( const char *pSoundName, bool isAmbient, sound.isAmbient = isAmbient; sound.position = position; sound.soundlevel = soundlevel; + + if (bForceSoundUpdate) + { + UpdateLoopingSound(sound); + } return soundSlot; } diff --git a/src/src/cl_dll/c_soundscape.h b/src/src/game/client/c_soundscape.h similarity index 100% rename from src/src/cl_dll/c_soundscape.h rename to src/src/game/client/c_soundscape.h diff --git a/src/src/cl_dll/c_spotlight_end.cpp b/src/src/game/client/c_spotlight_end.cpp similarity index 94% rename from src/src/cl_dll/c_spotlight_end.cpp rename to src/src/game/client/c_spotlight_end.cpp index 396297f..7fe61dd 100644 --- a/src/src/cl_dll/c_spotlight_end.cpp +++ b/src/src/game/client/c_spotlight_end.cpp @@ -100,6 +100,14 @@ void C_SpotlightEnd::ClientThink(void) if ( m_flLightScale <= 0 ) return; + ColorRGBExp32 color; + color.r = m_clrRender->r * m_clrRender->a; + color.g = m_clrRender->g * m_clrRender->a; + color.b = m_clrRender->b * m_clrRender->a; + color.exponent = 0; + if ( color.r == 0 && color.g == 0 && color.b == 0 ) + return; + // Deal with the environment light if ( !m_pDynamicLight || (m_pDynamicLight->key != index) ) { @@ -111,10 +119,7 @@ void C_SpotlightEnd::ClientThink(void) m_pDynamicLight->radius = m_flLightScale*3.0f; m_pDynamicLight->origin = GetAbsOrigin() + Vector(0,0,5); m_pDynamicLight->die = gpGlobals->curtime + 0.05f; - m_pDynamicLight->color.r = m_clrRender->r * m_clrRender->a; - m_pDynamicLight->color.g = m_clrRender->g * m_clrRender->a; - m_pDynamicLight->color.b = m_clrRender->b * m_clrRender->a; - m_pDynamicLight->color.exponent = 0.75f; + m_pDynamicLight->color = color; /* // For bumped lighting diff --git a/src/src/cl_dll/c_sprite.cpp b/src/src/game/client/c_sprite.cpp similarity index 97% rename from src/src/cl_dll/c_sprite.cpp rename to src/src/game/client/c_sprite.cpp index 1f08c2b..7c3f212 100644 --- a/src/src/cl_dll/c_sprite.cpp +++ b/src/src/game/client/c_sprite.cpp @@ -19,6 +19,7 @@ #include "viewrender.h" #include "tier1/KeyValues.h" #include "toolframework/itoolframework.h" +#include "toolframework_client.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -65,14 +66,16 @@ void DrawSpriteModel( IClientEntity *baseentity, CEngineSprite *psprite, const V psprite->SetRenderMode( rendermode ); psprite->SetFrame( frame ); + CMatRenderContextPtr pRenderContext( materials ); + if ( ShouldDrawInWireFrameMode() || r_drawsprites.GetInt() == 2 ) { IMaterial *pMaterial = materials->FindMaterial( "debug/debugspritewireframe", TEXTURE_GROUP_OTHER ); - materials->Bind( pMaterial, NULL ); + pRenderContext->Bind( pMaterial, NULL ); } else { - materials->Bind( material, (IClientRenderable*)baseentity ); + pRenderContext->Bind( material, (IClientRenderable*)baseentity ); } unsigned char color[4]; @@ -88,7 +91,7 @@ void DrawSpriteModel( IClientEntity *baseentity, CEngineSprite *psprite, const V } Vector point; - IMesh* pMesh = materials->GetDynamicMesh(); + IMesh* pMesh = pRenderContext->GetDynamicMesh(); CMeshBuilder meshBuilder; meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 ); @@ -490,6 +493,7 @@ void CSprite::GetToolRecordingState( KeyValues *msg ) static SpriteRecordingState_t state; state.m_flRenderScale = renderscale; state.m_flFrame = m_flFrame; + state.m_flProxyRadius = m_flGlowProxySize; state.m_nRenderMode = GetRenderMode(); state.m_nRenderFX = m_nRenderFX; state.m_Color.SetColor( m_clrRender.GetR(), m_clrRender.GetG(), m_clrRender.GetB(), GetRenderBrightness() ); diff --git a/src/src/cl_dll/c_sprite.h b/src/src/game/client/c_sprite.h similarity index 100% rename from src/src/cl_dll/c_sprite.h rename to src/src/game/client/c_sprite.h diff --git a/src/src/game/client/c_sprite_perfmonitor.cpp b/src/src/game/client/c_sprite_perfmonitor.cpp new file mode 100644 index 0000000..50a346e --- /dev/null +++ b/src/src/game/client/c_sprite_perfmonitor.cpp @@ -0,0 +1,68 @@ +//====== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======= +// +// Purpose: +// +//============================================================================= +#include "cbase.h" + +extern bool g_bMeasureParticlePerformance; +extern bool g_bDisplayParticlePerformance; + +void ResetParticlePerformanceCounters( void ); + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class C_ParticlePerformanceMonitor : public C_BaseEntity +{ + DECLARE_CLASS( C_ParticlePerformanceMonitor, C_BaseEntity ); +public: + DECLARE_CLIENTCLASS(); + + C_ParticlePerformanceMonitor(); + ~C_ParticlePerformanceMonitor(); + virtual void OnDataChanged( DataUpdateType_t updateType ); + +private: + bool m_bDisplayPerf; + bool m_bMeasurePerf; +private: + C_ParticlePerformanceMonitor( const C_ParticlePerformanceMonitor & ); +}; + +IMPLEMENT_CLIENTCLASS_DT( C_ParticlePerformanceMonitor, DT_ParticlePerformanceMonitor, CParticlePerformanceMonitor ) + RecvPropInt( RECVINFO(m_bMeasurePerf) ), + RecvPropInt( RECVINFO(m_bDisplayPerf) ), +END_RECV_TABLE() + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_ParticlePerformanceMonitor::C_ParticlePerformanceMonitor( void ) +{ + m_bDisplayPerf = false; + m_bMeasurePerf = false; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_ParticlePerformanceMonitor::~C_ParticlePerformanceMonitor( void ) +{ + g_bMeasureParticlePerformance = false; + g_bDisplayParticlePerformance = false; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_ParticlePerformanceMonitor::OnDataChanged( DataUpdateType_t updateType ) +{ + BaseClass::OnDataChanged(updateType); + + if ( m_bMeasurePerf && ( ! g_bMeasureParticlePerformance ) ) + ResetParticlePerformanceCounters(); + g_bMeasureParticlePerformance = m_bMeasurePerf; + g_bDisplayParticlePerformance = m_bDisplayPerf; +} + diff --git a/src/src/cl_dll/c_steamjet.cpp b/src/src/game/client/c_steamjet.cpp similarity index 98% rename from src/src/cl_dll/c_steamjet.cpp rename to src/src/game/client/c_steamjet.cpp index 5e0fcf4..f37463d 100644 --- a/src/src/cl_dll/c_steamjet.cpp +++ b/src/src/game/client/c_steamjet.cpp @@ -9,6 +9,7 @@ #include "particle_util.h" #include "baseparticleentity.h" #include "ClientEffectPrecacheSystem.h" +#include "fx.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -21,11 +22,6 @@ #define SF_EMISSIVE 0x00000001 -CLIENTEFFECT_REGISTER_BEGIN( PrecacheSteamJet ) -CLIENTEFFECT_MATERIAL( "particle/particle_smokegrenade" ) -CLIENTEFFECT_MATERIAL( "sprites/heatwave" ) -CLIENTEFFECT_REGISTER_END() - //================================================== // C_SteamJet //================================================== @@ -198,7 +194,7 @@ void C_SteamJet::Start(CParticleMgr *pParticleMgr, IPrototypeArgAccess *pArgs) { case STEAM_NORMAL: default: - m_MaterialHandle = m_ParticleEffect.FindOrAddMaterial("particle/particle_smokegrenade"); + m_MaterialHandle = g_Mat_DustPuff[0]; break; case STEAM_HEATWAVE: diff --git a/src/src/cl_dll/c_stickybolt.cpp b/src/src/game/client/c_stickybolt.cpp similarity index 100% rename from src/src/cl_dll/c_stickybolt.cpp rename to src/src/game/client/c_stickybolt.cpp diff --git a/src/src/cl_dll/c_sun.cpp b/src/src/game/client/c_sun.cpp similarity index 100% rename from src/src/cl_dll/c_sun.cpp rename to src/src/game/client/c_sun.cpp diff --git a/src/src/cl_dll/c_sun.h b/src/src/game/client/c_sun.h similarity index 100% rename from src/src/cl_dll/c_sun.h rename to src/src/game/client/c_sun.h diff --git a/src/src/cl_dll/c_te.cpp b/src/src/game/client/c_te.cpp similarity index 97% rename from src/src/cl_dll/c_te.cpp rename to src/src/game/client/c_te.cpp index 7c8402f..d5f2ad8 100644 --- a/src/src/cl_dll/c_te.cpp +++ b/src/src/game/client/c_te.cpp @@ -125,7 +125,8 @@ void TE_PhysicsProp( IRecipientFilter& filter, float delay, int modelindex, int skin, const Vector& pos, const QAngle &angles, const Vector& vel, bool breakmodel, int effects ); void TE_PhysicsProp( IRecipientFilter& filter, float delay, KeyValues *pKeyValues ); void TE_ConcussiveExplosion( IRecipientFilter& filter, float delay, KeyValues *pKeyValues ); - +void TE_ClientProjectile( IRecipientFilter& filter, float delay, + const Vector* vecOrigin, const Vector* vecVelocity, int modelindex, int lifetime, CBaseEntity *pOwner ); class C_TempEntsSystem : public ITempEntsSystem { @@ -515,11 +516,20 @@ public: TE_PhysicsProp( filter, delay, modelindex, skin, pos, angles, vel, flags, effects ); } } + virtual void ClientProjectile( IRecipientFilter& filter, float delay, + const Vector* vecOrigin, const Vector* vecVelocity, int modelindex, int lifetime, CBaseEntity *pOwner ) + { + if ( !SuppressTE( filter ) ) + { + TE_ClientProjectile( filter, delay, vecOrigin, vecVelocity, modelindex, lifetime, pOwner ); + } + } // For playback from external tools virtual void TriggerTempEntity( KeyValues *pKeyValues ) { g_pEffects->SuppressEffectsSounds( true ); + SuppressParticleEffects( true ); // While playing back, suppress recording bool bIsRecording = clienttools->IsInRecordingMode(); @@ -665,6 +675,7 @@ public: #endif } + SuppressParticleEffects( false ); g_pEffects->SuppressEffectsSounds( false ); clienttools->EnableRecordingMode( bIsRecording ); } diff --git a/src/src/cl_dll/c_te_armorricochet.cpp b/src/src/game/client/c_te_armorricochet.cpp similarity index 98% rename from src/src/cl_dll/c_te_armorricochet.cpp rename to src/src/game/client/c_te_armorricochet.cpp index 7e53e30..d92c9aa 100644 --- a/src/src/cl_dll/c_te_armorricochet.cpp +++ b/src/src/game/client/c_te_armorricochet.cpp @@ -10,6 +10,7 @@ #include "c_basetempentity.h" #include "IEffects.h" #include "tier1/keyvalues.h" +#include "tier0/vprof.h" #include "toolframework_client.h" // memdbgon must be the last include file in a .cpp file!!! @@ -94,6 +95,8 @@ static inline void RecordMetalSparks( const Vector &start, const Vector &directi //----------------------------------------------------------------------------- void C_TEMetalSparks::PostDataUpdate( DataUpdateType_t updateType ) { + VPROF( "C_TEMetalSparks::PostDataUpdate" ); + g_pEffects->MetalSparks( m_vecPos, m_vecDir ); RecordMetalSparks( m_vecPos, m_vecDir ); } diff --git a/src/src/cl_dll/c_te_basebeam.cpp b/src/src/game/client/c_te_basebeam.cpp similarity index 100% rename from src/src/cl_dll/c_te_basebeam.cpp rename to src/src/game/client/c_te_basebeam.cpp diff --git a/src/src/cl_dll/c_te_basebeam.h b/src/src/game/client/c_te_basebeam.h similarity index 100% rename from src/src/cl_dll/c_te_basebeam.h rename to src/src/game/client/c_te_basebeam.h diff --git a/src/src/cl_dll/c_te_beamentpoint.cpp b/src/src/game/client/c_te_beamentpoint.cpp similarity index 100% rename from src/src/cl_dll/c_te_beamentpoint.cpp rename to src/src/game/client/c_te_beamentpoint.cpp diff --git a/src/src/cl_dll/c_te_beaments.cpp b/src/src/game/client/c_te_beaments.cpp similarity index 100% rename from src/src/cl_dll/c_te_beaments.cpp rename to src/src/game/client/c_te_beaments.cpp diff --git a/src/src/cl_dll/c_te_beamfollow.cpp b/src/src/game/client/c_te_beamfollow.cpp similarity index 100% rename from src/src/cl_dll/c_te_beamfollow.cpp rename to src/src/game/client/c_te_beamfollow.cpp diff --git a/src/src/cl_dll/c_te_beamlaser.cpp b/src/src/game/client/c_te_beamlaser.cpp similarity index 100% rename from src/src/cl_dll/c_te_beamlaser.cpp rename to src/src/game/client/c_te_beamlaser.cpp diff --git a/src/src/cl_dll/c_te_beampoints.cpp b/src/src/game/client/c_te_beampoints.cpp similarity index 100% rename from src/src/cl_dll/c_te_beampoints.cpp rename to src/src/game/client/c_te_beampoints.cpp diff --git a/src/src/cl_dll/c_te_beamring.cpp b/src/src/game/client/c_te_beamring.cpp similarity index 100% rename from src/src/cl_dll/c_te_beamring.cpp rename to src/src/game/client/c_te_beamring.cpp diff --git a/src/src/cl_dll/c_te_beamringpoint.cpp b/src/src/game/client/c_te_beamringpoint.cpp similarity index 100% rename from src/src/cl_dll/c_te_beamringpoint.cpp rename to src/src/game/client/c_te_beamringpoint.cpp diff --git a/src/src/cl_dll/c_te_beamspline.cpp b/src/src/game/client/c_te_beamspline.cpp similarity index 97% rename from src/src/cl_dll/c_te_beamspline.cpp rename to src/src/game/client/c_te_beamspline.cpp index cb42c5b..a31f331 100644 --- a/src/src/cl_dll/c_te_beamspline.cpp +++ b/src/src/game/client/c_te_beamspline.cpp @@ -12,6 +12,7 @@ //=============================================================================// #include "cbase.h" #include "c_basetempentity.h" +#include "tier0/vprof.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -68,7 +69,8 @@ void TE_BeamSpline( IRecipientFilter& filter, float delay, //----------------------------------------------------------------------------- void C_TEBeamSpline::PostDataUpdate( DataUpdateType_t updateType ) { - // + VPROF( "C_TEBeamSpline::PostDataUpdate" ); + DevMsg( 1, "Beam spline with %i points received\n", m_nPoints ); } diff --git a/src/src/cl_dll/c_te_bloodsprite.cpp b/src/src/game/client/c_te_bloodsprite.cpp similarity index 98% rename from src/src/cl_dll/c_te_bloodsprite.cpp rename to src/src/game/client/c_te_bloodsprite.cpp index dba3b92..edae4ec 100644 --- a/src/src/cl_dll/c_te_bloodsprite.cpp +++ b/src/src/game/client/c_te_bloodsprite.cpp @@ -11,6 +11,7 @@ #include "c_te_legacytempents.h" #include "fx.h" #include "tier1/keyvalues.h" +#include "tier0/vprof.h" #include "toolframework_client.h" // memdbgon must be the last include file in a .cpp file!!! @@ -144,6 +145,8 @@ void TE_BloodSprite( IRecipientFilter& filter, float delay, //----------------------------------------------------------------------------- void C_TEBloodSprite::PostDataUpdate( DataUpdateType_t updateType ) { + VPROF( "C_TEBloodSprite::PostDataUpdate" ); + Vector offset = m_vecOrigin + ( m_vecDirection * 4.0f ); tempents->BloodSprite( offset, r, g, b, a, m_nSprayModel, m_nDropModel, m_nSize ); diff --git a/src/src/cl_dll/c_te_bloodstream.cpp b/src/src/game/client/c_te_bloodstream.cpp similarity index 100% rename from src/src/cl_dll/c_te_bloodstream.cpp rename to src/src/game/client/c_te_bloodstream.cpp diff --git a/src/src/cl_dll/c_te_breakmodel.cpp b/src/src/game/client/c_te_breakmodel.cpp similarity index 98% rename from src/src/cl_dll/c_te_breakmodel.cpp rename to src/src/game/client/c_te_breakmodel.cpp index 37e3356..28950c4 100644 --- a/src/src/cl_dll/c_te_breakmodel.cpp +++ b/src/src/game/client/c_te_breakmodel.cpp @@ -10,6 +10,7 @@ #include "c_basetempentity.h" #include "c_te_legacytempents.h" #include "tier1/keyvalues.h" +#include "tier0/vprof.h" #include "toolframework_client.h" // memdbgon must be the last include file in a .cpp file!!! @@ -141,6 +142,8 @@ void TE_BreakModel( IRecipientFilter& filter, float delay, //----------------------------------------------------------------------------- void C_TEBreakModel::PostDataUpdate( DataUpdateType_t updateType ) { + VPROF( "C_TEBreakModel::PostDataUpdate" ); + tempents->BreakModel( m_vecOrigin, m_angRotation, m_vecSize, m_vecVelocity, m_nRandomization, m_fTime, m_nCount, m_nModelIndex, m_nFlags ); RecordBreakModel( m_vecOrigin, m_angRotation, m_vecSize, m_vecVelocity, diff --git a/src/src/cl_dll/c_te_bspdecal.cpp b/src/src/game/client/c_te_bspdecal.cpp similarity index 97% rename from src/src/cl_dll/c_te_bspdecal.cpp rename to src/src/game/client/c_te_bspdecal.cpp index c7cf74a..a237dd0 100644 --- a/src/src/cl_dll/c_te_bspdecal.cpp +++ b/src/src/game/client/c_te_bspdecal.cpp @@ -10,6 +10,7 @@ #include "c_basetempentity.h" #include "iefx.h" #include "fx.h" +#include "tier0/vprof.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -85,6 +86,8 @@ void TE_BSPDecal( IRecipientFilter& filter, float delay, //----------------------------------------------------------------------------- void C_TEBSPDecal::PostDataUpdate( DataUpdateType_t updateType ) { + VPROF( "C_TEBSPDecal::PostDataUpdate" ); + C_BaseEntity *ent; if ( ( ent = cl_entitylist->GetEnt( m_nEntity ) ) == NULL ) { diff --git a/src/src/cl_dll/c_te_bubbles.cpp b/src/src/game/client/c_te_bubbles.cpp similarity index 97% rename from src/src/cl_dll/c_te_bubbles.cpp rename to src/src/game/client/c_te_bubbles.cpp index c6bea8c..58e2784 100644 --- a/src/src/cl_dll/c_te_bubbles.cpp +++ b/src/src/game/client/c_te_bubbles.cpp @@ -9,6 +9,7 @@ #include "cbase.h" #include "c_basetempentity.h" #include "c_te_legacytempents.h" +#include "tier0/vprof.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -68,6 +69,8 @@ void TE_Bubbles( IRecipientFilter& filter, float delay, //----------------------------------------------------------------------------- void C_TEBubbles::PostDataUpdate( DataUpdateType_t updateType ) { + VPROF( "C_TEBubbles::PostDataUpdate" ); + tempents->Bubbles( m_vecMins, m_vecMaxs, m_fHeight, m_nModelIndex, m_nCount, m_fSpeed ); } diff --git a/src/src/cl_dll/c_te_bubbletrail.cpp b/src/src/game/client/c_te_bubbletrail.cpp similarity index 97% rename from src/src/cl_dll/c_te_bubbletrail.cpp rename to src/src/game/client/c_te_bubbletrail.cpp index 2e6b17c..2f3fc52 100644 --- a/src/src/cl_dll/c_te_bubbletrail.cpp +++ b/src/src/game/client/c_te_bubbletrail.cpp @@ -9,6 +9,7 @@ #include "cbase.h" #include "c_basetempentity.h" #include "c_te_legacytempents.h" +#include "tier0/vprof.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -68,6 +69,8 @@ void TE_BubbleTrail( IRecipientFilter& filter, float delay, //----------------------------------------------------------------------------- void C_TEBubbleTrail::PostDataUpdate( DataUpdateType_t updateType ) { + VPROF( "C_TEBubbleTrail::PostDataUpdate" ); + tempents->BubbleTrail( m_vecMins, m_vecMaxs, m_flWaterZ, m_nModelIndex, m_nCount, m_fSpeed ); } diff --git a/src/src/game/client/c_te_clientprojectile.cpp b/src/src/game/client/c_te_clientprojectile.cpp new file mode 100644 index 0000000..375b020 --- /dev/null +++ b/src/src/game/client/c_te_clientprojectile.cpp @@ -0,0 +1,78 @@ +//====== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======= +// +// Purpose: +// +//============================================================================= +#include "cbase.h" +#include "c_basetempentity.h" +#include "c_te_legacytempents.h" +#include "tier0/vprof.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +//----------------------------------------------------------------------------- +// Purpose: Client Projectile TE +//----------------------------------------------------------------------------- +class C_TEClientProjectile : public C_BaseTempEntity +{ +public: + DECLARE_CLASS( C_TEClientProjectile, C_BaseTempEntity ); + DECLARE_CLIENTCLASS(); + + C_TEClientProjectile( void ); + virtual ~C_TEClientProjectile( void ); + + virtual void PostDataUpdate( DataUpdateType_t updateType ); + +public: + Vector m_vecOrigin; + Vector m_vecVelocity; + int m_nModelIndex; + int m_nLifeTime; + EHANDLE m_hOwner; +}; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_TEClientProjectile::C_TEClientProjectile( void ) +{ + m_vecOrigin.Init(); + m_vecVelocity.Init(); + m_nModelIndex = 0; + m_nLifeTime = 0; + m_hOwner = NULL; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_TEClientProjectile::~C_TEClientProjectile( void ) +{ +} + +void TE_ClientProjectile( IRecipientFilter& filter, float delay, + const Vector* vecOrigin, const Vector* vecVelocity, int modelindex, int lifetime, CBaseEntity *pOwner ) +{ + tempents->ClientProjectile( *vecOrigin, *vecVelocity, vec3_origin, modelindex, lifetime, pOwner ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : bool - +//----------------------------------------------------------------------------- +void C_TEClientProjectile::PostDataUpdate( DataUpdateType_t updateType ) +{ + VPROF( "C_TEClientProjectile::PostDataUpdate" ); + + tempents->ClientProjectile( m_vecOrigin, m_vecVelocity, vec3_origin, m_nModelIndex, m_nLifeTime, m_hOwner ); +} + +IMPLEMENT_CLIENTCLASS_EVENT_DT(C_TEClientProjectile, DT_TEClientProjectile, CTEClientProjectile) + RecvPropVector( RECVINFO(m_vecOrigin)), + RecvPropVector( RECVINFO(m_vecVelocity)), + RecvPropInt( RECVINFO(m_nModelIndex)), + RecvPropInt( RECVINFO(m_nLifeTime)), + RecvPropEHandle( RECVINFO(m_hOwner)), +END_RECV_TABLE() diff --git a/src/src/cl_dll/c_te_decal.cpp b/src/src/game/client/c_te_decal.cpp similarity index 98% rename from src/src/cl_dll/c_te_decal.cpp rename to src/src/game/client/c_te_decal.cpp index 89b8efe..894e190 100644 --- a/src/src/cl_dll/c_te_decal.cpp +++ b/src/src/game/client/c_te_decal.cpp @@ -11,6 +11,7 @@ #include "iefx.h" #include "engine/IStaticPropMgr.h" #include "tier1/keyvalues.h" +#include "tier0/vprof.h" #include "toolframework_client.h" // memdbgon must be the last include file in a .cpp file!!! @@ -152,6 +153,8 @@ void TE_Decal( IRecipientFilter& filter, float delay, //----------------------------------------------------------------------------- void C_TEDecal::PostDataUpdate( DataUpdateType_t updateType ) { + VPROF( "C_TEDecal::PostDataUpdate" ); + CBroadcastRecipientFilter filter; TE_Decal( filter, 0.0f, &m_vecOrigin, &m_vecStart, m_nEntity, m_nHitbox, m_nIndex ); } diff --git a/src/src/cl_dll/c_te_dynamiclight.cpp b/src/src/game/client/c_te_dynamiclight.cpp similarity index 98% rename from src/src/cl_dll/c_te_dynamiclight.cpp rename to src/src/game/client/c_te_dynamiclight.cpp index 76eee49..cfd5e5f 100644 --- a/src/src/cl_dll/c_te_dynamiclight.cpp +++ b/src/src/game/client/c_te_dynamiclight.cpp @@ -12,6 +12,7 @@ #include "iefx.h" #include "tier1/keyvalues.h" #include "toolframework_client.h" +#include "tier0/vprof.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -126,6 +127,8 @@ void TE_DynamicLight( IRecipientFilter& filter, float delay, //----------------------------------------------------------------------------- void C_TEDynamicLight::PostDataUpdate( DataUpdateType_t updateType ) { + VPROF( "C_TEDynamicLight::PostDataUpdate" ); + CBroadcastRecipientFilter filter; TE_DynamicLight( filter, 0.0f, &m_vecOrigin, r, g, b, exponent, m_fRadius, m_fTime, m_fDecay, LIGHT_INDEX_TE_DYNAMIC ); } diff --git a/src/src/cl_dll/c_te_effect_dispatch.cpp b/src/src/game/client/c_te_effect_dispatch.cpp similarity index 99% rename from src/src/cl_dll/c_te_effect_dispatch.cpp rename to src/src/game/client/c_te_effect_dispatch.cpp index 62bddb7..7c30f99 100644 --- a/src/src/cl_dll/c_te_effect_dispatch.cpp +++ b/src/src/game/client/c_te_effect_dispatch.cpp @@ -13,6 +13,7 @@ #include "c_te_effect_dispatch.h" #include "tier1/keyvalues.h" #include "toolframework_client.h" +#include "tier0/vprof.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -144,6 +145,8 @@ static void RecordEffect( const char *pEffectName, const CEffectData &data ) //----------------------------------------------------------------------------- void C_TEEffectDispatch::PostDataUpdate( DataUpdateType_t updateType ) { + VPROF( "C_TEEffectDispatch::PostDataUpdate" ); + // Find the effect name. const char *pEffectName = g_StringTableEffectDispatch->GetString( m_EffectData.GetEffectNameIndex() ); if ( pEffectName ) diff --git a/src/src/cl_dll/c_te_effect_dispatch.h b/src/src/game/client/c_te_effect_dispatch.h similarity index 100% rename from src/src/cl_dll/c_te_effect_dispatch.h rename to src/src/game/client/c_te_effect_dispatch.h diff --git a/src/src/cl_dll/c_te_energysplash.cpp b/src/src/game/client/c_te_energysplash.cpp similarity index 97% rename from src/src/cl_dll/c_te_energysplash.cpp rename to src/src/game/client/c_te_energysplash.cpp index d08c42c..c4c972b 100644 --- a/src/src/cl_dll/c_te_energysplash.cpp +++ b/src/src/game/client/c_te_energysplash.cpp @@ -9,6 +9,7 @@ #include "cbase.h" #include "c_basetempentity.h" #include "IEffects.h" +#include "tier0/vprof.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -67,6 +68,8 @@ void C_TEEnergySplash::Precache( void ) //----------------------------------------------------------------------------- void C_TEEnergySplash::PostDataUpdate( DataUpdateType_t updateType ) { + VPROF( "C_TEEnergySplash::PostDataUpdate" ); + g_pEffects->EnergySplash( m_vecPos, m_vecDir, m_bExplosive ); } diff --git a/src/src/cl_dll/c_te_explosion.cpp b/src/src/game/client/c_te_explosion.cpp similarity index 100% rename from src/src/cl_dll/c_te_explosion.cpp rename to src/src/game/client/c_te_explosion.cpp diff --git a/src/src/cl_dll/c_te_fizz.cpp b/src/src/game/client/c_te_fizz.cpp similarity index 97% rename from src/src/cl_dll/c_te_fizz.cpp rename to src/src/game/client/c_te_fizz.cpp index 0c01bfa..89411ad 100644 --- a/src/src/cl_dll/c_te_fizz.cpp +++ b/src/src/game/client/c_te_fizz.cpp @@ -13,6 +13,7 @@ #include "cbase.h" #include "c_basetempentity.h" #include "c_te_legacytempents.h" +#include "tier0/vprof.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -62,6 +63,8 @@ C_TEFizz::~C_TEFizz( void ) //----------------------------------------------------------------------------- void C_TEFizz::PostDataUpdate( DataUpdateType_t updateType ) { + VPROF( "C_TEFizz::PostDataUpdate" ); + C_BaseEntity *pEnt = cl_entitylist->GetEnt( m_nEntity ); if (pEnt != NULL) { diff --git a/src/src/cl_dll/c_te_footprint.cpp b/src/src/game/client/c_te_footprint.cpp similarity index 97% rename from src/src/cl_dll/c_te_footprint.cpp rename to src/src/game/client/c_te_footprint.cpp index a4a3097..a100be6 100644 --- a/src/src/cl_dll/c_te_footprint.cpp +++ b/src/src/game/client/c_te_footprint.cpp @@ -10,6 +10,8 @@ #include "c_basetempentity.h" #include "iefx.h" #include "fx.h" +#include "tier0/vprof.h" + // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -80,6 +82,8 @@ void C_TEFootprintDecal::Precache( void ) void C_TEFootprintDecal::PostDataUpdate( DataUpdateType_t updateType ) { + VPROF( "C_TEFootprintDecal::PostDataUpdate" ); + // FIXME: Make this choose the decal based on material type if ( r_decals.GetInt() ) { diff --git a/src/src/cl_dll/c_te_glassshatter.cpp b/src/src/game/client/c_te_glassshatter.cpp similarity index 94% rename from src/src/cl_dll/c_te_glassshatter.cpp rename to src/src/game/client/c_te_glassshatter.cpp index b7331d0..a62f577 100644 --- a/src/src/cl_dll/c_te_glassshatter.cpp +++ b/src/src/game/client/c_te_glassshatter.cpp @@ -10,6 +10,8 @@ #include "particle_simple3D.h" #include "tier1/keyvalues.h" #include "toolframework_client.h" +#include "fx.h" +#include "tier0/vprof.h" // memdbgon must be the last include file in a .cpp file!!! @@ -159,6 +161,8 @@ void C_TEShatterSurface::RecordShatterSurface( ) //----------------------------------------------------------------------------- void C_TEShatterSurface::PostDataUpdate( DataUpdateType_t updateType ) { + VPROF( "C_TEShatterSurface::PostDataUpdate" ); + RecordShatterSurface(); CSmartPtr pGlassEmitter = CSimple3DEmitter::Create( "C_TEShatterSurface 1" ); @@ -170,17 +174,14 @@ void C_TEShatterSurface::PostDataUpdate( DataUpdateType_t updateType ) // HACK: Blend a little toward white to match the materials... VectorLerp( vecColor, Vector( 1, 1, 1 ), 0.3, vecColor ); - PMaterialHandle hMaterial1; - PMaterialHandle hMaterial2; + PMaterialHandle *hMaterial; if (m_nSurfaceType == SHATTERSURFACE_GLASS) { - hMaterial1 = pGlassEmitter->GetPMaterial( "effects/fleck_glass1" ); - hMaterial2 = pGlassEmitter->GetPMaterial( "effects/fleck_glass2" ); + hMaterial = g_Mat_Fleck_Glass; } else { - hMaterial1 = pGlassEmitter->GetPMaterial( "effects/fleck_tile1" ); - hMaterial2 = pGlassEmitter->GetPMaterial( "effects/fleck_tile2" ); + hMaterial = g_Mat_Fleck_Tile; } // --------------------------------------------------- @@ -210,14 +211,7 @@ void C_TEShatterSurface::PostDataUpdate( DataUpdateType_t updateType ) { for (int height=0;heightRandomInt(0,1)) - { - pParticle = (Particle3D *) pGlassEmitter->AddParticle( sizeof(Particle3D), hMaterial1, vCurPos ); - } - else - { - pParticle = (Particle3D *) pGlassEmitter->AddParticle( sizeof(Particle3D), hMaterial2, vCurPos ); - } + pParticle = (Particle3D *) pGlassEmitter->AddParticle( sizeof(Particle3D), hMaterial[random->RandomInt(0,1)], vCurPos ); Vector vForceVel = Vector(0,0,0); if (random->RandomInt(0, 3) != 0) diff --git a/src/src/cl_dll/c_te_glowsprite.cpp b/src/src/game/client/c_te_glowsprite.cpp similarity index 98% rename from src/src/cl_dll/c_te_glowsprite.cpp rename to src/src/game/client/c_te_glowsprite.cpp index d0d8e3f..b6067f7 100644 --- a/src/src/cl_dll/c_te_glowsprite.cpp +++ b/src/src/game/client/c_te_glowsprite.cpp @@ -11,6 +11,8 @@ #include "tempent.h" #include "tier1/keyvalues.h" #include "toolframework_client.h" +#include "tier0/vprof.h" + // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -107,6 +109,8 @@ static inline void RecordGlowSprite( const Vector &start, int nModelIndex, //----------------------------------------------------------------------------- void C_TEGlowSprite::PostDataUpdate( DataUpdateType_t updateType ) { + VPROF( "C_TEGlowSprite::PostDataUpdate" ); + float a = ( 1.0 / 255.0 ) * m_nBrightness; C_LocalTempEntity *ent = tempents->TempSprite( m_vecOrigin, vec3_origin, m_fScale, m_nModelIndex, kRenderTransAdd, 0, a, m_fLife, FTENT_SPRANIMATE | FTENT_SPRANIMATELOOP ); if ( ent ) diff --git a/src/src/cl_dll/c_te_impact.cpp b/src/src/game/client/c_te_impact.cpp similarity index 97% rename from src/src/cl_dll/c_te_impact.cpp rename to src/src/game/client/c_te_impact.cpp index 65288d7..3057df6 100644 --- a/src/src/cl_dll/c_te_impact.cpp +++ b/src/src/game/client/c_te_impact.cpp @@ -8,6 +8,7 @@ //=============================================================================// #include "cbase.h" #include "c_basetempentity.h" +#include "tier0/vprof.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -71,6 +72,7 @@ void C_TEImpact::Precache( void ) //----------------------------------------------------------------------------- void C_TEImpact::PostDataUpdate( DataUpdateType_t updateType ) { + VPROF( "C_TEImpact::PostDataUpdate" ); } //----------------------------------------------------------------------------- diff --git a/src/src/cl_dll/c_te_killplayerattachments.cpp b/src/src/game/client/c_te_killplayerattachments.cpp similarity index 96% rename from src/src/cl_dll/c_te_killplayerattachments.cpp rename to src/src/game/client/c_te_killplayerattachments.cpp index 2d3bee7..0d17fc0 100644 --- a/src/src/cl_dll/c_te_killplayerattachments.cpp +++ b/src/src/game/client/c_te_killplayerattachments.cpp @@ -9,6 +9,7 @@ #include "cbase.h" #include "c_basetempentity.h" #include "c_te_legacytempents.h" +#include "tier0/vprof.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -52,6 +53,8 @@ C_TEKillPlayerAttachments::~C_TEKillPlayerAttachments( void ) //----------------------------------------------------------------------------- void C_TEKillPlayerAttachments::PostDataUpdate( DataUpdateType_t updateType ) { + VPROF( "C_TEKillPlayerAttachments::PostDataUpdate" ); + tempents->KillAttachedTents( m_nPlayer ); } diff --git a/src/src/cl_dll/c_te_largefunnel.cpp b/src/src/game/client/c_te_largefunnel.cpp similarity index 100% rename from src/src/cl_dll/c_te_largefunnel.cpp rename to src/src/game/client/c_te_largefunnel.cpp diff --git a/src/src/cl_dll/c_te_legacytempents.cpp b/src/src/game/client/c_te_legacytempents.cpp similarity index 90% rename from src/src/cl_dll/c_te_legacytempents.cpp rename to src/src/game/client/c_te_legacytempents.cpp index 8b70fa0..fbd6a6f 100644 --- a/src/src/cl_dll/c_te_legacytempents.cpp +++ b/src/src/game/client/c_te_legacytempents.cpp @@ -28,8 +28,11 @@ #include "tier0/vprof.h" #include "particles_localspace.h" #include "physpropclientside.h" -#include "vstdlib/ICommandLine.h" +#include "tier0/ICommandLine.h" #include "datacache/imdlcache.h" +#include "engine/IVDebugOverlay.h" +#include "effect_dispatch_data.h" +#include "c_te_effect_dispatch.h" // NOTE: Always include this last! #include "tier0/memdbgon.h" @@ -39,29 +42,32 @@ extern ConVar muzzleflash_light; #define TENT_WIND_ACCEL 50 //Precache the effects +#ifndef TF_CLIENT_DLL CLIENTEFFECT_REGISTER_BEGIN( PrecacheEffectMuzzleFlash ) -CLIENTEFFECT_MATERIAL( "effects/combinemuzzle1" ) -CLIENTEFFECT_MATERIAL( "effects/combinemuzzle2" ) -CLIENTEFFECT_MATERIAL( "effects/combinemuzzle1_noz" ) -CLIENTEFFECT_MATERIAL( "effects/combinemuzzle2_noz" ) + CLIENTEFFECT_MATERIAL( "effects/combinemuzzle1" ) + CLIENTEFFECT_MATERIAL( "effects/combinemuzzle2" ) + CLIENTEFFECT_MATERIAL( "effects/combinemuzzle1_noz" ) + CLIENTEFFECT_MATERIAL( "effects/combinemuzzle2_noz" ) -CLIENTEFFECT_MATERIAL( "effects/muzzleflash1" ) -CLIENTEFFECT_MATERIAL( "effects/muzzleflash2" ) -CLIENTEFFECT_MATERIAL( "effects/muzzleflash3" ) -CLIENTEFFECT_MATERIAL( "effects/muzzleflash4" ) -CLIENTEFFECT_MATERIAL( "effects/muzzleflash1_noz" ) -CLIENTEFFECT_MATERIAL( "effects/muzzleflash2_noz" ) -CLIENTEFFECT_MATERIAL( "effects/muzzleflash3_noz" ) -CLIENTEFFECT_MATERIAL( "effects/muzzleflash4_noz" ) + CLIENTEFFECT_MATERIAL( "effects/muzzleflash1" ) + CLIENTEFFECT_MATERIAL( "effects/muzzleflash2" ) + CLIENTEFFECT_MATERIAL( "effects/muzzleflash3" ) + CLIENTEFFECT_MATERIAL( "effects/muzzleflash4" ) + CLIENTEFFECT_MATERIAL( "effects/muzzleflash1_noz" ) + CLIENTEFFECT_MATERIAL( "effects/muzzleflash2_noz" ) + CLIENTEFFECT_MATERIAL( "effects/muzzleflash3_noz" ) + CLIENTEFFECT_MATERIAL( "effects/muzzleflash4_noz" ) -CLIENTEFFECT_MATERIAL( "effects/strider_muzzle" ) + CLIENTEFFECT_MATERIAL( "effects/strider_muzzle" ) CLIENTEFFECT_REGISTER_END() +#endif //Whether or not to eject brass from weapons ConVar cl_ejectbrass( "cl_ejectbrass", "1" ); ConVar func_break_max_pieces( "func_break_max_pieces", "15", FCVAR_ARCHIVE | FCVAR_REPLICATED ); +ConVar cl_fasttempentcollision( "cl_fasttempentcollision", "5" ); #if !defined( HL1_CLIENT_DLL ) // HL1 implements a derivative of CTempEnts // Temp entity interface @@ -81,7 +87,9 @@ C_LocalTempEntity::C_LocalTempEntity() m_vecTempEntAngVelocity.Init(); m_vecNormal.Init(); #endif + m_vecTempEntAcceleration.Init(); m_pfnDrawHelper = 0; + m_pszImpactEffect = NULL; } @@ -118,6 +126,7 @@ void C_LocalTempEntity::Prepare( model_t *pmodel, float time ) clientIndex = -1; bounceFactor = 1; m_nFlickerFrame = 0; + m_bParticleCollision = false; } //----------------------------------------------------------------------------- @@ -128,6 +137,14 @@ void C_LocalTempEntity::SetVelocity( const Vector &vecVelocity ) m_vecTempEntVelocity = vecVelocity; } +//----------------------------------------------------------------------------- +// Sets the velocity +//----------------------------------------------------------------------------- +void C_LocalTempEntity::SetAcceleration( const Vector &vecVelocity ) +{ + m_vecTempEntAcceleration = vecVelocity; +} + //----------------------------------------------------------------------------- // Purpose: @@ -280,6 +297,8 @@ bool C_LocalTempEntity::Frame( float frametime, int framenumber ) m_vecPrevLocalOrigin = GetLocalOrigin(); + m_vecTempEntVelocity = m_vecTempEntVelocity + ( m_vecTempEntAcceleration * frametime ); + if ( flags & FTENT_PLYRATTACHMENT ) { if ( IClientEntity *pClient = cl_entitylist->GetClientEntity( clientIndex ) ) @@ -346,39 +365,73 @@ bool C_LocalTempEntity::Frame( float frametime, int framenumber ) { SetLocalAngles( GetLocalAngles() + m_vecTempEntAngVelocity * frametime ); } + else if ( flags & FTENT_ALIGNTOMOTION ) + { + if ( m_vecTempEntVelocity.Length() > 0.0f ) + { + QAngle angles; + VectorAngles( m_vecTempEntVelocity, angles ); + SetAbsAngles( angles ); + } + } if ( flags & (FTENT_COLLIDEALL | FTENT_COLLIDEWORLD) ) { Vector traceNormal; - traceNormal.Init(); + bool bShouldCollide = true; + + trace_t trace; if ( flags & FTENT_COLLIDEALL ) { - // If the FTENT_COLLISIONGROUP flag is set, use the entity's collision group - int collisionGroup = COLLISION_GROUP_NONE; - if ( flags & FTENT_COLLISIONGROUP ) + Vector vPrevOrigin = m_vecPrevLocalOrigin; + + if ( cl_fasttempentcollision.GetInt() > 0 && flags & FTENT_USEFASTCOLLISIONS ) { - collisionGroup = GetCollisionGroup(); + if ( m_iLastCollisionFrame + cl_fasttempentcollision.GetInt() > gpGlobals->framecount ) + { + bShouldCollide = false; + } + else + { + if ( m_vLastCollisionOrigin != vec3_origin ) + { + vPrevOrigin = m_vLastCollisionOrigin; + } + + m_iLastCollisionFrame = gpGlobals->framecount; + bShouldCollide = true; + } } - trace_t pm; - UTIL_TraceLine( m_vecPrevLocalOrigin, GetLocalOrigin(), MASK_SOLID, NULL, collisionGroup, &pm ); - - // Make sure it didn't bump into itself... (?!?) - if ( - (pm.fraction != 1) && - ( (pm.DidHitWorld()) || - (pm.m_pEnt != ClientEntityList().GetEnt(clientIndex)) ) - ) + if ( bShouldCollide == true ) { - traceFraction = pm.fraction; - VectorCopy( pm.plane.normal, traceNormal ); + // If the FTENT_COLLISIONGROUP flag is set, use the entity's collision group + int collisionGroup = COLLISION_GROUP_NONE; + if ( flags & FTENT_COLLISIONGROUP ) + { + collisionGroup = GetCollisionGroup(); + } + + UTIL_TraceLine( vPrevOrigin, GetLocalOrigin(), MASK_SOLID, GetOwnerEntity(), collisionGroup, &trace ); + + // Make sure it didn't bump into itself... (?!?) + if ( + (trace.fraction != 1) && + ( (trace.DidHitWorld()) || + (trace.m_pEnt != ClientEntityList().GetEnt(clientIndex)) ) + ) + { + traceFraction = trace.fraction; + VectorCopy( trace.plane.normal, traceNormal ); + } + + m_vLastCollisionOrigin = trace.endpos; } } else if ( flags & FTENT_COLLIDEWORLD ) { - trace_t trace; CTraceFilterWorldOnly traceFilter; UTIL_TraceLine( m_vecPrevLocalOrigin, GetLocalOrigin(), MASK_SOLID, &traceFilter, &trace ); if ( trace.fraction != 1 ) @@ -388,14 +441,10 @@ bool C_LocalTempEntity::Frame( float frametime, int framenumber ) } } - if ( traceFraction != 1 ) // Decent collision now, and damping works + if ( traceFraction != 1 ) // Decent collision now, and damping works { float proj, damp; - - // Place at contact point - Vector newOrigin; - VectorMA( m_vecPrevLocalOrigin, traceFraction*frametime, m_vecTempEntVelocity, newOrigin ); - SetLocalOrigin( newOrigin ); + SetLocalOrigin( trace.endpos ); // Damp velocity damp = bounceFactor; @@ -425,12 +474,67 @@ bool C_LocalTempEntity::Frame( float frametime, int framenumber ) tempents->PlaySound(this, damp); } + if ( m_pszImpactEffect ) + { + CEffectData data; + //data.m_vOrigin = newOrigin; + data.m_vOrigin = trace.endpos; + data.m_vStart = trace.startpos; + data.m_nSurfaceProp = trace.surface.surfaceProps; + data.m_nHitBox = trace.hitbox; + + data.m_nDamageType = TEAM_UNASSIGNED; + + IClientNetworkable *pClient = cl_entitylist->GetClientEntity( clientIndex ); + + if ( pClient ) + { + C_BasePlayer *pPlayer = dynamic_cast(pClient); + if( pPlayer ) + { + data.m_nDamageType = pPlayer->GetTeamNumber(); + } + } + + if ( trace.m_pEnt ) + { + data.m_hEntity = ClientEntityList().EntIndexToHandle( trace.m_pEnt->entindex() ); + } + DispatchEffect( m_pszImpactEffect, data ); + } + + // Check for a collision and stop the particle system. + if ( flags & FTENT_CLIENTSIDEPARTICLES ) + { + // Stop the emission of particles on collision - removed from the ClientEntityList on removal from the tempent pool. + ParticleProp()->StopEmission(); + m_bParticleCollision = true; + } + if (flags & FTENT_COLLIDEKILL) { // die on impact flags &= ~FTENT_FADEOUT; die = gpGlobals->curtime; } + else if ( flags & FTENT_ATTACHTOTARGET) + { + // If we've hit the world, just stop moving + if ( trace.DidHitWorld() && !( trace.surface.flags & SURF_SKY ) ) + { + m_vecTempEntVelocity = vec3_origin; + m_vecTempEntAcceleration = vec3_origin; + + // Remove movement flags so we don't keep tracing + flags &= ~(FTENT_COLLIDEALL | FTENT_COLLIDEWORLD); + } + else + { + // Couldn't attach to this entity. Die. + flags &= ~FTENT_FADEOUT; + die = gpGlobals->curtime; + } + } else { // Reflect velocity @@ -506,6 +610,28 @@ bool C_LocalTempEntity::Frame( float frametime, int framenumber ) return true; } +//----------------------------------------------------------------------------- +// Purpose: Attach a particle effect to a temp entity. +//----------------------------------------------------------------------------- +void C_LocalTempEntity::AddParticleEffect( const char *pszParticleEffect ) +{ + // Do we have a valid particle effect. + if ( !pszParticleEffect || ( pszParticleEffect[0] == '\0' ) ) + return; + + // Check to see that we don't already have a particle effect. + if ( ( flags & FTENT_CLIENTSIDEPARTICLES ) != 0 ) + return; + + // Add the entity to the ClientEntityList and create the particle system. + ClientEntityList().AddNonNetworkableEntity( this ); + ParticleProp()->Create( pszParticleEffect, PATTACH_ABSORIGIN_FOLLOW ); + + // Set the particle flag on the temp entity and save the name of the particle effect. + flags |= FTENT_CLIENTSIDEPARTICLES; + SetParticleEffect( pszParticleEffect ); +} + //----------------------------------------------------------------------------- // Purpose: This helper keeps track of batches of "breakmodels" so that they can all share the lighting origin // of the first of the group (because the server sends down 15 chunks at a time, and rebuilding 15 light cache @@ -1003,6 +1129,57 @@ void CTempEnts::PhysicsProp( int modelindex, int skin, const Vector& pos, const } } +//----------------------------------------------------------------------------- +// Purpose: Create a clientside projectile +// Input : vecOrigin - +// vecVelocity - +// modelindex - +// lifetime - +// *pOwner - +//----------------------------------------------------------------------------- +C_LocalTempEntity *CTempEnts::ClientProjectile( const Vector& vecOrigin, const Vector& vecVelocity, const Vector& vecAcceleration, int modelIndex, int lifetime, CBaseEntity *pOwner, const char *pszImpactEffect, const char *pszParticleEffect ) +{ + C_LocalTempEntity *pTemp; + const model_t *model; + + if ( !modelIndex ) + return NULL; + + model = modelinfo->GetModel( modelIndex ); + if ( !model ) + { + Warning("ClientProjectile: No model %d!\n", modelIndex); + return NULL; + } + + pTemp = TempEntAlloc( vecOrigin, ( model_t * )model ); + if (!pTemp) + return NULL; + + pTemp->SetVelocity( vecVelocity ); + pTemp->SetAcceleration( vecAcceleration ); + QAngle angles; + VectorAngles( vecVelocity, angles ); + pTemp->SetAbsAngles( angles ); + pTemp->SetAbsOrigin( vecOrigin ); + pTemp->die = gpGlobals->curtime + lifetime; + pTemp->flags = FTENT_COLLIDEALL | FTENT_ATTACHTOTARGET | FTENT_ALIGNTOMOTION; + pTemp->clientIndex = ( pOwner != NULL ) ? pOwner->entindex() : 0; + pTemp->SetOwnerEntity( pOwner ); + pTemp->SetImpactEffect( pszImpactEffect ); + if ( pszParticleEffect ) + { + // Add the entity to the ClientEntityList and create the particle system. + ClientEntityList().AddNonNetworkableEntity( pTemp ); + pTemp->ParticleProp()->Create( pszParticleEffect, PATTACH_ABSORIGIN_FOLLOW ); + + // Set the particle flag on the temp entity and save the name of the particle effect. + pTemp->flags |= FTENT_CLIENTSIDEPARTICLES; + pTemp->SetParticleEffect( pszParticleEffect ); + } + return pTemp; +} + //----------------------------------------------------------------------------- // Purpose: Create sprite TE // Input : *pos - @@ -1636,6 +1813,9 @@ void CTempEnts::MuzzleFlash( const Vector& pos1, const QAngle& angles, int type, // UNDONE: These need their own effects/sprites. For now use the pistol // SMG1 +#if defined ( HL2MP ) // HACK for hl2mp, make the default muzzleflash the smg muzzleflash for weapons like the RPG that are using 'type 0' + default: +#endif // HL2MP case MUZZLEFLASH_SMG1: if ( firstPerson ) { @@ -1672,11 +1852,12 @@ void CTempEnts::MuzzleFlash( const Vector& pos1, const QAngle& angles, int type, MuzzleFlash_Combine_NPC( hEntity, 1 ); } break; - +#if !defined ( HL2MP ) // HACK for hl2mp, make the default muzzleflash the smg muzzleflash for weapons like the RPG that are using 'type 0' default: // There's no supported muzzle flash for the type specified! Assert(0); break; +#endif // HL2MP } #endif @@ -1823,6 +2004,17 @@ void CTempEnts::TempEntFree( int index ) // Cleanup its data. pTemp->RemoveFromLeafSystem(); + // Remove the tempent from the ClientEntityList before removing it from the pool. + if ( ( pTemp->flags & FTENT_CLIENTSIDEPARTICLES ) ) + { + // Stop the particle emission if this hasn't happened already - collision or system timing out on its own. + if ( !pTemp->m_bParticleCollision ) + { + pTemp->ParticleProp()->StopEmission(); + } + ClientEntityList().RemoveEntity( pTemp->GetRefEHandle() ); + } + pTemp->OnRemoveTempEntity(); m_TempEntsPool.Free( pTemp ); @@ -2103,6 +2295,7 @@ int CTempEnts::AddVisibleTempEntity( C_LocalTempEntity *pEntity ) //----------------------------------------------------------------------------- void CTempEnts::Update(void) { + VPROF_("CTempEnts::Update", 1, VPROF_BUDGETGROUP_CLIENT_SIM, false, BUDGETFLAG_CLIENT); static int gTempEntFrame = 0; float frametime; @@ -2169,6 +2362,7 @@ void CTempEnts::Update(void) // Recache tempents which might have been flushed void CTempEnts::LevelInit() { +#ifndef TF_CLIENT_DLL m_pSpriteMuzzleFlash[0] = (model_t *)engine->LoadModel( "sprites/ar2_muzzle1.vmt" ); m_pSpriteMuzzleFlash[1] = (model_t *)engine->LoadModel( "sprites/muzzleflash4.vmt" ); m_pSpriteMuzzleFlash[2] = (model_t *)engine->LoadModel( "sprites/muzzleflash4.vmt" ); @@ -2184,6 +2378,7 @@ void CTempEnts::LevelInit() m_pShells[0] = (model_t *) engine->LoadModel( "models/weapons/shell.mdl" ); m_pShells[1] = (model_t *) engine->LoadModel( "models/weapons/rifleshell.mdl" ); m_pShells[2] = (model_t *) engine->LoadModel( "models/weapons/shotgun_shell.mdl" ); +#endif #if defined( HL1_CLIENT_DLL ) m_pHL1Shell = (model_t *)engine->LoadModel( "models/shell.mdl" ); @@ -2375,8 +2570,8 @@ void CTempEnts::MuzzleFlash_Combine_Player( ClientEntityHandle_t hEntity, int at //----------------------------------------------------------------------------- void CTempEnts::MuzzleFlash_Combine_NPC( ClientEntityHandle_t hEntity, int attachmentIndex ) { - VPROF_BUDGET( "MuzzleFlash_Strider", VPROF_BUDGETGROUP_PARTICLE_RENDERING ); - CSmartPtr pSimple = CLocalSpaceEmitter::Create( "MuzzleFlash_Strider", hEntity, attachmentIndex ); + VPROF_BUDGET( "MuzzleFlash_Combine_NPC", VPROF_BUDGETGROUP_PARTICLE_RENDERING ); + CSmartPtr pSimple = CLocalSpaceEmitter::Create( "MuzzleFlash_Combine_NPC", hEntity, attachmentIndex ); SimpleParticle *pParticle; Vector forward(1,0,0), offset; //NOTENOTE: All coords are in local space @@ -2392,8 +2587,7 @@ void CTempEnts::MuzzleFlash_Combine_NPC( ClientEntityHandle_t hEntity, int attac { offset = (forward * (i*2.0f*flScale)); - pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), pSimple->GetPMaterial( VarArgs( "effects/combinemuzzle%d", random->RandomInt(1,2) ) ), offset ); - + pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Mat_Combine_Muzzleflash[random->RandomInt(0,1)], offset ); if ( pParticle == NULL ) return; @@ -2427,7 +2621,7 @@ void CTempEnts::MuzzleFlash_Combine_NPC( ClientEntityHandle_t hEntity, int attac { offset = (dir * (i*flScale)); - pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), pSimple->GetPMaterial( VarArgs( "effects/combinemuzzle%d", random->RandomInt(1,2) ) ), offset ); + pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Mat_Combine_Muzzleflash[random->RandomInt(0,1)], offset ); if ( pParticle == NULL ) return; @@ -2458,8 +2652,7 @@ void CTempEnts::MuzzleFlash_Combine_NPC( ClientEntityHandle_t hEntity, int attac { offset = (-dir * (i*flScale)); - pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), pSimple->GetPMaterial( VarArgs( "effects/combinemuzzle%d", random->RandomInt(1,2) ) ), offset ); - + pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Mat_Combine_Muzzleflash[random->RandomInt(0,1)], offset ); if ( pParticle == NULL ) return; @@ -2489,8 +2682,7 @@ void CTempEnts::MuzzleFlash_Combine_NPC( ClientEntityHandle_t hEntity, int attac { offset = (dir * (i*flScale)); - pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), pSimple->GetPMaterial( VarArgs( "effects/combinemuzzle%d", random->RandomInt(1,2) ) ), offset ); - + pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Mat_Combine_Muzzleflash[random->RandomInt(0,1)], offset ); if ( pParticle == NULL ) return; @@ -2512,8 +2704,7 @@ void CTempEnts::MuzzleFlash_Combine_NPC( ClientEntityHandle_t hEntity, int attac pParticle->m_flRollDelta = 0.0f; } - pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), pSimple->GetPMaterial( "effects/strider_muzzle" ), vec3_origin ); - + pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Mat_Combine_Muzzleflash[2], vec3_origin ); if ( pParticle == NULL ) return; @@ -2734,7 +2925,7 @@ void CTempEnts::MuzzleFlash_Shotgun_NPC( ClientEntityHandle_t hEntity, int attac for ( int i = 0; i < numEmbers; i++ ) { - pParticle = (SimpleParticle *) pEmbers->AddParticle( sizeof( SimpleParticle ), pEmbers->GetPMaterial( "effects/muzzleflash1" ), origin ); + pParticle = (SimpleParticle *) pEmbers->AddParticle( sizeof( SimpleParticle ), g_Mat_SMG_Muzzleflash[0], origin ); if ( pParticle == NULL ) return; @@ -2779,7 +2970,7 @@ void CTempEnts::MuzzleFlash_Shotgun_NPC( ClientEntityHandle_t hEntity, int attac for ( i = 0; i < numEmbers; i++ ) { - pTrailParticle = (TrailParticle *) pTrails->AddParticle( sizeof( TrailParticle ), pTrails->GetPMaterial( "effects/muzzleflash1" ), origin ); + pTrailParticle = (TrailParticle *) pTrails->AddParticle( sizeof( TrailParticle ), g_Mat_SMG_Muzzleflash[0], origin ); if ( pTrailParticle == NULL ) return; @@ -2836,7 +3027,7 @@ void CTempEnts::MuzzleFlash_357_Player( ClientEntityHandle_t hEntity, int attach // Smoke offset = origin + forward * 8.0f; - pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), pSimple->GetPMaterial( "particle/particle_smokegrenade" ), offset ); + pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Mat_DustPuff[0], offset ); if ( pParticle == NULL ) return; @@ -2924,7 +3115,7 @@ void CTempEnts::MuzzleFlash_Pistol_Player( ClientEntityHandle_t hEntity, int att if ( random->RandomInt( 0, 3 ) != 0 ) { - pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), pSimple->GetPMaterial( "particle/particle_smokegrenade" ), offset ); + pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Mat_DustPuff[0], offset ); if ( pParticle == NULL ) return; @@ -3205,3 +3396,4 @@ void CTempEnts::CSEjectBrass( const Vector &vecPosition, const QAngle &angVeloci } + diff --git a/src/src/cl_dll/c_te_legacytempents.h b/src/src/game/client/c_te_legacytempents.h similarity index 95% rename from src/src/cl_dll/c_te_legacytempents.h rename to src/src/game/client/c_te_legacytempents.h index 59eef8b..47743b6 100644 --- a/src/src/cl_dll/c_te_legacytempents.h +++ b/src/src/game/client/c_te_legacytempents.h @@ -71,6 +71,7 @@ public: virtual void PlaySound ( C_LocalTempEntity *pTemp, float damp ) = 0; virtual void PhysicsProp( int modelindex, int skin, const Vector& pos, const QAngle &angles, const Vector& vel, int flags, int effects = 0 ) = 0; + virtual C_LocalTempEntity *ClientProjectile( const Vector& vecOrigin, const Vector& vecVelocity, const Vector& vecAccel, int modelindex, int lifetime, CBaseEntity *pOwner, const char *pszImpactEffect = NULL, const char *pszParticleEffect = NULL ) = 0; }; @@ -122,6 +123,7 @@ public: void HL1EjectBrass( const Vector &vecPosition, const QAngle &angAngles, const Vector &vecVelocity, int nType ); void CSEjectBrass( const Vector &vecPosition, const QAngle &angAngles, int nType, int nShellType, CBasePlayer *pShooter ); void PhysicsProp( int modelindex, int skin, const Vector& pos, const QAngle &angles, const Vector& vel, int flags, int effects = 0 ); + C_LocalTempEntity *ClientProjectile( const Vector& vecOrigin, const Vector& vecVelocity, const Vector& vecAcceleration, int modelindex, int lifetime, CBaseEntity *pOwner, const char *pszImpactEffect = NULL, const char *pszParticleEffect = NULL ); // Data private: diff --git a/src/src/cl_dll/c_te_muzzleflash.cpp b/src/src/game/client/c_te_muzzleflash.cpp similarity index 97% rename from src/src/cl_dll/c_te_muzzleflash.cpp rename to src/src/game/client/c_te_muzzleflash.cpp index 5b85d57..be67f06 100644 --- a/src/src/cl_dll/c_te_muzzleflash.cpp +++ b/src/src/game/client/c_te_muzzleflash.cpp @@ -9,6 +9,8 @@ #include "IEffects.h" #include "tier1/keyvalues.h" #include "toolframework_client.h" +#include "tier0/vprof.h" + // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -88,6 +90,8 @@ static inline void RecordMuzzleFlash( const Vector &start, const QAngle &angles, //----------------------------------------------------------------------------- void C_TEMuzzleFlash::PostDataUpdate( DataUpdateType_t updateType ) { + VPROF( "C_TEMuzzleFlash::PostDataUpdate" ); + //FIXME: Index is incorrect g_pEffects->MuzzleFlash( m_vecOrigin, m_vecAngles, m_flScale, m_nType ); RecordMuzzleFlash( m_vecOrigin, m_vecAngles, m_flScale, m_nType ); diff --git a/src/src/cl_dll/c_te_particlesystem.cpp b/src/src/game/client/c_te_particlesystem.cpp similarity index 100% rename from src/src/cl_dll/c_te_particlesystem.cpp rename to src/src/game/client/c_te_particlesystem.cpp diff --git a/src/src/cl_dll/c_te_particlesystem.h b/src/src/game/client/c_te_particlesystem.h similarity index 100% rename from src/src/cl_dll/c_te_particlesystem.h rename to src/src/game/client/c_te_particlesystem.h diff --git a/src/src/cl_dll/c_te_physicsprop.cpp b/src/src/game/client/c_te_physicsprop.cpp similarity index 98% rename from src/src/cl_dll/c_te_physicsprop.cpp rename to src/src/game/client/c_te_physicsprop.cpp index 02da5a0..aeacdb5 100644 --- a/src/src/cl_dll/c_te_physicsprop.cpp +++ b/src/src/game/client/c_te_physicsprop.cpp @@ -11,6 +11,7 @@ #include "c_te_legacytempents.h" #include "tier1/keyvalues.h" #include "toolframework_client.h" +#include "tier0/vprof.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -133,6 +134,8 @@ void TE_PhysicsProp( IRecipientFilter& filter, float delay, //----------------------------------------------------------------------------- void C_TEPhysicsProp::PostDataUpdate( DataUpdateType_t updateType ) { + VPROF( "C_TEPhysicsProp::PostDataUpdate" ); + tempents->PhysicsProp( m_nModelIndex, m_nSkin, m_vecOrigin, m_angRotation, m_vecVelocity, m_nFlags, m_nEffects ); RecordPhysicsProp( m_vecOrigin, m_angRotation, m_vecVelocity, m_nModelIndex, m_nFlags, m_nSkin, m_nEffects ); } diff --git a/src/src/cl_dll/c_te_playerdecal.cpp b/src/src/game/client/c_te_playerdecal.cpp similarity index 93% rename from src/src/cl_dll/c_te_playerdecal.cpp rename to src/src/game/client/c_te_playerdecal.cpp index 77d03d3..f539854 100644 --- a/src/src/cl_dll/c_te_playerdecal.cpp +++ b/src/src/game/client/c_te_playerdecal.cpp @@ -15,11 +15,15 @@ #include "filesystem.h" #include "materialsystem/imaterial.h" #include "materialsystem/itexture.h" +#include "materialsystem/imaterialvar.h" #include "ClientEffectPrecacheSystem.h" +#include "tier0/vprof.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" +static ConVar cl_playerspraydisable( "cl_playerspraydisable", "0", FCVAR_CLIENTDLL | FCVAR_ARCHIVE, "Disable player sprays." ); + #ifndef _XBOX CLIENTEFFECT_REGISTER_BEGIN( PrecachePlayerDecal ) CLIENTEFFECT_MATERIAL( "decals/playerlogo01" ) @@ -158,7 +162,9 @@ void C_TEPlayerDecal::Precache( void ) void TE_PlayerDecal( IRecipientFilter& filter, float delay, const Vector* pos, int player, int entity ) { -#ifndef _XBOX + if ( cl_playerspraydisable.GetBool() ) + return; + // No valid target? C_BaseEntity *ent = cl_entitylist->GetEnt( entity ); if ( !ent ) @@ -206,6 +212,18 @@ void TE_PlayerDecal( IRecipientFilter& filter, float delay, return; // not found } + // Update the texture used by the material if need be. + bool bFound = false; + IMaterialVar *pMatVar = logo->FindVar( "$basetexture", &bFound ); + if ( bFound && pMatVar ) + { + if ( pMatVar->GetTextureValue() != texture ) + { + pMatVar->SetTextureValue( texture ); + logo->RefreshPreservingMaterialVars(); + } + } + color32 rgbaColor = { 255, 255, 255, 255 }; effects->PlayerDecalShoot( logo, @@ -218,7 +236,6 @@ void TE_PlayerDecal( IRecipientFilter& filter, float delay, 0, 0, rgbaColor ); -#endif } //----------------------------------------------------------------------------- @@ -228,6 +245,8 @@ void TE_PlayerDecal( IRecipientFilter& filter, float delay, void C_TEPlayerDecal::PostDataUpdate( DataUpdateType_t updateType ) { #ifndef _XBOX + VPROF( "C_TEPlayerDecal::PostDataUpdate" ); + // Decals disabled? if ( !r_decals.GetBool() ) return; diff --git a/src/src/cl_dll/c_te_projecteddecal.cpp b/src/src/game/client/c_te_projecteddecal.cpp similarity index 98% rename from src/src/cl_dll/c_te_projecteddecal.cpp rename to src/src/game/client/c_te_projecteddecal.cpp index 0e62821..60c6e82 100644 --- a/src/src/cl_dll/c_te_projecteddecal.cpp +++ b/src/src/game/client/c_te_projecteddecal.cpp @@ -12,6 +12,7 @@ #include "engine/IStaticPropMgr.h" #include "tier1/keyvalues.h" #include "toolframework_client.h" +#include "tier0/vprof.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -153,6 +154,8 @@ void TE_ProjectDecal( IRecipientFilter& filter, float delay, //----------------------------------------------------------------------------- void C_TEProjectedDecal::PostDataUpdate( DataUpdateType_t updateType ) { + VPROF( "C_TEProjectedDecal::PostDataUpdate" ); + CBroadcastRecipientFilter filter; TE_ProjectDecal( filter, 0.0f, &m_vecOrigin, &m_angRotation, m_flDistance, m_nIndex ); } diff --git a/src/src/cl_dll/c_te_showline.cpp b/src/src/game/client/c_te_showline.cpp similarity index 100% rename from src/src/cl_dll/c_te_showline.cpp rename to src/src/game/client/c_te_showline.cpp diff --git a/src/src/cl_dll/c_te_smoke.cpp b/src/src/game/client/c_te_smoke.cpp similarity index 98% rename from src/src/cl_dll/c_te_smoke.cpp rename to src/src/game/client/c_te_smoke.cpp index 131bd22..cc136c3 100644 --- a/src/src/cl_dll/c_te_smoke.cpp +++ b/src/src/game/client/c_te_smoke.cpp @@ -11,6 +11,7 @@ #include "IEffects.h" #include "tier1/keyvalues.h" #include "toolframework_client.h" +#include "tier0/vprof.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -87,6 +88,8 @@ static inline void RecordSmoke( const Vector &start, float flScale, int nFrameRa //----------------------------------------------------------------------------- void C_TESmoke::PostDataUpdate( DataUpdateType_t updateType ) { + VPROF( "C_TESmoke::PostDataUpdate" ); + // The number passed down is 10 times smaller... g_pEffects->Smoke( m_vecOrigin, m_nModelIndex, m_fScale * 10.0f, m_nFrameRate ); RecordSmoke( m_vecOrigin, m_fScale * 10.0f, m_nFrameRate ); diff --git a/src/src/cl_dll/c_te_sparks.cpp b/src/src/game/client/c_te_sparks.cpp similarity index 100% rename from src/src/cl_dll/c_te_sparks.cpp rename to src/src/game/client/c_te_sparks.cpp diff --git a/src/src/cl_dll/c_te_sprite.cpp b/src/src/game/client/c_te_sprite.cpp similarity index 98% rename from src/src/cl_dll/c_te_sprite.cpp rename to src/src/game/client/c_te_sprite.cpp index 8e70676..d61eba8 100644 --- a/src/src/cl_dll/c_te_sprite.cpp +++ b/src/src/game/client/c_te_sprite.cpp @@ -12,6 +12,7 @@ #include "tempent.h" #include "tier1/keyvalues.h" #include "toolframework_client.h" +#include "tier0/vprof.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -105,6 +106,8 @@ static inline void RecordSprite( const Vector& start, int nModelIndex, //----------------------------------------------------------------------------- void C_TESprite::PostDataUpdate( DataUpdateType_t updateType ) { + VPROF( "C_TESprite::PostDataUpdate" ); + float a = ( 1.0 / 255.0 ) * m_nBrightness; tempents->TempSprite( m_vecOrigin, vec3_origin, m_fScale, m_nModelIndex, kRenderTransAdd, 0, a, 0, FTENT_SPRANIMATE ); RecordSprite( m_vecOrigin, m_nModelIndex, m_fScale, m_nBrightness ); diff --git a/src/src/cl_dll/c_te_spritespray.cpp b/src/src/game/client/c_te_spritespray.cpp similarity index 98% rename from src/src/cl_dll/c_te_spritespray.cpp rename to src/src/game/client/c_te_spritespray.cpp index 4959e24..5004916 100644 --- a/src/src/cl_dll/c_te_spritespray.cpp +++ b/src/src/game/client/c_te_spritespray.cpp @@ -9,6 +9,8 @@ #include "c_te_legacytempents.h" #include "tier1/keyvalues.h" #include "toolframework_client.h" +#include "tier0/vprof.h" + // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -111,6 +113,8 @@ static inline void RecordSpriteSpray( const Vector& start, const Vector &directi //----------------------------------------------------------------------------- void C_TESpriteSpray::PostDataUpdate( DataUpdateType_t updateType ) { + VPROF( "C_TESpriteSpray::PostDataUpdate" ); + tempents->Sprite_Spray( m_vecOrigin, m_vecDirection, m_nModelIndex, m_nCount, m_nSpeed * 0.2, m_fNoise * 100.0 ); RecordSpriteSpray( m_vecOrigin, m_vecDirection, m_nModelIndex, m_nSpeed, m_fNoise, m_nCount ); } diff --git a/src/src/cl_dll/c_te_worlddecal.cpp b/src/src/game/client/c_te_worlddecal.cpp similarity index 98% rename from src/src/cl_dll/c_te_worlddecal.cpp rename to src/src/game/client/c_te_worlddecal.cpp index dc3efae..5403853 100644 --- a/src/src/cl_dll/c_te_worlddecal.cpp +++ b/src/src/game/client/c_te_worlddecal.cpp @@ -10,6 +10,7 @@ #include "tier1/keyvalues.h" #include "toolframework_client.h" #include "fx.h" +#include "tier0/vprof.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -98,6 +99,8 @@ static inline void RecordWorldDecal( const Vector *pos, int index ) //----------------------------------------------------------------------------- void C_TEWorldDecal::PostDataUpdate( DataUpdateType_t updateType ) { + VPROF( "C_TEWorldDecal::PostDataUpdate" ); + if ( r_decals.GetInt() ) { C_BaseEntity *ent = cl_entitylist->GetEnt( 0 ); diff --git a/src/src/cl_dll/c_team.cpp b/src/src/game/client/c_team.cpp similarity index 88% rename from src/src/cl_dll/c_team.cpp rename to src/src/game/client/c_team.cpp index 76f297d..bbf35e1 100644 --- a/src/src/cl_dll/c_team.cpp +++ b/src/src/game/client/c_team.cpp @@ -32,6 +32,7 @@ void RecvProxyArrayLength_PlayerArray( void *pStruct, int objectID, int currentA IMPLEMENT_CLIENTCLASS_DT_NOBASE(C_Team, DT_Team, CTeam) RecvPropInt( RECVINFO(m_iTeamNum)), RecvPropInt( RECVINFO(m_iScore)), + RecvPropInt( RECVINFO(m_iRoundsWon) ), RecvPropString( RECVINFO(m_szTeamname)), RecvPropArray2( @@ -43,6 +44,16 @@ IMPLEMENT_CLIENTCLASS_DT_NOBASE(C_Team, DT_Team, CTeam) ) END_RECV_TABLE() +BEGIN_PREDICTION_DATA( C_Team ) + DEFINE_PRED_ARRAY( m_szTeamname, FIELD_CHARACTER, MAX_TEAM_NAME_LENGTH, FTYPEDESC_PRIVATE ), + DEFINE_PRED_FIELD( m_iScore, FIELD_INTEGER, FTYPEDESC_PRIVATE ), + DEFINE_PRED_FIELD( m_iRoundsWon, FIELD_INTEGER, FTYPEDESC_PRIVATE ), + DEFINE_PRED_FIELD( m_iDeaths, FIELD_INTEGER, FTYPEDESC_PRIVATE ), + DEFINE_PRED_FIELD( m_iPing, FIELD_INTEGER, FTYPEDESC_PRIVATE ), + DEFINE_PRED_FIELD( m_iPacketloss, FIELD_INTEGER, FTYPEDESC_PRIVATE ), + DEFINE_PRED_FIELD( m_iTeamNum, FIELD_INTEGER, FTYPEDESC_PRIVATE ), +END_PREDICTION_DATA(); + // Global list of client side team entities CUtlVector< C_Team * > g_Teams; @@ -55,6 +66,7 @@ CUtlVector< C_Team * > g_Teams; C_Team::C_Team() { m_iScore = 0; + m_iRoundsWon = 0; memset( m_szTeamname, 0, sizeof(m_szTeamname) ); m_iDeaths = 0; @@ -94,7 +106,7 @@ C_BasePlayer* C_Team::GetPlayer( int idx ) } -int C_Team::GetTeamNumber() +int C_Team::GetTeamNumber() const { return m_iTeamNum; } @@ -234,3 +246,11 @@ bool ArePlayersOnSameTeam( int iPlayerIndex1, int iPlayerIndex2 ) return false; } + +//----------------------------------------------------------------------------- +// Purpose: Get the number of team managers +//----------------------------------------------------------------------------- +int GetNumberOfTeams( void ) +{ + return g_Teams.Size(); +} \ No newline at end of file diff --git a/src/src/cl_dll/c_team.h b/src/src/game/client/c_team.h similarity index 85% rename from src/src/cl_dll/c_team.h rename to src/src/game/client/c_team.h index f93891e..1957f2a 100644 --- a/src/src/cl_dll/c_team.h +++ b/src/src/game/client/c_team.h @@ -23,6 +23,7 @@ class C_Team : public C_BaseEntity DECLARE_CLASS( C_Team, C_BaseEntity ); public: DECLARE_CLIENTCLASS(); + DECLARE_PREDICTABLE(); C_Team(); virtual ~C_Team(); @@ -40,7 +41,12 @@ public: virtual bool ContainsPlayer( int iPlayerIndex ); C_BasePlayer* GetPlayer( int idx ); - int GetTeamNumber(); + // for shared code, use the same function name + virtual int GetNumPlayers( void ) { return Get_Number_Players(); } + + int GetTeamNumber() const; + + int GetRoundsWon(void) { return m_iRoundsWon; } void RemoveAllPlayers(); @@ -57,6 +63,7 @@ public: CUtlVector< int > m_aPlayers; char m_szTeamname[ MAX_TEAM_NAME_LENGTH ]; int m_iScore; + int m_iRoundsWon; // Data for the scoreboard int m_iDeaths; @@ -75,5 +82,6 @@ C_Team *GetGlobalTeam( int iTeamNumber ); C_Team *GetPlayersTeam( int iPlayerIndex ); C_Team *GetPlayersTeam( C_BasePlayer *pPlayer ); bool ArePlayersOnSameTeam( int iPlayerIndex1, int iPlayerIndex2 ); +extern int GetNumberOfTeams( void ); #endif // C_TEAM_H diff --git a/src/src/game/client/c_team_objectiveresource.cpp b/src/src/game/client/c_team_objectiveresource.cpp new file mode 100644 index 0000000..8819695 --- /dev/null +++ b/src/src/game/client/c_team_objectiveresource.cpp @@ -0,0 +1,401 @@ +//====== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======= +// +// Purpose: An entity that networks the state of the game's objectives. +// +//============================================================================= + +#include "cbase.h" +#include "c_team_objectiveresource.h" +#include "igameevents.h" +#include "teamplayroundbased_gamerules.h" +#include "c_baseplayer.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +#define RESOURCE_THINK_TIME 0.1 + +extern ConVar mp_capstyle; +extern ConVar mp_capdeteriorate_time; + +//----------------------------------------------------------------------------- +// Purpose: Owner recv proxy +//----------------------------------------------------------------------------- +void RecvProxy_Owner( const CRecvProxyData *pData, void *pStruct, void *pOut ) +{ + // hacks? Not sure how else to get the index of the integer that is + // being transmitted. + int index = pData->m_pRecvProp->GetOffset() / sizeof(int); + + ObjectiveResource()->SetOwningTeam( index, pData->m_Value.m_Int ); +} + +//----------------------------------------------------------------------------- +// Purpose: capper recv proxy +//----------------------------------------------------------------------------- +void RecvProxy_CappingTeam( const CRecvProxyData *pData, void *pStruct, void *pOut ) +{ + int index = pData->m_pRecvProp->GetOffset() / sizeof(int); + + ObjectiveResource()->SetCappingTeam( index, pData->m_Value.m_Int ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void RecvProxy_CapLayout( const CRecvProxyData *pData, void *pStruct, void *pOut ) +{ + ObjectiveResource()->SetCapLayout( pData->m_Value.m_pString ); +} + +IMPLEMENT_CLIENTCLASS_DT_NOBASE(C_BaseTeamObjectiveResource, DT_BaseTeamObjectiveResource, CBaseTeamObjectiveResource) + RecvPropInt( RECVINFO(m_iTimerToShowInHUD) ), + RecvPropInt( RECVINFO(m_iStopWatchTimer) ), + + RecvPropInt( RECVINFO(m_iNumControlPoints) ), + RecvPropBool( RECVINFO(m_bPlayingMiniRounds) ), + RecvPropBool( RECVINFO(m_bControlPointsReset) ), + RecvPropInt( RECVINFO(m_iUpdateCapHudParity) ), + + RecvPropArray( RecvPropVector(RECVINFO(m_vCPPositions[0])), m_vCPPositions), + RecvPropArray3( RECVINFO_ARRAY(m_bCPIsVisible), RecvPropInt( RECVINFO(m_bCPIsVisible[0]) ) ), + RecvPropArray3( RECVINFO_ARRAY(m_flLazyCapPerc), RecvPropFloat( RECVINFO(m_flLazyCapPerc[0]) ) ), + RecvPropArray3( RECVINFO_ARRAY(m_iTeamIcons), RecvPropInt( RECVINFO(m_iTeamIcons[0]) ) ), + RecvPropArray3( RECVINFO_ARRAY(m_iTeamOverlays), RecvPropInt( RECVINFO(m_iTeamOverlays[0]) ) ), + RecvPropArray3( RECVINFO_ARRAY(m_iTeamReqCappers), RecvPropInt( RECVINFO(m_iTeamReqCappers[0]) ) ), + RecvPropArray3( RECVINFO_ARRAY(m_flTeamCapTime), RecvPropTime( RECVINFO(m_flTeamCapTime[0]) ) ), + RecvPropArray3( RECVINFO_ARRAY(m_iPreviousPoints), RecvPropInt( RECVINFO(m_iPreviousPoints[0]) ) ), + RecvPropArray3( RECVINFO_ARRAY(m_bTeamCanCap), RecvPropBool( RECVINFO(m_bTeamCanCap[0]) ) ), + RecvPropArray3( RECVINFO_ARRAY(m_iTeamBaseIcons), RecvPropInt( RECVINFO(m_iTeamBaseIcons[0]) ) ), + RecvPropArray3( RECVINFO_ARRAY(m_iBaseControlPoints), RecvPropInt( RECVINFO(m_iBaseControlPoints[0]) ) ), + RecvPropArray3( RECVINFO_ARRAY(m_bInMiniRound), RecvPropBool( RECVINFO(m_bInMiniRound[0]) ) ), + RecvPropArray3( RECVINFO_ARRAY(m_iWarnOnCap), RecvPropInt( RECVINFO(m_iWarnOnCap[0]) ) ), + RecvPropArray( RecvPropString( RECVINFO( m_iszWarnSound[0]) ), m_iszWarnSound ), + RecvPropArray3( RECVINFO_ARRAY(m_flPathDistance), RecvPropFloat( RECVINFO(m_flPathDistance[0]) ) ), + + // state variables + RecvPropArray3( RECVINFO_ARRAY(m_iNumTeamMembers), RecvPropInt( RECVINFO(m_iNumTeamMembers[0]) ) ), + RecvPropArray3( RECVINFO_ARRAY(m_iCappingTeam), RecvPropInt( RECVINFO(m_iCappingTeam[0]), 0, RecvProxy_CappingTeam ) ), + RecvPropArray3( RECVINFO_ARRAY(m_iTeamInZone), RecvPropInt( RECVINFO(m_iTeamInZone[0]) ) ), + RecvPropArray3( RECVINFO_ARRAY(m_bBlocked), RecvPropInt( RECVINFO(m_bBlocked[0]) ) ), + RecvPropArray3( RECVINFO_ARRAY(m_iOwner), RecvPropInt( RECVINFO(m_iOwner[0]), 0, RecvProxy_Owner ) ), + RecvPropString( RECVINFO(m_pszCapLayoutInHUD), 0, RecvProxy_CapLayout ), +END_RECV_TABLE() + +C_BaseTeamObjectiveResource *g_pObjectiveResource = NULL; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_BaseTeamObjectiveResource::C_BaseTeamObjectiveResource() +{ + m_iNumControlPoints = 0; + m_iPrevNumControlPoints = 0; + m_pszCapLayoutInHUD[0] = 0; + m_iUpdateCapHudParity = 0; + m_bControlPointsReset = false; + + for ( int i=0; i < MAX_CONTROL_POINTS; i++ ) + { + m_flCapTimeLeft[i] = 0; + m_flCapLastThinkTime[i] = 0; + m_flLastCapWarningTime[i] = 0; + m_bWarnedOnFinalCap[i] = false; // have we warned + m_iWarnOnCap[i] = CP_WARN_NORMAL; // should we warn + m_iszWarnSound[i][0] = 0; // what sound should be played + m_flLazyCapPerc[i] = 0.0; + + for ( int team = 0; team < MAX_CONTROL_POINT_TEAMS; team++ ) + { + int iTeamIndex = TEAM_ARRAY( i, team ); + + m_iTeamIcons[ iTeamIndex ] = 0; + m_iTeamOverlays[ iTeamIndex ] = 0; + m_iTeamReqCappers[ iTeamIndex ] = 0; + m_flTeamCapTime[ iTeamIndex ] = 0.0f; + m_iNumTeamMembers[ iTeamIndex ] = 0; + for ( int ipoint = 0; ipoint < MAX_PREVIOUS_POINTS; ipoint++ ) + { + int iIntIndex = ipoint + (i * MAX_PREVIOUS_POINTS) + (team * MAX_CONTROL_POINTS * MAX_PREVIOUS_POINTS); + m_iPreviousPoints[ iIntIndex ] = -1; + } + } + } + + for ( int team = 0; team < MAX_CONTROL_POINT_TEAMS; team++ ) + { + m_iTeamBaseIcons[team] = 0; + } + + g_pObjectiveResource = this; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_BaseTeamObjectiveResource::~C_BaseTeamObjectiveResource() +{ + g_pObjectiveResource = NULL; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_BaseTeamObjectiveResource::OnPreDataChanged( DataUpdateType_t updateType ) +{ + BaseClass::OnPreDataChanged( updateType ); + + m_iPrevNumControlPoints = m_iNumControlPoints; + m_iOldUpdateCapHudParity = m_iUpdateCapHudParity; + m_bOldControlPointsReset = m_bControlPointsReset; + + memcpy( m_flOldLazyCapPerc, m_flLazyCapPerc, sizeof(float)*m_iNumControlPoints ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_BaseTeamObjectiveResource::OnDataChanged( DataUpdateType_t updateType ) +{ + BaseClass::OnDataChanged( updateType ); + + if ( m_bOldControlPointsReset != m_bControlPointsReset || m_iNumControlPoints != m_iPrevNumControlPoints ) + { + // Tell everyone we know how many control points we have + IGameEvent *event = gameeventmanager->CreateEvent( "controlpoint_initialized" ); + if ( event ) + { + gameeventmanager->FireEventClientSide( event ); + } + } + + if ( m_iUpdateCapHudParity != m_iOldUpdateCapHudParity ) + { + UpdateControlPoint( "controlpoint_updateimages" ); + } + + for ( int i = 0; i < m_iNumControlPoints; i++ ) + { + if ( m_flOldLazyCapPerc[i] != m_flLazyCapPerc[i] ) + { + m_flCapTimeLeft[i] = m_flLazyCapPerc[i] * m_flTeamCapTime[ TEAM_ARRAY(i,m_iCappingTeam[i]) ]; + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_BaseTeamObjectiveResource::UpdateControlPoint( const char *pszEvent, int index ) +{ + IGameEvent *event = gameeventmanager->CreateEvent( pszEvent ); + if ( event ) + { + event->SetInt( "index", index ); + gameeventmanager->FireEventClientSide( event ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +float C_BaseTeamObjectiveResource::GetCPCapPercentage( int index ) +{ + Assert( 0 <= index && index <= m_iNumControlPoints ); + + float flCapLength = m_flTeamCapTime[ TEAM_ARRAY(index,m_iCappingTeam[index]) ]; + + if( flCapLength <= 0 ) + return 0.0f; + + float flElapsedTime = flCapLength - m_flCapTimeLeft[index]; + + if( flElapsedTime > flCapLength ) + return 1.0f; + + return ( flElapsedTime / flCapLength ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +int C_BaseTeamObjectiveResource::GetNumControlPointsOwned( void ) +{ + C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); + if ( !pPlayer ) + return 0; + + int iTeam = pPlayer->GetTeamNumber(); + int nOwned = 0; + for ( int i = 0; i < GetNumControlPoints(); ++i ) + { + if ( GetOwningTeam( i ) == iTeam ) + { + ++nOwned; + } + } + return nOwned; +} + +//----------------------------------------------------------------------------- +// Purpose: +// team - +//----------------------------------------------------------------------------- +void C_BaseTeamObjectiveResource::SetOwningTeam( int index, int team ) +{ + if ( team == m_iCappingTeam[index] ) + { + // successful cap, reset things + m_iCappingTeam[index] = TEAM_UNASSIGNED; + m_flCapTimeLeft[index] = 0.0f; + m_flCapLastThinkTime[index] = 0; + } + + m_iOwner[index] = team; + + UpdateControlPoint( "controlpoint_updateowner", index ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_BaseTeamObjectiveResource::SetCappingTeam( int index, int team ) +{ + if ( team != GetOwningTeam( index ) && ( team > LAST_SHARED_TEAM ) ) + { + m_flCapTimeLeft[index] = m_flTeamCapTime[ TEAM_ARRAY(index,team) ]; + } + else + { + m_flCapTimeLeft[index] = 0.0; + } + + m_iCappingTeam[index] = team; + m_bWarnedOnFinalCap[index] = false; + + m_flCapLastThinkTime[index] = gpGlobals->curtime; + SetNextClientThink( gpGlobals->curtime + RESOURCE_THINK_TIME ); + UpdateControlPoint( "controlpoint_updatecapping", index ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_BaseTeamObjectiveResource::SetCapLayout( const char *pszLayout ) +{ + Q_strncpy( m_pszCapLayoutInHUD, pszLayout, MAX_CAPLAYOUT_LENGTH ); + + UpdateControlPoint( "controlpoint_updatelayout" ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool C_BaseTeamObjectiveResource::CapIsBlocked( int index ) +{ + Assert( 0 <= index && index <= m_iNumControlPoints ); + + if ( m_flCapTimeLeft[index] ) + { + // Blocked caps have capping teams & cap times, but no players on the point + if ( GetNumPlayersInArea( index, m_iCappingTeam[index] ) == 0 ) + return true; + } + + return false; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_BaseTeamObjectiveResource::ClientThink() +{ + BaseClass::ClientThink(); + + for ( int i = 0; i < MAX_CONTROL_POINTS; i++ ) + { + if ( m_flCapTimeLeft[i] ) + { + if ( !IsCPBlocked(i) ) + { + bool bDeteriorateNormally = true; + + // Make sure there is only 1 team on the cap + int iPlayersCapping = GetNumPlayersInArea( i, GetTeamInZone(i) ); + if ( iPlayersCapping > 0 ) + { + float flReduction = gpGlobals->curtime - m_flCapLastThinkTime[i]; + if ( mp_capstyle.GetInt() == 1 ) + { + // Diminishing returns for successive players. + for ( int iPlayer = 1; iPlayer < iPlayersCapping; iPlayer++ ) + { + flReduction += ((gpGlobals->curtime - m_flCapLastThinkTime[i]) / (float)(iPlayer+1)); + } + } + + if ( GetTeamInZone(i) == m_iCappingTeam[i] ) + { + bDeteriorateNormally = false; + m_flCapTimeLeft[i] -= flReduction; + + if ( !m_bWarnedOnFinalCap[i] ) + { + // If this the local player's team, warn him + C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); + if ( pPlayer ) + { + if ( m_iCappingTeam[i] != TEAM_UNASSIGNED && + pPlayer->GetTeamNumber() != m_iCappingTeam[i] && + GetCapWarningLevel( i ) == CP_WARN_FINALCAP ) + { + // Prevent spam + if ( gpGlobals->curtime > ( m_flLastCapWarningTime[i] + 5 ) ) + { + pPlayer->EmitSound( GetWarnSound( i ) ); + + m_bWarnedOnFinalCap[i] = true; + m_flLastCapWarningTime[i] = gpGlobals->curtime; + } + } + } + } + } + else if ( GetOwningTeam(i) == TEAM_UNASSIGNED && GetTeamInZone(i) != TEAM_UNASSIGNED ) + { + bDeteriorateNormally = false; + m_flCapTimeLeft[i] += flReduction; + } + } + + if ( bDeteriorateNormally ) + { + // Caps deteriorate over time + // If we're not cappable at all right now, wipe all progress + if ( TeamplayRoundBasedRules() && TeamplayRoundBasedRules()->TeamMayCapturePoint(m_iCappingTeam[i],i) ) + { + float flCapLength = m_flTeamCapTime[ TEAM_ARRAY(i,m_iCappingTeam[i]) ]; + float flDecrease = (flCapLength / mp_capdeteriorate_time.GetFloat()) * (gpGlobals->curtime - m_flCapLastThinkTime[i]); + if ( TeamplayRoundBasedRules() && TeamplayRoundBasedRules()->InOvertime() ) + { + flDecrease *= 6; + } + m_flCapTimeLeft[i] += flDecrease; + } + else + { + m_flCapTimeLeft[i] = 0.0; + } + + m_bWarnedOnFinalCap[i] = false; + } + } + + UpdateControlPoint( "controlpoint_updatelayout", i ); + m_flCapLastThinkTime[i] = gpGlobals->curtime; + } + } + + + SetNextClientThink( gpGlobals->curtime + RESOURCE_THINK_TIME ); +} diff --git a/src/src/game/client/c_team_objectiveresource.h b/src/src/game/client/c_team_objectiveresource.h new file mode 100644 index 0000000..03cb2aa --- /dev/null +++ b/src/src/game/client/c_team_objectiveresource.h @@ -0,0 +1,265 @@ +//====== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======= +// +// Purpose: +// +//============================================================================= + +#ifndef C_TEAM_OBJECTIVERESOURCE_H +#define C_TEAM_OBJECTIVERESOURCE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "shareddefs.h" +#include "const.h" +#include "c_baseentity.h" +#include + +#define TEAM_ARRAY( index, team ) (index + (team * MAX_CONTROL_POINTS)) + +//----------------------------------------------------------------------------- +// Purpose: An entity that networks the state of the game's objectives. +// May contain data for objectives that aren't used by your mod, but +// the extra data will never be networked as long as it's zeroed out. +//----------------------------------------------------------------------------- +class C_BaseTeamObjectiveResource : public C_BaseEntity +{ + DECLARE_CLASS( C_BaseTeamObjectiveResource, C_BaseEntity ); +public: + DECLARE_CLIENTCLASS(); + + C_BaseTeamObjectiveResource(); + virtual ~C_BaseTeamObjectiveResource(); + +public: + virtual void ClientThink(); + virtual void OnPreDataChanged( DataUpdateType_t updateType ); + virtual void OnDataChanged( DataUpdateType_t updateType ); + + void UpdateControlPoint( const char *pszEvent, int index = -1 ); + float GetCPCapPercentage( int index ); + int GetNumControlPoints( void ) { return m_iNumControlPoints; } + int GetNumControlPointsOwned( void ); + void SetOwningTeam( int index, int team ); + virtual void SetCappingTeam( int index, int team ); + void SetCapLayout( const char *pszLayout ); + + // Is the point visible in the objective display + bool IsCPVisible( int index ) + { + Assert( index < m_iNumControlPoints ); + return m_bCPIsVisible[index]; + } + + bool IsCPBlocked( int index ) + { + Assert( index < m_iNumControlPoints ); + return m_bBlocked[index]; + } + + // Get the world location of this control point + Vector& GetCPPosition( int index ) + { + Assert( index < m_iNumControlPoints ); + return m_vCPPositions[index]; + } + + int GetOwningTeam( int index ) + { + if ( index >= m_iNumControlPoints ) + return TEAM_UNASSIGNED; + + return m_iOwner[index]; + } + + int GetCappingTeam( int index ) + { + if ( index >= m_iNumControlPoints ) + return TEAM_UNASSIGNED; + + return m_iCappingTeam[index]; + } + + int GetTeamInZone( int index ) + { + if ( index >= m_iNumControlPoints ) + return TEAM_UNASSIGNED; + + return m_iTeamInZone[index]; + } + + // Icons + int GetCPCurrentOwnerIcon( int index, int iOwner ) + { + Assert( index < m_iNumControlPoints ); + + return GetIconForTeam( index, iOwner ); + } + + int GetCPCappingIcon( int index ) + { + Assert( index < m_iNumControlPoints ); + + int iCapper = GetCappingTeam(index); + + Assert( iCapper != TEAM_UNASSIGNED ); + + return GetIconForTeam( index, iCapper );; + } + + // Icon for the specified team + int GetIconForTeam( int index, int team ) + { + Assert( index < m_iNumControlPoints ); + return m_iTeamIcons[ TEAM_ARRAY(index,team) ]; + } + + // Overlay for the specified team + int GetOverlayForTeam( int index, int team ) + { + Assert( index < m_iNumControlPoints ); + return m_iTeamOverlays[ TEAM_ARRAY(index,team) ]; + } + + // Number of players in the area + int GetNumPlayersInArea( int index, int team ) + { + Assert( index < m_iNumControlPoints ); + return m_iNumTeamMembers[ TEAM_ARRAY(index,team) ]; + } + + // get the required cappers for the passed team + int GetRequiredCappers( int index, int team ) + { + Assert( index < m_iNumControlPoints ); + return m_iTeamReqCappers[ TEAM_ARRAY(index,team) ]; + } + + // Base Icon for the specified team + int GetBaseIconForTeam( int team ) + { + Assert( team < MAX_TEAMS ); + return m_iTeamBaseIcons[ team ]; + } + + int GetBaseControlPointForTeam( int iTeam ) + { + Assert( iTeam < MAX_TEAMS ); + return m_iBaseControlPoints[iTeam]; + } + + int GetPreviousPointForPoint( int index, int team, int iPrevIndex ) + { + Assert( index < m_iNumControlPoints ); + Assert( iPrevIndex >= 0 && iPrevIndex < MAX_PREVIOUS_POINTS ); + int iIntIndex = iPrevIndex + (index * MAX_PREVIOUS_POINTS) + (team * MAX_CONTROL_POINTS * MAX_PREVIOUS_POINTS); + return m_iPreviousPoints[ iIntIndex ]; + } + + bool TeamCanCapPoint( int index, int team ) + { + Assert( index < m_iNumControlPoints ); + return m_bTeamCanCap[ TEAM_ARRAY( index, team ) ]; + } + + const char *GetCapLayoutInHUD( void ) { return m_pszCapLayoutInHUD; } + + bool PlayingMiniRounds( void ){ return m_bPlayingMiniRounds; } + bool IsInMiniRound( int index ) { return m_bInMiniRound[index]; } + + int GetCapWarningLevel( int index ) + { + Assert( index < m_iNumControlPoints ); + return m_iWarnOnCap[index]; + } + + const char *GetWarnSound( int index ) + { + Assert( index < m_iNumControlPoints ); + return m_iszWarnSound[index]; + } + + virtual const char *GetGameSpecificCPCappingSwipe( int index, int iCappingTeam ) + { + // You need to implement this in your game's objective resource. + Assert(0); + return NULL; + } + virtual const char *GetGameSpecificCPBarFG( int index, int iOwningTeam ) + { + // You need to implement this in your game's objective resource. + Assert(0); + return NULL; + } + virtual const char *GetGameSpecificCPBarBG( int index, int iCappingTeam ) + { + // You need to implement this in your game's objective resource. + Assert(0); + return NULL; + } + + bool CapIsBlocked( int index ); + + int GetTimerToShowInHUD( void ) { return m_iTimerToShowInHUD; } + int GetStopWatchTimer( void ) { return m_iStopWatchTimer; } + + float GetPathDistance( int index ) + { + Assert( index < m_iNumControlPoints ); + return m_flPathDistance[index]; + } + +protected: + int m_iTimerToShowInHUD; + int m_iStopWatchTimer; + + int m_iNumControlPoints; + int m_iPrevNumControlPoints; + bool m_bPlayingMiniRounds; + bool m_bControlPointsReset; + bool m_bOldControlPointsReset; + int m_iUpdateCapHudParity; + int m_iOldUpdateCapHudParity; + + // data variables + Vector m_vCPPositions[MAX_CONTROL_POINTS]; + bool m_bCPIsVisible[MAX_CONTROL_POINTS]; + float m_flLazyCapPerc[MAX_CONTROL_POINTS]; + float m_flOldLazyCapPerc[MAX_CONTROL_POINTS]; + int m_iTeamIcons[MAX_CONTROL_POINTS * MAX_CONTROL_POINT_TEAMS]; + int m_iTeamOverlays[MAX_CONTROL_POINTS * MAX_CONTROL_POINT_TEAMS]; + int m_iTeamReqCappers[MAX_CONTROL_POINTS * MAX_CONTROL_POINT_TEAMS]; + float m_flTeamCapTime[MAX_CONTROL_POINTS * MAX_CONTROL_POINT_TEAMS]; + int m_iPreviousPoints[ MAX_CONTROL_POINTS * MAX_CONTROL_POINT_TEAMS * MAX_PREVIOUS_POINTS ]; + bool m_bTeamCanCap[ MAX_CONTROL_POINTS * MAX_CONTROL_POINT_TEAMS ]; + int m_iTeamBaseIcons[MAX_TEAMS]; + int m_iBaseControlPoints[MAX_TEAMS]; + bool m_bInMiniRound[MAX_CONTROL_POINTS]; + int m_iWarnOnCap[MAX_CONTROL_POINTS]; + char m_iszWarnSound[MAX_CONTROL_POINTS][255]; + float m_flPathDistance[MAX_CONTROL_POINTS]; + + // state variables + int m_iNumTeamMembers[MAX_CONTROL_POINTS * MAX_CONTROL_POINT_TEAMS]; + int m_iCappingTeam[MAX_CONTROL_POINTS]; + int m_iTeamInZone[MAX_CONTROL_POINTS]; + bool m_bBlocked[MAX_CONTROL_POINTS]; + int m_iOwner[MAX_CONTROL_POINTS]; + + // client calculated state + float m_flCapTimeLeft[MAX_CONTROL_POINTS]; + float m_flCapLastThinkTime[MAX_CONTROL_POINTS]; + + bool m_bWarnedOnFinalCap[MAX_CONTROL_POINTS]; + float m_flLastCapWarningTime[MAX_CONTROL_POINTS]; + char m_pszCapLayoutInHUD[MAX_CAPLAYOUT_LENGTH]; +}; + +extern C_BaseTeamObjectiveResource *g_pObjectiveResource; + +inline C_BaseTeamObjectiveResource *ObjectiveResource() +{ + return g_pObjectiveResource; +} + +#endif // C_TEAM_OBJECTIVERESOURCE_H diff --git a/src/src/game/client/c_team_train_watcher.cpp b/src/src/game/client/c_team_train_watcher.cpp new file mode 100644 index 0000000..ec55bd6 --- /dev/null +++ b/src/src/game/client/c_team_train_watcher.cpp @@ -0,0 +1,98 @@ +//========= Copyright © 1996-2006, Valve Corporation, All rights reserved. ============// +// +// Purpose: Entity that propagates train data for escort gametype +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "c_team_train_watcher.h" +#include "igameevents.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +IMPLEMENT_CLIENTCLASS_DT_NOBASE(C_TeamTrainWatcher, DT_TeamTrainWatcher, CTeamTrainWatcher) + + RecvPropFloat( RECVINFO( m_flTotalProgress ) ), + RecvPropInt( RECVINFO( m_iTrainSpeedLevel ) ), + RecvPropFloat( RECVINFO( m_flRecedeTime ) ), + RecvPropInt( RECVINFO( m_nNumCappers ) ), + +END_RECV_TABLE() + +C_TeamTrainWatcher *g_pTrainWatcher = NULL; + +C_TeamTrainWatcher::C_TeamTrainWatcher() +{ + g_pTrainWatcher = this; + + // force updates when we get our baseline + m_iTrainSpeedLevel = -2; + m_flTotalProgress = -1; + m_flRecedeTime = -1; + +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_TeamTrainWatcher::~C_TeamTrainWatcher() +{ + if ( g_pTrainWatcher == this ) + { + g_pTrainWatcher = NULL; + } +} + +void C_TeamTrainWatcher::OnPreDataChanged( DataUpdateType_t updateType ) +{ + BaseClass::OnPreDataChanged( updateType ); + + m_iOldTrainSpeedLevel = m_iTrainSpeedLevel; + m_flOldProgress = m_flTotalProgress; + m_flOldRecedeTime = m_flRecedeTime; + m_nOldNumCappers = m_nNumCappers; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_TeamTrainWatcher::OnDataChanged( DataUpdateType_t updateType ) +{ + if ( m_iOldTrainSpeedLevel != m_iTrainSpeedLevel || m_nOldNumCappers != m_nNumCappers ) + { + IGameEvent *event = gameeventmanager->CreateEvent( "escort_speed" ); + if ( event ) + { + event->SetInt( "speed", m_iTrainSpeedLevel ); + event->SetInt( "players", m_nNumCappers ); + gameeventmanager->FireEventClientSide( event ); + } + } + + if ( m_flOldProgress != m_flTotalProgress ) + { + IGameEvent *event = gameeventmanager->CreateEvent( "escort_progress" ); + if ( event ) + { + event->SetFloat( "progress", m_flTotalProgress ); + + if ( m_flOldProgress <= -1 ) + { + event->SetBool( "reset", true ); + } + + gameeventmanager->FireEventClientSide( event ); + } + } + + if ( m_flOldRecedeTime != m_flRecedeTime ) + { + IGameEvent *event = gameeventmanager->CreateEvent( "escort_recede" ); + if ( event ) + { + event->SetFloat( "recedetime", m_flRecedeTime ); + gameeventmanager->FireEventClientSide( event ); + } + } +} \ No newline at end of file diff --git a/src/src/game/client/c_team_train_watcher.h b/src/src/game/client/c_team_train_watcher.h new file mode 100644 index 0000000..041d63d --- /dev/null +++ b/src/src/game/client/c_team_train_watcher.h @@ -0,0 +1,59 @@ +//====== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======= +// +// Purpose: +// +//============================================================================= + +#ifndef C_TEAM_TRAIN_WATCHER_H +#define C_TEAM_TRAIN_WATCHER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "c_baseentity.h" + +class C_TeamTrainWatcher : public C_BaseEntity +{ + DECLARE_CLASS( C_TeamTrainWatcher, C_BaseEntity ); +public: + DECLARE_CLIENTCLASS(); + + C_TeamTrainWatcher(); + ~C_TeamTrainWatcher(); + + virtual void OnPreDataChanged( DataUpdateType_t updateType ); + virtual void OnDataChanged( DataUpdateType_t updateType ); + + float GetTotalProgress( void ) { return m_flTotalProgress; } + int GetSpeedLevel( void ) { return m_iTrainSpeedLevel; } + +private: + + // === Networked Data === + + // percent distance to cp1, distance to cp2, etc + // adds up to 1.0 + //CNetworkArray( float, m_flDistances, MAX_CONTROL_POINTS ); + + // current total progress, percentage + CNetworkVar( float, m_flTotalProgress ); + float m_flOldProgress; + + CNetworkVar( int, m_iTrainSpeedLevel ); + int m_iOldTrainSpeedLevel; + + CNetworkVar( float, m_flRecedeTime ); + float m_flOldRecedeTime; + + CNetworkVar( int, m_nNumCappers ); + int m_nOldNumCappers; +}; + +extern C_TeamTrainWatcher *g_pTrainWatcher; + +inline C_TeamTrainWatcher *TrainWatcher() +{ + return g_pTrainWatcher; +} + +#endif //C_TEAM_TRAIN_WATCHER_H \ No newline at end of file diff --git a/src/src/cl_dll/c_tesla.cpp b/src/src/game/client/c_tesla.cpp similarity index 100% rename from src/src/cl_dll/c_tesla.cpp rename to src/src/game/client/c_tesla.cpp diff --git a/src/src/cl_dll/c_tesla.h b/src/src/game/client/c_tesla.h similarity index 100% rename from src/src/cl_dll/c_tesla.h rename to src/src/game/client/c_tesla.h diff --git a/src/src/cl_dll/c_test_proxytoggle.cpp b/src/src/game/client/c_test_proxytoggle.cpp similarity index 90% rename from src/src/cl_dll/c_test_proxytoggle.cpp rename to src/src/game/client/c_test_proxytoggle.cpp index 7b18823..1923600 100644 --- a/src/src/cl_dll/c_test_proxytoggle.cpp +++ b/src/src/game/client/c_test_proxytoggle.cpp @@ -57,9 +57,9 @@ END_RECV_TABLE() // ---------------------------------------------------------------------------------------- // // The engine uses this to get the current value. -void Test_ProxyToggle_EnsureValue() +CON_COMMAND_F( Test_ProxyToggle_EnsureValue, "Test_ProxyToggle_EnsureValue", FCVAR_CHEAT ) { - if ( engine->Cmd_Argc() < 2 ) + if ( args.ArgC() < 2 ) { Error( "Test_ProxyToggle_EnsureValue: requires value parameter." ); } @@ -68,14 +68,13 @@ void Test_ProxyToggle_EnsureValue() Error( "Test_ProxyToggle_EnsureValue: object doesn't exist on the client." ); } - int wantedValue = atoi( engine->Cmd_Argv( 1 ) ); + int wantedValue = atoi( args[ 1 ] ); if ( g_pTestObj->m_WithProxy != wantedValue ) { Error( "Test_ProxyToggle_EnsureValue: value (%d) doesn't match wanted value (%d).", g_pTestObj->m_WithProxy, wantedValue ); } } -ConCommand cc_Test_ProxyToggle_EnsureValue( "Test_ProxyToggle_EnsureValue", Test_ProxyToggle_EnsureValue, 0, FCVAR_CHEAT ); diff --git a/src/src/cl_dll/c_testtraceline.cpp b/src/src/game/client/c_testtraceline.cpp similarity index 95% rename from src/src/cl_dll/c_testtraceline.cpp rename to src/src/game/client/c_testtraceline.cpp index 70b83cb..8997d12 100644 --- a/src/src/cl_dll/c_testtraceline.cpp +++ b/src/src/game/client/c_testtraceline.cpp @@ -131,7 +131,8 @@ void C_TestTraceline::DrawCube( Vector& center, unsigned char* pColor ) // Draw the face. CMeshBuilder meshBuilder; - IMesh* pMesh = materials->GetDynamicMesh(); + CMatRenderContextPtr pRenderContext( materials ); + IMesh* pMesh = pRenderContext->GetDynamicMesh(); meshBuilder.DrawQuad( pMesh, facePoints[nP1].Base(), facePoints[nP2].Base(), facePoints[nP3].Base(), facePoints[nP4].Base(), pColor, true ); } @@ -146,7 +147,8 @@ int C_TestTraceline::DrawModel( int flags ) UTIL_TraceLine( GetAbsOrigin(), endpos, MASK_SOLID_BRUSHONLY, NULL, COLLISION_GROUP_NONE, &tr ); - IMesh* pMesh = materials->GetDynamicMesh( true, NULL, NULL, m_pWireframe ); + CMatRenderContextPtr pRenderContext( materials ); + IMesh* pMesh = pRenderContext->GetDynamicMesh( true, NULL, NULL, m_pWireframe ); CMeshBuilder meshBuilder; meshBuilder.Begin( pMesh, MATERIAL_LINES, 1 ); diff --git a/src/src/cl_dll/c_tracer.cpp b/src/src/game/client/c_tracer.cpp similarity index 100% rename from src/src/cl_dll/c_tracer.cpp rename to src/src/game/client/c_tracer.cpp diff --git a/src/src/cl_dll/c_tracer.h b/src/src/game/client/c_tracer.h similarity index 100% rename from src/src/cl_dll/c_tracer.h rename to src/src/game/client/c_tracer.h diff --git a/src/src/cl_dll/c_user_message_register.cpp b/src/src/game/client/c_user_message_register.cpp similarity index 100% rename from src/src/cl_dll/c_user_message_register.cpp rename to src/src/game/client/c_user_message_register.cpp diff --git a/src/src/cl_dll/c_user_message_register.h b/src/src/game/client/c_user_message_register.h similarity index 100% rename from src/src/cl_dll/c_user_message_register.h rename to src/src/game/client/c_user_message_register.h diff --git a/src/src/cl_dll/c_vehicle_choreo_generic.cpp b/src/src/game/client/c_vehicle_choreo_generic.cpp similarity index 93% rename from src/src/cl_dll/c_vehicle_choreo_generic.cpp rename to src/src/game/client/c_vehicle_choreo_generic.cpp index 1855f0f..88cc387 100644 --- a/src/src/cl_dll/c_vehicle_choreo_generic.cpp +++ b/src/src/game/client/c_vehicle_choreo_generic.cpp @@ -6,11 +6,12 @@ #include "cbase.h" #include "hud.h" -#include "c_physicsprop.h" +#include "c_props.h" #include "IClientVehicle.h" #include #include #include "vehicle_choreo_generic_shared.h" +#include "vehicle_viewblend_shared.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -28,9 +29,9 @@ extern float RemapAngleRange( float startInterval, float endInterval, float valu //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- -class C_PropVehicleChoreoGeneric : public C_PhysicsProp, public IClientVehicle +class C_PropVehicleChoreoGeneric : public C_DynamicProp, public IClientVehicle { - DECLARE_CLASS( C_PropVehicleChoreoGeneric, C_PhysicsProp ); + DECLARE_CLASS( C_PropVehicleChoreoGeneric, C_DynamicProp ); public: @@ -45,7 +46,7 @@ public: public: // IClientVehicle overrides. - virtual void GetVehicleViewPosition( int nRole, Vector *pOrigin, QAngle *pAngles ); + virtual void GetVehicleViewPosition( int nRole, Vector *pOrigin, QAngle *pAngles, float *pFOV = NULL ); virtual void GetVehicleFOV( float &flFOV ) { flFOV = m_flFOV; @@ -60,6 +61,7 @@ public: 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: @@ -187,9 +189,14 @@ int C_PropVehicleChoreoGeneric::GetPassengerRole( C_BaseCombatCharacter *pPassen //----------------------------------------------------------------------------- // Purpose: Modify the player view/camera while in a vehicle //----------------------------------------------------------------------------- -void C_PropVehicleChoreoGeneric::GetVehicleViewPosition( int nRole, Vector *pAbsOrigin, QAngle *pAbsAngles ) +void C_PropVehicleChoreoGeneric::GetVehicleViewPosition( int nRole, Vector *pAbsOrigin, QAngle *pAbsAngles, float *pFOV /*=NULL*/ ) { - VehicleViewSmoothing( m_hPlayer, pAbsOrigin, pAbsAngles, m_bEnterAnimOn, m_bExitAnimOn, &m_vecEyeExitEndpoint, &m_ViewSmoothingData, &m_flFOV ); + SharedVehicleViewSmoothing( m_hPlayer, + pAbsOrigin, pAbsAngles, + m_bEnterAnimOn, m_bExitAnimOn, + m_vecEyeExitEndpoint, + &m_ViewSmoothingData, + pFOV ); } diff --git a/src/src/cl_dll/c_vehicle_jeep.cpp b/src/src/game/client/c_vehicle_jeep.cpp similarity index 89% rename from src/src/cl_dll/c_vehicle_jeep.cpp rename to src/src/game/client/c_vehicle_jeep.cpp index 8d51c53..728b06d 100644 --- a/src/src/cl_dll/c_vehicle_jeep.cpp +++ b/src/src/game/client/c_vehicle_jeep.cpp @@ -5,12 +5,13 @@ //=============================================================================// #include "cbase.h" -#include "c_prop_vehicle.h" +#include "c_vehicle_jeep.h" #include "movevars_shared.h" #include "view.h" #include "flashlighteffect.h" #include "c_baseplayer.h" #include "c_te_effect_dispatch.h" +#include "fx.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -20,57 +21,11 @@ extern ConVar default_fov; ConVar r_JeepViewBlendTo( "r_JeepViewBlendTo", "1", FCVAR_CHEAT ); ConVar r_JeepViewBlendToScale( "r_JeepViewBlendToScale", "0.03", FCVAR_CHEAT ); ConVar r_JeepViewBlendToTime( "r_JeepViewBlendToTime", "1.5", FCVAR_CHEAT ); -ConVar r_JeepFOV( "r_JeepFOV", "90", FCVAR_CHEAT ); #define JEEP_DELTA_LENGTH_MAX 12.0f // 1 foot #define JEEP_FRAMETIME_MIN 1e-6 #define JEEP_HEADLIGHT_DISTANCE 1000 -//============================================================================= -// -// Client-side Jeep Class -// -class C_PropJeep : public C_PropVehicleDriveable -{ - - DECLARE_CLASS( C_PropJeep, C_PropVehicleDriveable ); - -public: - - DECLARE_CLIENTCLASS(); - DECLARE_INTERPOLATION(); - - C_PropJeep(); - ~C_PropJeep(); - -public: - - void UpdateViewAngles( C_BasePlayer *pLocalPlayer, CUserCmd *pCmd ); - void DampenEyePosition( Vector &vecVehicleEyePos, QAngle &vecVehicleEyeAngles ); - - void OnEnteredVehicle( C_BasePlayer *pPlayer ); - void Simulate( void ); - -private: - - 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 ); - -private: - - Vector m_vecLastEyePos; - Vector m_vecLastEyeTarget; - Vector m_vecEyeSpeed; - Vector m_vecTargetSpeed; - - float m_flViewAngleDeltaTime; - - float m_flJeepFOV; - CHeadlightEffect *m_pHeadlight; - bool m_bHeadlightIsOn; -}; - IMPLEMENT_CLIENTCLASS_DT( C_PropJeep, DT_PropJeep, CPropJeep ) RecvPropBool( RECVINFO( m_bHeadlightIsOn ) ), END_RECV_TABLE() @@ -83,6 +38,8 @@ C_PropJeep::C_PropJeep() m_vecEyeSpeed.Init(); m_flViewAngleDeltaTime = 0.0f; m_pHeadlight = NULL; + + ConVarRef r_JeepFOV( "r_JeepFOV" ); m_ViewSmoothingData.flFOV = r_JeepFOV.GetFloat(); } @@ -176,7 +133,6 @@ void C_PropJeep::UpdateViewAngles( C_BasePlayer *pLocalPlayer, CUserCmd *pCmd ) //----------------------------------------------------------------------------- void C_PropJeep::DampenEyePosition( Vector &vecVehicleEyePos, QAngle &vecVehicleEyeAngles ) { -#ifdef HL2_CLIENT_DLL // Get the frametime. (Check to see if enough time has passed to warrent dampening). float flFrameTime = gpGlobals->frametime; @@ -193,7 +149,6 @@ void C_PropJeep::DampenEyePosition( Vector &vecVehicleEyePos, QAngle &vecVehicle // Blend up/down motion. DampenUpMotion( vecVehicleEyePos, vecVehicleEyeAngles, flFrameTime ); -#endif } @@ -335,14 +290,12 @@ void WheelDustCallback( const CEffectData &data ) //Find area ambient light color and use it to tint smoke Vector worldLight = WorldGetLightForPoint( offset, true ); - PMaterialHandle hMaterial = pSimple->GetPMaterial("particle/particle_smokegrenade");; - //Throw puffs offset.Random( -(data.m_flScale*16.0f), data.m_flScale*16.0f ); offset.z = 0.0f; offset += data.m_vOrigin + ( data.m_vNormal * data.m_flScale ); - pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof(SimpleParticle), hMaterial, offset ); + pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof(SimpleParticle), g_Mat_DustPuff[0], offset ); if ( pParticle != NULL ) { diff --git a/src/src/game/client/c_vehicle_jeep.h b/src/src/game/client/c_vehicle_jeep.h new file mode 100644 index 0000000..a1a8248 --- /dev/null +++ b/src/src/game/client/c_vehicle_jeep.h @@ -0,0 +1,66 @@ +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// +#ifndef C_VEHICLE_JEEP_H +#define C_VEHICLE_JEEP_H +#pragma once + +#include "cbase.h" +#include "c_prop_vehicle.h" +//#include "movevars_shared.h" +//#include "view.h" +#include "flashlighteffect.h" +//#include "c_baseplayer.h" +//#include "c_te_effect_dispatch.h" + +// memdbgon must be the last include file in a .cpp file!!! +//#include "tier0/memdbgon.h" + +//============================================================================= +// +// Client-side Jeep Class +// +class C_PropJeep : public C_PropVehicleDriveable +{ + + DECLARE_CLASS( C_PropJeep, C_PropVehicleDriveable ); + +public: + + DECLARE_CLIENTCLASS(); + DECLARE_INTERPOLATION(); + + C_PropJeep(); + ~C_PropJeep(); + +public: + + void UpdateViewAngles( C_BasePlayer *pLocalPlayer, CUserCmd *pCmd ); + void DampenEyePosition( Vector &vecVehicleEyePos, QAngle &vecVehicleEyeAngles ); + + void OnEnteredVehicle( C_BasePlayer *pPlayer ); + void Simulate( void ); + +private: + + 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 ); + +private: + + Vector m_vecLastEyePos; + Vector m_vecLastEyeTarget; + Vector m_vecEyeSpeed; + Vector m_vecTargetSpeed; + + float m_flViewAngleDeltaTime; + + float m_flJeepFOV; + CHeadlightEffect *m_pHeadlight; + bool m_bHeadlightIsOn; +}; + +#endif C_VEHICLE_JEEP_H \ No newline at end of file diff --git a/src/src/cl_dll/c_vguiscreen.cpp b/src/src/game/client/c_vguiscreen.cpp similarity index 80% rename from src/src/cl_dll/c_vguiscreen.cpp rename to src/src/game/client/c_vguiscreen.cpp index 02248bc..b27d2ea 100644 --- a/src/src/cl_dll/c_vguiscreen.cpp +++ b/src/src/game/client/c_vguiscreen.cpp @@ -10,7 +10,7 @@ #include #include "PanelMetaClassMgr.h" #include -#include "VMatrix.h" +#include "mathlib/VMatrix.h" #include "VGUIMatSurface/IMatSystemSurface.h" #include "view.h" #include "CollisionUtils.h" @@ -27,6 +27,7 @@ #include "vgui_bitmapbutton.h" #include "vgui_bitmappanel.h" #include "filesystem.h" +#include "iinput.h" #include extern vgui::IInputInternal *g_InputInternal; @@ -42,7 +43,6 @@ CLIENTEFFECT_MATERIAL( "engine/writez" ) CLIENTEFFECT_REGISTER_END() - // ----------------------------------------------------------------------------- // // This is a cache of preloaded keyvalues. // ----------------------------------------------------------------------------- // @@ -77,100 +77,6 @@ void ClearKeyValuesCache() } -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -class C_VGuiScreen : public C_BaseEntity -{ - DECLARE_CLASS( C_VGuiScreen, C_BaseEntity ); -public: - DECLARE_CLIENTCLASS(); - - C_VGuiScreen(); - - virtual void PreDataUpdate( DataUpdateType_t updateType ); - virtual void OnDataChanged( DataUpdateType_t type ); - virtual int DrawModel( int flags ); - virtual bool ShouldDraw() { return !IsEffectActive(EF_NODRAW); } - virtual void ClientThink( ); - virtual void GetAimEntOrigin( IClientEntity *pAttachedTo, Vector *pOrigin, QAngle *pAngles ); - - const char *PanelName() const; - - // The view screen has the cursor pointing at it - void GainFocus( ); - void LoseFocus(); - - // Button state... - void SetButtonState( int nButtonState ); - - // Is the screen backfaced given a view position? - bool IsBackfacing( const Vector &viewOrigin ); - - // Return intersection point of ray with screen in barycentric coords - bool IntersectWithRay( const Ray_t &ray, float *u, float *v, float *t ); - - // Is the screen turned on? - bool IsActive() const; - - // Are we only visible to teammates? - bool IsVisibleOnlyToTeammates() const; - - // Are we visible to someone on this team? - bool IsVisibleToTeam( int nTeam ); - - bool IsAttachedToViewModel() const; - - virtual RenderGroup_t GetRenderGroup(); - - bool AcceptsInput() const; - void SetAcceptsInput( bool acceptsinput ); - -private: - // Vgui screen management - void CreateVguiScreen( const char *pTypeName ); - void DestroyVguiScreen( ); - - // Computes the panel to world transform - void ComputePanelToWorld(); - - // Computes control points of the quad describing the screen - void ComputeEdges( Vector *pUpperLeft, Vector *pUpperRight, Vector *pLowerLeft ); - - // Writes the z buffer - void DrawScreenOverlay(); - -private: - int m_nPixelWidth; - int m_nPixelHeight; - float m_flWidth; - float m_flHeight; - int m_nPanelName; // The name of the panel - int m_nButtonState; - int m_nButtonPressed; - int m_nButtonReleased; - int m_nOldPx; - int m_nOldPy; - int m_nOldButtonState; - int m_nAttachmentIndex; - int m_nOverlayMaterial; - int m_fScreenFlags; - - int m_nOldPanelName; - int m_nOldOverlayMaterial; - - bool m_bLooseThinkNextFrame; - - bool m_bAcceptsInput; - - CMaterialReference m_WriteZMaterial; - CMaterialReference m_OverlayMaterial; - - VMatrix m_PanelToWorld; - - CPanelWrapper m_PanelWrapper; -}; - IMPLEMENT_CLIENTCLASS_DT(C_VGuiScreen, DT_VGuiScreen, CVGuiScreen) RecvPropFloat( RECVINFO(m_flWidth) ), RecvPropFloat( RECVINFO(m_flHeight) ), @@ -178,6 +84,7 @@ IMPLEMENT_CLIENTCLASS_DT(C_VGuiScreen, DT_VGuiScreen, CVGuiScreen) RecvPropInt( RECVINFO(m_nPanelName) ), RecvPropInt( RECVINFO(m_nAttachmentIndex) ), RecvPropInt( RECVINFO(m_nOverlayMaterial) ), + RecvPropEHandle( RECVINFO(m_hPlayerOwner) ), END_RECV_TABLE() @@ -190,13 +97,18 @@ C_VGuiScreen::C_VGuiScreen() m_nOldOverlayMaterial = m_nOverlayMaterial = -1; m_nOldPx = m_nOldPy = -1; m_nButtonState = 0; - m_bLooseThinkNextFrame = false; + m_bLoseThinkNextFrame = false; m_bAcceptsInput = true; m_WriteZMaterial.Init( "engine/writez", TEXTURE_GROUP_VGUI ); m_OverlayMaterial.Init( m_WriteZMaterial ); } +C_VGuiScreen::~C_VGuiScreen() +{ + DestroyVguiScreen(); +} + //----------------------------------------------------------------------------- // Network updates //----------------------------------------------------------------------------- @@ -244,9 +156,10 @@ void C_VGuiScreen::GetAimEntOrigin( IClientEntity *pAttachedTo, Vector *pOrigin, C_BaseEntity *pEnt = pAttachedTo->GetBaseEntity(); if (pEnt && (m_nAttachmentIndex > 0)) { - C_BaseAnimating::PushAllowBoneAccess( true, true ); - pEnt->GetAttachment( m_nAttachmentIndex, *pOrigin, *pAngles ); - C_BaseAnimating::PopBoneAccess(); + { + C_BaseAnimating::AutoAllowBoneAccess boneaccess( true, true ); + pEnt->GetAttachment( m_nAttachmentIndex, *pOrigin, *pAngles ); + } if ( IsAttachedToViewModel() ) { @@ -259,7 +172,6 @@ void C_VGuiScreen::GetAimEntOrigin( IClientEntity *pAttachedTo, Vector *pOrigin, } } - //----------------------------------------------------------------------------- // Create, destroy vgui panels... //----------------------------------------------------------------------------- @@ -268,6 +180,8 @@ void C_VGuiScreen::CreateVguiScreen( const char *pTypeName ) // Clear out any old screens. DestroyVguiScreen(); + AddEFlags( EFL_USE_PARTITION_WHEN_NOT_SOLID ); + // Create the new screen... VGuiScreenInitData_t initData( this ); m_PanelWrapper.Activate( pTypeName, NULL, 0, &initData ); @@ -372,25 +286,19 @@ bool C_VGuiScreen::IsVisibleToTeam( int nTeam ) void C_VGuiScreen::GainFocus( ) { SetNextClientThink( CLIENT_THINK_ALWAYS ); + m_bLoseThinkNextFrame = false; + m_nOldButtonState = 0; } void C_VGuiScreen::LoseFocus() { - m_bLooseThinkNextFrame = true; + m_bLoseThinkNextFrame = true; m_nOldButtonState = 0; } void C_VGuiScreen::SetButtonState( int nButtonState ) { - m_nOldButtonState = m_nButtonState; m_nButtonState = nButtonState; - - int nButtonsChanged = m_nOldButtonState ^ m_nButtonState; - - // Debounced button codes for pressed/released - // UNDONE: Do we need auto-repeat? - m_nButtonPressed = nButtonsChanged & m_nButtonState; // The changed ones still down are "pressed" - m_nButtonReleased = nButtonsChanged & (~m_nButtonState); // The ones not down are "released" } @@ -403,12 +311,68 @@ const char *C_VGuiScreen::PanelName() const return g_StringTableVguiScreen->GetString( m_nPanelName ); } +//-------------------------------------------------------------------------- +// Purpose: +// Given a field of view and mouse/screen positions as well as the current +// render origin and angles, returns a unit vector through the mouse position +// that can be used to trace into the world under the mouse click pixel. +// Input : +// mousex - +// mousey - +// fov - +// vecRenderOrigin - +// vecRenderAngles - +// Output : +// vecPickingRay +//-------------------------------------------------------------------------- +void ScreenToWorld( int mousex, int mousey, float fov, + const Vector& vecRenderOrigin, + const QAngle& vecRenderAngles, + Vector& vecPickingRay ) +{ + float dx, dy; + float c_x, c_y; + float dist; + Vector vpn, vup, vright; + + float scaled_fov = ScaleFOVByWidthRatio( fov, engine->GetScreenAspectRatio() * 0.75f ); + + c_x = ScreenWidth() / 2; + c_y = ScreenHeight() / 2; + + dx = (float)mousex - c_x; + // Invert Y + dy = c_y - (float)mousey; + + //Tony; fix for 2008 express. why this is an issue, is unbeknownst to me. - http://developer.valvesoftware.com/cgi-bin/bugzilla/show_bug.cgi?id=214 + // Convert view plane distance + //dist = c_x / tan( M_PI * scaled_fov / 360.0 ); + float dist_denom = tan(M_PI * scaled_fov / 360.0f); + dist = c_x / dist_denom; + // Decompose view angles + AngleVectors( vecRenderAngles, &vpn, &vright, &vup ); + + // Offset forward by view plane distance, and then by pixel offsets + vecPickingRay = vpn * dist + vright * ( dx ) + vup * ( dy ); + + // Convert to unit vector + VectorNormalize( vecPickingRay ); +} //----------------------------------------------------------------------------- // Purpose: Deal with input //----------------------------------------------------------------------------- void C_VGuiScreen::ClientThink( void ) { + int nButtonsChanged = m_nOldButtonState ^ m_nButtonState; + + m_nOldButtonState = m_nButtonState; + + // Debounced button codes for pressed/released + // UNDONE: Do we need auto-repeat? + m_nButtonPressed = nButtonsChanged & m_nButtonState; // The changed ones still down are "pressed" + m_nButtonReleased = nButtonsChanged & (~m_nButtonState); // The ones not down are "released" + BaseClass::ClientThink(); // FIXME: We should really be taking bob, shake, and roll into account @@ -428,20 +392,23 @@ void C_VGuiScreen::ClientThink( void ) QAngle viewAngles = pLocalPlayer->EyeAngles( ); - Vector viewDir, endPos; - AngleVectors( viewAngles, &viewDir ); - VectorMA( vecEyePosition, 1000.0f, viewDir, endPos ); - // Compute cursor position... Ray_t lookDir; - lookDir.Init( vecEyePosition, endPos ); + Vector endPos; float u, v; + // Viewmodel attached screens that take input need to have a moving cursor + // Do a pick under the cursor as our selection + Vector viewDir; + AngleVectors( viewAngles, &viewDir ); + VectorMA( vecEyePosition, 1000.0f, viewDir, endPos ); + lookDir.Init( vecEyePosition, endPos ); + if (!IntersectWithRay( lookDir, &u, &v, NULL )) return; - if ( ((u < 0) || (v < 0) || (u > 1) || (v > 1)) && !m_bLooseThinkNextFrame) + if ( ((u < 0) || (v < 0) || (u > 1) || (v > 1)) && !m_bLoseThinkNextFrame) return; // This will cause our panel to grab all input! @@ -461,28 +428,31 @@ void C_VGuiScreen::ClientThink( void ) if (m_nButtonPressed & IN_ATTACK) { - g_InputInternal->InternalMousePressed(vgui::MOUSE_LEFT); + g_InputInternal->SetMouseCodeState( MOUSE_LEFT, vgui::BUTTON_PRESSED ); + g_InputInternal->InternalMousePressed(MOUSE_LEFT); } if (m_nButtonPressed & IN_ATTACK2) { - g_InputInternal->InternalMousePressed(vgui::MOUSE_RIGHT); + g_InputInternal->SetMouseCodeState( MOUSE_RIGHT, vgui::BUTTON_PRESSED ); + g_InputInternal->InternalMousePressed( MOUSE_RIGHT ); } - if ( (m_nButtonReleased & IN_ATTACK) || m_bLooseThinkNextFrame) // for a button release on loosing focus + if ( (m_nButtonReleased & IN_ATTACK) || m_bLoseThinkNextFrame) // for a button release on loosing focus { - g_InputInternal->InternalMouseReleased(vgui::MOUSE_LEFT); + g_InputInternal->SetMouseCodeState( MOUSE_LEFT, vgui::BUTTON_RELEASED ); + g_InputInternal->InternalMouseReleased( MOUSE_LEFT ); } if (m_nButtonReleased & IN_ATTACK2) { - g_InputInternal->InternalMouseReleased(vgui::MOUSE_RIGHT); + g_InputInternal->SetMouseCodeState( MOUSE_RIGHT, vgui::BUTTON_RELEASED ); + g_InputInternal->InternalMouseReleased( MOUSE_RIGHT ); } - if ( m_bLooseThinkNextFrame == true ) + if ( m_bLoseThinkNextFrame == true ) { - m_bLooseThinkNextFrame = false; + m_bLoseThinkNextFrame = false; SetNextClientThink( CLIENT_THINK_NEVER ); } - g_pClientMode->DeactivateInGameVGuiContext( ); } @@ -553,14 +523,15 @@ void C_VGuiScreen::ComputePanelToWorld() //----------------------------------------------------------------------------- void C_VGuiScreen::DrawScreenOverlay() { - materials->MatrixMode( MATERIAL_MODEL ); - materials->PushMatrix(); - materials->LoadMatrix( m_PanelToWorld ); + CMatRenderContextPtr pRenderContext( materials ); + pRenderContext->MatrixMode( MATERIAL_MODEL ); + pRenderContext->PushMatrix(); + pRenderContext->LoadMatrix( m_PanelToWorld ); unsigned char pColor[4] = {255, 255, 255, 255}; CMeshBuilder meshBuilder; - IMesh *pMesh = materials->GetDynamicMesh( true, NULL, NULL, m_OverlayMaterial ); + IMesh *pMesh = pRenderContext->GetDynamicMesh( true, NULL, NULL, m_OverlayMaterial ); meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 ); meshBuilder.Position3f( 0.0f, 0.0f, 0 ); @@ -586,7 +557,7 @@ void C_VGuiScreen::DrawScreenOverlay() meshBuilder.End(); pMesh->Draw(); - materials->PopMatrix(); + pRenderContext->PopMatrix(); } @@ -603,6 +574,11 @@ int C_VGuiScreen::DrawModel( int flags ) C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer(); if (!pLocalPlayer || !IsVisibleToTeam(pLocalPlayer->GetTeamNumber()) ) return 0; + + if ( !IsVisibleToPlayer( pLocalPlayer ) ) + { + return 0; + } // Backface cull the entire panel here... if (IsBackfacing(CurrentViewOrigin())) @@ -621,8 +597,38 @@ int C_VGuiScreen::DrawModel( int flags ) return 1; } +bool C_VGuiScreen::ShouldDraw( void ) +{ + return !IsEffectActive(EF_NODRAW); +} +//----------------------------------------------------------------------------- +// Purpose: Hook for vgui screens to determine visibility +//----------------------------------------------------------------------------- +bool C_VGuiScreen::IsVisibleToPlayer( C_BasePlayer *pViewingPlayer ) +{ + return true; +} + +bool C_VGuiScreen::IsTransparent( void ) +{ + return (m_fScreenFlags & VGUI_SCREEN_TRANSPARENT) != 0; +} + +//----------------------------------------------------------------------------- +// Purpose: Sometimes we only want a specific player to be able to input to a panel +//----------------------------------------------------------------------------- +C_BasePlayer *C_VGuiScreen::GetPlayerOwner( void ) +{ + return ( C_BasePlayer * )( m_hPlayerOwner.Get() ); +} + +bool C_VGuiScreen::IsInputOnlyToOwner( void ) +{ + return (m_fScreenFlags & VGUI_SCREEN_ONLY_USABLE_BY_OWNER) != 0; +} + //----------------------------------------------------------------------------- // // Enumator class for finding vgui screens close to the local player @@ -666,7 +672,7 @@ int CVGuiScreenEnumerator::GetScreenCount() C_VGuiScreen *CVGuiScreenEnumerator::GetVGuiScreen( int index ) { return m_VguiScreens[index].Get(); -} +} //----------------------------------------------------------------------------- @@ -676,6 +682,19 @@ C_VGuiScreen *CVGuiScreenEnumerator::GetVGuiScreen( int index ) //----------------------------------------------------------------------------- C_BaseEntity *FindNearbyVguiScreen( const Vector &viewPosition, const QAngle &viewAngle, int nTeam ) { + if ( IsX360() ) + { + // X360TBD: Turn this on if feature actually used + return NULL; + } + + C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer(); + + Assert( pLocalPlayer ); + + if ( !pLocalPlayer ) + return NULL; + // Get the view direction... Vector lookDir; AngleVectors( viewAngle, &lookDir ); @@ -699,8 +718,14 @@ C_BaseEntity *FindNearbyVguiScreen( const Vector &viewPosition, const QAngle &vi { C_VGuiScreen *pScreen = localScreens.GetVGuiScreen(i); + if ( pScreen->IsAttachedToViewModel() ) + continue; + // Don't bother with screens I'm behind... - if (pScreen->IsBackfacing(viewPosition)) + // Hax - don't cancel backfacing with viewmodel attached screens. + // we can get prediction bugs that make us backfacing for one frame and + // it resets the mouse position if we lose focus. + if ( pScreen->IsBackfacing(viewPosition) ) continue; // Don't bother with screens that are turned off @@ -715,6 +740,9 @@ C_BaseEntity *FindNearbyVguiScreen( const Vector &viewPosition, const QAngle &vi if ( !pScreen->AcceptsInput() ) continue; + if ( pScreen->IsInputOnlyToOwner() && pScreen->GetPlayerOwner() != pLocalPlayer ) + continue; + // Test perpendicular distance from the screen... pScreen->GetVectors( NULL, NULL, &vecOut ); VectorSubtract( viewPosition, pScreen->GetAbsOrigin(), vecViewDelta ); @@ -738,7 +766,7 @@ C_BaseEntity *FindNearbyVguiScreen( const Vector &viewPosition, const QAngle &vi pBestScreen = pScreen; } } - + return pBestScreen; } @@ -836,4 +864,17 @@ vgui::Panel *CVGuiScreenPanel::CreateControlByName(const char *controlName) return BaseClass::CreateControlByName( controlName ); } +//----------------------------------------------------------------------------- +// Purpose: Called when the user presses a button +//----------------------------------------------------------------------------- +void CVGuiScreenPanel::OnCommand( const char *command) +{ + if ( Q_stricmp( command, "vguicancel" ) ) + { + engine->ClientCmd( const_cast( command ) ); + } + + BaseClass::OnCommand(command); +} + DECLARE_VGUI_SCREEN_FACTORY( CVGuiScreenPanel, "vgui_screen_panel" ); \ No newline at end of file diff --git a/src/src/cl_dll/c_vguiscreen.h b/src/src/game/client/c_vguiscreen.h similarity index 50% rename from src/src/cl_dll/c_vguiscreen.h rename to src/src/game/client/c_vguiscreen.h index c9bc103..8de0712 100644 --- a/src/src/cl_dll/c_vguiscreen.h +++ b/src/src/game/client/c_vguiscreen.h @@ -48,6 +48,7 @@ public: CVGuiScreenPanel( vgui::Panel *parent, const char *panelName, vgui::HScheme hScheme ); virtual bool Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData ); vgui::Panel *CreateControlByName(const char *controlName); + virtual void CVGuiScreenPanel::OnCommand( const char *command ); protected: C_BaseEntity *GetEntity() const { return m_hEntity.Get(); } @@ -56,6 +57,108 @@ private: EHANDLE m_hEntity; }; +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class C_VGuiScreen : public C_BaseEntity +{ + DECLARE_CLASS( C_VGuiScreen, C_BaseEntity ); +public: + DECLARE_CLIENTCLASS(); + + C_VGuiScreen(); + ~C_VGuiScreen(); + + virtual void PreDataUpdate( DataUpdateType_t updateType ); + virtual void OnDataChanged( DataUpdateType_t type ); + virtual int DrawModel( int flags ); + virtual bool ShouldDraw( void ); + virtual void ClientThink( ); + virtual void GetAimEntOrigin( IClientEntity *pAttachedTo, Vector *pOrigin, QAngle *pAngles ); + virtual bool IsVisibleToPlayer( C_BasePlayer *pViewingPlayer ); + virtual bool IsTransparent( void ); + + const char *PanelName() const; + + // The view screen has the cursor pointing at it + void GainFocus( ); + void LoseFocus(); + + // Button state... + void SetButtonState( int nButtonState ); + + // Is the screen backfaced given a view position? + bool IsBackfacing( const Vector &viewOrigin ); + + // Return intersection point of ray with screen in barycentric coords + bool IntersectWithRay( const Ray_t &ray, float *u, float *v, float *t ); + + // Is the screen turned on? + bool IsActive() const; + + // Are we only visible to teammates? + bool IsVisibleOnlyToTeammates() const; + + // Are we visible to someone on this team? + bool IsVisibleToTeam( int nTeam ); + + bool IsAttachedToViewModel() const; + + virtual RenderGroup_t GetRenderGroup(); + + bool AcceptsInput() const; + void SetAcceptsInput( bool acceptsinput ); + + C_BasePlayer *GetPlayerOwner( void ); + bool IsInputOnlyToOwner( void ); + +private: + // Vgui screen management + void CreateVguiScreen( const char *pTypeName ); + void DestroyVguiScreen( ); + + // Computes the panel to world transform + void ComputePanelToWorld(); + + // Computes control points of the quad describing the screen + void ComputeEdges( Vector *pUpperLeft, Vector *pUpperRight, Vector *pLowerLeft ); + + // Writes the z buffer + void DrawScreenOverlay(); + +private: + int m_nPixelWidth; + int m_nPixelHeight; + float m_flWidth; + float m_flHeight; + int m_nPanelName; // The name of the panel + int m_nButtonState; + int m_nButtonPressed; + int m_nButtonReleased; + int m_nOldPx; + int m_nOldPy; + int m_nOldButtonState; + int m_nAttachmentIndex; + int m_nOverlayMaterial; + int m_fScreenFlags; + + int m_nOldPanelName; + int m_nOldOverlayMaterial; + + bool m_bLoseThinkNextFrame; + + bool m_bAcceptsInput; + + CMaterialReference m_WriteZMaterial; + CMaterialReference m_OverlayMaterial; + + VMatrix m_PanelToWorld; + + CPanelWrapper m_PanelWrapper; + + CHandle m_hPlayerOwner; +}; + //----------------------------------------------------------------------------- // Returns an entity that is the nearby vgui screen; NULL if there isn't one diff --git a/src/src/cl_dll/hl2_hud/c_waterlodcontrol.cpp b/src/src/game/client/c_waterlodcontrol.cpp similarity index 100% rename from src/src/cl_dll/hl2_hud/c_waterlodcontrol.cpp rename to src/src/game/client/c_waterlodcontrol.cpp diff --git a/src/src/cl_dll/c_weapon__stubs.h b/src/src/game/client/c_weapon__stubs.h similarity index 93% rename from src/src/cl_dll/c_weapon__stubs.h rename to src/src/game/client/c_weapon__stubs.h index aa06fc1..1699e19 100644 --- a/src/src/cl_dll/c_weapon__stubs.h +++ b/src/src/game/client/c_weapon__stubs.h @@ -14,7 +14,7 @@ #include "client_class.h" // This is an ugly hack to link client classes to weapons for now -// these will be removed once we predict all weapons +// these will be removed once we predict all weapons, especially TF2 weapons #define STUB_WEAPON_CLASS_IMPLEMENT( entityName, className ) \ BEGIN_PREDICTION_DATA( className ) \ END_PREDICTION_DATA() \ diff --git a/src/src/cl_dll/c_world.cpp b/src/src/game/client/c_world.cpp similarity index 100% rename from src/src/cl_dll/c_world.cpp rename to src/src/game/client/c_world.cpp diff --git a/src/src/cl_dll/c_world.h b/src/src/game/client/c_world.h similarity index 95% rename from src/src/cl_dll/c_world.h rename to src/src/game/client/c_world.h index 480aba0..9c07358 100644 --- a/src/src/cl_dll/c_world.h +++ b/src/src/game/client/c_world.h @@ -33,7 +33,7 @@ public: virtual void Spawn(); // Don't worry about adding the world to the collision list; it's already there - virtual CollideType_t ShouldCollide( ) { return ENTITY_SHOULD_NOT_COLLIDE; } + virtual CollideType_t GetCollideType( void ) { return ENTITY_SHOULD_NOT_COLLIDE; } virtual void OnDataChanged( DataUpdateType_t updateType ); virtual void PreDataUpdate( DataUpdateType_t updateType ); diff --git a/src/src/cl_dll/camomaterialproxy.cpp b/src/src/game/client/camomaterialproxy.cpp similarity index 99% rename from src/src/cl_dll/camomaterialproxy.cpp rename to src/src/game/client/camomaterialproxy.cpp index 87d0b0f..273d805 100644 --- a/src/src/cl_dll/camomaterialproxy.cpp +++ b/src/src/game/client/camomaterialproxy.cpp @@ -42,6 +42,7 @@ public: virtual ~CCamoMaterialProxy(); virtual bool Init( IMaterial *pMaterial, KeyValues *pKeyValues ); virtual void OnBind(C_BaseEntity *pC_BaseEntity ); + virtual IMaterial *GetMaterial(); // Procedurally generates the camo texture... void GenerateCamoTexture( ITexture* pTexture, IVTFTexture *pVTFTexture ); @@ -573,4 +574,9 @@ void CCamoMaterialProxy::GenerateRandomPointsInNormalizedCube( void ) } } +IMaterial *CCamoMaterialProxy::GetMaterial() +{ + return m_pMaterial; +} + EXPOSE_INTERFACE( CCamoMaterialProxy, IMaterialProxy, "Camo" IMATERIAL_PROXY_INTERFACE_VERSION ); diff --git a/src/src/cl_dll/cbase.h b/src/src/game/client/cbase.h similarity index 97% rename from src/src/cl_dll/cbase.h rename to src/src/game/client/cbase.h index b1c2a87..12774dc 100644 --- a/src/src/cl_dll/cbase.h +++ b/src/src/game/client/cbase.h @@ -19,7 +19,7 @@ struct studiohdr_t; #include #include -#include +#include #include #include diff --git a/src/src/game/client/cdll_bounded_cvars.cpp b/src/src/game/client/cdll_bounded_cvars.cpp new file mode 100644 index 0000000..6a088db --- /dev/null +++ b/src/src/game/client/cdll_bounded_cvars.cpp @@ -0,0 +1,139 @@ +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// +// +// Purpose: +// +// $NoKeywords: $ +//===========================================================================// + +#include "cbase.h" +#include "cdll_bounded_cvars.h" +#include "convar_serverbounded.h" + + +bool g_bForceCLPredictOff = false; + +// ------------------------------------------------------------------------------------------ // +// cl_predict. +// ------------------------------------------------------------------------------------------ // + +class CBoundedCvar_Predict : public ConVar_ServerBounded +{ +public: + CBoundedCvar_Predict() : + ConVar_ServerBounded( "cl_predict", + "1.0", +#if defined(DOD_DLL) || defined(CSTRIKE_DLL) + FCVAR_USERINFO | FCVAR_CHEAT, +#else + FCVAR_USERINFO, +#endif + "Perform client side prediction." ) + { + } + + virtual float GetFloat() const + { + // Used temporarily for CS kill cam. + if ( g_bForceCLPredictOff ) + return 0; + + static const ConVar *pClientPredict = dynamic_cast< const ConVar* >( g_pCVar->FindCommandBase( "sv_client_predict" ) ); + if ( pClientPredict && pClientPredict->GetInt() != -1 ) + { + // Ok, the server wants to control this value. + return pClientPredict->GetFloat(); + } + else + { + return GetBaseFloatValue(); + } + } +}; + +static CBoundedCvar_Predict cl_predict_var; +ConVar_ServerBounded *cl_predict = &cl_predict_var; + + + +// ------------------------------------------------------------------------------------------ // +// cl_interp_ratio. +// ------------------------------------------------------------------------------------------ // + +class CBoundedCvar_InterpRatio : public ConVar_ServerBounded +{ +public: + CBoundedCvar_InterpRatio() : + ConVar_ServerBounded( "cl_interp_ratio", + "2.0", + FCVAR_USERINFO, + "Sets the interpolation amount (final amount is cl_interp_ratio / cl_updaterate)." ) + { + } + + virtual float GetFloat() const + { + static const ConVar *pMin = dynamic_cast< const ConVar* >( g_pCVar->FindCommandBase( "sv_client_min_interp_ratio" ) ); + static const ConVar *pMax = dynamic_cast< const ConVar* >( g_pCVar->FindCommandBase( "sv_client_max_interp_ratio" ) ); + if ( pMin && pMax && pMin->GetFloat() != -1 ) + { + return clamp( GetBaseFloatValue(), pMin->GetFloat(), pMax->GetFloat() ); + } + else + { + return GetBaseFloatValue(); + } + } +}; + +static CBoundedCvar_InterpRatio cl_interp_ratio_var; +ConVar_ServerBounded *cl_interp_ratio = &cl_interp_ratio_var; + + +// ------------------------------------------------------------------------------------------ // +// cl_interp +// ------------------------------------------------------------------------------------------ // + +class CBoundedCvar_Interp : public ConVar_ServerBounded +{ +public: + CBoundedCvar_Interp() : + ConVar_ServerBounded( "cl_interp", + "0.1", + FCVAR_USERINFO, + "Sets the interpolation amount (bounded on low side by server interp ratio settings).", true, 0.0f, true, 0.5f ) + { + } + + virtual float GetFloat() const + { + static const ConVar_ServerBounded *pUpdateRate = dynamic_cast< const ConVar_ServerBounded* >( g_pCVar->FindCommandBase( "cl_updaterate" ) ); + static const ConVar *pMin = dynamic_cast< const ConVar* >( g_pCVar->FindCommandBase( "sv_client_min_interp_ratio" ) ); + if ( pUpdateRate && pMin && pMin->GetFloat() != -1 ) + { + return max( GetBaseFloatValue(), pMin->GetFloat() / pUpdateRate->GetFloat() ); + } + else + { + return GetBaseFloatValue(); + } + } +}; + +static CBoundedCvar_Interp cl_interp_var; +ConVar_ServerBounded *cl_interp = &cl_interp_var; + +float GetClientInterpAmount() +{ + static const ConVar_ServerBounded *pUpdateRate = dynamic_cast< const ConVar_ServerBounded* >( g_pCVar->FindCommandBase( "cl_updaterate" ) ); + if ( pUpdateRate ) + { + // #define FIXME_INTERP_RATIO + return max( cl_interp->GetFloat(), cl_interp_ratio->GetFloat() / pUpdateRate->GetFloat() ); + } + else + { + AssertMsgOnce( false, "GetInterpolationAmount: can't get cl_updaterate cvar." ); + return 0.1; + } +} + diff --git a/src/src/game/client/cdll_bounded_cvars.h b/src/src/game/client/cdll_bounded_cvars.h new file mode 100644 index 0000000..a94bfc2 --- /dev/null +++ b/src/src/game/client/cdll_bounded_cvars.h @@ -0,0 +1,32 @@ +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: Provides access to cvars that are bounded in the client DLL. +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef CDLL_BOUNDED_CVARS_H +#define CDLL_BOUNDED_CVARS_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "convar_serverbounded.h" + + +extern ConVar_ServerBounded *cl_predict; +extern ConVar_ServerBounded *cl_interp; + +// Returns cl_interp_ratio / cl_updaterate. +float GetClientInterpAmount(); + + +#if !defined( NO_ENTITY_PREDICTION ) +extern bool g_bForceCLPredictOff; // If this is set to true, then prediction is forced off. Used temporarily for kill cam. +#endif + + + +#endif // CDLL_BOUNDED_CVARS_H + diff --git a/src/src/cl_dll/cdll_client_int.cpp b/src/src/game/client/cdll_client_int.cpp similarity index 77% rename from src/src/cl_dll/cdll_client_int.cpp rename to src/src/game/client/cdll_client_int.cpp index e3361a6..03f8ef7 100644 --- a/src/src/cl_dll/cdll_client_int.cpp +++ b/src/src/game/client/cdll_client_int.cpp @@ -8,7 +8,6 @@ #include #include "vgui_int.h" #include "clientmode.h" -#include "cdll_convar.h" #include "iinput.h" #include "iviewrender.h" #include "ivieweffects.h" @@ -16,6 +15,7 @@ #include "prediction.h" #include "clientsideeffects.h" #include "particlemgr.h" +#include "steam/steam_api.h" #include "initializer.h" #include "smoke_fog_overlay.h" #include "view.h" @@ -59,7 +59,7 @@ #include "datacache/idatacache.h" #include "datacache/imdlcache.h" #include "kbutton.h" -#include "vstdlib/icommandline.h" +#include "tier0/icommandline.h" #include "gamerules_register.h" #include "vgui_controls/AnimationController.h" #include "bitmap/tgawriter.h" @@ -67,24 +67,36 @@ #include "perfvisualbenchmark.h" #include "soundemittersystem/isoundemittersystembase.h" #include "hud_closecaption.h" +#include "colorcorrectionmgr.h" #include "physpropclientside.h" #include "panelmetaclassmgr.h" #include "c_vguiscreen.h" #include "imessagechars.h" -#include "cl_dll/IGameClientExports.h" +#include "game/client/IGameClientExports.h" #include "client_factorylist.h" #include "ragdoll_shared.h" #include "rendertexture.h" #include "view_scene.h" #include "iclientmode.h" #include "con_nprint.h" -#include "materialsystem/icolorcorrection.h" #include "inputsystem/iinputsystem.h" #include "appframework/IAppSystemGroup.h" #include "scenefilecache/ISceneFileCache.h" -#include "tier2/tier2.h" +#include "tier3/tier3.h" #include "avi/iavi.h" +#include "ihudlcd.h" +#include "toolframework_client.h" #include "hltvcamera.h" +#include "ixboxsystem.h" +#include "ipresence.h" +#include "engine/imatchmaking.h" +#include "cdll_bounded_cvars.h" +#include "matsys_controls/matsyscontrols.h" +#include "GameStats.h" + +#ifdef PORTAL +#include "PortalRender.h" +#endif // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -99,7 +111,6 @@ IVRenderView *render = NULL; IVDebugOverlay *debugoverlay = NULL; IMaterialSystemStub *materials_stub = NULL; IDataCache *datacache = NULL; -IMDLCache *mdlcache = NULL; IVModelInfoClient *modelinfo = NULL; IEngineVGui *enginevgui = NULL; INetworkStringTableContainer *networkstringtable = NULL; @@ -111,7 +122,6 @@ IEngineSound *enginesound = NULL; IUniformRandomStream *random = NULL; static CGaussianRandomStream s_GaussianRandomStream; CGaussianRandomStream *randomgaussian = &s_GaussianRandomStream; -IMatSystemSurface *g_pMatSystemSurface = NULL; ISharedGameRules *sharedgamerules = NULL; IEngineTrace *enginetrace = NULL; IGameUIFuncs *gameuifuncs = NULL; @@ -119,11 +129,31 @@ IGameEventManager2 *gameeventmanager = NULL; ISoundEmitterSystemBase *soundemitterbase = NULL; IInputSystem *inputsystem = NULL; ISceneFileCache *scenefilecache = NULL; +IXboxSystem *xboxsystem = NULL; // Xbox 360 only +IMatchmaking *matchmaking = NULL; IAvi *avi = NULL; +IUploadGameStats *gamestatsuploader = NULL; + IGameSystem *SoundEmitterSystem(); IGameSystem *ToolFrameworkClientSystem(); +static CSteamAPIContext g_SteamAPIContext; +CSteamAPIContext *steamapicontext = &g_SteamAPIContext; + +// Engine player info, no game related infos here +BEGIN_BYTESWAP_DATADESC( player_info_s ) + DEFINE_ARRAY( name, FIELD_CHARACTER, MAX_PLAYER_NAME_LENGTH ), + DEFINE_FIELD( userID, FIELD_INTEGER ), + DEFINE_ARRAY( guid, FIELD_CHARACTER, SIGNED_GUID_LEN + 1 ), + DEFINE_FIELD( friendsID, FIELD_INTEGER ), + DEFINE_ARRAY( friendsName, FIELD_CHARACTER, MAX_PLAYER_NAME_LENGTH ), + DEFINE_FIELD( fakeplayer, FIELD_BOOLEAN ), + DEFINE_FIELD( ishltv, FIELD_BOOLEAN ), + DEFINE_ARRAY( customFiles, FIELD_INTEGER, MAX_CUSTOM_FILES ), + DEFINE_FIELD( filesDownloaded, FIELD_INTEGER ), +END_BYTESWAP_DATADESC() + static bool g_bRequestCacheUsedMaterials = false; void RequestCacheUsedMaterials() { @@ -133,9 +163,7 @@ void RequestCacheUsedMaterials() void ProcessCacheUsedMaterials() { if ( !g_bRequestCacheUsedMaterials ) - { return; - } g_bRequestCacheUsedMaterials = false; if ( materials ) @@ -145,6 +173,7 @@ void ProcessCacheUsedMaterials() } // String tables +INetworkStringTable *g_pStringTableParticleEffectNames = NULL; INetworkStringTable *g_StringTableEffectDispatch = NULL; INetworkStringTable *g_StringTableVguiScreen = NULL; INetworkStringTable *g_pStringTableMaterials = NULL; @@ -203,13 +232,12 @@ static ConVar s_CV_ShowParticleCounts("showparticlecounts", "0", 0, "Display num static ConVar s_cl_team("cl_team", "default", FCVAR_USERINFO|FCVAR_ARCHIVE, "Default team when joining a game"); static ConVar s_cl_class("cl_class", "default", FCVAR_USERINFO|FCVAR_ARCHIVE, "Default class when joining a game"); -// Console variable accessor. -static CDLL_ConVarAccessor g_ConVarAccessor; - // Physics system bool g_bLevelInitialized; bool g_bTextMode = false; +static ConVar *g_pcv_ThreadMode = NULL; + //----------------------------------------------------------------------------- // Purpose: interface for gameui to modify voice bans //----------------------------------------------------------------------------- @@ -231,6 +259,24 @@ public: { GetClientVoiceMgr()->SetPlayerBlockedState(playerIndex, false); } + + void OnGameUIActivated( void ) + { + IGameEvent *event = gameeventmanager->CreateEvent( "gameui_activated" ); + if ( event ) + { + gameeventmanager->FireEventClientSide( event ); + } + } + + void OnGameUIHidden( void ) + { + IGameEvent *event = gameeventmanager->CreateEvent( "gameui_hidden" ); + if ( event ) + { + gameeventmanager->FireEventClientSide( event ); + } + } }; EXPOSE_SINGLE_INTERFACE( CGameClientExports, IGameClientExports, GAMECLIENTEXPORTS_INTERFACE_VERSION ); @@ -274,7 +320,6 @@ EXPOSE_SINGLE_INTERFACE( CClientDLLSharedAppSystems, IClientDLLSharedAppSystems, //----------------------------------------------------------------------------- // Helper interface for voice. //----------------------------------------------------------------------------- -#ifndef _XBOX class CHLVoiceStatusHelper : public IVoiceStatusHelper { public: @@ -293,7 +338,6 @@ public: } }; static CHLVoiceStatusHelper g_VoiceStatusHelper; -#endif //----------------------------------------------------------------------------- // Code to display which entities are having their bones setup each frame. @@ -402,6 +446,7 @@ public: virtual int Init( CreateInterfaceFn appSystemFactory, CreateInterfaceFn physicsFactory, CGlobalVarsBase *pGlobals ); + virtual void PostInit(); virtual void Shutdown( void ); virtual void LevelInitPreEntity( const char *pMapName ); @@ -419,12 +464,12 @@ public: // Mouse Input Interfaces virtual void IN_ActivateMouse( void ); virtual void IN_DeactivateMouse( void ); - virtual void IN_MouseEvent( int mstate, bool down ); virtual void IN_Accumulate( void ); virtual void IN_ClearStates( void ); virtual bool IN_IsKeyDown( const char *name, bool& isdown ); // Raw signal - virtual int IN_KeyEvent( int eventcode, int keynum, const char *pszCurrentBinding ); + virtual int IN_KeyEvent( int eventcode, ButtonCode_t keynum, const char *pszCurrentBinding ); + virtual void IN_SetSampleTime( float frametime ); // Create movement command virtual void CreateMove ( int sequence_number, float input_sample_frametime, bool active ); virtual void ExtraMouseSample( float frametime, bool active ); @@ -434,7 +479,7 @@ public: virtual void View_Render( vrect_t *rect ); - virtual void RenderView( const CViewSetup &view, int nClearFlags, bool drawViewmodel ); + virtual void RenderView( const CViewSetup &view, int nClearFlags, int whatToDraw ); virtual void View_Fade( ScreenFade_t *pSF ); virtual void SetCrosshairAngle( const QAngle& angle ); @@ -476,17 +521,23 @@ public: // save game screenshot writing virtual void WriteSaveGameScreenshotOfSize( const char *pFilename, int width, int height ); - // See RenderViewInfo_t - virtual void RenderViewEx( const CViewSetup &view, int nClearFlags, int whatToDraw ); - // Gets the location of the player viewpoint virtual bool GetPlayerView( CViewSetup &playerView ); + // Matchmaking + virtual void SetupGameProperties( CUtlVector< XUSER_CONTEXT > &contexts, CUtlVector< XUSER_PROPERTY > &properties ); + virtual uint GetPresenceID( const char *pIDName ); + virtual const char *GetPropertyIdString( const uint id ); + virtual void GetPropertyDisplayString( uint id, uint value, char *pOutput, int nBytes ); + virtual void StartStatsReporting( HANDLE handle, bool bArbitrated ); + + virtual void InvalidateMdlCache(); public: void PrecacheMaterial( const char *pMaterialName ); private: void UncacheAllMaterials( ); + void ResetStringTablePointers(); CUtlVector< IMaterial * > m_CachedMaterials; }; @@ -539,6 +590,55 @@ const char *GetMaterialNameFromIndex( int nIndex ) } +//----------------------------------------------------------------------------- +// Precaches a particle system +//----------------------------------------------------------------------------- +void PrecacheParticleSystem( const char *pParticleSystemName ) +{ + g_pStringTableParticleEffectNames->AddString( false, pParticleSystemName ); + g_pParticleSystemMgr->PrecacheParticleSystem( pParticleSystemName ); +} + + +//----------------------------------------------------------------------------- +// Converts a previously precached particle system into an index +//----------------------------------------------------------------------------- +int GetParticleSystemIndex( const char *pParticleSystemName ) +{ + if ( pParticleSystemName ) + { + int nIndex = g_pStringTableParticleEffectNames->FindStringIndex( pParticleSystemName ); + if ( nIndex != INVALID_STRING_INDEX ) + return nIndex; + DevWarning("Client: Missing precache for particle system \"%s\"!\n", pParticleSystemName ); + } + + // This is the invalid string index + return 0; +} + +//----------------------------------------------------------------------------- +// Converts precached particle system indices into strings +//----------------------------------------------------------------------------- +const char *GetParticleSystemNameFromIndex( int nIndex ) +{ + if ( nIndex < g_pStringTableParticleEffectNames->GetMaxStrings() ) + return g_pStringTableParticleEffectNames->GetString( nIndex ); + return "error"; +} + +//----------------------------------------------------------------------------- +// Returns true if host_thread_mode is set to non-zero (and engine is running in threaded mode) +//----------------------------------------------------------------------------- +bool IsEngineThreaded() +{ + if ( g_pcv_ThreadMode ) + { + return g_pcv_ThreadMode->GetBool(); + } + return false; +} + //----------------------------------------------------------------------------- // Constructor //----------------------------------------------------------------------------- @@ -551,7 +651,27 @@ CHLClient::CHLClient() extern IGameSystem *ViewportClientSystem(); +//Tony; added to fetch the gameinfo file and mount additional content. +static void MountAdditionalContent() +{ + KeyValues *pMainFile, *pFileSystemInfo; + int nExtraContentId = -1; + + pMainFile = new KeyValues( "gameinfo.txt" ); + if ( pMainFile->LoadFromFile( filesystem, VarArgs("%s/gameinfo.txt", engine->GetGameDirectory()), "MOD" ) ) + { + pFileSystemInfo = pMainFile->FindKey( "FileSystem" ); + if (pFileSystemInfo) + nExtraContentId = pFileSystemInfo->GetInt( "AdditionalContentId", -1 ); + } + pMainFile->deleteThis(); + if (nExtraContentId != -1) + { + if( filesystem->MountSteamContent(-nExtraContentId) != FILESYSTEM_MOUNT_OK ) + Warning("Unable to mount extra content with appId: %i\n", nExtraContentId); + } +} //----------------------------------------------------------------------------- // Purpose: Called when the DLL is first loaded. // Input : engineFactory - @@ -567,6 +687,9 @@ int CHLClient::Init( CreateInterfaceFn appSystemFactory, CreateInterfaceFn physi ConnectTier1Libraries( &appSystemFactory, 1 ); ConnectTier2Libraries( &appSystemFactory, 1 ); + ConnectTier3Libraries( &appSystemFactory, 1 ); + + g_SteamAPIContext.Init(); // We aren't happy unless we get all of our interfaces. // please don't collapse this into one monolithic boolean expression (impossible to debug) @@ -584,7 +707,7 @@ int CHLClient::Init( CreateInterfaceFn appSystemFactory, CreateInterfaceFn physi return false; if ( (datacache = (IDataCache*)appSystemFactory(DATACACHE_INTERFACE_VERSION, NULL )) == NULL ) return false; - if ( (mdlcache = (IMDLCache*)appSystemFactory(MDLCACHE_INTERFACE_VERSION, NULL )) == NULL ) + if ( !mdlcache ) return false; if ( (modelinfo = (IVModelInfoClient *)appSystemFactory(VMODELINFO_CLIENT_INTERFACE_VERSION, NULL )) == NULL ) return false; @@ -610,14 +733,22 @@ int CHLClient::Init( CreateInterfaceFn appSystemFactory, CreateInterfaceFn physi return false; if ( (soundemitterbase = (ISoundEmitterSystemBase *)appSystemFactory(SOUNDEMITTERSYSTEM_INTERFACE_VERSION, NULL)) == NULL ) return false; - if ( IsPC() && !colorcorrection ) - return false; if ( (inputsystem = (IInputSystem *)appSystemFactory(INPUTSYSTEM_INTERFACE_VERSION, NULL)) == NULL ) return false; - if ( (avi = (IAvi *)appSystemFactory(AVI_INTERFACE_VERSION, NULL)) == NULL ) + if ( IsPC() && (avi = (IAvi *)appSystemFactory(AVI_INTERFACE_VERSION, NULL)) == NULL ) return false; if ( (scenefilecache = (ISceneFileCache *)appSystemFactory( SCENE_FILE_CACHE_INTERFACE_VERSION, NULL )) == NULL ) return false; + if ( IsX360() && (xboxsystem = (IXboxSystem *)appSystemFactory( XBOXSYSTEM_INTERFACE_VERSION, NULL )) == NULL ) + return false; + if ( IsX360() && (matchmaking = (IMatchmaking *)appSystemFactory( VENGINE_MATCHMAKING_VERSION, NULL )) == NULL ) + return false; +#ifndef _XBOX + if ( ( gamestatsuploader = (IUploadGameStats *)appSystemFactory( INTERFACEVERSION_UPLOADGAMESTATS, NULL )) == NULL ) + return false; +#endif + if (!g_pMatSystemSurface) + return false; factorylist_t factories; factories.appSystemFactory = appSystemFactory; @@ -630,16 +761,17 @@ int CHLClient::Init( CreateInterfaceFn appSystemFactory, CreateInterfaceFn physi return false; } + //Tony; mount an extra appId if it exists. + MountAdditionalContent(); + if ( CommandLine()->FindParm( "-textmode" ) ) g_bTextMode = true; if ( CommandLine()->FindParm( "-makedevshots" ) ) g_MakingDevShots = true; -#ifndef _XBOX // Not fatal if the material system stub isn't around. materials_stub = (IMaterialSystemStub*)appSystemFactory( MATERIAL_SYSTEM_STUB_INTERFACE_VERSION, NULL ); -#endif if( !g_pMaterialSystemHardwareConfig ) return false; @@ -648,7 +780,9 @@ int CHLClient::Init( CreateInterfaceFn appSystemFactory, CreateInterfaceFn physi s_GaussianRandomStream.AttachToStream( random ); // Initialize the console variables. - ConCommandBaseMgr::OneTimeInit(&g_ConVarAccessor); + ConVar_Register( FCVAR_CLIENTDLL ); + + g_pcv_ThreadMode = g_pCVar->FindVar( "host_thread_mode" ); if (!Initializer::InitializeAllObjects()) return false; @@ -656,27 +790,24 @@ int CHLClient::Init( CreateInterfaceFn appSystemFactory, CreateInterfaceFn physi if (!ParticleMgr()->Init(MAX_TOTAL_PARTICLES, materials)) return false; + if (!VGui_Startup( appSystemFactory )) return false; - g_pMatSystemSurface = (IMatSystemSurface*)vgui::surface()->QueryInterface( MAT_SYSTEM_SURFACE_INTERFACE_VERSION ); - if (!g_pMatSystemSurface) - return false; + vgui::VGui_InitMatSysInterfacesList( "ClientDLL", &appSystemFactory, 1 ); // Add the client systems. // Client Leaf System has to be initialized first, since DetailObjectSystem uses it IGameSystem::Add( GameStringSystem() ); IGameSystem::Add( SoundEmitterSystem() ); - if ( ToolsEnabled() ) - { - IGameSystem::Add( ToolFrameworkClientSystem() ); - } + IGameSystem::Add( ToolFrameworkClientSystem() ); IGameSystem::Add( ClientLeafSystem() ); IGameSystem::Add( DetailObjectSystem() ); IGameSystem::Add( ViewportClientSystem() ); IGameSystem::Add( ClientEffectPrecacheSystem() ); IGameSystem::Add( g_pClientShadowMgr ); + IGameSystem::Add( g_pColorCorrectionMgr ); // NOTE: This must happen prior to ClientThinkList (color correction is updated there) IGameSystem::Add( ClientThinkList() ); IGameSystem::Add( ClientSoundscapeSystem() ); IGameSystem::Add( PerfVisualBenchmark() ); @@ -717,7 +848,6 @@ int CHLClient::Init( CreateInterfaceFn appSystemFactory, CreateInterfaceFn physi // Register user messages.. CUserMessageRegister::RegisterAll(); -#ifndef _XBOX ClientVoiceMgr_Init(); // Embed voice status icons inside chat element @@ -725,7 +855,6 @@ int CHLClient::Init( CreateInterfaceFn appSystemFactory, CreateInterfaceFn physi vgui::VPANEL parent = enginevgui->GetPanel( PANEL_CLIENTDLL ); GetClientVoiceMgr()->Init( &g_VoiceStatusHelper, parent ); } -#endif if ( !PhysicsDLLInit( physicsFactory ) ) return false; @@ -736,24 +865,32 @@ int CHLClient::Init( CreateInterfaceFn appSystemFactory, CreateInterfaceFn physi ClientWorldFactoryInit(); + C_BaseAnimating::InitBoneSetupThreadPool(); + return true; } +//----------------------------------------------------------------------------- +// Purpose: Called after client & server DLL are loaded and all systems initialized +//----------------------------------------------------------------------------- +void CHLClient::PostInit() +{ + IGameSystem::PostInitAllSystems(); +} //----------------------------------------------------------------------------- // Purpose: Called when the client .dll is being dismissed //----------------------------------------------------------------------------- void CHLClient::Shutdown( void ) { + C_BaseAnimating::ShutdownBoneSetupThreadPool(); ClientWorldFactoryShutdown(); g_pGameSaveRestoreBlockSet->RemoveBlockHandler( GetViewEffectsRestoreBlockHandler() ); g_pGameSaveRestoreBlockSet->RemoveBlockHandler( GetPhysSaveRestoreBlockHandler() ); g_pGameSaveRestoreBlockSet->RemoveBlockHandler( GetEntitySaveRestoreBlockHandler() ); -#ifndef _XBOX ClientVoiceMgr_Shutdown(); -#endif Initializer::FreeAllObjects(); @@ -764,6 +901,7 @@ void CHLClient::Shutdown( void ) C_BaseTempEntity::ClearDynamicTempEnts(); TermSmokeFogOverlay(); view->Shutdown(); + g_pParticleSystemMgr->UncacheAllParticleSystems(); UncacheAllMaterials(); IGameSystem::ShutdownAllSystems(); @@ -773,9 +911,9 @@ void CHLClient::Shutdown( void ) ClearKeyValuesCache(); - g_pMatSystemSurface = NULL; - + DisconnectTier3Libraries( ); DisconnectTier2Libraries( ); + ConVar_Unregister(); DisconnectTier1Libraries( ); } @@ -790,9 +928,8 @@ void CHLClient::Shutdown( void ) int CHLClient::HudVidInit( void ) { gHUD.VidInit(); -#ifndef _XBOX + GetClientVoiceMgr()->VidInit(); -#endif return 1; } @@ -813,18 +950,22 @@ void CHLClient::HudProcessInput( bool bActive ) void CHLClient::HudUpdate( bool bActive ) { float frametime = gpGlobals->frametime; -#ifndef _XBOX + GetClientVoiceMgr()->Frame( frametime ); -#endif + gHUD.UpdateHud( bActive ); - C_BaseAnimating::AllowBoneAccess( true, false ); - IGameSystem::UpdateAllSystems( frametime ); - C_BaseAnimating::AllowBoneAccess( false, false ); + { + C_BaseAnimating::AutoAllowBoneAccess boneaccess( true, false ); + IGameSystem::UpdateAllSystems( frametime ); + } // run vgui animations vgui::GetAnimationController()->UpdateAnimations( engine->Time() ); + hudlcd->SetGlobalStat( "(time_int)", VarArgs( "%d", (int)gpGlobals->curtime ) ); + hudlcd->SetGlobalStat( "(time_float)", VarArgs( "%.2f", gpGlobals->curtime ) ); + // I don't think this is necessary any longer, but I will leave it until // I can check into this further. C_BaseTempEntity::CheckDynamicTempEnts(); @@ -862,9 +1003,7 @@ ClientClass *CHLClient::GetAllClasses( void ) //----------------------------------------------------------------------------- void CHLClient::IN_ActivateMouse( void ) { -#ifndef _XBOX input->ActivateMouse(); -#endif } //----------------------------------------------------------------------------- @@ -872,20 +1011,7 @@ void CHLClient::IN_ActivateMouse( void ) //----------------------------------------------------------------------------- void CHLClient::IN_DeactivateMouse( void ) { -#ifndef _XBOX input->DeactivateMouse(); -#endif -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : mstate - -//----------------------------------------------------------------------------- -void CHLClient::IN_MouseEvent ( int mstate, bool down ) -{ -#ifndef _XBOX - input->MouseEvent( mstate, down ); -#endif } //----------------------------------------------------------------------------- @@ -893,9 +1019,7 @@ void CHLClient::IN_MouseEvent ( int mstate, bool down ) //----------------------------------------------------------------------------- void CHLClient::IN_Accumulate ( void ) { -#ifndef _XBOX input->AccumulateMouse(); -#endif } //----------------------------------------------------------------------------- @@ -931,7 +1055,7 @@ bool CHLClient::IN_IsKeyDown( const char *name, bool& isdown ) // *pszCurrentBinding - // Output : int //----------------------------------------------------------------------------- -int CHLClient::IN_KeyEvent( int eventcode, int keynum, const char *pszCurrentBinding ) +int CHLClient::IN_KeyEvent( int eventcode, ButtonCode_t keynum, const char *pszCurrentBinding ) { return input->KeyEvent( eventcode, keynum, pszCurrentBinding ); } @@ -941,14 +1065,17 @@ void CHLClient::ExtraMouseSample( float frametime, bool active ) Assert( C_BaseEntity::IsAbsRecomputationsEnabled() ); Assert( C_BaseEntity::IsAbsQueriesValid() ); - C_BaseAnimating::AllowBoneAccess( true, false ); + C_BaseAnimating::AutoAllowBoneAccess boneaccess( true, false ); MDLCACHE_CRITICAL_SECTION(); input->ExtraMouseSample( frametime, active ); - - C_BaseAnimating::AllowBoneAccess( false, false ); } +void CHLClient::IN_SetSampleTime( float frametime ) +{ + input->Joystick_SetSampleTime( frametime ); + input->IN_SetSampleTime( frametime ); +} //----------------------------------------------------------------------------- // Purpose: Fills in usercmd_s structure based on current view angles and key/controller inputs // Input : frametime - timestamp for last frame @@ -961,13 +1088,10 @@ void CHLClient::CreateMove ( int sequence_number, float input_sample_frametime, Assert( C_BaseEntity::IsAbsRecomputationsEnabled() ); Assert( C_BaseEntity::IsAbsQueriesValid() ); - C_BaseAnimating::AllowBoneAccess( true, false ); + C_BaseAnimating::AutoAllowBoneAccess boneaccess( true, false ); MDLCACHE_CRITICAL_SECTION(); input->CreateMove( sequence_number, input_sample_frametime, active ); - - C_BaseAnimating::AllowBoneAccess( false, false ); - } //----------------------------------------------------------------------------- @@ -1015,6 +1139,7 @@ void CHLClient::View_Render( vrect_t *rect ) return; view->Render( rect ); + UpdatePerfStats(); } @@ -1027,6 +1152,49 @@ bool CHLClient::GetPlayerView( CViewSetup &playerView ) return true; } +//----------------------------------------------------------------------------- +// Matchmaking +//----------------------------------------------------------------------------- +void CHLClient::SetupGameProperties( CUtlVector< XUSER_CONTEXT > &contexts, CUtlVector< XUSER_PROPERTY > &properties ) +{ + presence->SetupGameProperties( contexts, properties ); +} + +uint CHLClient::GetPresenceID( const char *pIDName ) +{ + return presence->GetPresenceID( pIDName ); +} + +const char *CHLClient::GetPropertyIdString( const uint id ) +{ + return presence->GetPropertyIdString( id ); +} + +void CHLClient::GetPropertyDisplayString( uint id, uint value, char *pOutput, int nBytes ) +{ + presence->GetPropertyDisplayString( id, value, pOutput, nBytes ); +} + +void CHLClient::StartStatsReporting( HANDLE handle, bool bArbitrated ) +{ + presence->StartStatsReporting( handle, bArbitrated ); +} + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +void CHLClient::InvalidateMdlCache() +{ + C_BaseAnimating *pAnimating; + for ( C_BaseEntity *pEntity = ClientEntityList().FirstBaseEntity(); pEntity; pEntity = ClientEntityList().NextBaseEntity(pEntity) ) + { + pAnimating = dynamic_cast(pEntity); + if ( pAnimating ) + { + pAnimating->InvalidateMdlCache(); + } + } +} //----------------------------------------------------------------------------- // Purpose: @@ -1052,8 +1220,14 @@ void CHLClient::LevelInitPreEntity( char const* pMapName ) vieweffects->LevelInit(); + //Tony; loadup per-map manifests. + ParseParticleEffectsMap( pMapName, true ); + // Tell mode manager that map is changing modemanager->LevelInit( pMapName ); + ParticleMgr()->LevelInit(); + + hudlcd->SetGlobalStat( "(mapname)", pMapName ); C_BaseTempEntity::ClearDynamicTempEnts(); clienteffects->Flush(); @@ -1068,16 +1242,16 @@ void CHLClient::LevelInitPreEntity( char const* pMapName ) #if !defined( NO_ENTITY_PREDICTION ) // don't do prediction if single player! // don't set direct because of FCVAR_USERINFO - if ( (gpGlobals->maxClients > 1) && !engine->IsHLTV() ) + if ( gpGlobals->maxClients > 1 ) { - if ( !cl_predict.GetBool() ) + if ( !cl_predict->GetInt() ) { engine->ClientCmd( "cl_predict 1" ); } } else { - if ( cl_predict.GetBool() ) + if ( cl_predict->GetInt() ) { engine->ClientCmd( "cl_predict 0" ); } @@ -1101,6 +1275,18 @@ void CHLClient::LevelInitPostEntity( ) internalCenterPrint->Clear(); } +//----------------------------------------------------------------------------- +// Purpose: Reset our global string table pointers +//----------------------------------------------------------------------------- +void CHLClient::ResetStringTablePointers() +{ + g_pStringTableParticleEffectNames = NULL; + g_StringTableEffectDispatch = NULL; + g_StringTableVguiScreen = NULL; + g_pStringTableMaterials = NULL; + g_pStringTableInfoPanel = NULL; + g_pStringTableClientSideChoreoScenes = NULL; +} //----------------------------------------------------------------------------- // Purpose: Per level de-init @@ -1110,6 +1296,7 @@ void CHLClient::LevelShutdown( void ) // HACK: Bogus, but the logic is too complicated in the engine if (!g_bLevelInitialized) return; + g_bLevelInitialized = false; // Disable abs recomputations when everything is shutting down @@ -1123,6 +1310,10 @@ void CHLClient::LevelShutdown( void ) modemanager->LevelShutdown(); + // Remove temporary entities before removing entities from the client entity list so that the te_* may + // clean up before hand. + tempents->LevelShutdown(); + // Now release/delete the entities cl_entitylist->Release(); @@ -1137,8 +1328,6 @@ void CHLClient::LevelShutdown( void ) IGameSystem::LevelShutdownPostEntityAllSystems(); view->LevelShutdown(); - - tempents->LevelShutdown(); beams->ClearBeams(); ParticleMgr()->RemoveAllEffects(); @@ -1147,25 +1336,18 @@ void CHLClient::LevelShutdown( void ) gHUD.LevelShutdown(); internalCenterPrint->Clear(); -#ifndef _XBOX + messagechars->Clear(); -#endif + + g_pParticleSystemMgr->UncacheAllParticleSystems(); UncacheAllMaterials(); #ifdef _XBOX ReleaseRenderTargets(); #endif -} - -//----------------------------------------------------------------------------- -// Purpose: Engine can directly ask to render a view ( timerefresh and envmap creation, e.g. ) -// Input : &vs - -// drawViewmodel - -//----------------------------------------------------------------------------- -void CHLClient::RenderView( const CViewSetup &vs, int nClearFlags, bool drawViewmodel ) -{ - view->RenderView( vs, nClearFlags, drawViewmodel ); + // string tables are cleared on disconnect from a server, so reset our global pointers to NULL + ResetStringTablePointers(); } @@ -1224,9 +1406,7 @@ int CHLClient::GetSpriteSize( void ) const //----------------------------------------------------------------------------- void CHLClient::VoiceStatus( int entindex, qboolean bTalking ) { -#ifndef _XBOX GetClientVoiceMgr()->UpdateSpeakerStatus( entindex, !!bTalking ); -#endif } @@ -1237,10 +1417,21 @@ void OnMaterialStringTableChanged( void *object, INetworkStringTable *stringTabl { // Make sure this puppy is precached gHLClient.PrecacheMaterial( newString ); - RequestCacheUsedMaterials(); } + +//----------------------------------------------------------------------------- +// Called when the string table for particle systems changes +//----------------------------------------------------------------------------- +void OnParticleSystemStringTableChanged( void *object, INetworkStringTable *stringTable, int stringNumber, const char *newString, void const *newData ) +{ + // Make sure this puppy is precached + g_pParticleSystemMgr->PrecacheParticleSystem( newString ); + RequestCacheUsedMaterials(); +} + + //----------------------------------------------------------------------------- // Called when the string table for VGUI changes //----------------------------------------------------------------------------- @@ -1262,7 +1453,6 @@ void OnVguiScreenTableChanged( void *object, INetworkStringTable *stringTable, i //----------------------------------------------------------------------------- void OnSceneStringTableChanged( void *object, INetworkStringTable *stringTable, int stringNumber, const char *newString, void const *newData ) { - scenefilecache->FindOrAddScene( newString ); } //----------------------------------------------------------------------------- @@ -1301,6 +1491,13 @@ void CHLClient::InstallStringTableCallback( const char *tableName ) g_pStringTableClientSideChoreoScenes = networkstringtable->FindTable( tableName ); g_pStringTableClientSideChoreoScenes->SetStringChangedCallback( NULL, OnSceneStringTableChanged ); } + else if ( !Q_strcasecmp( tableName, "ParticleEffectNames" ) ) + { + g_pStringTableParticleEffectNames = networkstringtable->FindTable( tableName ); + networkstringtable->SetAllowClientSideAddString( g_pStringTableParticleEffectNames, true ); + // When the particle system list changes, we need to know immediately + g_pStringTableParticleEffectNames->SetStringChangedCallback( NULL, OnParticleSystemStringTableChanged ); + } InstallStringTableCallback_GameRules(); @@ -1355,17 +1552,20 @@ bool CHLClient::DispatchUserMessage( int msg_type, bf_read &msg_data ) void SimulateEntities() { - input->CAM_Think(); + VPROF_BUDGET("Client SimulateEntities", VPROF_BUDGETGROUP_CLIENT_SIM); // Service timer events (think functions). ClientThinkList()->PerformThinkFunctions(); // TODO: make an ISimulateable interface so C_BaseNetworkables can simulate? - C_BaseEntityIterator iterator; - C_BaseEntity *pEnt; - while ( (pEnt = iterator.Next()) != NULL ) { - pEnt->Simulate(); + VPROF_("C_BaseEntity::Simulate", 1, VPROF_BUDGETGROUP_CLIENT_SIM, false, BUDGETFLAG_CLIENT); + C_BaseEntityIterator iterator; + C_BaseEntity *pEnt; + while ( (pEnt = iterator.Next()) != NULL ) + { + pEnt->Simulate(); + } } } @@ -1401,6 +1601,7 @@ void ClearDataChangedEvent( int iStoredEvent ) void ProcessOnDataChangedEvents() { + VPROF_("ProcessOnDataChangedEvents", 1, VPROF_BUDGETGROUP_CLIENT_SIM, false, BUDGETFLAG_CLIENT); FOR_EACH_LL( g_DataChangedEvents, i ) { CDataChangedEvent *pEvent = &g_DataChangedEvents[i]; @@ -1417,8 +1618,44 @@ void ProcessOnDataChangedEvents() } +void UpdateClientRenderableInPVSStatus() +{ + // Vis for this view should already be setup at this point. + + // For each client-only entity, notify it if it's newly coming into the PVS. + CUtlLinkedList &theList = ClientEntityList().GetPVSNotifiers(); + FOR_EACH_LL( theList, i ) + { + CClientEntityList::CPVSNotifyInfo *pInfo = &theList[i]; + + if ( pInfo->m_InPVSStatus & INPVS_YES ) + { + // Ok, this entity already thinks it's in the PVS. No need to notify it. + // We need to set the INPVS_YES_THISFRAME flag if it's in this frame at all, so we + // don't tell the entity it's not in the PVS anymore at the end of the frame. + if ( !( pInfo->m_InPVSStatus & INPVS_THISFRAME ) ) + { + if ( g_pClientLeafSystem->IsRenderableInPVS( pInfo->m_pRenderable ) ) + { + pInfo->m_InPVSStatus |= INPVS_THISFRAME; + } + } + } + else + { + // This entity doesn't think it's in the PVS yet. If it is now in the PVS, let it know. + if ( g_pClientLeafSystem->IsRenderableInPVS( pInfo->m_pRenderable ) ) + { + pInfo->m_InPVSStatus |= ( INPVS_YES | INPVS_THISFRAME | INPVS_NEEDSNOTIFY ); + } + } + } +} + void UpdatePVSNotifiers() { + MDLCACHE_CRITICAL_SECTION(); + // At this point, all the entities that were rendered in the previous frame have INPVS_THISFRAME set // so we can tell the entities that aren't in the PVS anymore so. CUtlLinkedList &theList = ClientEntityList().GetPVSNotifiers(); @@ -1431,8 +1668,12 @@ void UpdatePVSNotifiers() { if ( pInfo->m_InPVSStatus & INPVS_THISFRAME ) { + if ( pInfo->m_InPVSStatus & INPVS_NEEDSNOTIFY ) + { + pInfo->m_pNotify->OnPVSStatusChanged( true ); + } // Clear it for the next time around. - pInfo->m_InPVSStatus &= ~INPVS_THISFRAME; + pInfo->m_InPVSStatus &= ~( INPVS_THISFRAME | INPVS_NEEDSNOTIFY ); } else { @@ -1448,6 +1689,11 @@ void OnRenderStart() { VPROF( "OnRenderStart" ); MDLCACHE_CRITICAL_SECTION(); + MDLCACHE_COARSE_LOCK(); + +#ifdef PORTAL + g_pPortalRender->UpdatePortalPixelVisibility(); //updating this one or two lines before querying again just isn't cutting it. Update as soon as it's cheap to do so. +#endif partition->SuppressLists( PARTITION_ALL_CLIENT_EDICTS, true ); C_BaseEntity::SetAbsQueriesValid( false ); @@ -1455,27 +1701,40 @@ void OnRenderStart() Rope_ResetCounters(); // Interpolate server entities and move aiments. - C_BaseEntity::InterpolateServerEntities(); + { + PREDICTION_TRACKVALUECHANGESCOPE( "interpolation" ); + C_BaseEntity::InterpolateServerEntities(); + } - // Invalidate any bone information. - C_BaseAnimating::InvalidateBoneCaches(); + { + // vprof node for this bloc of math + VPROF( "OnRenderStart: dirty bone caches"); + // Invalidate any bone information. + C_BaseAnimating::InvalidateBoneCaches(); - C_BaseEntity::SetAbsQueriesValid( true ); - C_BaseEntity::EnableAbsRecomputations( true ); + C_BaseEntity::SetAbsQueriesValid( true ); + C_BaseEntity::EnableAbsRecomputations( true ); - // Enable access to all model bones except view models. - // This is necessary for aim-ent computation to occur properly - C_BaseAnimating::AllowBoneAccess( true, false ); + // Enable access to all model bones except view models. + // This is necessary for aim-ent computation to occur properly + C_BaseAnimating::PushAllowBoneAccess( true, false, "OnRenderStart->CViewRender::SetUpView" ); // pops in CViewRender::SetUpView - // FIXME: This needs to be done before the player moves; it forces - // aiments the player may be attached to to forcibly update their position - C_BaseEntity::MarkAimEntsDirty(); + // FIXME: This needs to be done before the player moves; it forces + // aiments the player may be attached to to forcibly update their position + C_BaseEntity::MarkAimEntsDirty(); + } + + // Make sure the camera simulation happens before OnRenderStart, where it's used. + // NOTE: the only thing that happens in CAM_Think is thirdperson related code. + input->CAM_Think(); // This will place the player + the view models + all parent // entities at the correct abs position so that their attachment points // are at the correct location view->OnRenderStart(); + RopeManager()->OnRenderStart(); + // This will place all entities in the correct position in world space and in the KD-tree C_BaseAnimating::UpdateClientSideAnimations(); @@ -1487,26 +1746,38 @@ void OnRenderStart() // Reset the overlay alpha. Entities can change the state of this in their think functions. g_SmokeFogOverlayAlpha = 0; + // This must occur prior to SimulatEntities, + // which is where the client thinks for c_colorcorrection + c_colorcorrectionvolumes + // update the color correction weights. + // FIXME: The place where IGameSystem::Update is called should be in here + // so we don't have to explicitly call ResetColorCorrectionWeights + SimulateEntities, etc. + g_pColorCorrectionMgr->ResetColorCorrectionWeights(); + // Simulate all the entities. SimulateEntities(); PhysicsSimulate(); - // This creates things like temp entities. - engine->FireEvents(); + C_BaseAnimating::ThreadedBoneSetup(); - // Update temp entities - tempents->Update(); + { + VPROF_("Client TempEnts", 0, VPROF_BUDGETGROUP_CLIENT_SIM, false, BUDGETFLAG_CLIENT); + // This creates things like temp entities. + engine->FireEvents(); - // Update temp ent beams... - beams->UpdateTempEntBeams(); - - // Lock the frame from beam additions - SetBeamCreationAllowed( false ); + // Update temp entities + tempents->Update(); + + // Update temp ent beams... + beams->UpdateTempEntBeams(); + + // Lock the frame from beam additions + SetBeamCreationAllowed( false ); + } // Update particle effects (eventually, the effects should use Simulate() instead of having // their own update system). { - VPROF_BUDGET( "ParticleMgr()->Update", VPROF_BUDGETGROUP_PARTICLE_RENDERING ); + VPROF_BUDGET( "ParticleMgr()->Simulate", VPROF_BUDGETGROUP_PARTICLE_SIMULATION ); ParticleMgr()->Simulate( gpGlobals->frametime ); } @@ -1516,7 +1787,9 @@ void OnRenderStart() // For entities marked for recording, post bone messages to IToolSystems if ( ToolsEnabled() ) + { C_BaseEntity::ToolRecordEntities(); + } // Finally, link all the entities into the leaf system right before rendering. C_BaseEntity::AddVisibleEntities(); @@ -1526,7 +1799,7 @@ void OnRenderStart() void OnRenderEnd() { // Disallow access to bones (access is enabled in CViewRender::SetUpView). - C_BaseAnimating::AllowBoneAccess( false, false ); + C_BaseAnimating::PopBoneAccess( "CViewRender::SetUpView->OnRenderEnd" ); UpdatePVSNotifiers(); @@ -1557,6 +1830,8 @@ void CHLClient::FrameStageNotify( ClientFrameStage_t curStage ) { VPROF( "CHLClient::FrameStageNotify FRAME_RENDER_END" ); OnRenderEnd(); + + PREDICTION_SPEWVALUECHANGES(); } break; @@ -1568,6 +1843,8 @@ void CHLClient::FrameStageNotify( ClientFrameStage_t curStage ) C_BaseEntity::SetAbsQueriesValid( false ); Interpolation_SetLastPacketTimeStamp( engine->GetLastTimeStamp() ); partition->SuppressLists( PARTITION_ALL_CLIENT_EDICTS, true ); + + PREDICTION_STARTTRACKVALUE( "netupdate" ); } break; case FRAME_NET_UPDATE_END: @@ -1578,16 +1855,20 @@ void CHLClient::FrameStageNotify( ClientFrameStage_t curStage ) C_BaseEntity::EnableAbsRecomputations( true ); C_BaseEntity::SetAbsQueriesValid( true ); partition->SuppressLists( PARTITION_ALL_CLIENT_EDICTS, false ); + + PREDICTION_ENDTRACKVALUE(); } break; case FRAME_NET_UPDATE_POSTDATAUPDATE_START: { VPROF( "CHLClient::FrameStageNotify FRAME_NET_UPDATE_POSTDATAUPDATE_START" ); + PREDICTION_STARTTRACKVALUE( "postdataupdate" ); } break; case FRAME_NET_UPDATE_POSTDATAUPDATE_END: { VPROF( "CHLClient::FrameStageNotify FRAME_NET_UPDATE_POSTDATAUPDATE_END" ); + PREDICTION_ENDTRACKVALUE(); // Let prediction copy off pristine data prediction->PostEntityPacketReceived(); HLTVCamera()->PostEntityPacketReceived(); @@ -1598,6 +1879,7 @@ void CHLClient::FrameStageNotify( ClientFrameStage_t curStage ) // Mark the frame as open for client fx additions SetFXCreationAllowed( true ); SetBeamCreationAllowed( true ); + C_BaseEntity::CheckCLInterpChanged(); } break; } @@ -1737,8 +2019,8 @@ void CHLClient::WriteSaveGameScreenshotOfSize( const char *pFilename, int width, } // See RenderViewInfo_t -void CHLClient::RenderViewEx( const CViewSetup &setup, int nClearFlags, int whatToDraw ) +void CHLClient::RenderView( const CViewSetup &setup, int nClearFlags, int whatToDraw ) { - VPROF("RenderViewEx"); - view->RenderViewEx( setup, nClearFlags, whatToDraw ); + VPROF("RenderView"); + view->RenderView( setup, nClearFlags, whatToDraw ); } diff --git a/src/src/cl_dll/cdll_client_int.h b/src/src/game/client/cdll_client_int.h similarity index 83% rename from src/src/cl_dll/cdll_client_int.h rename to src/src/game/client/cdll_client_int.h index 553028b..0579fbf 100644 --- a/src/src/cl_dll/cdll_client_int.h +++ b/src/src/game/client/cdll_client_int.h @@ -14,6 +14,7 @@ #include "iclientnetworkable.h" #include "utllinkedlist.h" #include "cdll_int.h" +#include "eiface.h" class IVModelRender; @@ -50,7 +51,11 @@ class C_BaseAnimating; class IColorCorrectionSystem; class IInputSystem; class ISceneFileCache; +class IXboxSystem; // Xbox 360 only +class IMatchmaking; class IAvi; +class IBik; +class CSteamAPIContext; extern IVModelRender *modelrender; extern IVEngineClient *engine; @@ -80,10 +85,15 @@ extern IGameEventManager2 *gameeventmanager; extern IPhysicsGameTrace *physgametrace; extern CGlobalVarsBase *gpGlobals; extern IClientTools *clienttools; -extern IColorCorrectionSystem *colorcorrection; extern IInputSystem *inputsystem; extern ISceneFileCache *scenefilecache; +extern IXboxSystem *xboxsystem; // Xbox 360 only +extern IMatchmaking *matchmaking; extern IAvi *avi; +extern IBik *bik; +extern IUploadGameStats *gamestatsuploader; +extern CSteamAPIContext *steamapicontext; + // Set to true between LevelInit and LevelShutdown. extern bool g_bLevelInitialized; @@ -110,10 +120,19 @@ int GetMaterialIndex( const char *pMaterialName ); //----------------------------------------------------------------------------- const char *GetMaterialNameFromIndex( int nIndex ); +//----------------------------------------------------------------------------- +// Precache-related methods for particle systems +//----------------------------------------------------------------------------- +void PrecacheParticleSystem( const char *pParticleSystemName ); +int GetParticleSystemIndex( const char *pParticleSystemName ); +const char *GetParticleSystemNameFromIndex( int nIndex ); + + //----------------------------------------------------------------------------- // Called during bone setup to test perf //----------------------------------------------------------------------------- void TrackBoneSetupEnt( C_BaseAnimating *pEnt ); +bool IsEngineThreaded(); #endif // CDLL_CLIENT_INT_H diff --git a/src/src/cl_dll/cdll_util.cpp b/src/src/game/client/cdll_util.cpp similarity index 79% rename from src/src/cl_dll/cdll_util.cpp rename to src/src/game/client/cdll_util.cpp index eca2e6d..df000bc 100644 --- a/src/src/cl_dll/cdll_util.cpp +++ b/src/src/game/client/cdll_util.cpp @@ -24,7 +24,9 @@ #include "c_te_effect_dispatch.h" #include #include +#include #include "view.h" +#include "ixboxsystem.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -767,6 +769,119 @@ const char * UTIL_SafeName( const char *oldName ) } +//----------------------------------------------------------------------------- +// Purpose: Looks up key bindings for commands and replaces them in string. +// %% will get replaced with its bound control, e.g. %attack2% +// Input buffer sizes are in bytes rather than unicode character count +// for consistency with other APIs. If inbufsizebytes is 0 a NULL-terminated +// input buffer is assumed, or you can pass the size of the input buffer if +// not NULL-terminated. +//----------------------------------------------------------------------------- +void UTIL_ReplaceKeyBindings( const wchar_t *inbuf, int inbufsizebytes, wchar_t *outbuf, int outbufsizebytes ) +{ + if ( !inbuf || !inbuf[0] ) + return; + + // copy to a new buf if there are vars + outbuf[0]=0; + int pos = 0; + const wchar_t *inbufend = NULL; + if ( inbufsizebytes > 0 ) + { + inbufend = inbuf + ( inbufsizebytes / 2 ); + } + + while( inbuf != inbufend && *inbuf != 0 ) + { + // check for variables + if ( *inbuf == '%' ) + { + ++inbuf; + + const wchar_t *end = wcschr( inbuf, '%' ); + if ( end && ( end != inbuf ) ) // make sure we handle %% in the string, which should be treated in the output as % + { + wchar_t token[64]; + wcsncpy( token, inbuf, end - inbuf ); + token[end - inbuf] = 0; + + inbuf += end - inbuf; + + // lookup key names + char binding[64]; + g_pVGuiLocalize->ConvertUnicodeToANSI( token, binding, sizeof(binding) ); + + const char *key = engine->Key_LookupBinding( *binding == '+' ? binding + 1 : binding ); + if ( !key ) + { + key = IsX360() ? "" : "< not bound >"; + } + + //!! change some key names into better names + char friendlyName[64]; + bool bAddBrackets = false; + if ( IsX360() ) + { + if ( !key || !key[0] ) + { + Q_snprintf( friendlyName, sizeof(friendlyName), "#GameUI_None" ); + bAddBrackets = true; + } + else + { + Q_snprintf( friendlyName, sizeof(friendlyName), "#GameUI_KeyNames_%s", key ); + } + } + else + { + Q_snprintf( friendlyName, sizeof(friendlyName), "%s", key ); + } + Q_strupr( friendlyName ); + + wchar_t *locName = g_pVGuiLocalize->Find( friendlyName ); + if ( !locName || wcslen(locName) <= 0) + { + g_pVGuiLocalize->ConvertANSIToUnicode( friendlyName, token, sizeof(token) ); + + outbuf[pos] = '\0'; + wcscat( outbuf, token ); + pos += wcslen(token); + } + else + { + outbuf[pos] = '\0'; + if ( bAddBrackets ) + { + wcscat( outbuf, L"[" ); + pos += 1; + } + wcscat( outbuf, locName ); + pos += wcslen(locName); + if ( bAddBrackets ) + { + wcscat( outbuf, L"]" ); + pos += 1; + } + } + } + else + { + outbuf[pos] = *inbuf; + ++pos; + } + } + else + { + outbuf[pos] = *inbuf; + ++pos; + } + + ++inbuf; + } + + outbuf[pos] = '\0'; +} + //----------------------------------------------------------------------------- // Purpose: // Input : *filename - @@ -928,3 +1043,153 @@ unsigned char UTIL_ComputeEntityFade( C_BaseEntity *pEntity, float flMinDist, fl return nAlpha; } + + +//----------------------------------------------------------------------------- +// Purpose: Given a vector, clamps the scalar axes to MAX_COORD_FLOAT ranges from worldsize.h +// Input : *pVecPos - +//----------------------------------------------------------------------------- +void UTIL_BoundToWorldSize( Vector *pVecPos ) +{ + Assert( pVecPos ); + for ( int i = 0; i < 3; ++i ) + { + (*pVecPos)[ i ] = clamp( (*pVecPos)[ i ], MIN_COORD_FLOAT, MAX_COORD_FLOAT ); + } +} + +#ifdef _X360 +#define MAP_KEY_FILE_DIR "cfg" +#else +#define MAP_KEY_FILE_DIR "media" +#endif + +//----------------------------------------------------------------------------- +// Purpose: Returns the filename to count map loads in +//----------------------------------------------------------------------------- +bool UTIL_GetMapLoadCountFileName( const char *pszFilePrependName, char *pszBuffer, int iBuflen ) +{ + if ( IsX360() ) + { +#ifdef _X360 + if ( XBX_GetStorageDeviceId() == XBX_INVALID_STORAGE_ID || XBX_GetStorageDeviceId() == XBX_STORAGE_DECLINED ) + return false; +#endif + } + + if ( IsX360() ) + { + Q_snprintf( pszBuffer, iBuflen, "%s:/%s", MAP_KEY_FILE_DIR, pszFilePrependName ); + } + else + { + Q_snprintf( pszBuffer, iBuflen, "%s/%s", MAP_KEY_FILE_DIR, pszFilePrependName ); + } + + return true; +} + +#ifdef TF_CLIENT_DLL +#define MAP_KEY_FILE "viewed.res" +#else +#define MAP_KEY_FILE "mapkeys.res" +#endif + +void UTIL_IncrementMapKey( const char *pszCustomKey ) +{ + if ( !pszCustomKey ) + return; + + char szFilename[ _MAX_PATH ]; + if ( !UTIL_GetMapLoadCountFileName( MAP_KEY_FILE, szFilename, _MAX_PATH ) ) + return; + + int iCount = 1; + + KeyValues *kvMapLoadFile = new KeyValues( MAP_KEY_FILE ); + if ( kvMapLoadFile ) + { + kvMapLoadFile->LoadFromFile( g_pFullFileSystem, szFilename, "MOD" ); + + char mapname[MAX_MAP_NAME]; + Q_FileBase( engine->GetLevelName(), mapname, sizeof( mapname) ); + Q_strlower( mapname ); + + // Increment existing, or add a new one + KeyValues *pMapKey = kvMapLoadFile->FindKey( mapname ); + if ( pMapKey ) + { + iCount = pMapKey->GetInt( pszCustomKey, 0 ) + 1; + pMapKey->SetInt( pszCustomKey, iCount ); + } + else + { + KeyValues *pNewKey = new KeyValues( mapname ); + if ( pNewKey ) + { + pNewKey->SetString( pszCustomKey, "1" ); + kvMapLoadFile->AddSubKey( pNewKey ); + } + } + + // Write it out + + // force create this directory incase it doesn't exist + filesystem->CreateDirHierarchy( MAP_KEY_FILE_DIR, "MOD"); + + CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER ); + kvMapLoadFile->RecursiveSaveToFile( buf, 0 ); + g_pFullFileSystem->WriteFile( szFilename, "MOD", buf ); + + kvMapLoadFile->deleteThis(); + } + + if ( IsX360() ) + { +#ifdef _X360 + xboxsystem->FinishContainerWrites(); +#endif + } +} + +int UTIL_GetMapKeyCount( const char *pszCustomKey ) +{ + if ( !pszCustomKey ) + return 0; + + char szFilename[ _MAX_PATH ]; + if ( !UTIL_GetMapLoadCountFileName( MAP_KEY_FILE, szFilename, _MAX_PATH ) ) + return 0; + + int iCount = 0; + + KeyValues *kvMapLoadFile = new KeyValues( MAP_KEY_FILE ); + if ( kvMapLoadFile ) + { + // create an empty file if none exists + if ( !g_pFullFileSystem->FileExists( szFilename, "MOD" ) ) + { + // force create this directory incase it doesn't exist + filesystem->CreateDirHierarchy( MAP_KEY_FILE_DIR, "MOD"); + + CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER ); + g_pFullFileSystem->WriteFile( szFilename, "MOD", buf ); + } + + kvMapLoadFile->LoadFromFile( g_pFullFileSystem, szFilename, "MOD" ); + + char mapname[MAX_MAP_NAME]; + Q_FileBase( engine->GetLevelName(), mapname, sizeof( mapname) ); + Q_strlower( mapname ); + + KeyValues *pMapKey = kvMapLoadFile->FindKey( mapname ); + if ( pMapKey ) + { + iCount = pMapKey->GetInt( pszCustomKey ); + } + + kvMapLoadFile->deleteThis(); + } + + return iCount; +} \ No newline at end of file diff --git a/src/src/cl_dll/cdll_util.h b/src/src/game/client/cdll_util.h similarity index 89% rename from src/src/cl_dll/cdll_util.h rename to src/src/game/client/cdll_util.h index 38bf33c..3888214 100644 --- a/src/src/cl_dll/cdll_util.h +++ b/src/src/game/client/cdll_util.h @@ -14,7 +14,7 @@ #endif #include -#include +#include "mathlib/vector.h" #include #include "ispatialpartition.h" @@ -66,6 +66,7 @@ byte *UTIL_LoadFileForMe( const char *filename, int *pLength ); void UTIL_FreeFile( byte *buffer ); void UTIL_MakeSafeName( const char *oldName, char *newName, int newNameBufSize ); ///< Cleans up player names for putting in vgui controls (cleaned names can be up to original*2+1 in length) const char *UTIL_SafeName( const char *oldName ); ///< Wraps UTIL_MakeSafeName, and returns a static buffer +void UTIL_ReplaceKeyBindings( const wchar_t *inbuf, int inbufsizebytes, wchar_t *outbuf, int outbufsizebytes ); // Fade out an entity based on distance fades unsigned char UTIL_ComputeEntityFade( C_BaseEntity *pEntity, float flMinDist, float flMaxDist, float flFadeScale ); @@ -157,4 +158,15 @@ inline bool FStrEq(const char *sz1, const char *sz2) return(stricmp(sz1, sz2) == 0); } +// Given a vector, clamps the scalar axes to MAX_COORD_FLOAT ranges from worldsize.h +void UTIL_BoundToWorldSize( Vector *pVecPos ); + +// Increments the passed key for the current map, eg "viewed" if TF holds the number of times the player has +// viewed the intro movie for this map +void UTIL_IncrementMapKey( const char *pszCustomKey ); + +// Gets the value of the passed key for the current map, eg "viewed" for number of times the player has viewed +// the intro movie for this map +int UTIL_GetMapKeyCount( const char *pszCustomKey ); + #endif // !UTIL_H diff --git a/src/src/cl_dll/cl_animevent.h b/src/src/game/client/cl_animevent.h similarity index 100% rename from src/src/cl_dll/cl_animevent.h rename to src/src/game/client/cl_animevent.h diff --git a/src/src/cl_dll/cl_mat_stub.cpp b/src/src/game/client/cl_mat_stub.cpp similarity index 100% rename from src/src/cl_dll/cl_mat_stub.cpp rename to src/src/game/client/cl_mat_stub.cpp diff --git a/src/src/cl_dll/cl_mat_stub.h b/src/src/game/client/cl_mat_stub.h similarity index 100% rename from src/src/cl_dll/cl_mat_stub.h rename to src/src/game/client/cl_mat_stub.h diff --git a/src/src/cl_dll/classmap.cpp b/src/src/game/client/classmap.cpp similarity index 98% rename from src/src/cl_dll/classmap.cpp rename to src/src/game/client/classmap.cpp index f1ad839..7ed2c4d 100644 --- a/src/src/cl_dll/classmap.cpp +++ b/src/src/game/client/classmap.cpp @@ -99,7 +99,7 @@ C_BaseEntity *CClassMap::CreateEntity( const char *mapname ) if ( !lookup ) continue; - if ( Q_strcmp( lookup->GetMapName(), mapname ) ) + if ( Q_stricmp( lookup->GetMapName(), mapname ) ) continue; if ( !lookup->factory ) diff --git a/src/src/cl_dll/client_factorylist.cpp b/src/src/game/client/client_factorylist.cpp similarity index 100% rename from src/src/cl_dll/client_factorylist.cpp rename to src/src/game/client/client_factorylist.cpp diff --git a/src/src/cl_dll/client_factorylist.h b/src/src/game/client/client_factorylist.h similarity index 100% rename from src/src/cl_dll/client_factorylist.h rename to src/src/game/client/client_factorylist.h diff --git a/src/src/game/client/client_scratch-2005.vcproj b/src/src/game/client/client_scratch-2005.vcproj new file mode 100644 index 0000000..b61363e --- /dev/null +++ b/src/src/game/client/client_scratch-2005.vcproj @@ -0,0 +1,5052 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/src/cl_dll/client_thinklist.cpp b/src/src/game/client/client_thinklist.cpp similarity index 98% rename from src/src/cl_dll/client_thinklist.cpp rename to src/src/game/client/client_thinklist.cpp index 53776c7..0f8a062 100644 --- a/src/src/cl_dll/client_thinklist.cpp +++ b/src/src/game/client/client_thinklist.cpp @@ -6,6 +6,8 @@ //=============================================================================// #include "cbase.h" +#include "tier0/vprof.h" + // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -263,6 +265,8 @@ void CClientThinkList::AddEntityToFrameThinkList( ThinkEntry_t *pEntry, bool bAl //----------------------------------------------------------------------------- void CClientThinkList::PerformThinkFunctions() { + VPROF_("Client Thinks", 1, VPROF_BUDGETGROUP_CLIENT_SIM, false, BUDGETFLAG_CLIENT); + int nMaxList = m_ThinkEntries.Count(); if ( nMaxList == 0 ) return; diff --git a/src/src/cl_dll/client_thinklist.h b/src/src/game/client/client_thinklist.h similarity index 99% rename from src/src/cl_dll/client_thinklist.h rename to src/src/game/client/client_thinklist.h index 009fb6e..305dc20 100644 --- a/src/src/cl_dll/client_thinklist.h +++ b/src/src/game/client/client_thinklist.h @@ -57,6 +57,7 @@ public: public: virtual bool Init(); + virtual void PostInit() {}; virtual void Shutdown(); virtual void LevelInitPreEntity(); virtual void LevelInitPostEntity() {} diff --git a/src/src/cl_dll/clienteffectprecachesystem.cpp b/src/src/game/client/clienteffectprecachesystem.cpp similarity index 95% rename from src/src/cl_dll/clienteffectprecachesystem.cpp rename to src/src/game/client/clienteffectprecachesystem.cpp index 7b09a0e..5f07229 100644 --- a/src/src/cl_dll/clienteffectprecachesystem.cpp +++ b/src/src/game/client/clienteffectprecachesystem.cpp @@ -6,7 +6,9 @@ // $NoKeywords: $ //=============================================================================// #include "cbase.h" +#include "fx.h" #include "ClientEffectPrecacheSystem.h" +#include "particles/particles.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -32,6 +34,9 @@ void CClientEffectPrecacheSystem::LevelInitPreEntity( void ) //FIXME: Double check this //Finally, force the cache of these materials materials->CacheUsedMaterials(); + + // Now, cache off our material handles + FX_CacheMaterialHandles(); } //----------------------------------------------------------------------------- diff --git a/src/src/cl_dll/clienteffectprecachesystem.h b/src/src/game/client/clienteffectprecachesystem.h similarity index 99% rename from src/src/cl_dll/clienteffectprecachesystem.h rename to src/src/game/client/clienteffectprecachesystem.h index 3bdcab2..694b020 100644 --- a/src/src/cl_dll/clienteffectprecachesystem.h +++ b/src/src/game/client/clienteffectprecachesystem.h @@ -44,6 +44,7 @@ public: // Init, shutdown virtual bool Init() { return true; } + virtual void PostInit() {} virtual void Shutdown(); // Level init, shutdown diff --git a/src/src/cl_dll/cliententitylist.cpp b/src/src/game/client/cliententitylist.cpp similarity index 100% rename from src/src/cl_dll/cliententitylist.cpp rename to src/src/game/client/cliententitylist.cpp diff --git a/src/src/cl_dll/cliententitylist.h b/src/src/game/client/cliententitylist.h similarity index 99% rename from src/src/cl_dll/cliententitylist.h rename to src/src/game/client/cliententitylist.h index b006655..f0deb7e 100644 --- a/src/src/cl_dll/cliententitylist.h +++ b/src/src/game/client/cliententitylist.h @@ -31,6 +31,7 @@ class C_BaseEntity; #define INPVS_YES 0x0001 // The entity thinks it's in the PVS. #define INPVS_THISFRAME 0x0002 // Accumulated as different views are rendered during the frame and used to notify the entity if // it is not in the PVS anymore (at the end of the frame). +#define INPVS_NEEDSNOTIFY 0x0004 // The entity thinks it's in the PVS. class IClientEntityListener; diff --git a/src/src/cl_dll/clientleafsystem.cpp b/src/src/game/client/clientleafsystem.cpp similarity index 72% rename from src/src/cl_dll/clientleafsystem.cpp rename to src/src/game/client/clientleafsystem.cpp index 679f362..ff3af0d 100644 --- a/src/src/cl_dll/clientleafsystem.cpp +++ b/src/src/game/client/clientleafsystem.cpp @@ -1,4 +1,4 @@ -//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// +//===== Copyright © 1996-2007, Valve Corporation, All rights reserved. ======// // // Purpose: // @@ -11,13 +11,19 @@ #include "cbase.h" #include "ClientLeafSystem.h" #include "UtlBidirectionalSet.h" -#include "BSPTreeData.h" #include "model_types.h" #include "IVRenderView.h" #include "tier0/vprof.h" +#include "BSPTreeData.h" #include "DetailObjectSystem.h" #include "engine/IStaticPropMgr.h" #include "engine/IVDebugOverlay.h" +#include "vstdlib/jobthread.h" +#include "tier1/utllinkedlist.h" +#include "datacache/imdlcache.h" +#include "view.h" +#include "viewrender.h" +#include // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -26,8 +32,31 @@ class VMatrix; // forward decl static ConVar cl_drawleaf("cl_drawleaf", "-1", FCVAR_CHEAT ); static ConVar r_PortalTestEnts( "r_PortalTestEnts", "1", FCVAR_CHEAT, "Clip entities against portal frustums." ); -static ConVar r_portalsopenall( "r_portalsopenall", "1", FCVAR_CHEAT, "Open all portals" ); - +static ConVar r_portalsopenall( "r_portalsopenall", "0", FCVAR_CHEAT, "Open all portals" ); +static ConVar cl_threaded_client_leaf_system("cl_threaded_client_leaf_system", "0" ); + + +DEFINE_FIXEDSIZE_ALLOCATOR( CClientRenderablesList, 1, CMemoryPool::GROW_SLOW ); + +//----------------------------------------------------------------------------- +// Threading helpers +//----------------------------------------------------------------------------- + +static void FrameLock() +{ + mdlcache->BeginLock(); +} + +static void FrameUnlock() +{ + mdlcache->EndLock(); +} + +static void CallComputeFXBlend( IClientRenderable *&pRenderable ) +{ + pRenderable->ComputeFxBlend(); +} + //----------------------------------------------------------------------------- // The client leaf system //----------------------------------------------------------------------------- @@ -42,6 +71,7 @@ public: // Methods of IClientSystem bool Init() { return true; } + void PostInit() {} void Shutdown() {} virtual bool IsPerFrame() { return true; } @@ -66,6 +96,11 @@ public: virtual bool IsRenderableInPVS( IClientRenderable *pRenderable ); virtual void CreateRenderableHandle( IClientRenderable* pRenderable, bool bIsStaticProp ); virtual void RemoveRenderable( ClientRenderHandle_t handle ); + + + virtual void SetSubSystemDataInLeaf( int leaf, int nSubSystemIdx, CClientLeafSubSystemData *pData ); + virtual CClientLeafSubSystemData *GetSubSystemDataInLeaf( int leaf, int nSubSystemIdx ); + // FIXME: There's an incestuous relationship between DetailObjectSystem // and the ClientLeafSystem. Maybe they should be the same system? virtual void GetDetailObjectsInLeaf( int leaf, int& firstDetailObject, int& detailObjectCount ); @@ -74,9 +109,10 @@ public: virtual bool ShouldDrawDetailObjectsInLeaf( int leaf, int frameNumber ); virtual void RenderableChanged( ClientRenderHandle_t handle ); virtual void SetRenderGroup( ClientRenderHandle_t handle, RenderGroup_t group ); - virtual void ComputeTranslucentRenderLeaf( int count, LeafIndex_t *pLeafList, LeafFogVolume_t *pLeafFogVolumeList, int frameNumber ); + virtual void ComputeTranslucentRenderLeaf( int count, const LeafIndex_t *pLeafList, const LeafFogVolume_t *pLeafFogVolumeList, int frameNumber, int viewID ); virtual void CollateViewModelRenderables( CUtlVector< IClientRenderable * >& opaque, CUtlVector< IClientRenderable * >& translucent ); - virtual void CollateRenderablesInLeaf( int leaf, int worldListLeafIndex, SetupRenderInfo_t &info ); + virtual void BuildRenderablesList( const SetupRenderInfo_t &info ); + void CollateRenderablesInLeaf( int leaf, int worldListLeafIndex, const SetupRenderInfo_t &info ); virtual void DrawStaticProps( bool enable ); virtual void DrawSmallEntities( bool enable ); virtual void EnableAlternateSorting( ClientRenderHandle_t handle, bool bEnable ); @@ -85,12 +121,11 @@ public: virtual void AddRenderableToLeaves( ClientRenderHandle_t handle, int nLeafCount, unsigned short *pLeaves ); // The following methods are related to shadows... - virtual ClientLeafShadowHandle_t AddShadow( unsigned short userId, unsigned short flags ); + virtual ClientLeafShadowHandle_t AddShadow( ClientShadowHandle_t userId, unsigned short flags ); virtual void RemoveShadow( ClientLeafShadowHandle_t h ); - virtual void ProjectShadow( ClientLeafShadowHandle_t handle, const Vector& origin, - const Vector& dir, const Vector2D& size, float maxDist ); - virtual void ProjectFlashlight( ClientLeafShadowHandle_t handle, const VMatrix &worldToShadow ); + virtual void ProjectShadow( ClientLeafShadowHandle_t handle, int nLeafCount, const int *pLeafList ); + virtual void ProjectFlashlight( ClientLeafShadowHandle_t handle, int nLeafCount, const int *pLeafList ); // Find all shadow casters in a set of leaves virtual void EnumerateShadowsInLeaves( int leafCount, LeafIndex_t* pLeaves, IClientLeafShadowEnum* pEnum ); @@ -120,11 +155,13 @@ private: // Adds a renderable to the list of renderables void AddRenderableToLeaf( int leaf, ClientRenderHandle_t handle ); + void SortEntities( const Vector &vecRenderOrigin, const Vector &vecRenderForward, CClientRenderablesList::CEntry *pEntities, int nEntities ); + // Returns -1 if the renderable spans more than one area. If it's totally in one area, then this returns the leaf. short GetRenderableArea( ClientRenderHandle_t handle ); - // insert, remove renderables from leaves - void InsertIntoTree( ClientRenderHandle_t handle ); + // remove renderables from leaves + void InsertIntoTree( ClientRenderHandle_t &handle ); void RemoveFromTree( ClientRenderHandle_t handle ); // Returns if it's a view model render group @@ -183,6 +220,15 @@ private: return s_ClientLeafSystem.m_Shadows[shadow].m_FirstRenderable; } + void FrameLock() + { + mdlcache->BeginLock(); + } + + void FrameUnlock() + { + mdlcache->EndLock(); + } private: enum @@ -202,12 +248,14 @@ private: int m_RenderFrame; // which frame did I render it in? int m_RenderFrame2; int m_EnumCount; // Have I been added to a particular shadow yet? + int m_TranslucencyCalculated; unsigned short m_LeafList; // What leafs is it in? unsigned short m_RenderLeaf; // What leaf do I render in? unsigned char m_Flags; // rendering flags unsigned char m_RenderGroup; // RenderGroup_t type unsigned short m_FirstShadow; // The first shadow caster that cast on it short m_Area; // -1 if the renderable spans multiple areas. + signed char m_TranslucencyCalculatedView; }; // The leaf contains an index into a list of renderables @@ -216,12 +264,11 @@ private: unsigned short m_FirstElement; unsigned short m_FirstShadow; - // An optimization for detail objects since there are tens - // of thousands of them, and since we're assuming they lie in - // exactly one leaf (a bogus assumption, but too bad) unsigned short m_FirstDetailProp; unsigned short m_DetailPropCount; int m_DetailPropRenderFrame; + CClientLeafSubSystemData *m_pSubSystemData[N_CLSUBSYSTEMS]; + }; // Shadow information @@ -230,28 +277,39 @@ private: unsigned short m_FirstLeaf; unsigned short m_FirstRenderable; int m_EnumCount; - unsigned short m_Shadow; + ClientShadowHandle_t m_Shadow; unsigned short m_Flags; }; + struct EnumResult_t + { + int leaf; + EnumResult_t *pNext; + }; + + struct EnumResultList_t + { + EnumResult_t *pHead; + ClientRenderHandle_t handle; + }; // Stores data associated with each leaf. CUtlVector< ClientLeaf_t > m_Leaf; // Stores all unique non-detail renderables - CUtlLinkedList< RenderableInfo_t, ClientRenderHandle_t > m_Renderables; + CUtlLinkedList< RenderableInfo_t, ClientRenderHandle_t, false, unsigned int > m_Renderables; // Information associated with shadows registered with the client leaf system - CUtlLinkedList< ShadowInfo_t, ClientLeafShadowHandle_t > m_Shadows; + CUtlLinkedList< ShadowInfo_t, ClientLeafShadowHandle_t, false, unsigned int > m_Shadows; // Maintains the list of all renderables in a particular leaf - CBidirectionalSet< int, ClientRenderHandle_t, unsigned short > m_RenderablesInLeaf; + CBidirectionalSet< int, ClientRenderHandle_t, unsigned short, unsigned int > m_RenderablesInLeaf; // Maintains a list of all shadows in a particular leaf - CBidirectionalSet< int, ClientLeafShadowHandle_t, unsigned short > m_ShadowsInLeaf; + CBidirectionalSet< int, ClientLeafShadowHandle_t, unsigned short, unsigned int > m_ShadowsInLeaf; // Maintains a list of all shadows cast on a particular renderable - CBidirectionalSet< ClientRenderHandle_t, ClientLeafShadowHandle_t, unsigned short > m_ShadowsOnRenderable; + CBidirectionalSet< ClientRenderHandle_t, ClientLeafShadowHandle_t, unsigned short, unsigned int > m_ShadowsOnRenderable; // Dirty list of renderables CUtlVector< ClientRenderHandle_t > m_DirtyRenderables; @@ -265,6 +323,8 @@ private: // A little enumerator to help us when adding shadows to renderables int m_ShadowEnum; + + CTSList m_DeferredInserts; }; @@ -422,6 +482,7 @@ void CClientLeafSystem::LevelInitPreEntity() ClientLeaf_t newLeaf; newLeaf.m_FirstElement = m_RenderablesInLeaf.InvalidIndex(); newLeaf.m_FirstShadow = m_ShadowsInLeaf.InvalidIndex(); + memset( newLeaf.m_pSubSystemData, 0, sizeof( newLeaf.m_pSubSystemData ) ); newLeaf.m_FirstDetailProp = 0; newLeaf.m_DetailPropCount = 0; newLeaf.m_DetailPropRenderFrame = -1; @@ -441,6 +502,19 @@ void CClientLeafSystem::LevelShutdownPostEntity() m_Renderables.Purge(); m_RenderablesInLeaf.Purge(); m_Shadows.Purge(); + + // delete subsystem data + for( int i = 0; i < m_Leaf.Count() ; i++ ) + { + for( int j = 0 ; j < ARRAYSIZE( m_Leaf[i].m_pSubSystemData ) ; j++ ) + { + if ( m_Leaf[i].m_pSubSystemData[j] ) + { + delete m_Leaf[i].m_pSubSystemData[j]; + m_Leaf[i].m_pSubSystemData[j] = NULL; + } + } + } m_Leaf.Purge(); m_ShadowsInLeaf.Purge(); m_ShadowsOnRenderable.Purge(); @@ -453,22 +527,74 @@ void CClientLeafSystem::LevelShutdownPostEntity() //----------------------------------------------------------------------------- void CClientLeafSystem::PreRender() { - VPROF( "CClientLeafSystem::PreRender" ); + VPROF_BUDGET( "CClientLeafSystem::PreRender", "PreRender" ); - // Iterate through all renderables and tell them to compute their FX blend - for ( int i = m_DirtyRenderables.Count(); --i >= 0; ) + int i; + int nIterations = 0; + + while ( m_DirtyRenderables.Count() ) { - ClientRenderHandle_t handle = m_DirtyRenderables[i]; - RenderableInfo_t& renderable = m_Renderables[ handle ]; + if ( ++nIterations > 10 ) + { + Warning( "Too many dirty renderables!\n" ); + break; + } - Assert( renderable.m_Flags & RENDER_FLAGS_HASCHANGED ); + int nDirty = m_DirtyRenderables.Count(); + for ( i = nDirty; --i >= 0; ) + { + ClientRenderHandle_t handle = m_DirtyRenderables[i]; + Assert( m_Renderables[ handle ].m_Flags & RENDER_FLAGS_HASCHANGED ); - // Update position in leaf system - RemoveFromTree( handle ); - InsertIntoTree( handle ); - renderable.m_Flags &= ~RENDER_FLAGS_HASCHANGED; + // Update position in leaf system + RemoveFromTree( handle ); + } + + bool bThreaded = ( nDirty > 5 && cl_threaded_client_leaf_system.GetBool() && g_pThreadPool->NumThreads() ); + + if ( !bThreaded ) + { + for ( i = nDirty; --i >= 0; ) + { + InsertIntoTree( m_DirtyRenderables[i] ); + } + } + else + { + // InsertIntoTree can result in new renderables being added, so copy: + ClientRenderHandle_t *pDirtyRenderables = (ClientRenderHandle_t *)alloca( sizeof(ClientRenderHandle_t) * nDirty ); + memcpy( pDirtyRenderables, m_DirtyRenderables.Base(), sizeof(ClientRenderHandle_t) * nDirty ); + ParallelProcess( pDirtyRenderables, nDirty, this, &CClientLeafSystem::InsertIntoTree, &CClientLeafSystem::FrameLock, &CClientLeafSystem::FrameUnlock ); + } + + if ( m_DeferredInserts.Count() ) + { + EnumResultList_t enumResultList; + while ( m_DeferredInserts.PopItem( &enumResultList ) ) + { + m_ShadowEnum++; + while ( enumResultList.pHead ) + { + EnumResult_t *p = enumResultList.pHead; + enumResultList.pHead = p->pNext; + AddRenderableToLeaf( p->leaf, enumResultList.handle ); + delete p; + } + } + } + + for ( i = nDirty; --i >= 0; ) + { + // Cache off the area it's sitting in. + ClientRenderHandle_t handle = m_DirtyRenderables[i]; + RenderableInfo_t& renderable = m_Renderables[ handle ]; + + renderable.m_Flags &= ~RENDER_FLAGS_HASCHANGED; + m_Renderables[handle].m_Area = GetRenderableArea( handle ); + } + + m_DirtyRenderables.RemoveMultiple( 0, nDirty ); } - m_DirtyRenderables.RemoveAll(); } @@ -497,6 +623,8 @@ void CClientLeafSystem::NewRenderable( IClientRenderable* pRenderable, RenderGro info.m_pRenderable = pRenderable; info.m_RenderFrame = -1; info.m_RenderFrame2 = -1; + info.m_TranslucencyCalculated = -1; + info.m_TranslucencyCalculatedView = VIEW_ILLEGAL; info.m_FirstShadow = m_ShadowsOnRenderable.InvalidIndex(); info.m_LeafList = m_RenderablesInLeaf.InvalidIndex(); info.m_Flags = flags; @@ -523,19 +651,25 @@ void CClientLeafSystem::CreateRenderableHandle( IClientRenderable* pRenderable, RenderGroup_t group = pRenderable->IsTransparent() ? RENDER_GROUP_TRANSLUCENT_ENTITY : RENDER_GROUP_OPAQUE_ENTITY; bool bTwoPass = false; - if (group == RENDER_GROUP_TRANSLUCENT_ENTITY) - bTwoPass = modelinfo->IsTranslucentTwoPass( pRenderable->GetModel() ); + if ( group == RENDER_GROUP_TRANSLUCENT_ENTITY ) + { + bTwoPass = pRenderable->IsTwoPass( ); + } int flags = 0; if ( bIsStaticProp ) { flags = RENDER_FLAGS_STATIC_PROP; if ( group == RENDER_GROUP_OPAQUE_ENTITY ) + { group = RENDER_GROUP_OPAQUE_STATIC; + } } if (bTwoPass) + { flags |= RENDER_FLAGS_TWOPASS; + } NewRenderable( pRenderable, group, flags ); } @@ -730,6 +864,20 @@ short CClientLeafSystem::GetRenderableArea( ClientRenderHandle_t handle ) } +void CClientLeafSystem::SetSubSystemDataInLeaf( int leaf, int nSubSystemIdx, CClientLeafSubSystemData *pData ) +{ + assert( nSubSystemIdx < N_CLSUBSYSTEMS ); + if ( m_Leaf[leaf].m_pSubSystemData[nSubSystemIdx] ) + delete m_Leaf[leaf].m_pSubSystemData[nSubSystemIdx]; + m_Leaf[leaf].m_pSubSystemData[nSubSystemIdx] = pData; +} + +CClientLeafSubSystemData *CClientLeafSystem::GetSubSystemDataInLeaf( int leaf, int nSubSystemIdx ) +{ + assert( nSubSystemIdx < N_CLSUBSYSTEMS ); + return m_Leaf[leaf].m_pSubSystemData[nSubSystemIdx]; +} + //----------------------------------------------------------------------------- // Indicates which leaves detail objects are in //----------------------------------------------------------------------------- @@ -754,7 +902,7 @@ void CClientLeafSystem::GetDetailObjectsInLeaf( int leaf, int& firstDetailObject //----------------------------------------------------------------------------- // Create/destroy shadows... //----------------------------------------------------------------------------- -ClientLeafShadowHandle_t CClientLeafSystem::AddShadow( unsigned short userId, unsigned short flags ) +ClientLeafShadowHandle_t CClientLeafSystem::AddShadow( ClientShadowHandle_t userId, unsigned short flags ) { ClientLeafShadowHandle_t idx = m_Shadows.AddToTail(); m_Shadows[idx].m_Shadow = userId; @@ -863,20 +1011,9 @@ void CClientLeafSystem::RemoveShadowFromLeaves( ClientLeafShadowHandle_t handle //----------------------------------------------------------------------------- -// Adds a shadow to all leaves along a ray +// Adds a shadow to all leaves listed //----------------------------------------------------------------------------- -class CShadowLeafEnum : public ISpatialLeafEnumerator -{ -public: - bool EnumerateLeaf( int leaf, int context ) - { - CClientLeafSystem::s_ClientLeafSystem.AddShadowToLeaf( leaf, (ClientLeafShadowHandle_t)context ); - return true; - } -}; - -void CClientLeafSystem::ProjectShadow( ClientLeafShadowHandle_t handle, const Vector& origin, - const Vector& dir, const Vector2D& size, float maxDist ) +void CClientLeafSystem::ProjectShadow( ClientLeafShadowHandle_t handle, int nLeafCount, const int *pLeafList ) { // Remove the shadow from any leaves it current exists in RemoveShadowFromLeaves( handle ); @@ -887,26 +1024,16 @@ void CClientLeafSystem::ProjectShadow( ClientLeafShadowHandle_t handle, const Ve // This will help us to avoid adding the shadow multiple times to a renderable ++m_ShadowEnum; - // Create a ray starting at the origin, with a boxsize == to the - // maximum size, and cast it along the direction of the shadow - // Then mark each leaf that the ray hits with the shadow - Ray_t ray; - VectorCopy( origin, ray.m_Start ); - VectorMultiply( dir, maxDist, ray.m_Delta ); - ray.m_StartOffset.Init( 0, 0, 0 ); - - float maxsize = max( size.x, size.y ) * 0.5f; - ray.m_Extents.Init( maxsize, maxsize, maxsize ); - ray.m_IsRay = false; - ray.m_IsSwept = true; - - CShadowLeafEnum leafEnum; - ISpatialQuery* pQuery = engine->GetBSPTreeQuery(); - pQuery->EnumerateLeavesAlongRay( ray, &leafEnum, handle ); + for ( int i = 0; i < nLeafCount; ++i ) + { + AddShadowToLeaf( pLeafList[i], handle ); + } } -void CClientLeafSystem::ProjectFlashlight( ClientLeafShadowHandle_t handle, const VMatrix &worldToShadow ) +void CClientLeafSystem::ProjectFlashlight( ClientLeafShadowHandle_t handle, int nLeafCount, const int *pLeafList ) { + VPROF_BUDGET( "CClientLeafSystem::ProjectFlashlight", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING ); + // Remove the shadow from any leaves it current exists in RemoveShadowFromLeaves( handle ); RemoveShadowFromRenderables( handle ); @@ -916,13 +1043,10 @@ void CClientLeafSystem::ProjectFlashlight( ClientLeafShadowHandle_t handle, cons // This will help us to avoid adding the shadow multiple times to a renderable ++m_ShadowEnum; - // Use an AABB around the frustum to enumerate leaves. - Vector mins, maxs; - CalculateAABBFromProjectionMatrix( worldToShadow, &mins, &maxs ); - - CShadowLeafEnum leafEnum; - ISpatialQuery* pQuery = engine->GetBSPTreeQuery(); - pQuery->EnumerateLeavesInBox( mins, maxs, &leafEnum, handle ); + for ( int i = 0; i < nLeafCount; ++i ) + { + AddShadowToLeaf( pLeafList[i], handle ); + } } @@ -964,6 +1088,9 @@ void CClientLeafSystem::EnumerateShadowsInLeaves( int leafCount, LeafIndex_t* pL //----------------------------------------------------------------------------- void CClientLeafSystem::AddRenderableToLeaf( int leaf, ClientRenderHandle_t renderable ) { +#ifdef VALIDATE_CLIENT_LEAF_SYSTEM + m_RenderablesInLeaf.ValidateAddElementToBucket( leaf, renderable ); +#endif m_RenderablesInLeaf.AddElementToBucket( leaf, renderable ); if ( !ShouldRenderableReceiveShadow( renderable, SHADOW_FLAGS_PROJECTED_TEXTURE_TYPE_MASK ) ) @@ -1006,17 +1133,31 @@ void CClientLeafSystem::AddRenderableToLeaves( ClientRenderHandle_t handle, int //----------------------------------------------------------------------------- bool CClientLeafSystem::EnumerateLeaf( int leaf, int context ) { - ClientRenderHandle_t handle = (ClientRenderHandle_t)context; - AddRenderableToLeaf( leaf, handle ); + EnumResultList_t *pList = (EnumResultList_t *)context; + if ( ThreadInMainThread() ) + { + AddRenderableToLeaf( leaf, pList->handle ); + } + else + { + EnumResult_t *p = new EnumResult_t; + p->leaf = leaf; + p->pNext = pList->pHead; + pList->pHead = p; + } return true; } - -void CClientLeafSystem::InsertIntoTree( ClientRenderHandle_t handle ) +void CClientLeafSystem::InsertIntoTree( ClientRenderHandle_t &handle ) { - // When we insert into the tree, increase the shadow enumerator - // to make sure each shadow is added exactly once to each renderable - ++m_ShadowEnum; + if ( ThreadInMainThread() ) + { + // When we insert into the tree, increase the shadow enumerator + // to make sure each shadow is added exactly once to each renderable + m_ShadowEnum++; + } + + EnumResultList_t list = { NULL, handle }; // NOTE: The render bounds here are relative to the renderable's coordinate system IClientRenderable* pRenderable = m_Renderables[handle].m_pRenderable; @@ -1026,10 +1167,12 @@ void CClientLeafSystem::InsertIntoTree( ClientRenderHandle_t handle ) Assert( absMins.IsValid() && absMaxs.IsValid() ); ISpatialQuery* pQuery = engine->GetBSPTreeQuery(); - pQuery->EnumerateLeavesInBox( absMins, absMaxs, this, handle ); + pQuery->EnumerateLeavesInBox( absMins, absMaxs, this, (int)&list ); - // Cache off the area it's sitting in. - m_Renderables[handle].m_Area = GetRenderableArea( handle ); + if ( list.pHead ) + { + m_DeferredInserts.PushItem( list ); + } } //----------------------------------------------------------------------------- @@ -1168,56 +1311,103 @@ void CClientLeafSystem::DrawDetailObjectsInLeaf( int leaf, int nFrameNumber, int bool CClientLeafSystem::ShouldDrawDetailObjectsInLeaf( int leaf, int frameNumber ) { ClientLeaf_t &leafInfo = m_Leaf[leaf]; - return ( (leafInfo.m_DetailPropRenderFrame == frameNumber ) && ( leafInfo.m_DetailPropCount != 0 ) ); + return ( (leafInfo.m_DetailPropRenderFrame == frameNumber ) && + ( ( leafInfo.m_DetailPropCount != 0 ) || ( leafInfo.m_pSubSystemData[CLSUBSYSTEM_DETAILOBJECTS] ) ) ); } //----------------------------------------------------------------------------- // Compute which leaf the translucent renderables should render in //----------------------------------------------------------------------------- -void CClientLeafSystem::ComputeTranslucentRenderLeaf( int count, LeafIndex_t *pLeafList, LeafFogVolume_t *pLeafFogVolumeList, int frameNumber ) +void CClientLeafSystem::ComputeTranslucentRenderLeaf( int count, const LeafIndex_t *pLeafList, const LeafFogVolume_t *pLeafFogVolumeList, int frameNumber, int viewID ) { - VPROF( "CClientLeafSystem::ComputeTranslucentRenderLeaf" ); + ASSERT_NO_REENTRY(); + VPROF_BUDGET( "CClientLeafSystem::ComputeTranslucentRenderLeaf", "ComputeTranslucentRenderLeaf" ); - // For better sorting, we're gonna choose the leaf that is closest to - // the camera. The leaf list passed in here is sorted front to back - for (int i = 0; i < count; ++i ) + #define LeafToMarker( leaf ) reinterpret_cast(( (leaf) << 1 ) | 1) + #define IsLeafMarker( p ) (bool)((reinterpret_cast(p)) & 1) + #define MarkerToLeaf( p ) (int)((reinterpret_cast(p)) >> 1) + + // For better sorting, we're gonna choose the leaf that is closest to the camera. + // The leaf list passed in here is sorted front to back + bool bThreaded = ( cl_threaded_client_leaf_system.GetBool() && g_pThreadPool->NumThreads() ); + int globalFrameCount = gpGlobals->framecount; + int i; + + static CUtlVector orderedList; // @MULTICORE (toml 8/30/2006): will need to make non-static if thread this function + static CUtlVector renderablesToUpdate; + int leaf = 0; + for ( i = 0; i < count; ++i ) { - int leaf = pLeafList[i]; + leaf = pLeafList[i]; + orderedList.AddToTail( LeafToMarker( leaf ) ); // iterate over all elements in this leaf unsigned short idx = m_RenderablesInLeaf.FirstElement(leaf); while (idx != m_RenderablesInLeaf.InvalidIndex()) { RenderableInfo_t& info = m_Renderables[m_RenderablesInLeaf.Element(idx)]; - if( info.m_RenderFrame != frameNumber ) - { + if ( info.m_TranslucencyCalculated != globalFrameCount || info.m_TranslucencyCalculatedView != viewID ) + { // Compute translucency - info.m_pRenderable->ComputeFxBlend(); - - if( info.m_RenderGroup == RENDER_GROUP_TRANSLUCENT_ENTITY ) + if ( bThreaded ) { - info.m_RenderLeaf = leaf; + renderablesToUpdate.AddToTail( info.m_pRenderable ); } - info.m_RenderFrame = frameNumber; - } - else if ( info.m_Flags & RENDER_FLAGS_ALTERNATE_SORTING ) - { - if( info.m_RenderGroup == RENDER_GROUP_TRANSLUCENT_ENTITY ) + else { - info.m_RenderLeaf = leaf; + info.m_pRenderable->ComputeFxBlend(); } + info.m_TranslucencyCalculated = globalFrameCount; + info.m_TranslucencyCalculatedView = viewID; } + orderedList.AddToTail( &info ); idx = m_RenderablesInLeaf.NextElement(idx); } } + + if ( bThreaded ) + { + ParallelProcess( renderablesToUpdate.Base(), renderablesToUpdate.Count(), &CallComputeFXBlend, &::FrameLock, &::FrameUnlock ); + renderablesToUpdate.RemoveAll(); + } + + for ( i = 0; i != orderedList.Count(); i++ ) + { + RenderableInfo_t *pInfo = orderedList[i]; + if ( !IsLeafMarker( pInfo ) ) + { + if( pInfo->m_RenderFrame != frameNumber ) + { + if( pInfo->m_RenderGroup == RENDER_GROUP_TRANSLUCENT_ENTITY ) + { + pInfo->m_RenderLeaf = leaf; + } + pInfo->m_RenderFrame = frameNumber; + } + else if ( pInfo->m_Flags & RENDER_FLAGS_ALTERNATE_SORTING ) + { + if( pInfo->m_RenderGroup == RENDER_GROUP_TRANSLUCENT_ENTITY ) + { + pInfo->m_RenderLeaf = leaf; + } + } + + } + else + { + leaf = MarkerToLeaf( pInfo ); + } + } + + orderedList.RemoveAll(); } //----------------------------------------------------------------------------- // Adds a renderable to the list of renderables to render this frame //----------------------------------------------------------------------------- -inline void AddRenderableToRenderList( CRenderList &renderList, IClientRenderable *pRenderable, +inline void AddRenderableToRenderList( CClientRenderablesList &renderList, IClientRenderable *pRenderable, int iLeaf, RenderGroup_t group, ClientRenderHandle_t renderHandle, bool bTwoPass = false ) { #ifdef _DEBUG @@ -1231,11 +1421,11 @@ inline void AddRenderableToRenderList( CRenderList &renderList, IClientRenderabl Assert( group >= 0 && group < RENDER_GROUP_COUNT ); int &curCount = renderList.m_RenderGroupCounts[group]; - if ( curCount < CRenderList::MAX_GROUP_ENTITIES ) + if ( curCount < CClientRenderablesList::MAX_GROUP_ENTITIES ) { Assert( (iLeaf >= 0) && (iLeaf <= 65535) ); - CRenderList::CEntry *pEntry = &renderList.m_RenderGroups[group][curCount]; + CClientRenderablesList::CEntry *pEntry = &renderList.m_RenderGroups[group][curCount]; pEntry->m_pRenderable = pRenderable; pEntry->m_iWorldListInfoLeaf = iLeaf; pEntry->m_TwoPass = bTwoPass; @@ -1244,7 +1434,7 @@ inline void AddRenderableToRenderList( CRenderList &renderList, IClientRenderabl } else { - engine->Con_NPrintf( 10, "Warning: overflowed CRenderList group %d", group ); + engine->Con_NPrintf( 10, "Warning: overflowed CClientRenderablesList group %d", group ); } } @@ -1276,9 +1466,49 @@ void CClientLeafSystem::CollateViewModelRenderables( CUtlVector< IClientRenderab } } -void CClientLeafSystem::CollateRenderablesInLeaf( int leaf, int worldListLeafIndex, SetupRenderInfo_t &info ) +static RenderGroup_t DetectBucketedRenderGroup( RenderGroup_t group, float fDimension ) +{ + float const arrThresholds[ 3 ] = { + 200.f, // tree size + 80.f, // player size + 30.f, // crate size + }; + Assert( ARRAYSIZE( arrThresholds ) + 1 >= RENDER_GROUP_CFG_NUM_OPAQUE_ENT_BUCKETS ); + Assert( group >= RENDER_GROUP_OPAQUE_STATIC && group <= RENDER_GROUP_OPAQUE_ENTITY ); + + int bucketedGroupIndex; + if ( RENDER_GROUP_CFG_NUM_OPAQUE_ENT_BUCKETS <= 2 || + fDimension >= arrThresholds[1] ) + { + if ( RENDER_GROUP_CFG_NUM_OPAQUE_ENT_BUCKETS <= 1 || + fDimension >= arrThresholds[0] ) + bucketedGroupIndex = 0; + else + bucketedGroupIndex = 1; + } + else + { + if ( RENDER_GROUP_CFG_NUM_OPAQUE_ENT_BUCKETS <= 3 || + fDimension >= arrThresholds[2] ) + bucketedGroupIndex = 2; + else + bucketedGroupIndex = 3; + } + + // Determine the new bucketed group + RenderGroup_t bucketedGroup = RenderGroup_t( group - ( ( RENDER_GROUP_CFG_NUM_OPAQUE_ENT_BUCKETS - 1 ) - bucketedGroupIndex ) * 2 ); + Assert( bucketedGroup >= RENDER_GROUP_OPAQUE_STATIC_HUGE && bucketedGroup <= RENDER_GROUP_OPAQUE_ENTITY ); + + return bucketedGroup; +} + +void CClientLeafSystem::CollateRenderablesInLeaf( int leaf, int worldListLeafIndex, const SetupRenderInfo_t &info ) { bool portalTestEnts = r_PortalTestEnts.GetBool() && !r_portalsopenall.GetBool(); + + // Place a fake entity for static/opaque ents in this leaf + AddRenderableToRenderList( *info.m_pRenderList, NULL, worldListLeafIndex, RENDER_GROUP_OPAQUE_STATIC, NULL ); + AddRenderableToRenderList( *info.m_pRenderList, NULL, worldListLeafIndex, RENDER_GROUP_OPAQUE_ENTITY, NULL ); // Collate everything. unsigned short idx = m_RenderablesInLeaf.FirstElement(leaf); @@ -1312,20 +1542,26 @@ void CClientLeafSystem::CollateRenderablesInLeaf( int leaf, int worldListLeafInd renderable.m_RenderFrame2 = info.m_nRenderFrame; } - else + else // translucent { + // Shadow depth skips ComputeTranslucentRenderLeaf! + // Translucent entities already have had ComputeTranslucentRenderLeaf called on them // so m_RenderLeaf should be set to the nearest leaf, so that's what we want here. if ( renderable.m_RenderLeaf != leaf ) continue; } - // Prevent culling if the renderable is invisible - // NOTE: OPAQUE objects can have alpha == 0. - // They are made to be opaque because they don't have to be sorted. - unsigned char nAlpha = renderable.m_pRenderable->GetFxBlend(); - if ( nAlpha == 0 ) - continue; + unsigned char nAlpha = 255; + if ( info.m_bDrawTranslucentObjects ) + { + // Prevent culling if the renderable is invisible + // NOTE: OPAQUE objects can have alpha == 0. + // They are made to be opaque because they don't have to be sorted. + nAlpha = renderable.m_pRenderable->GetFxBlend(); + if ( nAlpha == 0 ) + continue; + } Vector absMins, absMaxs; CalcRenderableWorldSpaceAABB( renderable.m_pRenderable, absMins, absMaxs ); @@ -1351,21 +1587,58 @@ void CClientLeafSystem::CollateRenderablesInLeaf( int leaf, int worldListLeafInd continue; } +#ifdef INVASION_CLIENT_DLL + if (info.m_flRenderDistSq != 0.0f) + { + Vector mins, maxs; + renderable.m_pRenderable->GetRenderBounds( mins, maxs ); + + if ((maxs.z - mins.z) < 100) + { + Vector vCenter; + VectorLerp( mins, maxs, 0.5f, vCenter ); + vCenter += renderable.m_pRenderable->GetRenderOrigin(); + + float flDistSq = info.m_vecRenderOrigin.DistToSqr( vCenter ); + if (info.m_flRenderDistSq <= flDistSq) + continue; + } + } +#endif + if( renderable.m_RenderGroup != RENDER_GROUP_TRANSLUCENT_ENTITY ) { RenderGroup_t group = (RenderGroup_t)renderable.m_RenderGroup; + + // Determine object group offset + if ( RENDER_GROUP_CFG_NUM_OPAQUE_ENT_BUCKETS > 1 && + group >= RENDER_GROUP_OPAQUE_STATIC && + group <= RENDER_GROUP_OPAQUE_ENTITY ) + { + Vector dims; + VectorSubtract( absMaxs, absMins, dims ); + + float const fDimension = max( max( fabs(dims.x), fabs(dims.y) ), fabs(dims.z) ); + group = DetectBucketedRenderGroup( group, fDimension ); + + Assert( group >= RENDER_GROUP_OPAQUE_STATIC_HUGE && group <= RENDER_GROUP_OPAQUE_ENTITY ); + } + AddRenderableToRenderList( *info.m_pRenderList, renderable.m_pRenderable, worldListLeafIndex, group, handle); } else { - bool bTwoPass = ((renderable.m_Flags & RENDER_FLAGS_TWOPASS) != 0) && ( nAlpha == 255 ); - - AddRenderableToRenderList( *info.m_pRenderList, renderable.m_pRenderable, - worldListLeafIndex, (RenderGroup_t)renderable.m_RenderGroup, handle, bTwoPass ); + bool bTwoPass = ((renderable.m_Flags & RENDER_FLAGS_TWOPASS) != 0) && ( nAlpha == 255 ); // Two pass? - // Add to both lists if it's a two-pass model... - if (bTwoPass) + // Add to appropriate list if drawing translucent objects (shadow depth mapping will skip this) + if ( info.m_bDrawTranslucentObjects ) + { + AddRenderableToRenderList( *info.m_pRenderList, renderable.m_pRenderable, + worldListLeafIndex, (RenderGroup_t)renderable.m_RenderGroup, handle, bTwoPass ); + } + + if ( bTwoPass ) // Also add to opaque list if it's a two-pass model... { AddRenderableToRenderList( *info.m_pRenderList, renderable.m_pRenderable, worldListLeafIndex, RENDER_GROUP_OPAQUE_ENTITY, handle, bTwoPass ); @@ -1375,7 +1648,7 @@ void CClientLeafSystem::CollateRenderablesInLeaf( int leaf, int worldListLeafInd // Do detail objects. // These don't have render handles! - if ( IsPC() && info.m_bDrawDetailObjects && ShouldDrawDetailObjectsInLeaf( leaf, info.m_nDetailBuildFrame ) ) + if ( info.m_bDrawDetailObjects && ShouldDrawDetailObjectsInLeaf( leaf, info.m_nDetailBuildFrame ) ) { idx = m_Leaf[leaf].m_FirstDetailProp; int count = m_Leaf[leaf].m_DetailPropCount; @@ -1383,17 +1656,19 @@ void CClientLeafSystem::CollateRenderablesInLeaf( int leaf, int worldListLeafInd { IClientRenderable* pRenderable = DetailObjectSystem()->GetDetailModel(idx); - // FIXME: This if check here is necessary because the detail object system also maintains - // lists of sprites... + // FIXME: This if check here is necessary because the detail object system also maintains lists of sprites... if (pRenderable) { if( pRenderable->IsTransparent() ) { - // Lots of the detail entities are invsible so avoid sorting them and all that. - if( pRenderable->GetFxBlend() > 0 ) + if ( info.m_bDrawTranslucentObjects ) // Don't draw translucent objects into shadow depth maps { - AddRenderableToRenderList( *info.m_pRenderList, pRenderable, - worldListLeafIndex, RENDER_GROUP_TRANSLUCENT_ENTITY, DETAIL_PROP_RENDER_HANDLE ); + // Lots of the detail entities are invisible so avoid sorting them and all that. + if( pRenderable->GetFxBlend() > 0 ) + { + AddRenderableToRenderList( *info.m_pRenderList, pRenderable, + worldListLeafIndex, RENDER_GROUP_TRANSLUCENT_ENTITY, DETAIL_PROP_RENDER_HANDLE ); + } } } else @@ -1405,4 +1680,88 @@ void CClientLeafSystem::CollateRenderablesInLeaf( int leaf, int worldListLeafInd ++idx; } } -} \ No newline at end of file +} + + +//----------------------------------------------------------------------------- +// Sort entities in a back-to-front ordering +//----------------------------------------------------------------------------- +void CClientLeafSystem::SortEntities( const Vector &vecRenderOrigin, const Vector &vecRenderForward, CClientRenderablesList::CEntry *pEntities, int nEntities ) +{ + // Don't sort if we only have 1 entity + if ( nEntities <= 1 ) + return; + + float dists[CClientRenderablesList::MAX_GROUP_ENTITIES]; + + // First get a distance for each entity. + int i; + for( i=0; i < nEntities; i++ ) + { + IClientRenderable *pRenderable = pEntities[i].m_pRenderable; + + // Compute the center of the object (needed for translucent brush models) + Vector boxcenter; + Vector mins,maxs; + pRenderable->GetRenderBounds( mins, maxs ); + VectorAdd( mins, maxs, boxcenter ); + VectorMA( pRenderable->GetRenderOrigin(), 0.5f, boxcenter, boxcenter ); + + // Compute distance... + Vector delta; + VectorSubtract( boxcenter, vecRenderOrigin, delta ); + dists[i] = DotProduct( delta, vecRenderForward ); + } + + // H-sort. + int stepSize = 4; + while( stepSize ) + { + int end = nEntities - stepSize; + for( i=0; i < end; i += stepSize ) + { + if( dists[i] > dists[i+stepSize] ) + { + swap( pEntities[i], pEntities[i+stepSize] ); + swap( dists[i], dists[i+stepSize] ); + + if( i == 0 ) + { + i = -stepSize; + } + else + { + i -= stepSize << 1; + } + } + } + + stepSize >>= 1; + } +} + + +void CClientLeafSystem::BuildRenderablesList( const SetupRenderInfo_t &info ) +{ + VPROF_BUDGET( "BuildRenderablesList", "BuildRenderablesList" ); + int leafCount = info.m_pWorldListInfo->m_LeafCount; + const Vector &vecRenderOrigin = info.m_vecRenderOrigin; + const Vector &vecRenderForward = info.m_vecRenderForward; + CClientRenderablesList::CEntry *pTranslucentEntries = info.m_pRenderList->m_RenderGroups[RENDER_GROUP_TRANSLUCENT_ENTITY]; + int &nTranslucentEntries = info.m_pRenderList->m_RenderGroupCounts[RENDER_GROUP_TRANSLUCENT_ENTITY]; + + for( int i = 0; i < leafCount; i++ ) + { + int nTranslucent = nTranslucentEntries; + + // Add renderables from this leaf... + CollateRenderablesInLeaf( info.m_pWorldListInfo->m_pLeafList[i], i, info ); + + int nNewTranslucent = nTranslucentEntries - nTranslucent; + if( (nNewTranslucent != 0 ) && info.m_bDrawTranslucentObjects ) + { + // Sort the new translucent entities. + SortEntities( vecRenderOrigin, vecRenderForward, &pTranslucentEntries[nTranslucent], nNewTranslucent ); + } + } +} diff --git a/src/src/cl_dll/clientleafsystem.h b/src/src/game/client/clientleafsystem.h similarity index 75% rename from src/src/cl_dll/clientleafsystem.h rename to src/src/game/client/clientleafsystem.h index 1458336..a52b4e5 100644 --- a/src/src/cl_dll/clientleafsystem.h +++ b/src/src/game/client/clientleafsystem.h @@ -1,4 +1,4 @@ -//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +//===== Copyright © 1996-2007, Valve Corporation, All rights reserved. ======// // // Purpose: // @@ -7,7 +7,7 @@ // // This file contains code to allow us to associate client data with bsp leaves. // -//=============================================================================// +//===========================================================================// #if !defined( CLIENTLEAFSYSTEM_H ) #define CLIENTLEAFSYSTEM_H @@ -19,10 +19,12 @@ #include "engine/IClientLeafSystem.h" #include "cdll_int.h" #include "IVRenderView.h" +#include "tier1/mempool.h" +#include "tier1/refcount.h" //----------------------------------------------------------------------------- -// Foward declarations +// Forward declarations //----------------------------------------------------------------------------- struct WorldListInfo_t; class IClientRenderable; @@ -35,7 +37,7 @@ class CStaticProp; //----------------------------------------------------------------------------- -// Handle to an renderable in the client leaf system +// Handle to an renderables in the client leaf system //----------------------------------------------------------------------------- enum { @@ -43,8 +45,10 @@ enum }; -class CRenderList +class CClientRenderablesList : public CRefCounted<> { + DECLARE_FIXEDSIZE_ALLOCATOR( CClientRenderablesList ); + public: enum { @@ -70,12 +74,21 @@ public: //----------------------------------------------------------------------------- struct SetupRenderInfo_t { - CRenderList *m_pRenderList; + WorldListInfo_t *m_pWorldListInfo; + CClientRenderablesList *m_pRenderList; Vector m_vecRenderOrigin; + Vector m_vecRenderForward; int m_nRenderFrame; int m_nDetailBuildFrame; // The "render frame" for detail objects float m_flRenderDistSq; - bool m_bDrawDetailObjects; + bool m_bDrawDetailObjects : 1; + bool m_bDrawTranslucentObjects : 1; + + SetupRenderInfo_t::SetupRenderInfo_t() + { + m_bDrawDetailObjects = true; + m_bDrawTranslucentObjects = true; + } }; @@ -96,10 +109,26 @@ abstract_class IClientLeafShadowEnum { public: // The user ID is the id passed into CreateShadow - virtual void EnumShadow( unsigned short userId ) = 0; + virtual void EnumShadow( ClientShadowHandle_t userId ) = 0; }; +// subclassed by things which wish to add per-leaf data managed by the client leafsystem +class CClientLeafSubSystemData +{ +public: + virtual ~CClientLeafSubSystemData( void ) + { + } +}; + + +// defines for subsystem ids. each subsystem id uses up one pointer in each leaf +#define CLSUBSYSTEM_DETAILOBJECTS 0 +#define N_CLSUBSYSTEMS 1 + + + //----------------------------------------------------------------------------- // The client leaf system //----------------------------------------------------------------------------- @@ -113,7 +142,10 @@ public: // with RenderableChanged() calls virtual bool IsRenderableInPVS( IClientRenderable *pRenderable ) = 0; - // Indicates which leaves detail objects are in + virtual void SetSubSystemDataInLeaf( int leaf, int nSubSystemIdx, CClientLeafSubSystemData *pData ) =0; + virtual CClientLeafSubSystemData *GetSubSystemDataInLeaf( int leaf, int nSubSystemIdx ) =0; + + virtual void SetDetailObjectsInLeaf( int leaf, int firstDetailObject, int detailObjectCount ) = 0; virtual void GetDetailObjectsInLeaf( int leaf, int& firstDetailObject, int& detailObjectCount ) = 0; @@ -130,11 +162,11 @@ public: // Set a render group virtual void SetRenderGroup( ClientRenderHandle_t handle, RenderGroup_t group ) = 0; - // Comptes which leaf translucent objects should be rendered in - virtual void ComputeTranslucentRenderLeaf( int count, LeafIndex_t *pLeafList, LeafFogVolume_t *pLeafFogVolumeList, int frameNumber ) = 0; + // Computes which leaf translucent objects should be rendered in + virtual void ComputeTranslucentRenderLeaf( int count, const LeafIndex_t *pLeafList, const LeafFogVolume_t *pLeafFogVolumeList, int frameNumber, int viewID ) = 0; - // Put renderables in the leaf into their appropriate lists. - virtual void CollateRenderablesInLeaf( int leaf, int worldListLeafIndex, SetupRenderInfo_t &info ) = 0; + // Put renderables into their appropriate lists. + virtual void BuildRenderablesList( const SetupRenderInfo_t &info ) = 0; // Put renderables in the leaf into their appropriate lists. virtual void CollateViewModelRenderables( CUtlVector< IClientRenderable * >& opaqueList, CUtlVector< IClientRenderable * >& translucentList ) = 0; @@ -146,15 +178,14 @@ public: virtual void DrawSmallEntities( bool enable ) = 0; // The following methods are related to shadows... - virtual ClientLeafShadowHandle_t AddShadow( unsigned short userId, unsigned short flags ) = 0; + virtual ClientLeafShadowHandle_t AddShadow( ClientShadowHandle_t userId, unsigned short flags ) = 0; virtual void RemoveShadow( ClientLeafShadowHandle_t h ) = 0; // Project a shadow - virtual void ProjectShadow( ClientLeafShadowHandle_t handle, const Vector& origin, - const Vector& dir, const Vector2D& size, float maxDist ) = 0; + virtual void ProjectShadow( ClientLeafShadowHandle_t handle, int nLeafCount, const int *pLeafList ) = 0; // Project a projected texture spotlight - virtual void ProjectFlashlight( ClientLeafShadowHandle_t handle, const VMatrix &worldToShadow ) = 0; + virtual void ProjectFlashlight( ClientLeafShadowHandle_t handle, int nLeafCount, const int *pLeafList ) = 0; // Find all shadow casters in a set of leaves virtual void EnumerateShadowsInLeaves( int leafCount, LeafIndex_t* pLeaves, IClientLeafShadowEnum* pEnum ) = 0; diff --git a/src/src/cl_dll/clientmode.h b/src/src/game/client/clientmode.h similarity index 100% rename from src/src/cl_dll/clientmode.h rename to src/src/game/client/clientmode.h diff --git a/src/src/cl_dll/clientmode_normal.cpp b/src/src/game/client/clientmode_normal.cpp similarity index 100% rename from src/src/cl_dll/clientmode_normal.cpp rename to src/src/game/client/clientmode_normal.cpp diff --git a/src/src/cl_dll/clientmode_normal.h b/src/src/game/client/clientmode_normal.h similarity index 100% rename from src/src/cl_dll/clientmode_normal.h rename to src/src/game/client/clientmode_normal.h diff --git a/src/src/cl_dll/clientmode_shared.cpp b/src/src/game/client/clientmode_shared.cpp similarity index 55% rename from src/src/cl_dll/clientmode_shared.cpp rename to src/src/game/client/clientmode_shared.cpp index 3c699dc..b5f19ff 100644 --- a/src/src/cl_dll/clientmode_shared.cpp +++ b/src/src/game/client/clientmode_shared.cpp @@ -12,7 +12,6 @@ #include "clientmode_shared.h" #include "iinput.h" #include "view_shared.h" -#include "keydefs.h" #include "iviewrender.h" #include "hud_basechat.h" #include "weapon_selection.h" @@ -29,6 +28,13 @@ #include "c_vguiscreen.h" #include "c_team.h" #include "c_rumble.h" +#include "fmtstr.h" +#include "achievementmgr.h" +#include "c_playerresource.h" +#include +#if defined( _X360 ) +#include "xbox/xbox_console.h" +#endif // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -38,10 +44,13 @@ class CHudChat; static vgui::HContext s_hVGuiContext = DEFAULT_VGUI_CONTEXT; -ConVar cl_drawhud( "cl_drawhud","1", FCVAR_CHEAT, "Enable the rendering of the hud" ); +ConVar cl_drawhud( "cl_drawhud", "1", FCVAR_CHEAT, "Enable the rendering of the hud" ); +ConVar hud_takesshots( "hud_takesshots", "0", FCVAR_CLIENTDLL | FCVAR_ARCHIVE, "Auto-save a scoreboard screenshot at the end of a map." ); extern ConVar v_viewmodel_fov; +extern bool IsInCommentaryMode( void ); + CON_COMMAND( hud_reloadscheme, "Reloads hud layout and animation scripts." ) { ClientModeShared *mode = ( ClientModeShared * )GetClientModeNormal(); @@ -51,8 +60,37 @@ CON_COMMAND( hud_reloadscheme, "Reloads hud layout and animation scripts." ) mode->ReloadScheme(); } -#ifdef _XBOX -static void __MsgFunc_XBoxRumble( bf_read &msg ) +#ifdef _DEBUG +CON_COMMAND_F( crash, "Crash the client. Optional parameter -- type of crash:\n 0: read from NULL\n 1: write to NULL\n 2: DmCrashDump() (xbox360 only)", FCVAR_CHEAT ) +{ + int crashtype = 0; + int dummy; + if ( args.ArgC() > 1 ) + { + crashtype = Q_atoi( args[1] ); + } + switch (crashtype) + { + case 0: + dummy = *((int *) NULL); + Msg("Crashed! %d\n", dummy); // keeps dummy from optimizing out + break; + case 1: + *((int *)NULL) = 42; + break; +#if defined( _X360 ) + case 2: + XBX_CrashDump(false); + break; +#endif + default: + Msg("Unknown variety of crash. You have now failed to crash. I hope you're happy.\n"); + break; + } +} +#endif // _DEBUG + +static void __MsgFunc_Rumble( bf_read &msg ) { unsigned char waveformIndex; unsigned char rumbleData; @@ -64,7 +102,6 @@ static void __MsgFunc_XBoxRumble( bf_read &msg ) RumbleEffect( waveformIndex, rumbleData, rumbleFlags ); } -#endif//_XBOX static void __MsgFunc_VGUIMenu( bf_read &msg ) { @@ -104,6 +141,15 @@ static void __MsgFunc_VGUIMenu( bf_read &msg ) keys->deleteThis(); } + // is the server telling us to show the scoreboard (at the end of a map)? + if ( Q_stricmp( panelname, "scores" ) == 0 ) + { + if ( hud_takesshots.GetBool() == true ) + { + gHUD.SetScreenShotTime( gpGlobals->curtime + 1.0 ); // take a screenshot in 1 second + } + } + gViewPortInterface->ShowPanel( viewport, bShow ); } @@ -137,34 +183,31 @@ void ClientModeShared::ReloadScheme( void ) //----------------------------------------------------------------------------- void ClientModeShared::Init() { - if ( IsPC() ) - { - m_pChatElement = ( CBaseHudChat * )GET_HUDELEMENT( CHudChat ); - Assert( m_pChatElement ); - } + m_pChatElement = ( CBaseHudChat * )GET_HUDELEMENT( CHudChat ); + Assert( m_pChatElement ); m_pWeaponSelection = ( CBaseHudWeaponSelection * )GET_HUDELEMENT( CHudWeaponSelection ); Assert( m_pWeaponSelection ); // Derived ClientMode class must make sure m_Viewport is instantiated Assert( m_pViewport ); - m_pViewport->LoadControlSettings("scripts/HudLayout.res"); + m_pViewport->LoadControlSettings( "scripts/HudLayout.res" ); + + ListenForGameEvent( "player_connect" ); + ListenForGameEvent( "player_disconnect" ); + ListenForGameEvent( "player_team" ); + ListenForGameEvent( "server_cvar" ); + ListenForGameEvent( "player_changename" ); + ListenForGameEvent( "teamplay_broadcast_audio" ); + ListenForGameEvent( "achievement_earned" ); - gameeventmanager->AddListener( this, "player_connect", false ); - gameeventmanager->AddListener( this, "player_disconnect", false ); - gameeventmanager->AddListener( this, "player_team", false ); - gameeventmanager->AddListener( this, "server_cvar", false ); - gameeventmanager->AddListener( this, "player_changename", false ); #ifndef _XBOX HLTVCamera()->Init(); #endif m_CursorNone = vgui::dc_none; HOOK_MESSAGE( VGUIMenu ); - -#ifdef _XBOX - HOOK_MESSAGE( XBoxRumble ); -#endif //_XBOX + HOOK_MESSAGE( Rumble ); } @@ -185,7 +228,6 @@ void ClientModeShared::VGui_Shutdown() //----------------------------------------------------------------------------- void ClientModeShared::Shutdown() { - gameeventmanager->RemoveListener( this ); } //----------------------------------------------------------------------------- @@ -193,15 +235,15 @@ void ClientModeShared::Shutdown() // Input : frametime - // *cmd - //----------------------------------------------------------------------------- -void ClientModeShared::CreateMove( float flInputSampleTime, CUserCmd *cmd ) +bool ClientModeShared::CreateMove( float flInputSampleTime, CUserCmd *cmd ) { // Let the player override the view. C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); if(!pPlayer) - return; + return true; // Let the player at it - pPlayer->CreateMove( flInputSampleTime, cmd ); + return pPlayer->CreateMove( flInputSampleTime, cmd ); } //----------------------------------------------------------------------------- @@ -355,9 +397,7 @@ void ClientModeShared::Update() m_pViewport->SetVisible( cl_drawhud.GetBool() ); } -#ifdef _XBOX UpdateRumbleEffects(); -#endif//_XBOX } //----------------------------------------------------------------------------- @@ -372,7 +412,7 @@ void ClientModeShared::ProcessInput(bool bActive) //----------------------------------------------------------------------------- // Purpose: We've received a keypress from the engine. Return 1 if the engine is allowed to handle it. //----------------------------------------------------------------------------- -int ClientModeShared::KeyInput( int down, int keynum, const char *pszCurrentBinding ) +int ClientModeShared::KeyInput( int down, ButtonCode_t keynum, const char *pszCurrentBinding ) { if ( engine->Con_IsVisible() ) return 1; @@ -401,38 +441,18 @@ int ClientModeShared::KeyInput( int down, int keynum, const char *pszCurrentBind C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); - // if ingame spectator mode, intercept key event here - if( pPlayer && pPlayer->GetObserverMode() > OBS_MODE_DEATHCAM ) + // if ingame spectator mode, let spectator input intercept key event here + if( pPlayer && + ( pPlayer->GetObserverMode() > OBS_MODE_DEATHCAM ) && + !HandleSpectatorKeyInput( down, keynum, pszCurrentBinding ) ) { - // we are in spectator mode, open spectator menu - if ( down && pszCurrentBinding && Q_strcmp( pszCurrentBinding, "+duck" ) == 0 ) - { - m_pViewport->ShowPanel( PANEL_SPECMENU, true ); - return 0; // we handled it, don't handle twice or send to server - } - else if ( down && pszCurrentBinding && Q_strcmp( pszCurrentBinding, "+attack" ) == 0 ) - { - engine->ClientCmd( "spec_next" ); - return 0; - } - else if ( down && pszCurrentBinding && Q_strcmp( pszCurrentBinding, "+attack2" ) == 0 ) - { - engine->ClientCmd( "spec_prev" ); - return 0; - } - else if ( down && pszCurrentBinding && Q_strcmp( pszCurrentBinding, "+jump" ) == 0 ) - { - engine->ClientCmd( "spec_mode" ); - return 0; - } + return 0; } - if ( m_pWeaponSelection ) + // Let game-specific hud elements get a crack at the key input + if ( !HudElementKeyInput( down, keynum, pszCurrentBinding ) ) { - if ( !m_pWeaponSelection->KeyInput( down, keynum, pszCurrentBinding ) ) - { - return 0; - } + return 0; } C_BaseCombatWeapon *pWeapon = GetActiveWeapon(); @@ -444,6 +464,57 @@ int ClientModeShared::KeyInput( int down, int keynum, const char *pszCurrentBind return 1; } +//----------------------------------------------------------------------------- +// Purpose: See if spectator input occurred. Return 0 if the key is swallowed. +//----------------------------------------------------------------------------- +int ClientModeShared::HandleSpectatorKeyInput( int down, ButtonCode_t keynum, const char *pszCurrentBinding ) +{ + // we are in spectator mode, open spectator menu + if ( down && pszCurrentBinding && Q_strcmp( pszCurrentBinding, "+duck" ) == 0 ) + { + m_pViewport->ShowPanel( PANEL_SPECMENU, true ); + return 0; // we handled it, don't handle twice or send to server + } + else if ( down && pszCurrentBinding && Q_strcmp( pszCurrentBinding, "+attack" ) == 0 ) + { + engine->ClientCmd( "spec_next" ); + return 0; + } + else if ( down && pszCurrentBinding && Q_strcmp( pszCurrentBinding, "+attack2" ) == 0 ) + { + engine->ClientCmd( "spec_prev" ); + return 0; + } + else if ( down && pszCurrentBinding && Q_strcmp( pszCurrentBinding, "+jump" ) == 0 ) + { + engine->ClientCmd( "spec_mode" ); + return 0; + } + else if ( down && pszCurrentBinding && Q_strcmp( pszCurrentBinding, "+strafe" ) == 0 ) + { + HLTVCamera()->SetAutoDirector( true ); + return 0; + } + + return 1; +} + +//----------------------------------------------------------------------------- +// Purpose: See if hud elements want key input. Return 0 if the key is swallowed +//----------------------------------------------------------------------------- +int ClientModeShared::HudElementKeyInput( int down, ButtonCode_t keynum, const char *pszCurrentBinding ) +{ + if ( m_pWeaponSelection ) + { + if ( !m_pWeaponSelection->KeyInput( down, keynum, pszCurrentBinding ) ) + { + return 0; + } + } + + return 1; +} + //----------------------------------------------------------------------------- // Purpose: // Output : vgui::Panel @@ -536,11 +607,18 @@ void ClientModeShared::Enable() m_pViewport->SetParent( pRoot ); } + // All hud elements should be proportional + // This sets that flag on the viewport and all child panels + m_pViewport->SetProportional( true ); + m_pViewport->SetCursor( m_CursorNone ); vgui::surface()->SetCursor( m_CursorNone ); m_pViewport->SetVisible( true ); - m_pViewport->RequestFocus(); + if ( m_pViewport->IsKeyBoardInputEnabled() ) + { + m_pViewport->RequestFocus(); + } Layout(); } @@ -589,6 +667,20 @@ float ClientModeShared::GetViewModelFOV( void ) class CHudChat; +bool PlayerNameNotSetYet( const char *pszName ) +{ + if ( pszName && pszName[0] ) + { + // Don't show "unconnected" if we haven't got the players name yet + if ( Q_strnicmp(pszName,"unconnected",11) == 0 ) + return true; + if ( Q_strnicmp(pszName,"NULLNAME",11) == 0 ) + return true; + } + + return false; +} + void ClientModeShared::FireGameEvent( IGameEvent *event ) { CBaseHudChat *hudChat = (CBaseHudChat *)GET_HUDELEMENT( CHudChat ); @@ -599,8 +691,21 @@ void ClientModeShared::FireGameEvent( IGameEvent *event ) { if ( !hudChat ) return; + if ( PlayerNameNotSetYet(event->GetString("name")) ) + return; - hudChat->Printf( "%s has joined the game\n", event->GetString("name") ); + if ( !IsInCommentaryMode() ) + { + wchar_t wszLocalized[100]; + wchar_t wszPlayerName[MAX_PLAYER_NAME_LENGTH]; + g_pVGuiLocalize->ConvertANSIToUnicode( event->GetString("name"), wszPlayerName, sizeof(wszPlayerName) ); + g_pVGuiLocalize->ConstructString( wszLocalized, sizeof( wszLocalized ), g_pVGuiLocalize->Find( "#game_player_joined_game" ), 1, wszPlayerName ); + + char szLocalized[100]; + g_pVGuiLocalize->ConvertUnicodeToANSI( wszLocalized, szLocalized, sizeof(szLocalized) ); + + hudChat->Printf( CHAT_FILTER_JOINLEAVE, "%s", szLocalized ); + } } else if ( Q_strcmp( "player_disconnect", eventname ) == 0 ) { @@ -608,18 +713,38 @@ void ClientModeShared::FireGameEvent( IGameEvent *event ) if ( !hudChat || !pPlayer ) return; + if ( PlayerNameNotSetYet(event->GetString("name")) ) + return; - hudChat->Printf( "%s left the game (%s)\n", - pPlayer->GetPlayerName(), - event->GetString("reason") ); + if ( !IsInCommentaryMode() ) + { + wchar_t wszPlayerName[MAX_PLAYER_NAME_LENGTH]; + g_pVGuiLocalize->ConvertANSIToUnicode( pPlayer->GetPlayerName(), wszPlayerName, sizeof(wszPlayerName) ); + + wchar_t wszReason[64]; + g_pVGuiLocalize->ConvertANSIToUnicode( event->GetString("reason"), wszReason, sizeof(wszReason) ); + + wchar_t wszLocalized[100]; + if (IsPC()) + { + g_pVGuiLocalize->ConstructString( wszLocalized, sizeof( wszLocalized ), g_pVGuiLocalize->Find( "#game_player_left_game" ), 2, wszPlayerName, wszReason ); + } + else + { + g_pVGuiLocalize->ConstructString( wszLocalized, sizeof( wszLocalized ), g_pVGuiLocalize->Find( "#game_player_left_game" ), 1, wszPlayerName ); + } + + char szLocalized[100]; + g_pVGuiLocalize->ConvertUnicodeToANSI( wszLocalized, szLocalized, sizeof(szLocalized) ); + + hudChat->Printf( CHAT_FILTER_JOINLEAVE, "%s", szLocalized ); + } } else if ( Q_strcmp( "player_team", eventname ) == 0 ) { C_BasePlayer *pPlayer = USERID2PLAYER( event->GetInt("userid") ); if ( !hudChat ) return; - if ( !pPlayer ) - return; bool bDisconnected = event->GetBool("disconnect"); @@ -627,18 +752,49 @@ void ClientModeShared::FireGameEvent( IGameEvent *event ) return; int team = event->GetInt( "team" ); + bool bAutoTeamed = event->GetInt( "autoteam", false ); + bool bSilent = event->GetInt( "silent", false ); - C_Team *pTeam = GetGlobalTeam( team ); - if ( pTeam ) + const char *pszName = event->GetString( "name" ); + if ( PlayerNameNotSetYet( pszName ) ) + return; + + if ( !bSilent ) { - hudChat->Printf( "Player %s joined team %s\n", pPlayer->GetPlayerName(), pTeam->Get_Name() ); - } - else - { - hudChat->Printf( "Player %s joined team %i\n", pPlayer->GetPlayerName(), team ); + wchar_t wszPlayerName[MAX_PLAYER_NAME_LENGTH]; + g_pVGuiLocalize->ConvertANSIToUnicode( pszName, wszPlayerName, sizeof(wszPlayerName) ); + + wchar_t wszTeam[64]; + C_Team *pTeam = GetGlobalTeam( team ); + if ( pTeam ) + { + g_pVGuiLocalize->ConvertANSIToUnicode( pTeam->Get_Name(), wszTeam, sizeof(wszTeam) ); + } + else + { + _snwprintf ( wszTeam, sizeof( wszTeam ) / sizeof( wchar_t ), L"%d", team ); + } + + if ( !IsInCommentaryMode() ) + { + wchar_t wszLocalized[100]; + if ( bAutoTeamed ) + { + g_pVGuiLocalize->ConstructString( wszLocalized, sizeof( wszLocalized ), g_pVGuiLocalize->Find( "#game_player_joined_autoteam" ), 2, wszPlayerName, wszTeam ); + } + else + { + g_pVGuiLocalize->ConstructString( wszLocalized, sizeof( wszLocalized ), g_pVGuiLocalize->Find( "#game_player_joined_team" ), 2, wszPlayerName, wszTeam ); + } + + char szLocalized[100]; + g_pVGuiLocalize->ConvertUnicodeToANSI( wszLocalized, szLocalized, sizeof(szLocalized) ); + + hudChat->Printf( CHAT_FILTER_TEAMCHANGE, "%s", szLocalized ); + } } - if ( pPlayer->IsLocalPlayer() ) + if ( pPlayer && pPlayer->IsLocalPlayer() ) { // that's me pPlayer->TeamChange( team ); @@ -649,16 +805,140 @@ void ClientModeShared::FireGameEvent( IGameEvent *event ) if ( !hudChat ) return; - hudChat->Printf( "%s changed name to %s\n", - event->GetString( "oldname" ), - event->GetString( "newname" ) ); + const char *pszOldName = event->GetString("oldname"); + if ( PlayerNameNotSetYet(pszOldName) ) + return; + + wchar_t wszOldName[MAX_PLAYER_NAME_LENGTH]; + g_pVGuiLocalize->ConvertANSIToUnicode( pszOldName, wszOldName, sizeof(wszOldName) ); + + wchar_t wszNewName[MAX_PLAYER_NAME_LENGTH]; + g_pVGuiLocalize->ConvertANSIToUnicode( event->GetString( "newname" ), wszNewName, sizeof(wszNewName) ); + + wchar_t wszLocalized[100]; + g_pVGuiLocalize->ConstructString( wszLocalized, sizeof( wszLocalized ), g_pVGuiLocalize->Find( "#game_player_changed_name" ), 2, wszOldName, wszNewName ); + + char szLocalized[100]; + g_pVGuiLocalize->ConvertUnicodeToANSI( wszLocalized, szLocalized, sizeof(szLocalized) ); + + hudChat->Printf( CHAT_FILTER_NAMECHANGE, "%s", szLocalized ); + } + else if ( Q_strcmp( "teamplay_broadcast_audio", eventname ) == 0 ) + { + int team = event->GetInt( "team" ); + + bool bValidTeam = false; + + if ( (GetLocalTeam() && GetLocalTeam()->GetTeamNumber() == team) ) + { + bValidTeam = true; + } + + //If we're in the spectator team then we should be getting whatever messages the person I'm spectating gets. + if ( bValidTeam == false ) + { + CBasePlayer *pSpectatorTarget = UTIL_PlayerByIndex( GetSpectatorTarget() ); + + if ( pSpectatorTarget && (GetSpectatorMode() == OBS_MODE_IN_EYE || GetSpectatorMode() == OBS_MODE_CHASE) ) + { + if ( pSpectatorTarget->GetTeamNumber() == team ) + { + bValidTeam = true; + } + } + } + + if ( team == 0 && GetLocalTeam() > 0 ) + { + bValidTeam = false; + } + + if ( bValidTeam == true ) + { + CLocalPlayerFilter filter; + const char *pszSoundName = event->GetString("sound"); + C_BaseEntity::EmitSound( filter, SOUND_FROM_LOCAL_PLAYER, pszSoundName ); + } + } + else if ( Q_strcmp( "teamplay_broadcast_audio", eventname ) == 0 ) + { + int team = event->GetInt( "team" ); + if ( !team || (GetLocalTeam() && GetLocalTeam()->GetTeamNumber() == team) ) + { + CLocalPlayerFilter filter; + const char *pszSoundName = event->GetString("sound"); + C_BaseEntity::EmitSound( filter, SOUND_FROM_LOCAL_PLAYER, pszSoundName ); + } } - else if ( Q_strcmp( "server_cvar", eventname ) == 0 ) { - hudChat->Printf( "Server cvar \"%s\" changed to %s\n", event->GetString("cvarname"), event->GetString("cvarvalue") ); - } + if ( !IsInCommentaryMode() ) + { + wchar_t wszCvarName[64]; + g_pVGuiLocalize->ConvertANSIToUnicode( event->GetString("cvarname"), wszCvarName, sizeof(wszCvarName) ); + wchar_t wszCvarValue[16]; + g_pVGuiLocalize->ConvertANSIToUnicode( event->GetString("cvarvalue"), wszCvarValue, sizeof(wszCvarValue) ); + + wchar_t wszLocalized[100]; + g_pVGuiLocalize->ConstructString( wszLocalized, sizeof( wszLocalized ), g_pVGuiLocalize->Find( "#game_server_cvar_changed" ), 2, wszCvarName, wszCvarValue ); + + char szLocalized[100]; + g_pVGuiLocalize->ConvertUnicodeToANSI( wszLocalized, szLocalized, sizeof(szLocalized) ); + + hudChat->Printf( CHAT_FILTER_SERVERMSG, "%s", szLocalized ); + } + } + else if ( Q_strcmp( "achievement_earned", eventname ) == 0 ) + { + int iPlayerIndex = event->GetInt( "player" ); + C_BasePlayer *pPlayer = UTIL_PlayerByIndex( iPlayerIndex ); + int iAchievement = event->GetInt( "achievement" ); + + if ( !hudChat || !pPlayer ) + return; + + if ( !IsInCommentaryMode() ) + { + CAchievementMgr *pAchievementMgr = dynamic_cast( engine->GetAchievementMgr() ); + if ( !pAchievementMgr ) + return; + + IAchievement *pAchievement = pAchievementMgr->GetAchievementByID( iAchievement ); + if ( pAchievement ) + { + if ( !pPlayer->IsDormant() ) + { + // no particle effect if the local player is the one with the achievement or the player is dead + if ( !pPlayer->IsLocalPlayer() && pPlayer->IsAlive() ) + { + //tagES using the "head" attachment won't work for CS and DoD + pPlayer->ParticleProp()->Create( "achieved", PATTACH_POINT_FOLLOW, "head" ); + } + + pPlayer->OnAchievementAchieved( iAchievement ); + } + + if ( g_PR ) + { + wchar_t wszPlayerName[MAX_PLAYER_NAME_LENGTH]; + g_pVGuiLocalize->ConvertANSIToUnicode( g_PR->GetPlayerName( iPlayerIndex ), wszPlayerName, sizeof( wszPlayerName ) ); + + const wchar_t *pchLocalizedAchievement = ACHIEVEMENT_LOCALIZED_NAME_FROM_STR( pAchievement->GetName() ); + if ( pchLocalizedAchievement ) + { + wchar_t wszLocalizedString[128]; + g_pVGuiLocalize->ConstructString( wszLocalizedString, sizeof( wszLocalizedString ), g_pVGuiLocalize->Find( "#Achievement_Earned" ), 2, wszPlayerName, pchLocalizedAchievement ); + + char szLocalized[128]; + g_pVGuiLocalize->ConvertUnicodeToANSI( wszLocalizedString, szLocalized, sizeof( szLocalized ) ); + + hudChat->ChatPrintf( iPlayerIndex, CHAT_FILTER_SERVERMSG, "%s", szLocalized ); + } + } + } + } + } else { DevMsg( 2, "Unhandled GameEvent in ClientModeShared::FireGameEvent - %s\n", event->GetName() ); diff --git a/src/src/cl_dll/clientmode_shared.h b/src/src/game/client/clientmode_shared.h similarity index 84% rename from src/src/cl_dll/clientmode_shared.h rename to src/src/game/client/clientmode_shared.h index d79d39f..fd741d7 100644 --- a/src/src/cl_dll/clientmode_shared.h +++ b/src/src/game/client/clientmode_shared.h @@ -13,7 +13,7 @@ #endif #include "iclientmode.h" -#include +#include "gameeventlistener.h" #include class CBaseHudChat; @@ -31,8 +31,8 @@ class Panel; extern IClientMode *GetClientModeNormal(); // must be implemented -// This class implements client mode functionality -class ClientModeShared : public IClientMode, public IGameEventListener2 +// This class implements client mode functionality common to HL2 and TF2. +class ClientModeShared : public IClientMode, public CGameEventListener { // IClientMode overrides. public: @@ -66,11 +66,12 @@ public: virtual void PostRender(); virtual void PostRenderVGui(); virtual void ProcessInput(bool bActive); - virtual void CreateMove( float flInputSampleTime, CUserCmd *cmd ); + virtual bool CreateMove( float flInputSampleTime, CUserCmd *cmd ); virtual void Update(); // Input - virtual int KeyInput( int down, int keynum, const char *pszCurrentBinding ); + virtual int KeyInput( int down, ButtonCode_t keynum, const char *pszCurrentBinding ); + virtual int HudElementKeyInput( int down, ButtonCode_t keynum, const char *pszCurrentBinding ); virtual void OverrideMouseInput( float *x, float *y ); virtual void StartMessageMode( int iMessageModeType ); virtual vgui::Panel *GetMessagePanel(); @@ -91,6 +92,8 @@ public: virtual bool CanRecordDemo( char *errorMsg, int length ) const { return true; } + virtual int HandleSpectatorKeyInput( int down, ButtonCode_t keynum, const char *pszCurrentBinding ); + protected: CBaseViewport *m_pViewport; diff --git a/src/src/cl_dll/clientshadowmgr.cpp b/src/src/game/client/clientshadowmgr.cpp similarity index 73% rename from src/src/cl_dll/clientshadowmgr.cpp rename to src/src/game/client/clientshadowmgr.cpp index 474706b..d1776c4 100644 --- a/src/src/cl_dll/clientshadowmgr.cpp +++ b/src/src/game/client/clientshadowmgr.cpp @@ -64,8 +64,10 @@ #include "materialsystem/IMaterial.h" #include "materialsystem/IMesh.h" #include "materialsystem/ITexture.h" +#include "BSPTreeData.h" #include "utlmultilist.h" #include "CollisionUtils.h" +#include "iviewrender.h" #include "IVRenderView.h" #include "tier0/vprof.h" #include "engine/ivmodelinfo.h" @@ -73,24 +75,40 @@ #include "engine/IVDebugOverlay.h" #include "engine/IStaticPropMgr.h" #include "datacache/imdlcache.h" +#include "viewrender.h" +#include "tier0/ICommandLine.h" +#include "vstdlib/jobthread.h" +#include "toolframework_client.h" +#include "bonetoworldarray.h" +#include "cmodel.h" + // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" static ConVar r_flashlightdrawfrustum( "r_flashlightdrawfrustum", "0" ); static ConVar r_flashlightmodels( "r_flashlightmodels", "1" ); -static ConVar r_shadowrendertotexture( "r_shadowrendertotexture", "1" ); +static ConVar r_shadowrendertotexture( "r_shadowrendertotexture", "0" ); +static ConVar r_flashlight_version2( "r_flashlight_version2", "0" ); -#ifdef DOSHADOWEDFLASHLIGHT -static ConVar r_flashlightdepthtexture( "r_flashlightdepthtexture", "0" ); -static ConVar r_flashlightdepthres( "r_flashlightdepthres", "512" ); +ConVar r_flashlightdepthtexture( "r_flashlightdepthtexture", "1" ); + +#if defined( _X360 ) +ConVar r_flashlightdepthres( "r_flashlightdepthres", "512" ); +#else +ConVar r_flashlightdepthres( "r_flashlightdepthres", "1024" ); #endif +ConVar r_threaded_client_shadow_manager( "r_threaded_client_shadow_manager", "0" ); #ifdef _WIN32 #pragma warning( disable: 4701 ) #endif +// forward declarations +void ToolFramework_RecordMaterialParams( IMaterial *pMaterial ); + + //----------------------------------------------------------------------------- // A texture allocator used to batch textures together // At the moment, the implementation simply allocates blocks of max 256x256 @@ -121,6 +139,7 @@ public: // Mark texture as being used... (return true if re-render is needed) bool UseTexture( TextureHandle_t h, bool bWillRedraw, float flArea ); + bool HasValidTexture( TextureHandle_t h ); // Advance frame... void AdvanceFrame(); @@ -129,7 +148,7 @@ public: void GetTextureRect(TextureHandle_t handle, int& x, int& y, int& w, int& h ); // Get at the texture it's a part of - ITexture* GetTexture(); + ITexture *GetTexture(); // Get at the total texture size. void GetTotalTextureSize( int& w, int& h ); @@ -142,14 +161,12 @@ private: enum { INVALID_FRAGMENT_HANDLE = (FragmentHandle_t)~0, -#ifndef _XBOX TEXTURE_PAGE_SIZE = 1024, MAX_TEXTURE_POWER = 8, +#if !defined( _X360 ) MIN_TEXTURE_POWER = 4, #else - TEXTURE_PAGE_SIZE = 512, - MAX_TEXTURE_POWER = 7, - MIN_TEXTURE_POWER = 3, + MIN_TEXTURE_POWER = 5, // per resolve requirements to ensure 32x32 aligned offsets #endif MAX_TEXTURE_SIZE = (1 << MAX_TEXTURE_POWER), MIN_TEXTURE_SIZE = (1 << MIN_TEXTURE_POWER), @@ -214,7 +231,6 @@ private: unsigned int m_CurrentFrame; }; - //----------------------------------------------------------------------------- // Allocate/deallocate the texture page //----------------------------------------------------------------------------- @@ -225,19 +241,27 @@ void CTextureAllocator::Init() m_Cache[i].m_List = m_Fragments.InvalidIndex(); } -#ifndef _XBOX - // GR: don't need depth buffer for shadows - m_TexturePage.InitRenderTarget( TEXTURE_PAGE_SIZE, TEXTURE_PAGE_SIZE, RT_SIZE_NO_CHANGE, IMAGE_FORMAT_ARGB8888, MATERIAL_RT_DEPTH_NONE, false ); +#if !defined( _X360 ) + // don't need depth buffer for shadows + m_TexturePage.InitRenderTarget( TEXTURE_PAGE_SIZE, TEXTURE_PAGE_SIZE, RT_SIZE_NO_CHANGE, IMAGE_FORMAT_ARGB8888, MATERIAL_RT_DEPTH_NONE, false, "_rt_Shadows" ); #else - // xboxissue - has to be linear format because swizzled render targets cannot be subrect cleared. - // can use a 16 bit format, and use rgb channel instead of alpha for shadow info - m_TexturePage.InitRenderTarget( TEXTURE_PAGE_SIZE, TEXTURE_PAGE_SIZE, RT_SIZE_NO_CHANGE, IMAGE_FORMAT_LINEAR_BGRX5551, MATERIAL_RT_DEPTH_NONE, false ); + // unfortunate explicit management required for this render target + // 32bpp edram is only largest shadow fragment, but resolved to actual shadow atlas + // because full-res 1024x1024 shadow buffer is too large for EDRAM + m_TexturePage.InitRenderTargetTexture( TEXTURE_PAGE_SIZE, TEXTURE_PAGE_SIZE, RT_SIZE_NO_CHANGE, IMAGE_FORMAT_ARGB8888, MATERIAL_RT_DEPTH_NONE, false, "_rt_Shadows" ); + + // edram footprint is only 256x256x4 = 256K + m_TexturePage.InitRenderTargetSurface( MAX_TEXTURE_SIZE, MAX_TEXTURE_SIZE, IMAGE_FORMAT_ARGB8888, false ); + + // due to texture/surface size mismatch, ensure texture page is entirely cleared translucent + // otherwise border artifacts at edge of shadows due to pixel shader averaging of unwanted bits + m_TexturePage->ClearTexture( 0, 0, 0, 0 ); #endif } void CTextureAllocator::Shutdown() { - m_TexturePage.Shutdown( ); + m_TexturePage.Shutdown(); } @@ -253,41 +277,26 @@ void CTextureAllocator::Reset() // Set up the block sizes.... // FIXME: Improve heuristic?!? -#ifndef _XBOX - m_Blocks[0].m_FragmentPower = 4; // 128 x 16 - m_Blocks[1].m_FragmentPower = 5; // 64 x 32 - m_Blocks[2].m_FragmentPower = 6; // 32 x 64 - m_Blocks[3].m_FragmentPower = 6; - m_Blocks[4].m_FragmentPower = 7; // 24 x 128 - m_Blocks[5].m_FragmentPower = 7; - m_Blocks[6].m_FragmentPower = 7; - m_Blocks[7].m_FragmentPower = 7; - m_Blocks[8].m_FragmentPower = 7; - m_Blocks[9].m_FragmentPower = 7; - m_Blocks[10].m_FragmentPower = 8; // 6 x 256 - m_Blocks[11].m_FragmentPower = 8; - m_Blocks[12].m_FragmentPower = 8; - m_Blocks[13].m_FragmentPower = 8; - m_Blocks[14].m_FragmentPower = 8; - m_Blocks[15].m_FragmentPower = 8; +#if !defined( _X360 ) + m_Blocks[0].m_FragmentPower = MAX_TEXTURE_POWER-4; // 128 cells at ExE resolution #else - m_Blocks[0].m_FragmentPower = MAX_TEXTURE_POWER-4; // 128 cells at ExE - m_Blocks[1].m_FragmentPower = MAX_TEXTURE_POWER-3; // 64 cells at DxD - m_Blocks[2].m_FragmentPower = MAX_TEXTURE_POWER-2; // 32 cells at CxC + m_Blocks[0].m_FragmentPower = MAX_TEXTURE_POWER-3; // 64 cells at DxD resolution +#endif + m_Blocks[1].m_FragmentPower = MAX_TEXTURE_POWER-3; // 64 cells at DxD resolution + m_Blocks[2].m_FragmentPower = MAX_TEXTURE_POWER-2; // 32 cells at CxC resolution m_Blocks[3].m_FragmentPower = MAX_TEXTURE_POWER-2; - m_Blocks[4].m_FragmentPower = MAX_TEXTURE_POWER-1; // 24 cells at BxB + m_Blocks[4].m_FragmentPower = MAX_TEXTURE_POWER-1; // 24 cells at BxB resolution m_Blocks[5].m_FragmentPower = MAX_TEXTURE_POWER-1; m_Blocks[6].m_FragmentPower = MAX_TEXTURE_POWER-1; m_Blocks[7].m_FragmentPower = MAX_TEXTURE_POWER-1; m_Blocks[8].m_FragmentPower = MAX_TEXTURE_POWER-1; m_Blocks[9].m_FragmentPower = MAX_TEXTURE_POWER-1; - m_Blocks[10].m_FragmentPower = MAX_TEXTURE_POWER; // 6 cells at AxA + m_Blocks[10].m_FragmentPower = MAX_TEXTURE_POWER; // 6 cells at AxA resolution m_Blocks[11].m_FragmentPower = MAX_TEXTURE_POWER; m_Blocks[12].m_FragmentPower = MAX_TEXTURE_POWER; m_Blocks[13].m_FragmentPower = MAX_TEXTURE_POWER; m_Blocks[14].m_FragmentPower = MAX_TEXTURE_POWER; m_Blocks[15].m_FragmentPower = MAX_TEXTURE_POWER; -#endif // Initialize the LRU int i; @@ -482,6 +491,17 @@ void CTextureAllocator::DisconnectTextureFromFragment( FragmentHandle_t f ) } +//----------------------------------------------------------------------------- +// Do we have a valid texture assigned? +//----------------------------------------------------------------------------- +bool CTextureAllocator::HasValidTexture( TextureHandle_t h ) +{ + TextureInfo_t& info = m_Textures[h]; + FragmentHandle_t currentFragment = info.m_Fragment; + return (currentFragment != INVALID_FRAGMENT_HANDLE); +} + + //----------------------------------------------------------------------------- // Mark texture as being used... //----------------------------------------------------------------------------- @@ -492,9 +512,9 @@ bool CTextureAllocator::UseTexture( TextureHandle_t h, bool bWillRedraw, float f TextureInfo_t& info = m_Textures[h]; - // 4 is the minimum power we have allocated - int nDesiredPower = 4; - int nDesiredWidth = 16; + // spin up to the best fragment size + int nDesiredPower = MIN_TEXTURE_POWER; + int nDesiredWidth = MIN_TEXTURE_SIZE; while ( (nDesiredWidth * nDesiredWidth) < flArea ) { if ( nDesiredPower >= info.m_Power ) @@ -504,7 +524,7 @@ bool CTextureAllocator::UseTexture( TextureHandle_t h, bool bWillRedraw, float f } ++nDesiredPower; - nDesiredWidth *= 2; + nDesiredWidth <<= 1; } // If we've got a valid fragment for this texture, no worries! @@ -619,7 +639,6 @@ ITexture* CTextureAllocator::GetTexture() return m_TexturePage; } - //----------------------------------------------------------------------------- // Get at the total texture size. //----------------------------------------------------------------------------- @@ -664,7 +683,7 @@ void CTextureAllocator::GetTextureRect(TextureHandle_t handle, int& x, int& y, i static ConVar r_shadows( "r_shadows", "1" ); // hook into engine's cvars.. static ConVar r_shadowmaxrendered("r_shadowmaxrendered", "32"); -static ConVar r_shadows_gamecontrol( "r_shadows_gamecontrol", "-1" ); // hook into engine's cvars.. +static ConVar r_shadows_gamecontrol( "r_shadows_gamecontrol", "-1", FCVAR_CHEAT ); // hook into engine's cvars.. //----------------------------------------------------------------------------- // The class responsible for dealing with shadows on the client side @@ -680,6 +699,7 @@ public: // Inherited from IClientShadowMgr virtual bool Init(); + virtual void PostInit() {} virtual void Shutdown(); virtual void LevelInitPreEntity(); virtual void LevelInitPostEntity() {} @@ -723,7 +743,13 @@ public: void RemoveAllShadowsFromReceiver( IClientRenderable* pRenderable, ShadowReceiver_t type ); // Re-renders all shadow textures for shadow casters that lie in the leaf list - void ComputeShadowTextures( const CViewSetup *pView, int leafCount, LeafIndex_t* pLeafList ); + void ComputeShadowTextures( const CViewSetup &view, int leafCount, LeafIndex_t* pLeafList ); + + // Kicks off rendering into shadow depth maps (if any) + void ComputeShadowDepthTextures( const CViewSetup &view ); + + // Frees shadow depth textures for use in subsequent view/frame + void FreeShadowDepthTextures(); // Returns the shadow texture ITexture* GetShadowTexture( unsigned short h ); @@ -758,9 +784,6 @@ public: // Computes a rough bounding box encompassing the volume of the shadow void ComputeShadowBBox( IClientRenderable *pRenderable, const Vector &vecAbsCenter, float flRadius, Vector *pAbsMins, Vector *pAbsMaxs ); - // Returns true if the shadow is far enough to want to use blobby shadows - bool ShouldUseBlobbyShadows( float flRadius, float flScreenArea ); - bool WillParentRenderBlobbyShadow( IClientRenderable *pRenderable ); // Are we the child of a shadow with render-to-texture? @@ -777,6 +800,7 @@ private: SHADOW_FLAGS_TEXTURE_DIRTY = (CLIENT_SHADOW_FLAGS_LAST_FLAG << 1), SHADOW_FLAGS_BRUSH_MODEL = (CLIENT_SHADOW_FLAGS_LAST_FLAG << 2), SHADOW_FLAGS_USING_LOD_SHADOW = (CLIENT_SHADOW_FLAGS_LAST_FLAG << 3), + SHADOW_FLAGS_LIGHT_WORLD = (CLIENT_SHADOW_FLAGS_LAST_FLAG << 4), }; struct ClientShadow_t @@ -793,7 +817,6 @@ private: CTextureReference m_ShadowDepthTexture; int m_nRenderFrame; EHANDLE m_hTargetEntity; - bool m_bLightWorld; }; private: @@ -806,19 +829,18 @@ private: IClientRenderable *GetParentShadowEntity( ClientShadowHandle_t handle ); // Adds the child bounds to the bounding box - void AddChildBounds( matrix3x4_t &worldToBBox, IClientRenderable* pParent, Vector &vecMins, Vector &vecMaxs ); + void AddChildBounds( matrix3x4_t &matWorldToBBox, IClientRenderable* pParent, Vector &vecMins, Vector &vecMaxs ); // Compute a bounds for the entity + children void ComputeHierarchicalBounds( IClientRenderable *pRenderable, Vector &vecMins, Vector &vecMaxs ); // Builds matrices transforming from world space to shadow space - void BuildGeneralWorldToShadowMatrix( VMatrix& worldToShadow, + void BuildGeneralWorldToShadowMatrix( VMatrix& matWorldToShadow, const Vector& origin, const Vector& dir, const Vector& xvec, const Vector& yvec ); - void BuildOrthoWorldToShadowMatrix( VMatrix& worldToShadow, - const Vector& origin, const Vector& dir, const Vector& xvec, const Vector& yvec ); - void BuildPerspectiveWorldToFlashlightMatrix( VMatrix& worldToShadow, - const Vector& origin, const Vector& dir, const Vector& xvec, const Vector& yvec, float fovDegrees, - float zNear, float zFar ); + + void BuildWorldToShadowMatrix( VMatrix& matWorldToShadow, const Vector& origin, const Quaternion& quatOrientation ); + + void BuildPerspectiveWorldToFlashlightMatrix( VMatrix& matWorldToShadow, const FlashlightState_t &flashlightState ); // Update a shadow void UpdateProjectedTextureInternal( ClientShadowHandle_t handle, bool force ); @@ -848,8 +870,6 @@ private: void SetupRenderToTextureShadow( ClientShadowHandle_t h ); void CleanUpRenderToTextureShadow( ClientShadowHandle_t h ); - void CleanUpDepthTextureShadow( ClientShadowHandle_t h ); - // Compute the extra shadow planes void ComputeExtraClipPlanes( IClientRenderable* pRenderable, ClientShadowHandle_t handle, const Vector* vec, @@ -874,6 +894,10 @@ private: // Draws all children shadows into our own bool DrawShadowHierarchy( IClientRenderable *pRenderable, const ClientShadow_t &shadow, bool bChild = false ); + // Setup stage for threading + bool BuildSetupListForRenderToTextureShadow( unsigned short clientShadowHandle, float flArea ); + bool BuildSetupShadowHierarchy( IClientRenderable *pRenderable, const ClientShadow_t &shadow, bool bChild = false ); + // Computes + sets the render-to-texture texcoords void SetRenderToTextureShadowTexCoords( ShadowHandle_t handle, int x, int y, int w, int h ); @@ -902,9 +926,9 @@ private: ClientShadowHandle_t CreateProjectedTexture( ClientEntityHandle_t entity, int flags ); - // Allocate/deallocate a depth buffer for use by a shadow map - bool AllocateDepthBuffer( CTextureReference &depthBuffer ); - void DeallocateDepthBuffer( CTextureReference &depthBuffer ); + // Lock down the usage of a shadow depth texture...must be unlocked use on subsequent views / frames + bool LockShadowDepthTexture( CTextureReference *shadowDepthTexture ); + void UnlockAllShadowDepthTextures(); // Set and clear flashlight target renderable void SetFlashlightTarget( ClientShadowHandle_t shadowHandle, EHANDLE targetEntity ); @@ -914,29 +938,44 @@ private: bool IsFlashlightTarget( ClientShadowHandle_t shadowHandle, IClientRenderable *pRenderable ); + // Builds a list of active shadows requiring shadow depth renders + int BuildActiveShadowDepthList( const CViewSetup &viewSetup, int nMaxDepthShadows, ClientShadowHandle_t *pActiveDepthShadows ); + + // Sets the view's active flashlight render state + void SetViewFlashlightState( int nActiveFlashlightCount, ClientShadowHandle_t* pActiveFlashlights ); + private: Vector m_SimpleShadowDir; color32 m_AmbientLightColor; CMaterialReference m_SimpleShadow; CMaterialReference m_RenderShadow; CMaterialReference m_RenderModelShadow; + CTextureReference m_DummyColorTexture; CUtlLinkedList< ClientShadow_t, ClientShadowHandle_t > m_Shadows; CTextureAllocator m_ShadowAllocator; + bool m_RenderToTextureActive; bool m_bRenderTargetNeedsClear; bool m_bUpdatingDirtyShadows; + bool m_bThreaded; float m_flShadowCastDist; float m_flMinShadowArea; CUtlRBTree< ClientShadowHandle_t, unsigned short > m_DirtyShadows; + CUtlVector< ClientShadowHandle_t > m_TransparentShadows; + + // These members maintain current state of depth texturing (size and global active state) + // If either changes in a frame, PreRender() will catch it and do the appropriate allocation, deallocation or reallocation + bool m_bDepthTextureActive; + int m_nDepthTextureResolution; // Assume square (height == width) - bool m_DepthTextureActive; CUtlVector< CTextureReference > m_DepthTextureCache; + CUtlVector< bool > m_DepthTextureCacheLocks; int m_nMaxDepthTextureShadows; friend class CVisibleShadowList; + friend class CVisibleShadowFrustumList; }; - //----------------------------------------------------------------------------- // Singleton //----------------------------------------------------------------------------- @@ -944,39 +983,225 @@ static CClientShadowMgr s_ClientShadowMgr; IClientShadowMgr* g_pClientShadowMgr = &s_ClientShadowMgr; -CClientShadowMgr::CClientShadowMgr() : - m_DirtyShadows( 0, 0, ShadowHandleCompareFunc ), - m_DepthTextureActive( false ) +//----------------------------------------------------------------------------- +// Builds a list of potential shadows that lie within our PVS + view frustum +//----------------------------------------------------------------------------- +struct VisibleShadowInfo_t +{ + ClientShadowHandle_t m_hShadow; + float m_flArea; + Vector m_vecAbsCenter; +}; + +class CVisibleShadowList : public IClientLeafShadowEnum +{ +public: + + CVisibleShadowList(); + int FindShadows( const CViewSetup *pView, int nLeafCount, LeafIndex_t *pLeafList ); + int GetVisibleShadowCount() const; + + const VisibleShadowInfo_t &GetVisibleShadow( int i ) const; + +private: + void EnumShadow( unsigned short clientShadowHandle ); + float ComputeScreenArea( const Vector &vecCenter, float r ) const; + void PrioritySort(); + + CUtlVector m_ShadowsInView; + CUtlVector m_PriorityIndex; +}; + + +//----------------------------------------------------------------------------- +// Singleton instances of shadow and shadow frustum lists +//----------------------------------------------------------------------------- +static CVisibleShadowList s_VisibleShadowList; + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +static CUtlVector s_NPCShadowBoneSetups; +static CUtlVector s_NonNPCShadowBoneSetups; + +//----------------------------------------------------------------------------- +// CVisibleShadowList - Constructor and Accessors +//----------------------------------------------------------------------------- +CVisibleShadowList::CVisibleShadowList() : m_ShadowsInView( 0, 64 ), m_PriorityIndex( 0, 64 ) { } +int CVisibleShadowList::GetVisibleShadowCount() const +{ + return m_ShadowsInView.Count(); +} + +const VisibleShadowInfo_t &CVisibleShadowList::GetVisibleShadow( int i ) const +{ + return m_ShadowsInView[m_PriorityIndex[i]]; +} + + +//----------------------------------------------------------------------------- +// CVisibleShadowList - Computes approximate screen area of the shadow +//----------------------------------------------------------------------------- +float CVisibleShadowList::ComputeScreenArea( const Vector &vecCenter, float r ) const +{ + CMatRenderContextPtr pRenderContext( materials ); + float flScreenDiameter = pRenderContext->ComputePixelDiameterOfSphere( vecCenter, r ); + return flScreenDiameter * flScreenDiameter; +} + + +//----------------------------------------------------------------------------- +// CVisibleShadowList - Visits every shadow in the list of leaves +//----------------------------------------------------------------------------- +void CVisibleShadowList::EnumShadow( unsigned short clientShadowHandle ) +{ + CClientShadowMgr::ClientShadow_t& shadow = s_ClientShadowMgr.m_Shadows[clientShadowHandle]; + + // Don't bother if we rendered it this frame, no matter which view it was rendered for + if ( shadow.m_nRenderFrame == gpGlobals->framecount ) + return; + + // We don't need to bother with it if it's not render-to-texture + if ( s_ClientShadowMgr.GetActualShadowCastType( clientShadowHandle ) != SHADOWS_RENDER_TO_TEXTURE ) + return; + + // Don't bother with it if the shadow is totally transparent + const ShadowInfo_t &shadowInfo = shadowmgr->GetInfo( shadow.m_ShadowHandle ); + if ( shadowInfo.m_FalloffBias == 255 ) + return; + + IClientRenderable *pRenderable = ClientEntityList().GetClientRenderableFromHandle( shadow.m_Entity ); + Assert( pRenderable ); + + // Don't bother with children of hierarchy; they will be drawn with their parents + if ( s_ClientShadowMgr.ShouldUseParentShadow( pRenderable ) || s_ClientShadowMgr.WillParentRenderBlobbyShadow( pRenderable ) ) + return; + + // Compute a sphere surrounding the shadow + // FIXME: This doesn't account for children of hierarchy... too bad! + Vector vecAbsCenter; + float flRadius; + s_ClientShadowMgr.ComputeBoundingSphere( pRenderable, vecAbsCenter, flRadius ); + + // Compute a box surrounding the shadow + Vector vecAbsMins, vecAbsMaxs; + s_ClientShadowMgr.ComputeShadowBBox( pRenderable, vecAbsCenter, flRadius, &vecAbsMins, &vecAbsMaxs ); + + // FIXME: Add distance check here? + + // Make sure it's in the frustum. If it isn't it's not interesting + if (engine->CullBox( vecAbsMins, vecAbsMaxs )) + return; + + int i = m_ShadowsInView.AddToTail( ); + VisibleShadowInfo_t &info = m_ShadowsInView[i]; + info.m_hShadow = clientShadowHandle; + m_ShadowsInView[i].m_flArea = ComputeScreenArea( vecAbsCenter, flRadius ); + + // Har, har. When water is rendering (or any multipass technique), + // we may well initially render from a viewpoint which doesn't include this shadow. + // That doesn't mean we shouldn't check it again though. Sucks that we need to compute + // the sphere + bbox multiply times though. + shadow.m_nRenderFrame = gpGlobals->framecount; +} + + +//----------------------------------------------------------------------------- +// CVisibleShadowList - Sort based on screen area/priority +//----------------------------------------------------------------------------- +void CVisibleShadowList::PrioritySort() +{ + int nCount = m_ShadowsInView.Count(); + m_PriorityIndex.EnsureCapacity( nCount ); + + m_PriorityIndex.RemoveAll(); + + int i, j; + for ( i = 0; i < nCount; ++i ) + { + m_PriorityIndex.AddToTail(i); + } + + for ( i = 0; i < nCount - 1; ++i ) + { + int nLargestInd = i; + float flLargestArea = m_ShadowsInView[m_PriorityIndex[i]].m_flArea; + for ( j = i + 1; j < nCount; ++j ) + { + int nIndex = m_PriorityIndex[j]; + if ( flLargestArea < m_ShadowsInView[nIndex].m_flArea ) + { + nLargestInd = j; + flLargestArea = m_ShadowsInView[nIndex].m_flArea; + } + } + swap( m_PriorityIndex[i], m_PriorityIndex[nLargestInd] ); + } +} + + +//----------------------------------------------------------------------------- +// CVisibleShadowList - Main entry point for finding shadows in the leaf list +//----------------------------------------------------------------------------- +int CVisibleShadowList::FindShadows( const CViewSetup *pView, int nLeafCount, LeafIndex_t *pLeafList ) +{ + VPROF_BUDGET( "CVisibleShadowList::FindShadows", VPROF_BUDGETGROUP_SHADOW_RENDERING ); + + m_ShadowsInView.RemoveAll(); + ClientLeafSystem()->EnumerateShadowsInLeaves( nLeafCount, pLeafList, this ); + int nCount = m_ShadowsInView.Count(); + if (nCount != 0) + { + // Sort based on screen area/priority + PrioritySort(); + } + return nCount; +} + + +//----------------------------------------------------------------------------- +// Constructor +//----------------------------------------------------------------------------- +CClientShadowMgr::CClientShadowMgr() : + m_DirtyShadows( 0, 0, ShadowHandleCompareFunc ), + m_RenderToTextureActive( false ), + m_bDepthTextureActive( false ) +{ + m_nDepthTextureResolution = r_flashlightdepthres.GetInt(); + m_bThreaded = false; +} + + //----------------------------------------------------------------------------- // Changes the shadow direction... //----------------------------------------------------------------------------- -static void ShadowDir_f() +CON_COMMAND_F( r_shadowdir, "Set shadow direction", FCVAR_CHEAT ) { Vector dir; - if (engine->Cmd_Argc() == 1) + if ( args.ArgC() == 1 ) { Vector dir = s_ClientShadowMgr.GetShadowDirection(); Msg( "%.2f %.2f %.2f\n", dir.x, dir.y, dir.z ); return; } - if (engine->Cmd_Argc() == 4) + if ( args.ArgC() == 4 ) { - dir.x = atof( engine->Cmd_Argv(1) ); - dir.y = atof( engine->Cmd_Argv(2) ); - dir.z = atof( engine->Cmd_Argv(3) ); + dir.x = atof( args[1] ); + dir.y = atof( args[2] ); + dir.z = atof( args[3] ); s_ClientShadowMgr.SetShadowDirection(dir); } } -static void ShadowAngles_f() +CON_COMMAND_F( r_shadowangles, "Set shadow angles", FCVAR_CHEAT ) { Vector dir; QAngle angles; - if (engine->Cmd_Argc() == 1) + if (args.ArgC() == 1) { Vector dir = s_ClientShadowMgr.GetShadowDirection(); QAngle angles; @@ -985,19 +1210,19 @@ static void ShadowAngles_f() return; } - if (engine->Cmd_Argc() == 4) + if (args.ArgC() == 4) { - angles.x = atof( engine->Cmd_Argv(1) ); - angles.y = atof( engine->Cmd_Argv(2) ); - angles.z = atof( engine->Cmd_Argv(3) ); + angles.x = atof( args[1] ); + angles.y = atof( args[2] ); + angles.z = atof( args[3] ); AngleVectors( angles, &dir ); s_ClientShadowMgr.SetShadowDirection(dir); } } -static void ShadowColor_f() +CON_COMMAND_F( r_shadowcolor, "Set shadow color", FCVAR_CHEAT ) { - if (engine->Cmd_Argc() == 1) + if (args.ArgC() == 1) { unsigned char r, g, b; s_ClientShadowMgr.GetShadowColor( &r, &g, &b ); @@ -1005,53 +1230,47 @@ static void ShadowColor_f() return; } - if (engine->Cmd_Argc() == 4) + if (args.ArgC() == 4) { - int r = atoi( engine->Cmd_Argv(1) ); - int g = atoi( engine->Cmd_Argv(2) ); - int b = atoi( engine->Cmd_Argv(3) ); + int r = atoi( args[1] ); + int g = atoi( args[2] ); + int b = atoi( args[3] ); s_ClientShadowMgr.SetShadowColor(r, g, b); } } -static void ShadowDistance_f() +CON_COMMAND_F( r_shadowdist, "Set shadow distance", FCVAR_CHEAT ) { - if (engine->Cmd_Argc() == 1) + if (args.ArgC() == 1) { float flDist = s_ClientShadowMgr.GetShadowDistance( ); Msg( "Shadow distance %.2f\n", flDist ); return; } - if (engine->Cmd_Argc() == 2) + if (args.ArgC() == 2) { - float flDistance = atof( engine->Cmd_Argv(1) ); + float flDistance = atof( args[1] ); s_ClientShadowMgr.SetShadowDistance( flDistance ); } } -static void ShadowBlobbyCutoff_f() +CON_COMMAND_F( r_shadowblobbycutoff, "some shadow stuff", FCVAR_CHEAT ) { - if (engine->Cmd_Argc() == 1) + if (args.ArgC() == 1) { float flArea = s_ClientShadowMgr.GetBlobbyCutoffArea( ); Msg( "Cutoff area %.2f\n", flArea ); return; } - if (engine->Cmd_Argc() == 2) + if (args.ArgC() == 2) { - float flArea = atof( engine->Cmd_Argv(1) ); + float flArea = atof( args[1] ); s_ClientShadowMgr.SetShadowBlobbyCutoffArea( flArea ); } } -static ConCommand r_shadowdir("r_shadowdir", ShadowDir_f, "Set shadow direction", FCVAR_CHEAT ); -static ConCommand r_shadowangles("r_shadowangles", ShadowAngles_f, "Set shadow angles", FCVAR_CHEAT ); -static ConCommand r_shadowcolor("r_shadowcolor", ShadowColor_f, "Set shadow color", FCVAR_CHEAT ); -static ConCommand r_shadowdist("r_shadowdist", ShadowDistance_f, "Set shadow distance", FCVAR_CHEAT ); -static ConCommand r_shadowblobbycutoff("r_shadowblobbycutoff", ShadowBlobbyCutoff_f, "some shadow stuff", FCVAR_CHEAT ); - static void ShadowRestoreFunc( int nChangeFlags ) { s_ClientShadowMgr.RestoreRenderState(); @@ -1068,25 +1287,30 @@ bool CClientShadowMgr::Init() Vector dir( 0.1, 0.1, -1 ); SetShadowDirection(dir); SetShadowDistance( 50 ); -#ifndef _XBOX + SetShadowBlobbyCutoffArea( 0.005 ); -#else - SetShadowBlobbyCutoffArea( 5000 ); -#endif - m_nMaxDepthTextureShadows = 4; + bool bTools = CommandLine()->CheckParm( "-tools" ) != NULL; + m_nMaxDepthTextureShadows = bTools ? 4 : 1; // Just one shadow depth texture in games, more in tools - if ( r_shadowrendertotexture.GetBool() ) + bool bLowEnd = ( g_pMaterialSystemHardwareConfig->GetDXSupportLevel() < 80 ); + + if ( !bLowEnd && r_shadowrendertotexture.GetBool() ) { InitRenderToTextureShadows(); } -#ifdef DOSHADOWEDFLASHLIGHT - if ( r_flashlightdepthtexture.GetBool() ) + // If someone turned shadow depth mapping on but we can't do it, force it off + if ( r_flashlightdepthtexture.GetBool() && !materials->SupportsShadowDepthTextures() ) + { + r_flashlightdepthtexture.SetValue( 0 ); + ShutdownDepthTextureShadows(); + } + + if ( !bLowEnd && r_flashlightdepthtexture.GetBool() ) { InitDepthTextureShadows(); } -#endif materials->AddRestoreFunc( ShadowRestoreFunc ); @@ -1110,39 +1334,78 @@ void CClientShadowMgr::Shutdown() //----------------------------------------------------------------------------- void CClientShadowMgr::InitDepthTextureShadows() { -#ifdef DOSHADOWEDFLASHLIGHT - if( !m_DepthTextureActive ) - { - m_DepthTextureActive = true; + VPROF_BUDGET( "CClientShadowMgr::InitDepthTextureShadows", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING ); + if( !m_bDepthTextureActive ) + { + m_bDepthTextureActive = true; + + ImageFormat dstFormat = materials->GetShadowDepthTextureFormat(); // Vendor-dependent depth texture format +#if !defined( _X360 ) + ImageFormat nullFormat = materials->GetNullTextureFormat(); // Vendor-dependent null texture format (takes as little memory as possible) +#endif materials->BeginRenderTargetAllocation(); +#if defined( _X360 ) + // For the 360, we'll be rendering depth directly into the dummy depth and Resolve()ing to the depth texture. + // only need the dummy surface, don't care about color results + m_DummyColorTexture.InitRenderTargetTexture( r_flashlightdepthres.GetInt(), r_flashlightdepthres.GetInt(), RT_SIZE_OFFSCREEN, IMAGE_FORMAT_BGR565, MATERIAL_RT_DEPTH_SHARED, false, "_rt_ShadowDummy" ); + m_DummyColorTexture.InitRenderTargetSurface( r_flashlightdepthres.GetInt(), r_flashlightdepthres.GetInt(), IMAGE_FORMAT_BGR565, true ); +#else + m_DummyColorTexture.InitRenderTarget( r_flashlightdepthres.GetInt(), r_flashlightdepthres.GetInt(), RT_SIZE_OFFSCREEN, nullFormat, MATERIAL_RT_DEPTH_NONE, false, "_rt_ShadowDummy" ); +#endif + + // Create some number of depth-stencil textures m_DepthTextureCache.Purge(); - for( int i=0;iGetActualWidth(); + r_flashlightdepthres.SetValue( m_nDepthTextureResolution ); + } m_DepthTextureCache.AddToTail( depthTex ); + m_DepthTextureCacheLocks.AddToTail( bFalse ); } materials->EndRenderTargetAllocation(); } -#endif } - void CClientShadowMgr::ShutdownDepthTextureShadows() { - if( m_DepthTextureActive ) + if( m_bDepthTextureActive ) { + // Shut down the dummy texture + m_DummyColorTexture.Shutdown(); + while( m_DepthTextureCache.Count() ) { m_DepthTextureCache[ m_DepthTextureCache.Count()-1 ].Shutdown(); + + m_DepthTextureCacheLocks.Remove( m_DepthTextureCache.Count()-1 ); m_DepthTextureCache.Remove( m_DepthTextureCache.Count()-1 ); } - m_DepthTextureActive = false; + m_bDepthTextureActive = false; } } @@ -1151,7 +1414,7 @@ void CClientShadowMgr::ShutdownDepthTextureShadows() //----------------------------------------------------------------------------- void CClientShadowMgr::InitRenderToTextureShadows() { - if (!m_RenderToTextureActive) + if ( !m_RenderToTextureActive ) { m_RenderToTextureActive = true; m_RenderShadow.Init( "decals/rendershadow", TEXTURE_GROUP_DECAL ); @@ -1263,7 +1526,7 @@ void CClientShadowMgr::LevelInitPreEntity() SetShadowColor(r, g, b); // Set up the texture allocator - if (m_RenderToTextureActive) + if ( m_RenderToTextureActive ) { m_ShadowAllocator.Reset(); m_bRenderTargetNeedsClear = true; @@ -1310,7 +1573,7 @@ void CClientShadowMgr::RestoreRenderState() m_Shadows[h].m_Flags |= SHADOW_FLAGS_TEXTURE_DIRTY; } - SetShadowColor(m_AmbientLightColor.r, m_AmbientLightColor.g, m_AmbientLightColor.b); + SetShadowColor( m_AmbientLightColor.r, m_AmbientLightColor.g, m_AmbientLightColor.b ); m_bRenderTargetNeedsClear = true; } @@ -1363,30 +1626,26 @@ void CClientShadowMgr::CleanUpRenderToTextureShadow( ClientShadowHandle_t h ) } -void CClientShadowMgr::CleanUpDepthTextureShadow( ClientShadowHandle_t h ) -{ - ClientShadow_t& shadow = m_Shadows[h]; - if( m_DepthTextureActive && (shadow.m_Flags & SHADOW_FLAGS_USE_DEPTH_TEXTURE ) ) - { - DeallocateDepthBuffer( shadow.m_ShadowDepthTexture ); - } -} - - //----------------------------------------------------------------------------- // Causes all shadows to be re-updated //----------------------------------------------------------------------------- void CClientShadowMgr::UpdateAllShadows() { - m_bUpdatingDirtyShadows = true; - - for (ClientShadowHandle_t i = m_Shadows.Head(); i != m_Shadows.InvalidIndex(); i = m_Shadows.Next(i) ) + for ( ClientShadowHandle_t i = m_Shadows.Head(); i != m_Shadows.InvalidIndex(); i = m_Shadows.Next(i) ) { - UpdateProjectedTextureInternal( i, true ); - } - m_DirtyShadows.RemoveAll(); + ClientShadow_t& shadow = m_Shadows[i]; - m_bUpdatingDirtyShadows = false; + // Don't bother with flashlights + if ( ( shadow.m_Flags & SHADOW_FLAGS_FLASHLIGHT ) != 0 ) + continue; + + IClientRenderable *pRenderable = ClientEntityList().GetClientRenderableFromHandle( shadow.m_Entity ); + if ( !pRenderable ) + continue; + + Assert( pRenderable->GetShadowHandle() == i ); + AddToDirtyShadowList( pRenderable, true ); + } } @@ -1501,19 +1760,9 @@ void CClientShadowMgr::RenderShadowTexture( int w, int h ) { if (m_RenderToTextureActive) { - float flTexWidth, flTexHeight; -#ifdef _XBOX - // xboxissue - need non-normalized texture coords - int textureW, textureH; - m_ShadowAllocator.GetTotalTextureSize( textureW, textureH ); - flTexWidth = textureW; - flTexHeight = textureH; -#else - flTexWidth = 1.0f; - flTexHeight = 1.0f; -#endif - materials->Bind( m_RenderShadow ); - IMesh* pMesh = materials->GetDynamicMesh( true ); + CMatRenderContextPtr pRenderContext( materials ); + pRenderContext->Bind( m_RenderShadow ); + IMesh* pMesh = pRenderContext->GetDynamicMesh( true ); CMeshBuilder meshBuilder; meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 ); @@ -1524,17 +1773,17 @@ void CClientShadowMgr::RenderShadowTexture( int w, int h ) meshBuilder.AdvanceVertex(); meshBuilder.Position3f( w, 0.0f, 0.0f ); - meshBuilder.TexCoord2f( 0, flTexWidth, 0.0f ); + meshBuilder.TexCoord2f( 0, 1.0f, 0.0f ); meshBuilder.Color4ub( 0, 0, 0, 0 ); meshBuilder.AdvanceVertex(); meshBuilder.Position3f( w, h, 0.0f ); - meshBuilder.TexCoord2f( 0, flTexWidth, flTexHeight ); + meshBuilder.TexCoord2f( 0, 1.0f, 1.0f ); meshBuilder.Color4ub( 0, 0, 0, 0 ); meshBuilder.AdvanceVertex(); meshBuilder.Position3f( 0.0f, h, 0.0f ); - meshBuilder.TexCoord2f( 0, 0.0f, flTexHeight ); + meshBuilder.TexCoord2f( 0, 0.0f, 1.0f ); meshBuilder.Color4ub( 0, 0, 0, 0 ); meshBuilder.AdvanceVertex(); @@ -1587,9 +1836,6 @@ ClientShadowHandle_t CClientShadowMgr::CreateProjectedTexture( ClientEntityHandl if( flags & SHADOW_FLAGS_USE_DEPTH_TEXTURE ) { - // This should be changed to handle the error more gracefully - AllocateDepthBuffer( shadow.m_ShadowDepthTexture ); - pShadowMaterial = m_RenderShadow; pShadowModelMaterial = m_RenderModelShadow; pShadowProxyData = (void*)h; @@ -1606,7 +1852,7 @@ ClientShadowHandle_t CClientShadowMgr::CreateProjectedTexture( ClientEntityHandl { createShadowFlags = SHADOW_CACHE_VERTS; } - shadow.m_ShadowHandle = shadowmgr->CreateShadowEx( pShadowMaterial, pShadowModelMaterial, pShadowProxyData, createShadowFlags, shadow.m_ShadowDepthTexture ); + shadow.m_ShadowHandle = shadowmgr->CreateShadowEx( pShadowMaterial, pShadowModelMaterial, pShadowProxyData, createShadowFlags ); return h; } @@ -1615,20 +1861,19 @@ ClientShadowHandle_t CClientShadowMgr::CreateFlashlight( const FlashlightState_t // We don't really need a model entity handle for a projective light source, so use an invalid one. static ClientEntityHandle_t invalidHandle = INVALID_CLIENTENTITY_HANDLE; - int shadowFlags = SHADOW_FLAGS_FLASHLIGHT; -#ifdef DOSHADOWEDFLASHLIGHT + int shadowFlags = SHADOW_FLAGS_FLASHLIGHT | SHADOW_FLAGS_LIGHT_WORLD; if( lightState.m_bEnableShadows && r_flashlightdepthtexture.GetBool() ) + { shadowFlags |= SHADOW_FLAGS_USE_DEPTH_TEXTURE; -#endif - ClientShadowHandle_t shadowHandle = CreateProjectedTexture( invalidHandle, shadowFlags ); + } - m_Shadows[ shadowHandle ].m_bLightWorld = true; + ClientShadowHandle_t shadowHandle = CreateProjectedTexture( invalidHandle, shadowFlags ); UpdateFlashlightState( shadowHandle, lightState ); UpdateProjectedTexture( shadowHandle, true ); return shadowHandle; } - + ClientShadowHandle_t CClientShadowMgr::CreateShadow( ClientEntityHandle_t entity, int flags ) { // We don't really need a model entity handle for a projective light source, so use an invalid one. @@ -1643,7 +1888,7 @@ ClientShadowHandle_t CClientShadowMgr::CreateShadow( ClientEntityHandle_t entity pRenderable->MarkShadowDirty( true ); } - // NOTE: We *have * to call the version that takes a shadow handle + // NOTE: We *have* to call the version that takes a shadow handle // even if we have an entity because this entity hasn't set its shadow handle yet AddToDirtyShadowList( shadowHandle, true ); return shadowHandle; @@ -1655,22 +1900,11 @@ ClientShadowHandle_t CClientShadowMgr::CreateShadow( ClientEntityHandle_t entity //----------------------------------------------------------------------------- void CClientShadowMgr::UpdateFlashlightState( ClientShadowHandle_t shadowHandle, const FlashlightState_t &flashlightState ) { - Vector lightXVec; - Vector lightYVec( 0.0f, 0.0f, 1.0f ); - if( fabs( DotProduct( lightYVec, flashlightState.m_vecLightDirection ) ) > 0.9f ) - { - // Don't want lightYVec and m_vecLightDirection to be parallel - lightYVec.Init( 0.0f, 1.0f, 0.0f ); - } - CrossProduct( lightYVec, flashlightState.m_vecLightDirection, lightXVec ); - VectorNormalize( lightXVec ); - CrossProduct( flashlightState.m_vecLightDirection, lightXVec, lightYVec ); - VectorNormalize( lightYVec ); + VPROF_BUDGET( "CClientShadowMgr::UpdateFlashlightState", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING ); - BuildPerspectiveWorldToFlashlightMatrix( m_Shadows[shadowHandle].m_WorldToShadow, flashlightState.m_vecLightOrigin, flashlightState.m_vecLightDirection, - lightXVec, lightYVec, flashlightState.m_fVerticalFOVDegrees, flashlightState.m_NearZ, flashlightState.m_FarZ ); + BuildPerspectiveWorldToFlashlightMatrix( m_Shadows[shadowHandle].m_WorldToShadow, flashlightState ); - shadowmgr->UpdateFlashlightStateEx( m_Shadows[shadowHandle].m_ShadowHandle, flashlightState, m_Shadows[shadowHandle].m_ShadowDepthTexture ); + shadowmgr->UpdateFlashlightState( m_Shadows[shadowHandle].m_ShadowHandle, flashlightState ); } void CClientShadowMgr::DestroyFlashlight( ClientShadowHandle_t shadowHandle ) @@ -1707,7 +1941,6 @@ void CClientShadowMgr::DestroyShadow( ClientShadowHandle_t handle ) shadowmgr->DestroyShadow( m_Shadows[handle].m_ShadowHandle ); ClientLeafSystem()->RemoveShadow( m_Shadows[handle].m_ClientLeafShadowHandle ); CleanUpRenderToTextureShadow( handle ); - CleanUpDepthTextureShadow( handle ); m_Shadows.Remove(handle); } @@ -1715,7 +1948,7 @@ void CClientShadowMgr::DestroyShadow( ClientShadowHandle_t handle ) //----------------------------------------------------------------------------- // Build the worldtotexture matrix //----------------------------------------------------------------------------- -void CClientShadowMgr::BuildGeneralWorldToShadowMatrix( VMatrix& worldToShadow, +void CClientShadowMgr::BuildGeneralWorldToShadowMatrix( VMatrix& matWorldToShadow, const Vector& origin, const Vector& dir, const Vector& xvec, const Vector& yvec ) { // We're assuming here that xvec + yvec aren't necessary perpendicular @@ -1723,55 +1956,61 @@ void CClientShadowMgr::BuildGeneralWorldToShadowMatrix( VMatrix& worldToShadow, // The shadow->world matrix is pretty simple: // Just stick the origin in the translation component // and the vectors in the columns... - worldToShadow.SetBasisVectors( xvec, yvec, dir ); - worldToShadow.SetTranslation( origin ); - worldToShadow[3][0] = worldToShadow[3][1] = worldToShadow[3][2] = 0.0f; - worldToShadow[3][3] = 1.0f; + matWorldToShadow.SetBasisVectors( xvec, yvec, dir ); + matWorldToShadow.SetTranslation( origin ); + matWorldToShadow[3][0] = matWorldToShadow[3][1] = matWorldToShadow[3][2] = 0.0f; + matWorldToShadow[3][3] = 1.0f; - // Now do a general inverse to get worldToShadow - MatrixInverseGeneral( worldToShadow, worldToShadow ); + // Now do a general inverse to get matWorldToShadow + MatrixInverseGeneral( matWorldToShadow, matWorldToShadow ); } -void CClientShadowMgr::BuildOrthoWorldToShadowMatrix( VMatrix& worldToShadow, - const Vector& origin, const Vector& dir, const Vector& xvec, const Vector& yvec ) +void CClientShadowMgr::BuildWorldToShadowMatrix( VMatrix& matWorldToShadow, const Vector& origin, const Quaternion& quatOrientation ) { - // This version is faster and assumes dir, xvec, yvec are perpendicular - AssertFloatEquals( DotProduct( dir, xvec ), 0.0f, 1e-3 ); - AssertFloatEquals( DotProduct( dir, yvec ), 0.0f, 1e-3 ); - AssertFloatEquals( DotProduct( xvec, yvec ), 0.0f, 1e-3 ); - // The shadow->world matrix is pretty simple: // Just stick the origin in the translation component // and the vectors in the columns... // The inverse of this transposes the rotational component // and the translational component = - (rotation transpose) * origin - worldToShadow.SetBasisVectors( xvec, yvec, dir ); - MatrixTranspose( worldToShadow, worldToShadow ); + + matrix3x4_t matOrientation; + QuaternionMatrix( quatOrientation, matOrientation ); // Convert quat to matrix3x4 + PositionMatrix( vec3_origin, matOrientation ); // Zero out translation elements + + VMatrix matBasis( matOrientation ); // Convert matrix3x4 to VMatrix + + Vector vForward, vLeft, vUp; + matBasis.GetBasisVectors( vForward, vLeft, vUp ); + matBasis.SetForward( vLeft ); // Bizarre vector flip inherited from earlier code, WTF? + matBasis.SetLeft( vUp ); + matBasis.SetUp( vForward ); + matWorldToShadow = matBasis.Transpose(); // Transpose Vector translation; - Vector3DMultiply( worldToShadow, origin, translation ); + Vector3DMultiply( matWorldToShadow, origin, translation ); translation *= -1.0f; - worldToShadow.SetTranslation( translation ); + matWorldToShadow.SetTranslation( translation ); // The the bottom row. - worldToShadow[3][0] = worldToShadow[3][1] = worldToShadow[3][2] = 0.0f; - worldToShadow[3][3] = 1.0f; + matWorldToShadow[3][0] = matWorldToShadow[3][1] = matWorldToShadow[3][2] = 0.0f; + matWorldToShadow[3][3] = 1.0f; } -void CClientShadowMgr::BuildPerspectiveWorldToFlashlightMatrix( VMatrix& worldToShadow, - const Vector& origin, const Vector& dir, const Vector& xvec, const Vector& yvec, float fovDegrees, - float zNear, float zFar ) +void CClientShadowMgr::BuildPerspectiveWorldToFlashlightMatrix( VMatrix& matWorldToShadow, const FlashlightState_t &flashlightState ) { - // build the ortho shadow matrix to get us from world to shadow space. We'll build the perspective - // part separately and concatenate. - VMatrix worldToShadowView; - BuildOrthoWorldToShadowMatrix( worldToShadowView, origin, dir, xvec, yvec ); + VPROF_BUDGET( "CClientShadowMgr::BuildPerspectiveWorldToFlashlightMatrix", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING ); - VMatrix perspective; - MatrixBuildPerspective( perspective, fovDegrees, fovDegrees, zNear, zFar ); + // Buildworld to shadow matrix, then perspective projection and concatenate + VMatrix matWorldToShadowView, matPerspective; + BuildWorldToShadowMatrix( matWorldToShadowView, flashlightState.m_vecLightOrigin, + flashlightState.m_quatOrientation ); - MatrixMultiply( perspective, worldToShadowView, worldToShadow ); + MatrixBuildPerspective( matPerspective, flashlightState.m_fHorizontalFOVDegrees, + flashlightState.m_fVerticalFOVDegrees, + flashlightState.m_NearZ, flashlightState.m_FarZ ); + + MatrixMultiply( matPerspective, matWorldToShadowView, matWorldToShadow ); } //----------------------------------------------------------------------------- @@ -1867,8 +2106,8 @@ static inline void SortAbsVectorComponents( const Vector& src, int* pVecIdx ) //----------------------------------------------------------------------------- // Build the worldtotexture matrix //----------------------------------------------------------------------------- -static void BuildWorldToTextureMatrix( const VMatrix& worldToShadow, - const Vector2D& size, VMatrix& worldToTexture ) +static void BuildWorldToTextureMatrix( const VMatrix& matWorldToShadow, + const Vector2D& size, VMatrix& matWorldToTexture ) { // Build a matrix that maps from shadow space to (u,v) coordinates VMatrix shadowToUnit; @@ -1876,7 +2115,36 @@ static void BuildWorldToTextureMatrix( const VMatrix& worldToShadow, shadowToUnit[0][3] = shadowToUnit[1][3] = 0.5f; // Store off the world to (u,v) transformation - MatrixMultiply( shadowToUnit, worldToShadow, worldToTexture ); + MatrixMultiply( shadowToUnit, matWorldToShadow, matWorldToTexture ); +} + + + +static void BuildOrthoWorldToShadowMatrix( VMatrix& worldToShadow, + const Vector& origin, const Vector& dir, const Vector& xvec, const Vector& yvec ) +{ + // This version is faster and assumes dir, xvec, yvec are perpendicular + AssertFloatEquals( DotProduct( dir, xvec ), 0.0f, 1e-3 ); + AssertFloatEquals( DotProduct( dir, yvec ), 0.0f, 1e-3 ); + AssertFloatEquals( DotProduct( xvec, yvec ), 0.0f, 1e-3 ); + + // The shadow->world matrix is pretty simple: + // Just stick the origin in the translation component + // and the vectors in the columns... + // The inverse of this transposes the rotational component + // and the translational component = - (rotation transpose) * origin + worldToShadow.SetBasisVectors( xvec, yvec, dir ); + MatrixTranspose( worldToShadow, worldToShadow ); + + Vector translation; + Vector3DMultiply( worldToShadow, origin, translation ); + + translation *= -1.0f; + worldToShadow.SetTranslation( translation ); + + // The the bottom row. + worldToShadow[3][0] = worldToShadow[3][1] = worldToShadow[3][2] = 0.0f; + worldToShadow[3][3] = 1.0f; } @@ -1930,6 +2198,16 @@ void CClientShadowMgr::ComputeExtraClipPlanes( IClientRenderable* pRenderable, float dist = DotProduct( normal, origin ); AddExtraClipPlane( handle, normal, dist ); } + + ClientShadow_t& shadow = m_Shadows[handle]; + C_BaseEntity *pEntity = ClientEntityList().GetBaseEntityFromHandle( shadow.m_Entity ); + if ( pEntity && pEntity->m_bEnableRenderingClipPlane ) + { + normal[ 0 ] = -pEntity->m_fRenderingClipPlane[ 0 ]; + normal[ 1 ] = -pEntity->m_fRenderingClipPlane[ 1 ]; + normal[ 2 ] = -pEntity->m_fRenderingClipPlane[ 2 ]; + AddExtraClipPlane( handle, normal, -pEntity->m_fRenderingClipPlane[ 3 ] - 0.5f ); + } } @@ -1960,6 +2238,43 @@ inline ShadowType_t CClientShadowMgr::GetActualShadowCastType( IClientRenderable } +//----------------------------------------------------------------------------- +// Adds a shadow to all leaves along a ray +//----------------------------------------------------------------------------- +class CShadowLeafEnum : public ISpatialLeafEnumerator +{ +public: + bool EnumerateLeaf( int leaf, int context ) + { + m_LeafList.AddToTail( leaf ); + return true; + } + + CUtlVectorFixedGrowable< int, 512 > m_LeafList; +}; + + +//----------------------------------------------------------------------------- +// Builds a list of leaves inside the shadow volume +//----------------------------------------------------------------------------- +static void BuildShadowLeafList( CShadowLeafEnum *pEnum, const Vector& origin, + const Vector& dir, const Vector2D& size, float maxDist ) +{ + Ray_t ray; + VectorCopy( origin, ray.m_Start ); + VectorMultiply( dir, maxDist, ray.m_Delta ); + ray.m_StartOffset.Init( 0, 0, 0 ); + + float flRadius = sqrt( size.x * size.x + size.y * size.y ) * 0.5f; + ray.m_Extents.Init( flRadius, flRadius, flRadius ); + ray.m_IsRay = false; + ray.m_IsSwept = true; + + ISpatialQuery* pQuery = engine->GetBSPTreeQuery(); + pQuery->EnumerateLeavesAlongRay( ray, pEnum, 0 ); +} + + //----------------------------------------------------------------------------- // Builds a simple blobby shadow //----------------------------------------------------------------------------- @@ -2034,9 +2349,9 @@ void CClientShadowMgr::BuildOrthoShadow( IClientRenderable* pRenderable, worldOrigin.z = (int)(worldOrigin.z / dx) * dx; // NOTE: We gotta use the general matrix because xvec and yvec aren't perp - VMatrix worldToShadow, worldToTexture; + VMatrix matWorldToShadow, matWorldToTexture; BuildGeneralWorldToShadowMatrix( m_Shadows[handle].m_WorldToShadow, worldOrigin, vecShadowDir, xvec, yvec ); - BuildWorldToTextureMatrix( m_Shadows[handle].m_WorldToShadow, size, worldToTexture ); + BuildWorldToTextureMatrix( m_Shadows[handle].m_WorldToShadow, size, matWorldToTexture ); Vector2DCopy( size, m_Shadows[handle].m_WorldSize ); // Compute the falloff attenuation @@ -2047,8 +2362,13 @@ void CClientShadowMgr::BuildOrthoShadow( IClientRenderable* pRenderable, float flShadowCastDistance = GetShadowDistance( pRenderable ); float maxHeight = flShadowCastDistance + falloffStart; //3.0f * sqrt( shadowArea ); - shadowmgr->ProjectShadow( m_Shadows[handle].m_ShadowHandle, worldOrigin, - vecShadowDir, worldToTexture, size, maxHeight, falloffStart, MAX_FALLOFF_AMOUNT, pRenderable->GetRenderOrigin() ); + CShadowLeafEnum leafList; + BuildShadowLeafList( &leafList, worldOrigin, vecShadowDir, size, maxHeight ); + int nCount = leafList.m_LeafList.Count(); + const int *pLeafList = leafList.m_LeafList.Base(); + + shadowmgr->ProjectShadow( m_Shadows[handle].m_ShadowHandle, worldOrigin, + vecShadowDir, matWorldToTexture, size, nCount, pLeafList, maxHeight, falloffStart, MAX_FALLOFF_AMOUNT, pRenderable->GetRenderOrigin() ); // Compute extra clip planes to prevent poke-thru // FIXME!!!!!!!!!!!!!! Removing this for now since it seems to mess up the blobby shadows. @@ -2056,8 +2376,7 @@ void CClientShadowMgr::BuildOrthoShadow( IClientRenderable* pRenderable, // Add the shadow to the client leaf system so it correctly marks // leafs as being affected by a particular shadow - ClientLeafSystem()->ProjectShadow( m_Shadows[handle].m_ClientLeafShadowHandle, - worldOrigin, vecShadowDir, size, maxHeight ); + ClientLeafSystem()->ProjectShadow( m_Shadows[handle].m_ClientLeafShadowHandle, nCount, pLeafList ); } @@ -2130,13 +2449,20 @@ void CClientShadowMgr::DrawRenderToTextureDebugInfo( IClientRenderable* pRendera } +extern ConVar cl_drawshadowtexture; +extern ConVar cl_shadowtextureoverlaysize; + //----------------------------------------------------------------------------- // Builds a more complex shadow... //----------------------------------------------------------------------------- void CClientShadowMgr::BuildRenderToTextureShadow( IClientRenderable* pRenderable, ClientShadowHandle_t handle, const Vector& mins, const Vector& maxs) { -// DrawRenderToTextureDebugInfo( pRenderable, mins, maxs ); + if ( cl_drawshadowtexture.GetInt() ) + { + // Red wireframe bounding box around objects whose RTT shadows are being updated that frame + DrawRenderToTextureDebugInfo( pRenderable, mins, maxs ); + } // Get the object's basis Vector vec[3]; @@ -2145,34 +2471,40 @@ void CClientShadowMgr::BuildRenderToTextureShadow( IClientRenderable* pRenderabl Vector vecShadowDir = GetShadowDirection( pRenderable ); +// Debugging aid +// const model_t *pModel = pRenderable->GetModel(); +// const char *pDebugName = modelinfo->GetModelName( pModel ); + // Project the shadow casting direction into the space of the object Vector localShadowDir; localShadowDir[0] = DotProduct( vec[0], vecShadowDir ); localShadowDir[1] = DotProduct( vec[1], vecShadowDir ); localShadowDir[2] = DotProduct( vec[2], vecShadowDir ); - // Figure out which vector has the largest component perpendicular - // to the shadow handle... - // Sort by how perpendicular it is - int vecIdx[3]; - SortAbsVectorComponents( localShadowDir, vecIdx ); + // Compute the box size + Vector boxSize; + VectorSubtract( maxs, mins, boxSize ); + + Vector yvec; + float fProjMax = 0.0f; + for( int i = 0; i != 3; ++i ) + { + Vector test = vec[i] - ( vecShadowDir * DotProduct( vecShadowDir, vec[i] ) ); + test *= boxSize[i]; //doing after the projection to simplify projection math + float fLengthSqr = test.LengthSqr(); + if( fLengthSqr > fProjMax ) + { + fProjMax = fLengthSqr; + yvec = test; + } + } - // Here's our shadow basis vectors; namely the ones that are - // most perpendicular to the shadow casting direction - Vector yvec = vec[vecIdx[0]]; - - // Project it into a plane perpendicular to the shadow direction - yvec -= vecShadowDir * DotProduct( vecShadowDir, yvec ); VectorNormalize( yvec ); // Compute the x vector Vector xvec; CrossProduct( yvec, vecShadowDir, xvec ); - // Compute the box size - Vector boxSize; - VectorSubtract( maxs, mins, 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; @@ -2196,9 +2528,9 @@ void CClientShadowMgr::BuildRenderToTextureShadow( IClientRenderable* pRenderabl VectorMA( worldOrigin, org.y, vec[1], worldOrigin ); VectorMA( worldOrigin, org.z, vec[2], worldOrigin ); - VMatrix worldToTexture; + VMatrix matWorldToTexture; BuildOrthoWorldToShadowMatrix( m_Shadows[handle].m_WorldToShadow, worldOrigin, vecShadowDir, xvec, yvec ); - BuildWorldToTextureMatrix( m_Shadows[handle].m_WorldToShadow, size, worldToTexture ); + BuildWorldToTextureMatrix( m_Shadows[handle].m_WorldToShadow, size, matWorldToTexture ); Vector2DCopy( size, m_Shadows[handle].m_WorldSize ); // Compute the falloff attenuation @@ -2210,16 +2542,20 @@ void CClientShadowMgr::BuildRenderToTextureShadow( IClientRenderable* pRenderabl float flShadowCastDistance = GetShadowDistance( pRenderable ); float maxHeight = flShadowCastDistance + falloffStart; //3.0f * sqrt( shadowArea ); + CShadowLeafEnum leafList; + BuildShadowLeafList( &leafList, worldOrigin, vecShadowDir, size, maxHeight ); + int nCount = leafList.m_LeafList.Count(); + const int *pLeafList = leafList.m_LeafList.Base(); + shadowmgr->ProjectShadow( m_Shadows[handle].m_ShadowHandle, worldOrigin, - vecShadowDir, worldToTexture, size, maxHeight, falloffStart, MAX_FALLOFF_AMOUNT, pRenderable->GetRenderOrigin() ); + vecShadowDir, matWorldToTexture, size, nCount, pLeafList, maxHeight, falloffStart, MAX_FALLOFF_AMOUNT, pRenderable->GetRenderOrigin() ); // Compute extra clip planes to prevent poke-thru ComputeExtraClipPlanes( pRenderable, handle, vec, mins, maxs, localShadowDir ); // Add the shadow to the client leaf system so it correctly marks // leafs as being affected by a particular shadow - ClientLeafSystem()->ProjectShadow( m_Shadows[handle].m_ClientLeafShadowHandle, - worldOrigin, vecShadowDir, size, maxHeight ); + ClientLeafSystem()->ProjectShadow( m_Shadows[handle].m_ClientLeafShadowHandle, nCount, pLeafList ); } static void LineDrawHelper( const Vector &startShadowSpace, const Vector &endShadowSpace, @@ -2231,41 +2567,79 @@ static void LineDrawHelper( const Vector &startShadowSpace, const Vector &endSha Vector3DMultiplyPositionProjective( shadowToWorld, endShadowSpace, endWorldSpace ); debugoverlay->AddLineOverlay( startWorldSpace + Vector( 0.0f, 0.0f, 1.0f ), - endWorldSpace + Vector( 0.0f, 0.0f, 1.0f ), r, g, b, false - , 0.0 ); + endWorldSpace + Vector( 0.0f, 0.0f, 1.0f ), r, g, b, false, -1 ); } -static void DebugDrawFrustum( const VMatrix &worldToFlashlight ) +static void DebugDrawFrustum( const Vector &vOrigin, const VMatrix &matWorldToFlashlight ) { VMatrix flashlightToWorld; - MatrixInverseGeneral( worldToFlashlight, flashlightToWorld ); + MatrixInverseGeneral( matWorldToFlashlight, flashlightToWorld ); - LineDrawHelper( Vector( 0.0f, 0.0f, 0.0f ), Vector( 0.0f, 0.0f, 1.0f ), flashlightToWorld, 255, 0, 0 ); - LineDrawHelper( Vector( 0.0f, 0.0f, 1.0f ), Vector( 0.0f, 1.0f, 1.0f ), flashlightToWorld, 255, 0, 0 ); - LineDrawHelper( Vector( 0.0f, 1.0f, 1.0f ), Vector( 0.0f, 1.0f, 0.0f ), flashlightToWorld, 255, 0, 0 ); - LineDrawHelper( Vector( 0.0f, 1.0f, 0.0f ), Vector( 0.0f, 0.0f, 0.0f ), flashlightToWorld, 255, 0, 0 ); - LineDrawHelper( Vector( 1.0f, 0.0f, 0.0f ), Vector( 1.0f, 0.0f, 1.0f ), flashlightToWorld, 255, 0, 0 ); - LineDrawHelper( Vector( 1.0f, 0.0f, 1.0f ), Vector( 1.0f, 1.0f, 1.0f ), flashlightToWorld, 255, 0, 0 ); - LineDrawHelper( Vector( 1.0f, 1.0f, 1.0f ), Vector( 1.0f, 1.0f, 0.0f ), flashlightToWorld, 255, 0, 0 ); - LineDrawHelper( Vector( 1.0f, 1.0f, 0.0f ), Vector( 1.0f, 0.0f, 0.0f ), flashlightToWorld, 255, 0, 0 ); - LineDrawHelper( Vector( 0.0f, 0.0f, 0.0f ), Vector( 1.0f, 0.0f, 0.0f ), flashlightToWorld, 255, 0, 0 ); - LineDrawHelper( Vector( 0.0f, 0.0f, 1.0f ), Vector( 1.0f, 0.0f, 1.0f ), flashlightToWorld, 255, 0, 0 ); - LineDrawHelper( Vector( 0.0f, 1.0f, 1.0f ), Vector( 1.0f, 1.0f, 1.0f ), flashlightToWorld, 255, 0, 0 ); - LineDrawHelper( Vector( 0.0f, 1.0f, 0.0f ), Vector( 1.0f, 1.0f, 0.0f ), flashlightToWorld, 255, 0, 0 ); + // Draw boundaries of frustum + LineDrawHelper( Vector( 0.0f, 0.0f, 0.0f ), Vector( 0.0f, 0.0f, 1.0f ), flashlightToWorld, 255, 255, 255 ); + LineDrawHelper( Vector( 0.0f, 0.0f, 1.0f ), Vector( 0.0f, 1.0f, 1.0f ), flashlightToWorld, 255, 255, 255 ); + LineDrawHelper( Vector( 0.0f, 1.0f, 1.0f ), Vector( 0.0f, 1.0f, 0.0f ), flashlightToWorld, 255, 255, 255 ); + LineDrawHelper( Vector( 0.0f, 1.0f, 0.0f ), Vector( 0.0f, 0.0f, 0.0f ), flashlightToWorld, 255, 255, 255 ); + LineDrawHelper( Vector( 1.0f, 0.0f, 0.0f ), Vector( 1.0f, 0.0f, 1.0f ), flashlightToWorld, 255, 255, 255 ); + LineDrawHelper( Vector( 1.0f, 0.0f, 1.0f ), Vector( 1.0f, 1.0f, 1.0f ), flashlightToWorld, 255, 255, 255 ); + LineDrawHelper( Vector( 1.0f, 1.0f, 1.0f ), Vector( 1.0f, 1.0f, 0.0f ), flashlightToWorld, 255, 255, 255 ); + LineDrawHelper( Vector( 1.0f, 1.0f, 0.0f ), Vector( 1.0f, 0.0f, 0.0f ), flashlightToWorld, 255, 255, 255 ); + LineDrawHelper( Vector( 0.0f, 0.0f, 0.0f ), Vector( 1.0f, 0.0f, 0.0f ), flashlightToWorld, 255, 255, 255 ); + LineDrawHelper( Vector( 0.0f, 0.0f, 1.0f ), Vector( 1.0f, 0.0f, 1.0f ), flashlightToWorld, 255, 255, 255 ); + LineDrawHelper( Vector( 0.0f, 1.0f, 1.0f ), Vector( 1.0f, 1.0f, 1.0f ), flashlightToWorld, 255, 255, 255 ); + LineDrawHelper( Vector( 0.0f, 1.0f, 0.0f ), Vector( 1.0f, 1.0f, 0.0f ), flashlightToWorld, 255, 255, 255 ); + + // Draw RGB triad at front plane + LineDrawHelper( Vector( 0.5f, 0.5f, 0.0f ), Vector( 1.0f, 0.5f, 0.0f ), flashlightToWorld, 255, 0, 0 ); + LineDrawHelper( Vector( 0.5f, 0.5f, 0.0f ), Vector( 0.5f, 1.0f, 0.0f ), flashlightToWorld, 0, 255, 0 ); + LineDrawHelper( Vector( 0.5f, 0.5f, 0.0f ), Vector( 0.5f, 0.5f, 0.35f ), flashlightToWorld, 0, 0, 255 ); } + +//----------------------------------------------------------------------------- +// Builds a list of leaves inside the flashlight volume +//----------------------------------------------------------------------------- +static void BuildFlashlightLeafList( CShadowLeafEnum *pEnum, const VMatrix &worldToShadow ) +{ + // Use an AABB around the frustum to enumerate leaves. + Vector mins, maxs; + CalculateAABBFromProjectionMatrix( worldToShadow, &mins, &maxs ); + ISpatialQuery* pQuery = engine->GetBSPTreeQuery(); + pQuery->EnumerateLeavesInBox( mins, maxs, pEnum, 0 ); +} + + void CClientShadowMgr::BuildFlashlight( ClientShadowHandle_t handle ) { + // For the 360, we just draw flashlights with the main geometry + // and bypass the entire shadow casting system. ClientShadow_t &shadow = m_Shadows[handle]; - - if( r_flashlightdrawfrustum.GetBool() ) + if ( IsX360() || r_flashlight_version2.GetInt() ) { - DebugDrawFrustum( shadow.m_WorldToShadow ); + // This will update the matrices, but not do work to add the flashlight to surfaces + shadowmgr->ProjectFlashlight( shadow.m_ShadowHandle, shadow.m_WorldToShadow, 0, NULL ); + return; } - if( shadow.m_bLightWorld ) + VPROF_BUDGET( "CClientShadowMgr::BuildFlashlight", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING ); + + bool bLightModels = r_flashlightmodels.GetBool(); + bool bLightSpecificEntity = shadow.m_hTargetEntity.Get() != NULL; + bool bLightWorld = ( shadow.m_Flags & SHADOW_FLAGS_LIGHT_WORLD ) != 0; + int nCount = 0; + const int *pLeafList = 0; + + CShadowLeafEnum leafList; + if ( bLightWorld || ( bLightModels && !bLightSpecificEntity ) ) { - shadowmgr->ProjectFlashlight( shadow.m_ShadowHandle, shadow.m_WorldToShadow ); + BuildFlashlightLeafList( &leafList, shadow.m_WorldToShadow ); + nCount = leafList.m_LeafList.Count(); + pLeafList = leafList.m_LeafList.Base(); + } + + if( bLightWorld ) + { + shadowmgr->ProjectFlashlight( shadow.m_ShadowHandle, shadow.m_WorldToShadow, nCount, pLeafList ); } else { @@ -2274,52 +2648,52 @@ void CClientShadowMgr::BuildFlashlight( ClientShadowHandle_t handle ) shadowmgr->EnableShadow( shadow.m_ShadowHandle, true ); } - if( r_flashlightmodels.GetBool() ) - { - if( shadow.m_hTargetEntity==NULL ) - { - // Add the shadow to the client leaf system so it correctly marks - // leafs as being affected by a particular shadow - ClientLeafSystem()->ProjectFlashlight( shadow.m_ClientLeafShadowHandle, shadow.m_WorldToShadow ); - } - else - { - // We know what we are focused on, so just add the shadow directly to that receiver - Assert( shadow.m_hTargetEntity->GetModel() ); + if ( !bLightModels ) + return; - C_BaseEntity *pChild = shadow.m_hTargetEntity->FirstMoveChild(); - while( pChild ) - { - int modelType = modelinfo->GetModelType( pChild->GetModel() ); - if (modelType == mod_brush) - { - AddShadowToReceiver( handle, pChild, SHADOW_RECEIVER_BRUSH_MODEL ); - } - else if ( modelType == mod_studio ) - { - AddShadowToReceiver( handle, pChild, SHADOW_RECEIVER_STUDIO_MODEL ); - } - - pChild = pChild->NextMovePeer(); - } - - int modelType = modelinfo->GetModelType( shadow.m_hTargetEntity->GetModel() ); - if (modelType == mod_brush) - { - AddShadowToReceiver( handle, shadow.m_hTargetEntity, SHADOW_RECEIVER_BRUSH_MODEL ); - } - else if ( modelType == mod_studio ) - { - AddShadowToReceiver( handle, shadow.m_hTargetEntity, SHADOW_RECEIVER_STUDIO_MODEL ); - } + if ( !bLightSpecificEntity ) + { + // Add the shadow to the client leaf system so it correctly marks + // leafs as being affected by a particular shadow + ClientLeafSystem()->ProjectFlashlight( shadow.m_ClientLeafShadowHandle, nCount, pLeafList ); + return; + } + + // We know what we are focused on, so just add the shadow directly to that receiver + Assert( shadow.m_hTargetEntity->GetModel() ); + + C_BaseEntity *pChild = shadow.m_hTargetEntity->FirstMoveChild(); + while( pChild ) + { + int modelType = modelinfo->GetModelType( pChild->GetModel() ); + if (modelType == mod_brush) + { + AddShadowToReceiver( handle, pChild, SHADOW_RECEIVER_BRUSH_MODEL ); } + else if ( modelType == mod_studio ) + { + AddShadowToReceiver( handle, pChild, SHADOW_RECEIVER_STUDIO_MODEL ); + } + + pChild = pChild->NextMovePeer(); + } + + int modelType = modelinfo->GetModelType( shadow.m_hTargetEntity->GetModel() ); + if (modelType == mod_brush) + { + AddShadowToReceiver( handle, shadow.m_hTargetEntity, SHADOW_RECEIVER_BRUSH_MODEL ); + } + else if ( modelType == mod_studio ) + { + AddShadowToReceiver( handle, shadow.m_hTargetEntity, SHADOW_RECEIVER_STUDIO_MODEL ); } } + //----------------------------------------------------------------------------- // Adds the child bounds to the bounding box //----------------------------------------------------------------------------- -void CClientShadowMgr::AddChildBounds( matrix3x4_t &worldToBBox, IClientRenderable* pParent, Vector &vecMins, Vector &vecMaxs ) +void CClientShadowMgr::AddChildBounds( matrix3x4_t &matWorldToBBox, IClientRenderable* pParent, Vector &vecMins, Vector &vecMaxs ) { Vector vecChildMins, vecChildMaxs; Vector vecNewChildMins, vecNewChildMaxs; @@ -2333,13 +2707,13 @@ void CClientShadowMgr::AddChildBounds( matrix3x4_t &worldToBBox, IClientRenderab if ( GetActualShadowCastType( pChild ) != SHADOWS_NONE) { pChild->GetShadowRenderBounds( vecChildMins, vecChildMaxs, SHADOWS_RENDER_TO_TEXTURE ); - ConcatTransforms( worldToBBox, pChild->RenderableToWorldTransform(), childToBBox ); + ConcatTransforms( matWorldToBBox, pChild->RenderableToWorldTransform(), childToBBox ); TransformAABB( childToBBox, vecChildMins, vecChildMaxs, vecNewChildMins, vecNewChildMaxs ); VectorMin( vecMins, vecNewChildMins, vecMins ); VectorMax( vecMaxs, vecNewChildMaxs, vecMaxs ); } - AddChildBounds( worldToBBox, pChild, vecMins, vecMaxs ); + AddChildBounds( matWorldToBBox, pChild, vecMins, vecMaxs ); pChild = pChild->NextShadowPeer(); } } @@ -2363,9 +2737,9 @@ void CClientShadowMgr::ComputeHierarchicalBounds( IClientRenderable *pRenderable // Don't recurse down the tree when we hit a blobby shadow if ( pChild && shadowType != SHADOWS_SIMPLE ) { - matrix3x4_t worldToBBox; - MatrixInvert( pRenderable->RenderableToWorldTransform(), worldToBBox ); - AddChildBounds( worldToBBox, pRenderable, vecMins, vecMaxs ); + matrix3x4_t matWorldToBBox; + MatrixInvert( pRenderable->RenderableToWorldTransform(), matWorldToBBox ); + AddChildBounds( matWorldToBBox, pRenderable, vecMins, vecMaxs ); } } } @@ -2417,6 +2791,8 @@ void CClientShadowMgr::UpdateBrushShadow( IClientRenderable *pRenderable, Client } else { + VPROF_BUDGET( "CClientShadowMgr::UpdateBrushShadow", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING ); + BuildFlashlight( handle ); } } @@ -2488,6 +2864,52 @@ void CClientShadowMgr::PreRender() VPROF_BUDGET( "CClientShadowMgr::PreRender", VPROF_BUDGETGROUP_SHADOW_RENDERING ); MDLCACHE_CRITICAL_SECTION(); + // + // -- Shadow Depth Textures ----------------------- + // + + { + // VPROF scope + VPROF_BUDGET( "CClientShadowMgr::PreRender", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING ); + + // If someone turned shadow depth mapping on but we can't do it, force it off + if ( r_flashlightdepthtexture.GetBool() && !materials->SupportsShadowDepthTextures() ) + { + r_flashlightdepthtexture.SetValue( 0 ); + ShutdownDepthTextureShadows(); + } + + bool bDepthTextureActive = r_flashlightdepthtexture.GetBool(); + int nDepthTextureResolution = r_flashlightdepthres.GetInt(); + + // If shadow depth texture size or enable/disable changed, do appropriate deallocation/(re)allocation + if ( ( bDepthTextureActive != m_bDepthTextureActive ) || ( nDepthTextureResolution != m_nDepthTextureResolution ) ) + { + // If shadow depth texturing remains on, but resolution changed, shut down and reinitialize depth textures + if ( ( bDepthTextureActive == true ) && ( m_bDepthTextureActive == true ) && + ( nDepthTextureResolution != m_nDepthTextureResolution ) ) + { + ShutdownDepthTextureShadows(); + InitDepthTextureShadows(); + } + else + { + if ( m_bDepthTextureActive && !bDepthTextureActive ) // Turning off shadow depth texturing + { + ShutdownDepthTextureShadows(); + } + else if ( bDepthTextureActive && !m_bDepthTextureActive) // Turning on shadow depth mapping + { + InitDepthTextureShadows(); + } + } + } + } + + // + // -- Render to Texture Shadows ----------------------- + // + bool bRenderToTextureActive = r_shadowrendertotexture.GetBool(); if ( bRenderToTextureActive != m_RenderToTextureActive ) { @@ -2504,38 +2926,27 @@ void CClientShadowMgr::PreRender() return; } -#ifdef DOSHADOWEDFLASHLIGHT - bool bDepthTextureActive = r_flashlightdepthtexture.GetBool(); - if ( bDepthTextureActive != m_DepthTextureActive ) - { - if( m_DepthTextureActive ) - { - ShutdownDepthTextureShadows(); - } - else - { - InitDepthTextureShadows(); - } - - UpdateAllShadows(); - - return; - } -#endif - m_bUpdatingDirtyShadows = true; unsigned short i = m_DirtyShadows.FirstInorder(); while ( i != m_DirtyShadows.InvalidIndex() ) { + MDLCACHE_CRITICAL_SECTION(); ClientShadowHandle_t& handle = m_DirtyShadows[ i ]; Assert( m_Shadows.IsValidIndex( handle ) ); UpdateProjectedTextureInternal( handle, false ); i = m_DirtyShadows.NextInorder(i); } - m_DirtyShadows.RemoveAll(); + // Transparent shadows must remain dirty, since they were not re-projected + int nCount = m_TransparentShadows.Count(); + for ( int i = 0; i < nCount; ++i ) + { + m_DirtyShadows.Insert( m_TransparentShadows[i] ); + } + m_TransparentShadows.RemoveAll(); + m_bUpdatingDirtyShadows = false; } @@ -2617,7 +3028,7 @@ void CClientShadowMgr::AddToDirtyShadowList( IClientRenderable *pRenderable, boo #ifdef _DEBUG // Make sure everything's consistent - if ( pRenderable->GetShadowHandle() != CLIENTSHADOW_INVALID_HANDLE ) + if ( handle != CLIENTSHADOW_INVALID_HANDLE ) { IClientRenderable *pShadowRenderable = ClientEntityList().GetClientRenderableFromHandle( m_Shadows[handle].m_Entity ); Assert( pRenderable == pShadowRenderable ); @@ -2671,12 +3082,25 @@ void CClientShadowMgr::UpdateShadow( ClientShadowHandle_t handle, bool force ) return; } + // Don't bother if there's no model on the renderable if ( !pRenderable->GetModel() ) { pRenderable->MarkShadowDirty( false ); return; } + // FIXME: NOTE! Because this is called from PreRender, the falloff bias is + // off by a frame. We could move the code in PreRender to occur after world + // list building is done to fix this issue. + // Don't bother with it if the shadow is totally transparent + const ShadowInfo_t &shadowInfo = shadowmgr->GetInfo( shadow.m_ShadowHandle ); + if ( shadowInfo.m_FalloffBias == 255 ) + { + shadowmgr->EnableShadow( shadow.m_ShadowHandle, false ); + m_TransparentShadows.AddToTail( handle ); + return; + } + #ifdef _DEBUG if (s_bBreak) { @@ -2706,9 +3130,10 @@ void CClientShadowMgr::UpdateShadow( ClientShadowHandle_t handle, bool force ) VectorCopy( origin, shadow.m_LastOrigin ); VectorCopy( angles, shadow.m_LastAngles ); + CMatRenderContextPtr pRenderContext( materials ); const model_t *pModel = pRenderable->GetModel(); - MaterialFogMode_t fogMode = materials->GetFogMode(); - materials->FogMode( MATERIAL_FOG_NONE ); + MaterialFogMode_t fogMode = pRenderContext->GetFogMode(); + pRenderContext->FogMode( MATERIAL_FOG_NONE ); switch( modelinfo->GetModelType( pModel ) ) { case mod_brush: @@ -2724,7 +3149,7 @@ void CClientShadowMgr::UpdateShadow( ClientShadowHandle_t handle, bool force ) Assert(0); break; } - materials->FogMode( fogMode ); + pRenderContext->FogMode( fogMode ); } // NOTE: We can't do this earlier because pEnt->GetRenderOrigin() can @@ -2743,29 +3168,13 @@ void CClientShadowMgr::UpdateProjectedTextureInternal( ClientShadowHandle_t hand if( shadow.m_Flags & SHADOW_FLAGS_FLASHLIGHT ) { + VPROF_BUDGET( "CClientShadowMgr::UpdateProjectedTextureInternal", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING ); + Assert( ( shadow.m_Flags & SHADOW_FLAGS_SHADOW ) == 0 ); ClientShadow_t& shadow = m_Shadows[handle]; shadowmgr->EnableShadow( shadow.m_ShadowHandle, true ); - // Make sure to allocate/deallocated shadow depth texture here - // if they are out of sync with flags -#ifdef DOSHADOWEDFLASHLIGHT - if( shadow.m_Flags & SHADOW_FLAGS_USE_DEPTH_TEXTURE ) - { - if( !shadow.m_ShadowDepthTexture && r_flashlightdepthtexture.GetBool() ) - { - AllocateDepthBuffer( shadow.m_ShadowDepthTexture ); - } - } - else -#endif - { - if( shadow.m_ShadowDepthTexture ) - { - DeallocateDepthBuffer( shadow.m_ShadowDepthTexture ); - } - } // FIXME: What's the difference between brush and model shadows for light projectors? Answer: nothing. UpdateBrushShadow( NULL, handle ); } @@ -2783,9 +3192,20 @@ void CClientShadowMgr::UpdateProjectedTextureInternal( ClientShadowHandle_t hand //----------------------------------------------------------------------------- void CClientShadowMgr::UpdateProjectedTexture( ClientShadowHandle_t handle, bool force ) { - if (handle == CLIENTSHADOW_INVALID_HANDLE) + VPROF_BUDGET( "CClientShadowMgr::UpdateProjectedTexture", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING ); + + if ( handle == CLIENTSHADOW_INVALID_HANDLE ) return; + // NOTE: This can only work for flashlights, since UpdateProjectedTextureInternal + // depends on the falloff offset to cull shadows. + ClientShadow_t &shadow = m_Shadows[ handle ]; + if( ( shadow.m_Flags & SHADOW_FLAGS_FLASHLIGHT ) == 0 ) + { + Warning( "CClientShadowMgr::UpdateProjectedTexture can only be used with flashlights!\n" ); + return; + } + UpdateProjectedTextureInternal( handle, force ); RemoveShadowFromDirtyList( handle ); } @@ -2872,6 +3292,8 @@ bool CClientShadowMgr::CullReceiver( ClientShadowHandle_t handle, IClientRendera // check flags here instead and assert !pSourceRenderable if( m_Shadows[handle].m_Flags & SHADOW_FLAGS_FLASHLIGHT ) { + VPROF_BUDGET( "CClientShadowMgr::CullReceiver", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING ); + Assert( !pSourceRenderable ); const Frustum_t &frustum = shadowmgr->GetFlashlightFrustum( m_Shadows[handle].m_ShadowHandle ); @@ -2896,7 +3318,7 @@ bool CClientShadowMgr::CullReceiver( ClientShadowHandle_t handle, IClientRendera // Compute a rough bounding box for the shadow (in shadow space) Vector shadowMin, shadowMax; shadowMin.Init( -shadow.m_WorldSize.x * 0.5f, -shadow.m_WorldSize.y * 0.5f, 0 ); - shadowMax.Init( shadow.m_WorldSize.x * 0.5f, shadow.m_WorldSize.y * 0.5f, info.m_FalloffOffset + info.m_MaxDist ); + shadowMax.Init( shadow.m_WorldSize.x * 0.5f, shadow.m_WorldSize.y * 0.5f, info.m_MaxDist ); // If the bounding sphere doesn't intersect with the shadow volume, cull if (!IsBoxIntersectingSphere( shadowMin, shadowMax, localOrigin, radius )) @@ -3033,6 +3455,8 @@ void CClientShadowMgr::AddShadowToReceiver( ClientShadowHandle_t handle, if( shadow.m_Flags & SHADOW_FLAGS_FLASHLIGHT ) { + VPROF_BUDGET( "CClientShadowMgr::AddShadowToReceiver", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING ); + if( (!shadow.m_hTargetEntity) || IsFlashlightTarget( handle, pRenderable ) ) { shadowmgr->AddShadowToBrushModel( shadow.m_ShadowHandle, @@ -3064,6 +3488,8 @@ void CClientShadowMgr::AddShadowToReceiver( ClientShadowHandle_t handle, } else if( shadow.m_Flags & SHADOW_FLAGS_FLASHLIGHT ) { + VPROF_BUDGET( "CClientShadowMgr::AddShadowToReceiver", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING ); + if( (!shadow.m_hTargetEntity) || IsFlashlightTarget( handle, pRenderable ) ) { staticpropmgr->AddShadowToStaticProp( shadow.m_ShadowHandle, pRenderable ); @@ -3076,6 +3502,8 @@ void CClientShadowMgr::AddShadowToReceiver( ClientShadowHandle_t handle, case SHADOW_RECEIVER_STUDIO_MODEL: if( shadow.m_Flags & SHADOW_FLAGS_FLASHLIGHT ) { + VPROF_BUDGET( "CClientShadowMgr::AddShadowToReceiver", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING ); + if( (!shadow.m_hTargetEntity) || IsFlashlightTarget( handle, pRenderable ) ) { pRenderable->CreateModelInstance(); @@ -3140,22 +3568,74 @@ void CClientShadowMgr::SetRenderToTextureShadowTexCoords( ShadowHandle_t handle, // Go in a half-pixel to avoid blending with neighboring textures.. float u, v, du, dv; -#ifndef _XBOX + u = ((float)x + 0.5f) / (float)textureW; v = ((float)y + 0.5f) / (float)textureH; du = ((float)w - 1) / (float)textureW; dv = ((float)h - 1) / (float)textureH; -#else - // xboxissue - need non-normalized tecture coords - u = ((float)x + 0.5f); - v = ((float)y + 0.5f); - du = ((float)w - 1); - dv = ((float)h - 1); -#endif + shadowmgr->SetShadowTexCoord( handle, u, v, du, dv ); } +//----------------------------------------------------------------------------- +// Setup all children shadows +//----------------------------------------------------------------------------- +bool CClientShadowMgr::BuildSetupShadowHierarchy( IClientRenderable *pRenderable, const ClientShadow_t &shadow, bool bChild ) +{ + bool bDrewTexture = false; + + // Stop traversing when we hit a blobby shadow + ShadowType_t shadowType = GetActualShadowCastType( pRenderable ); + if ( pRenderable && shadowType == SHADOWS_SIMPLE ) + return false; + + if ( !pRenderable || shadowType != SHADOWS_NONE ) + { + bool bDrawModelShadow; + if ( !bChild ) + { + bDrawModelShadow = ((shadow.m_Flags & SHADOW_FLAGS_BRUSH_MODEL) == 0); + } + else + { + int nModelType = modelinfo->GetModelType( pRenderable->GetModel() ); + bDrawModelShadow = nModelType == mod_studio; + } + + if ( bDrawModelShadow ) + { + C_BaseEntity *pEntity = pRenderable->GetIClientUnknown()->GetBaseEntity(); + if ( pEntity ) + { + if ( pEntity->IsNPC() ) + { + s_NPCShadowBoneSetups.AddToTail( assert_cast( pEntity ) ); + } + else if ( pEntity->GetBaseAnimating() ) + { + s_NonNPCShadowBoneSetups.AddToTail( assert_cast( pEntity ) ); + } + + } + bDrewTexture = true; + } + } + + if ( !pRenderable ) + return bDrewTexture; + + IClientRenderable *pChild; + for ( pChild = pRenderable->FirstShadowChild(); pChild; pChild = pChild->NextShadowPeer() ) + { + if ( BuildSetupShadowHierarchy( pChild, shadow, true ) ) + { + bDrewTexture = true; + } + } + return bDrewTexture; +} + //----------------------------------------------------------------------------- // Draws all children shadows into our own //----------------------------------------------------------------------------- @@ -3186,12 +3666,18 @@ bool CClientShadowMgr::DrawShadowHierarchy( IClientRenderable *pRenderable, cons if ( bDrawModelShadow ) { - modelrender->DrawModelShadowEx( pRenderable, pRenderable->GetBody(), pRenderable->GetSkin() ); + DrawModelInfo_t info; + matrix3x4_t *pBoneToWorld = modelrender->DrawModelShadowSetup( pRenderable, pRenderable->GetBody(), pRenderable->GetSkin(), &info ); + if ( pBoneToWorld ) + { + modelrender->DrawModelShadow( pRenderable, info, pBoneToWorld ); + } bDrewTexture = true; } else if ( bDrawBrushShadow ) { render->DrawBrushModelShadow( pRenderable ); + bDrewTexture = true; } } @@ -3209,6 +3695,29 @@ bool CClientShadowMgr::DrawShadowHierarchy( IClientRenderable *pRenderable, cons return bDrewTexture; } +//----------------------------------------------------------------------------- +// This gets called with every shadow that potentially will need to re-render +//----------------------------------------------------------------------------- +bool CClientShadowMgr::BuildSetupListForRenderToTextureShadow( unsigned short clientShadowHandle, float flArea ) +{ + ClientShadow_t& shadow = m_Shadows[clientShadowHandle]; + bool bDirtyTexture = (shadow.m_Flags & SHADOW_FLAGS_TEXTURE_DIRTY) != 0; + bool bNeedsRedraw = m_ShadowAllocator.UseTexture( shadow.m_ShadowTexture, bDirtyTexture, flArea ); + if ( bNeedsRedraw || bDirtyTexture ) + { + shadow.m_Flags |= SHADOW_FLAGS_TEXTURE_DIRTY; + + if ( !m_ShadowAllocator.HasValidTexture( shadow.m_ShadowTexture ) ) + return false; + + // shadow to be redrawn; for now, we'll always do it. + IClientRenderable *pRenderable = ClientEntityList().GetClientRenderableFromHandle( shadow.m_Entity ); + + if ( BuildSetupShadowHierarchy( pRenderable, shadow ) ) + return true; + } + return false; +} //----------------------------------------------------------------------------- // This gets called with every shadow that potentially will need to re-render @@ -3218,7 +3727,9 @@ bool CClientShadowMgr::DrawRenderToTextureShadow( unsigned short clientShadowHan ClientShadow_t& shadow = m_Shadows[clientShadowHandle]; // If we were previously using the LOD shadow, set the material - if ( shadow.m_Flags & SHADOW_FLAGS_USING_LOD_SHADOW ) + bool bPreviouslyUsingLODShadow = ( shadow.m_Flags & SHADOW_FLAGS_USING_LOD_SHADOW ) != 0; + shadow.m_Flags &= ~SHADOW_FLAGS_USING_LOD_SHADOW; + if ( bPreviouslyUsingLODShadow ) { shadowmgr->SetShadowMaterial( shadow.m_ShadowHandle, m_RenderShadow, m_RenderModelShadow, (void*)clientShadowHandle ); } @@ -3226,27 +3737,48 @@ bool CClientShadowMgr::DrawRenderToTextureShadow( unsigned short clientShadowHan // Mark texture as being used... bool bDirtyTexture = (shadow.m_Flags & SHADOW_FLAGS_TEXTURE_DIRTY) != 0; bool bDrewTexture = false; - bool needsRedraw = m_ShadowAllocator.UseTexture( shadow.m_ShadowTexture, bDirtyTexture, flArea ); - if (needsRedraw || bDirtyTexture) + bool bNeedsRedraw = ( !m_bThreaded && m_ShadowAllocator.UseTexture( shadow.m_ShadowTexture, bDirtyTexture, flArea ) ); + + if ( !m_ShadowAllocator.HasValidTexture( shadow.m_ShadowTexture ) ) + { + DrawRenderToTextureShadowLOD( clientShadowHandle ); + return false; + } + + if ( bNeedsRedraw || bDirtyTexture ) { // shadow to be redrawn; for now, we'll always do it. IClientRenderable *pRenderable = ClientEntityList().GetClientRenderableFromHandle( shadow.m_Entity ); + CMatRenderContextPtr pRenderContext( materials ); + // Sets the viewport state int x, y, w, h; m_ShadowAllocator.GetTextureRect( shadow.m_ShadowTexture, x, y, w, h ); - materials->Viewport( x, y, w, h ); + pRenderContext->Viewport( IsX360() ? 0 : x, IsX360() ? 0 : y, w, h ); - // Clear the selected viewport only - // GR: don't need to clear depth - materials->ClearBuffers( true, false ); + // Clear the selected viewport only (don't need to clear depth) + pRenderContext->ClearBuffers( true, false ); - materials->MatrixMode( MATERIAL_VIEW ); - materials->LoadMatrix( shadowmgr->GetInfo( shadow.m_ShadowHandle ).m_WorldToShadow ); + pRenderContext->MatrixMode( MATERIAL_VIEW ); + pRenderContext->LoadMatrix( shadowmgr->GetInfo( shadow.m_ShadowHandle ).m_WorldToShadow ); if ( DrawShadowHierarchy( pRenderable, shadow ) ) { bDrewTexture = true; + if ( IsX360() ) + { + // resolve render target to system memory texture + Rect_t srcRect = { 0, 0, w, h }; + Rect_t dstRect = { x, y, w, h }; + pRenderContext->CopyRenderTargetToTextureEx( m_ShadowAllocator.GetTexture(), 0, &srcRect, &dstRect ); + } + } + else + { + // NOTE: Think the flags reset + texcoord set should only happen in DrawShadowHierarchy + // but it's 2 days before 360 ship.. not going to change this now. + DevMsg( "Didn't draw shadow hierarchy.. bad shadow texcoords probably going to happen..grab Brian!\n" ); } // Only clear the dirty flag if the caster isn't animating @@ -3257,7 +3789,7 @@ bool CClientShadowMgr::DrawRenderToTextureShadow( unsigned short clientShadowHan SetRenderToTextureShadowTexCoords( shadow.m_ShadowHandle, x, y, w, h ); } - else if ( shadow.m_Flags & SHADOW_FLAGS_USING_LOD_SHADOW ) + else if ( bPreviouslyUsingLODShadow ) { // In this case, we were previously using the LOD shadow, but we didn't // have to reconstitute the texture. In this case, we need to reset the texcoord @@ -3266,7 +3798,6 @@ bool CClientShadowMgr::DrawRenderToTextureShadow( unsigned short clientShadowHan SetRenderToTextureShadowTexCoords( shadow.m_ShadowHandle, x, y, w, h ); } - shadow.m_Flags &= ~SHADOW_FLAGS_USING_LOD_SHADOW; return bDrewTexture; } @@ -3287,202 +3818,6 @@ void CClientShadowMgr::DrawRenderToTextureShadowLOD( unsigned short clientShadow } -#define SMALL_OBJECT_FIXUP_FACTOR 10 - -//----------------------------------------------------------------------------- -// Returns true if the shadow is far enough to want to use blobby shadows -//----------------------------------------------------------------------------- -bool CClientShadowMgr::ShouldUseBlobbyShadows( float flRadius, float flScreenArea ) -{ - // Adjust the shadow area up for small objects; we don't want blobby shadows for - // really small things if we're real close to them... - float flMaxFixupRadius = 20; - float flMinFixupRadius = 6; - if (flRadius < flMaxFixupRadius) - { - if (flRadius >= flMinFixupRadius) - flScreenArea *= SMALL_OBJECT_FIXUP_FACTOR * (1.0f - (flRadius - flMinFixupRadius) / (flMaxFixupRadius - flMinFixupRadius) ) + 1.0f; - else - flScreenArea *= SMALL_OBJECT_FIXUP_FACTOR + 1.0f; - } - - return (flScreenArea <= m_flMinShadowArea); -} - - -//----------------------------------------------------------------------------- -// Builds a list of potential shadows that lie within our PVS + view frustum -//----------------------------------------------------------------------------- -struct VisibleShadowInfo_t -{ - ClientShadowHandle_t m_hShadow; - float m_flArea; - Vector m_vecAbsCenter; - float m_flRadius; -}; - -class CVisibleShadowList : public IClientLeafShadowEnum -{ -public: - - CVisibleShadowList(); - int FindShadows( const CViewSetup *pView, int nLeafCount, LeafIndex_t *pLeafList ); - int GetVisibleShadowCount() const; - - const VisibleShadowInfo_t &GetVisibleShadow( int i ) const; - -private: - void EnumShadow( unsigned short clientShadowHandle ); - float ComputeScreenArea( const Vector &vecCenter, float r ) const; - void PrioritySort(); - - CUtlVector m_ShadowsInView; - CUtlVector m_PriorityIndex; -}; - - -//----------------------------------------------------------------------------- -// Singleton instance -//----------------------------------------------------------------------------- -static CVisibleShadowList s_VisibleShadowList; - - - -CVisibleShadowList::CVisibleShadowList() : m_ShadowsInView( 0, 64 ), m_PriorityIndex( 0, 64 ) -{ -} - - -//----------------------------------------------------------------------------- -// Accessors -//----------------------------------------------------------------------------- -int CVisibleShadowList::GetVisibleShadowCount() const -{ - return m_ShadowsInView.Count(); -} - -const VisibleShadowInfo_t &CVisibleShadowList::GetVisibleShadow( int i ) const -{ - return m_ShadowsInView[m_PriorityIndex[i]]; -} - - -//----------------------------------------------------------------------------- -// Computes approximate screen area of the shadow -//----------------------------------------------------------------------------- -float CVisibleShadowList::ComputeScreenArea( const Vector &vecCenter, float r ) const -{ - float flScreenDiameter = materials->ComputePixelDiameterOfSphere( vecCenter, r ); - return flScreenDiameter * flScreenDiameter; -} - - -//----------------------------------------------------------------------------- -// Visits every shadow in the list of leaves -//----------------------------------------------------------------------------- -void CVisibleShadowList::EnumShadow( unsigned short clientShadowHandle ) -{ - CClientShadowMgr::ClientShadow_t& shadow = s_ClientShadowMgr.m_Shadows[clientShadowHandle]; - - // Don't bother if we rendered it this frame, no matter which view it was rendered for - if (shadow.m_nRenderFrame == gpGlobals->framecount) - return; - - // We don't need to bother with it - if ( s_ClientShadowMgr.GetActualShadowCastType( clientShadowHandle ) != SHADOWS_RENDER_TO_TEXTURE ) - return; - - IClientRenderable *pRenderable = ClientEntityList().GetClientRenderableFromHandle( shadow.m_Entity ); - Assert( pRenderable ); - - // Don't bother with children of hierarchy; they will be drawn with their parents - if ( s_ClientShadowMgr.ShouldUseParentShadow( pRenderable ) || s_ClientShadowMgr.WillParentRenderBlobbyShadow( pRenderable ) ) - return; - - // Compute a sphere surrounding the shadow - // FIXME: This doesn't account for children of hierarchy... too bad! - Vector vecAbsCenter; - float flRadius; - s_ClientShadowMgr.ComputeBoundingSphere( pRenderable, vecAbsCenter, flRadius ); - - // Compute a box surrounding the shadow - Vector vecAbsMins, vecAbsMaxs; - s_ClientShadowMgr.ComputeShadowBBox( pRenderable, vecAbsCenter, flRadius, &vecAbsMins, &vecAbsMaxs ); - - // FIXME: Add distance check here? - - // Make sure it's in the frustum. If it isn't it's not interesting - if (engine->CullBox( vecAbsMins, vecAbsMaxs )) - return; - - int i = m_ShadowsInView.AddToTail( ); - VisibleShadowInfo_t &info = m_ShadowsInView[i]; - info.m_hShadow = clientShadowHandle; - info.m_vecAbsCenter = vecAbsCenter; - info.m_flRadius = flRadius; - m_ShadowsInView[i].m_flArea = ComputeScreenArea( vecAbsCenter, flRadius ); - - // Har, har. When water is rendering (or any multipass technique), - // we may well initially render from a viewpoint which doesn't include this shadow. - // That doesn't mean we shouldn't check it again though. Sucks that we need to compute - // the sphere + bbox multiply times though. - shadow.m_nRenderFrame = gpGlobals->framecount; -} - - -//----------------------------------------------------------------------------- -// Sort based on screen area/priority -//----------------------------------------------------------------------------- -void CVisibleShadowList::PrioritySort() -{ - int nCount = m_ShadowsInView.Count(); - m_PriorityIndex.EnsureCapacity( nCount ); - - m_PriorityIndex.RemoveAll(); - - int i, j; - for ( i = 0; i < nCount; ++i ) - { - m_PriorityIndex.AddToTail(i); - } - - for ( i = 0; i < nCount - 1; ++i ) - { - int nLargestInd = i; - float flLargestArea = m_ShadowsInView[m_PriorityIndex[i]].m_flArea; - for ( j = i + 1; j < nCount; ++j ) - { - int nIndex = m_PriorityIndex[j]; - if ( flLargestArea < m_ShadowsInView[nIndex].m_flArea ) - { - nLargestInd = j; - flLargestArea = m_ShadowsInView[nIndex].m_flArea; - } - } - swap( m_PriorityIndex[i], m_PriorityIndex[nLargestInd] ); - } -} - - -//----------------------------------------------------------------------------- -// Main entry point for finding shadows in the leaf list -//----------------------------------------------------------------------------- -int CVisibleShadowList::FindShadows( const CViewSetup *pView, int nLeafCount, LeafIndex_t *pLeafList ) -{ - VPROF_BUDGET( "CVisibleShadowList::FindShadows", VPROF_BUDGETGROUP_SHADOW_RENDERING ); - - m_ShadowsInView.RemoveAll(); - ClientLeafSystem()->EnumerateShadowsInLeaves( nLeafCount, pLeafList, this ); - int nCount = m_ShadowsInView.Count(); - if (nCount != 0) - { - // Sort based on screen area/priority - PrioritySort(); - } - return nCount; -} - - //----------------------------------------------------------------------------- // Advances to the next frame, //----------------------------------------------------------------------------- @@ -3493,65 +3828,248 @@ void CClientShadowMgr::AdvanceFrame() } +//----------------------------------------------------------------------------- +// Re-render shadow depth textures that lie in the leaf list +//----------------------------------------------------------------------------- +int CClientShadowMgr::BuildActiveShadowDepthList( const CViewSetup &viewSetup, int nMaxDepthShadows, ClientShadowHandle_t *pActiveDepthShadows ) +{ + int nActiveDepthShadowCount = 0; + for ( ClientShadowHandle_t i = m_Shadows.Head(); i != m_Shadows.InvalidIndex(); i = m_Shadows.Next(i) ) + { + ClientShadow_t& shadow = m_Shadows[i]; + // If this is not a flashlight which should use a shadow depth texture, skip! + if ( ( shadow.m_Flags & SHADOW_FLAGS_USE_DEPTH_TEXTURE ) == 0 ) + continue; + + const FlashlightState_t& flashlightState = shadowmgr->GetFlashlightState( shadow.m_ShadowHandle ); + + // Bail if this flashlight doesn't want shadows + if ( !flashlightState.m_bEnableShadows ) + continue; + + // Calculate an AABB around the shadow frustum + Vector vecAbsMins, vecAbsMaxs; + CalculateAABBFromProjectionMatrix( shadow.m_WorldToShadow, &vecAbsMins, &vecAbsMaxs ); + + Frustum_t viewFrustum; + GeneratePerspectiveFrustum( viewSetup.origin, viewSetup.angles, viewSetup.zNear, viewSetup.zFar, viewSetup.fov, viewSetup.m_flAspectRatio, viewFrustum ); + + // FIXME: Could do other sorts of culling here, such as frustum-frustum test, distance etc. + // If it's not in the view frustum, move on + if ( R_CullBox( vecAbsMins, vecAbsMaxs, viewFrustum ) ) + { + shadowmgr->SetFlashlightDepthTexture( shadow.m_ShadowHandle, NULL, 0 ); + continue; + } + + if ( nActiveDepthShadowCount >= nMaxDepthShadows ) + { + static bool s_bOverflowWarning = false; + if ( !s_bOverflowWarning ) + { + Warning( "Too many depth textures rendered in a single view!\n" ); + Assert( 0 ); + s_bOverflowWarning = true; + } + shadowmgr->SetFlashlightDepthTexture( shadow.m_ShadowHandle, NULL, 0 ); + continue; + } + + pActiveDepthShadows[nActiveDepthShadowCount++] = i; + } + return nActiveDepthShadowCount; +} + + +//----------------------------------------------------------------------------- +// Sets the view's active flashlight render state +//----------------------------------------------------------------------------- +void CClientShadowMgr::SetViewFlashlightState( int nActiveFlashlightCount, ClientShadowHandle_t* pActiveFlashlights ) +{ + // NOTE: On the 360, we render the entire scene with the flashlight state + // set and don't render flashlights additively in the shadow mgr at a far later time + // because the CPU costs are prohibitive + if ( !IsX360() && !r_flashlight_version2.GetInt() ) + return; + + Assert( nActiveFlashlightCount<= 1 ); + if ( nActiveFlashlightCount > 0 ) + { + Assert( ( m_Shadows[ pActiveFlashlights[0] ].m_Flags & SHADOW_FLAGS_FLASHLIGHT ) != 0 ); + shadowmgr->SetFlashlightRenderState( pActiveFlashlights[0] ); + } + else + { + shadowmgr->SetFlashlightRenderState( SHADOW_HANDLE_INVALID ); + } +} + + +//----------------------------------------------------------------------------- +// Re-render shadow depth textures that lie in the leaf list +//----------------------------------------------------------------------------- +void CClientShadowMgr::ComputeShadowDepthTextures( const CViewSetup &viewSetup ) +{ + VPROF_BUDGET( "CClientShadowMgr::ComputeShadowDepthTextures", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING ); + + CMatRenderContextPtr pRenderContext( materials ); + PIXEVENT( pRenderContext, "Shadow Depth Textures" ); + + // Build list of active render-to-texture shadows + ClientShadowHandle_t pActiveDepthShadows[1024]; + int nActiveDepthShadowCount = BuildActiveShadowDepthList( viewSetup, ARRAYSIZE( pActiveDepthShadows ), pActiveDepthShadows ); + + // Iterate over all existing textures and allocate shadow textures + bool bDebugFrustum = r_flashlightdrawfrustum.GetBool(); + for ( int j = 0; j < nActiveDepthShadowCount; ++j ) + { + ClientShadow_t& shadow = m_Shadows[ pActiveDepthShadows[j] ]; + + CTextureReference shadowDepthTexture; + bool bGotShadowDepthTexture = LockShadowDepthTexture( &shadowDepthTexture ); + if ( !bGotShadowDepthTexture ) + { + // If we don't get one, that means we have too many this frame so bind no depth texture + static int bitchCount = 0; + if( bitchCount < 10 ) + { + Warning( "Too many shadow maps this frame!\n" ); + bitchCount++; + } + + Assert(0); + shadowmgr->SetFlashlightDepthTexture( shadow.m_ShadowHandle, NULL, 0 ); + continue; + } + + CViewSetup shadowView; + shadowView.m_flAspectRatio = 1.0f; + shadowView.x = shadowView.y = 0; + shadowView.width = shadowDepthTexture->GetActualWidth(); + shadowView.height = shadowDepthTexture->GetActualHeight(); + shadowView.m_bOrtho = false; + shadowView.m_bDoBloomAndToneMapping = false; + + // Copy flashlight parameters + const FlashlightState_t& flashlightState = shadowmgr->GetFlashlightState( shadow.m_ShadowHandle ); + shadowView.fov = shadowView.fovViewmodel = flashlightState.m_fHorizontalFOVDegrees; + shadowView.origin = flashlightState.m_vecLightOrigin; + QuaternionAngles( flashlightState.m_quatOrientation, shadowView.angles ); // Convert from Quaternion to QAngle + + shadowView.zNear = shadowView.zNearViewmodel = flashlightState.m_NearZ; + shadowView.zFar = shadowView.zFarViewmodel = flashlightState.m_FarZ; + + // Can turn on all light frustum overlays or per light with flashlightState parameter... + if ( bDebugFrustum || flashlightState.m_bDrawShadowFrustum ) + { + DebugDrawFrustum( shadowView.origin, shadow.m_WorldToShadow ); + } + + // Set depth bias factors specific to this flashlight + CMatRenderContextPtr pRenderContext( materials ); + pRenderContext->SetShadowDepthBiasFactors( flashlightState.m_flShadowSlopeScaleDepthBias, flashlightState.m_flShadowDepthBias ); + + // Render to the shadow depth texture with appropriate view + view->UpdateShadowDepthTexture( m_DummyColorTexture, shadowDepthTexture, shadowView ); + + // Associate the shadow depth texture and stencil bit with the flashlight for use during scene rendering + shadowmgr->SetFlashlightDepthTexture( shadow.m_ShadowHandle, shadowDepthTexture, 0 ); + } + + SetViewFlashlightState( nActiveDepthShadowCount, pActiveDepthShadows ); +} + + //----------------------------------------------------------------------------- // Re-renders all shadow textures for shadow casters that lie in the leaf list //----------------------------------------------------------------------------- -void CClientShadowMgr::ComputeShadowTextures( const CViewSetup *pView, int leafCount, LeafIndex_t* pLeafList ) +static void SetupBonesOnBaseAnimating( C_BaseAnimating *&pBaseAnimating ) +{ + pBaseAnimating->SetupBones( NULL, -1, -1, gpGlobals->curtime ); +} + + +void CClientShadowMgr::ComputeShadowTextures( const CViewSetup &view, int leafCount, LeafIndex_t* pLeafList ) { VPROF_BUDGET( "CClientShadowMgr::ComputeShadowTextures", VPROF_BUDGETGROUP_SHADOW_RENDERING ); - + if ( !m_RenderToTextureActive || (r_shadows.GetInt() == 0) || r_shadows_gamecontrol.GetInt() == 0 ) return; + m_bThreaded = ( r_threaded_client_shadow_manager.GetBool() && g_pThreadPool->NumIdleThreads() ); + MDLCACHE_CRITICAL_SECTION(); // First grab all shadow textures we may want to render - int nCount = s_VisibleShadowList.FindShadows( pView, leafCount, pLeafList ); + int nCount = s_VisibleShadowList.FindShadows( &view, leafCount, pLeafList ); if ( nCount == 0 ) return; // FIXME: Add heuristics based on distance, etc. to futz with // the shadow allocator + to select blobby shadows - // Clear to white, black alpha -#ifndef _XBOX - materials->ClearColor4ub( 255, 255, 255, 0 ); -#else - // xboxissue - using rgb instead - materials->ClearColor4ub( 0, 0, 0, 255 ); -#endif + CMatRenderContextPtr pRenderContext( materials ); + + PIXEVENT( pRenderContext, "Render-To-Texture Shadows" ); + + // Clear to white (color unused), black alpha + pRenderContext->ClearColor4ub( 255, 255, 255, 0 ); // No height clip mode please. - MaterialHeightClipMode_t oldHeightClipMode = materials->GetHeightClipMode(); - materials->SetHeightClipMode( MATERIAL_HEIGHTCLIPMODE_DISABLE ); + MaterialHeightClipMode_t oldHeightClipMode = pRenderContext->GetHeightClipMode(); + pRenderContext->SetHeightClipMode( MATERIAL_HEIGHTCLIPMODE_DISABLE ); // No projection matrix (orthographic mode) // FIXME: Make it work for projective shadows? - materials->MatrixMode( MATERIAL_PROJECTION ); - materials->PushMatrix(); - materials->LoadIdentity(); - materials->Scale( 1, -1, 1 ); - materials->Ortho( 0, 0, 1, 1, -9999, 0 ); + pRenderContext->MatrixMode( MATERIAL_PROJECTION ); + pRenderContext->PushMatrix(); + pRenderContext->LoadIdentity(); + pRenderContext->Scale( 1, -1, 1 ); + pRenderContext->Ortho( 0, 0, 1, 1, -9999, 0 ); - materials->MatrixMode( MATERIAL_VIEW ); - materials->PushMatrix(); + pRenderContext->MatrixMode( MATERIAL_VIEW ); + pRenderContext->PushMatrix(); - materials->PushRenderTargetAndViewport( m_ShadowAllocator.GetTexture() ); + pRenderContext->PushRenderTargetAndViewport( m_ShadowAllocator.GetTexture() ); - if ( m_bRenderTargetNeedsClear ) + if ( !IsX360() && m_bRenderTargetNeedsClear ) { - // GR - draw with disabled depth buffer - // GR: don't need to clear depth - materials->ClearBuffers( true, false ); + // don't need to clear absent depth buffer + pRenderContext->ClearBuffers( true, false ); m_bRenderTargetNeedsClear = false; } int nMaxShadows = r_shadowmaxrendered.GetInt(); int nModelsRendered = 0; - for (int i = 0; i < nCount; ++i) + int i; + + if ( m_bThreaded && g_pThreadPool->NumIdleThreads() ) + { + s_NPCShadowBoneSetups.RemoveAll(); + s_NonNPCShadowBoneSetups.RemoveAll(); + + for (i = 0; i < nCount; ++i) + { + const VisibleShadowInfo_t &info = s_VisibleShadowList.GetVisibleShadow(i); + if ( nModelsRendered < nMaxShadows ) + { + if ( BuildSetupListForRenderToTextureShadow( info.m_hShadow, info.m_flArea ) ) + { + ++nModelsRendered; + } + } + } + + ParallelProcess( s_NPCShadowBoneSetups.Base(), s_NPCShadowBoneSetups.Count(), &SetupBonesOnBaseAnimating ); + ParallelProcess( s_NonNPCShadowBoneSetups.Base(), s_NonNPCShadowBoneSetups.Count(), &SetupBonesOnBaseAnimating ); + + nModelsRendered = 0; + } + + for (i = 0; i < nCount; ++i) { const VisibleShadowInfo_t &info = s_VisibleShadowList.GetVisibleShadow(i); - if ( (nModelsRendered < nMaxShadows) && ( !IsXbox() || !ShouldUseBlobbyShadows( info.m_flRadius, info.m_flArea ) ) ) + if ( nModelsRendered < nMaxShadows ) { if ( DrawRenderToTextureShadow( info.m_hShadow, info.m_flArea ) ) { @@ -3565,49 +4083,59 @@ void CClientShadowMgr::ComputeShadowTextures( const CViewSetup *pView, int leafC } // Render to the backbuffer again - materials->PopRenderTargetAndViewport(); + pRenderContext->PopRenderTargetAndViewport(); // Restore the matrices - materials->MatrixMode( MATERIAL_PROJECTION ); - materials->PopMatrix(); + pRenderContext->MatrixMode( MATERIAL_PROJECTION ); + pRenderContext->PopMatrix(); - materials->MatrixMode( MATERIAL_VIEW ); - materials->PopMatrix(); + pRenderContext->MatrixMode( MATERIAL_VIEW ); + pRenderContext->PopMatrix(); - materials->SetHeightClipMode( oldHeightClipMode ); + pRenderContext->SetHeightClipMode( oldHeightClipMode ); - materials->SetHeightClipMode( oldHeightClipMode ); + pRenderContext->SetHeightClipMode( oldHeightClipMode ); // Restore the clear color - materials->ClearColor3ub( 0, 0, 0 ); + pRenderContext->ClearColor3ub( 0, 0, 0 ); } - -bool CClientShadowMgr::AllocateDepthBuffer( CTextureReference &depthBuffer ) +//------------------------------------------------------------------------------------------------------- +// Lock down the usage of a shadow depth texture...must be unlocked for use on subsequent views / frames +//------------------------------------------------------------------------------------------------------- +bool CClientShadowMgr::LockShadowDepthTexture( CTextureReference *shadowDepthTexture ) { - if( !m_DepthTextureCache.Count() ) - return false; + for ( int i=0; i < m_DepthTextureCache.Count(); i++ ) // Search for cached shadow depth texture + { + if ( m_DepthTextureCacheLocks[i] == false ) // If a free one is found + { + *shadowDepthTexture = m_DepthTextureCache[i]; + m_DepthTextureCacheLocks[i] = true; + return true; + } + } - depthBuffer = m_DepthTextureCache[ m_DepthTextureCache.Count()-1 ]; - m_DepthTextureCache.Remove( m_DepthTextureCache.Count()-1 ); - - return true; -} - - -void CClientShadowMgr::DeallocateDepthBuffer( CTextureReference &depthBuffer ) -{ - m_DepthTextureCache.AddToTail( depthBuffer ); - depthBuffer.Shutdown(); + return false; // Didn't find it... } +//------------------------------------------------------------------ +// Unlock shadow depth texture for use on subsequent views / frames +//------------------------------------------------------------------ +void CClientShadowMgr::UnlockAllShadowDepthTextures() +{ + for (int i=0; i< m_DepthTextureCache.Count(); i++ ) + { + m_DepthTextureCacheLocks[i] = false; + } + SetViewFlashlightState( 0, NULL ); +} void CClientShadowMgr::SetFlashlightTarget( ClientShadowHandle_t shadowHandle, EHANDLE targetEntity ) { Assert( m_Shadows.IsValidIndex( shadowHandle ) ); CClientShadowMgr::ClientShadow_t &shadow = m_Shadows[ shadowHandle ]; - if( (shadow.m_Flags&SHADOW_FLAGS_FLASHLIGHT) == 0 ) + if( ( shadow.m_Flags & SHADOW_FLAGS_FLASHLIGHT ) == 0 ) return; // shadow.m_pTargetRenderable = pRenderable; @@ -3619,11 +4147,18 @@ void CClientShadowMgr::SetFlashlightLightWorld( ClientShadowHandle_t shadowHandl { Assert( m_Shadows.IsValidIndex( shadowHandle ) ); - CClientShadowMgr::ClientShadow_t &shadow = m_Shadows[ shadowHandle ]; - if( (shadow.m_Flags&SHADOW_FLAGS_FLASHLIGHT) == 0 ) + ClientShadow_t &shadow = m_Shadows[ shadowHandle ]; + if( ( shadow.m_Flags & SHADOW_FLAGS_FLASHLIGHT ) == 0 ) return; - shadow.m_bLightWorld = bLightWorld; + if ( bLightWorld ) + { + shadow.m_Flags |= SHADOW_FLAGS_LIGHT_WORLD; + } + else + { + shadow.m_Flags &= ~SHADOW_FLAGS_LIGHT_WORLD; + } } @@ -3657,6 +4192,7 @@ public: virtual bool Init( IMaterial *pMaterial, KeyValues *pKeyValues ); virtual void OnBind( void *pProxyData ); virtual void Release( void ) { delete this; } + virtual IMaterial *GetMaterial(); private: IMaterialVar* m_BaseTextureVar; @@ -3683,13 +4219,18 @@ void CShadowProxy::OnBind( void *pProxyData ) { unsigned short clientShadowHandle = ( unsigned short )pProxyData; ITexture* pTex = s_ClientShadowMgr.GetShadowTexture( clientShadowHandle ); - if ((m_BaseTextureVar->GetType() != MATERIAL_VAR_TYPE_TEXTURE) || - (pTex != m_BaseTextureVar->GetTextureValue())) + m_BaseTextureVar->SetTextureValue( pTex ); + if ( ToolsEnabled() ) { - m_BaseTextureVar->SetTextureValue( pTex ); + ToolFramework_RecordMaterialParams( GetMaterial() ); } } +IMaterial *CShadowProxy::GetMaterial() +{ + return m_BaseTextureVar->GetOwningMaterial(); +} + EXPOSE_INTERFACE( CShadowProxy, IMaterialProxy, "Shadow" IMATERIAL_PROXY_INTERFACE_VERSION ); @@ -3705,6 +4246,7 @@ public: virtual bool Init( IMaterial *pMaterial, KeyValues *pKeyValues ); virtual void OnBind( void *pProxyData ); virtual void Release( void ) { delete this; } + virtual IMaterial *GetMaterial(); private: IMaterialVar* m_BaseTextureVar; @@ -3770,14 +4312,16 @@ void CShadowModelProxy::OnBind( void *pProxyData ) m_FalloffOffsetVar->SetFloatValue( info.m_FalloffOffset ); m_FalloffDistanceVar->SetFloatValue( info.m_MaxDist ); m_FalloffAmountVar->SetFloatValue( info.m_FalloffAmount ); + + if ( ToolsEnabled() ) + { + ToolFramework_RecordMaterialParams( GetMaterial() ); + } +} + +IMaterial *CShadowModelProxy::GetMaterial() +{ + return m_BaseTextureVar->GetOwningMaterial(); } EXPOSE_INTERFACE( CShadowModelProxy, IMaterialProxy, "ShadowModel" IMATERIAL_PROXY_INTERFACE_VERSION ); - - - - - - - - diff --git a/src/src/cl_dll/clientsideeffects.cpp b/src/src/game/client/clientsideeffects.cpp similarity index 100% rename from src/src/cl_dll/clientsideeffects.cpp rename to src/src/game/client/clientsideeffects.cpp diff --git a/src/src/cl_dll/clientsideeffects.h b/src/src/game/client/clientsideeffects.h similarity index 100% rename from src/src/cl_dll/clientsideeffects.h rename to src/src/game/client/clientsideeffects.h diff --git a/src/src/cl_dll/clientsideeffects_test.cpp b/src/src/game/client/clientsideeffects_test.cpp similarity index 100% rename from src/src/cl_dll/clientsideeffects_test.cpp rename to src/src/game/client/clientsideeffects_test.cpp diff --git a/src/src/game/client/colorcorrectionmgr.cpp b/src/src/game/client/colorcorrectionmgr.cpp new file mode 100644 index 0000000..61b3291 --- /dev/null +++ b/src/src/game/client/colorcorrectionmgr.cpp @@ -0,0 +1,119 @@ +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// +// +// Purpose : Singleton manager for color correction on the client +// +// $NoKeywords: $ +//===========================================================================// + +#include "cbase.h" +#include "tier0/vprof.h" +#include "colorcorrectionmgr.h" + + +//------------------------------------------------------------------------------ +// Singleton access +//------------------------------------------------------------------------------ +static CColorCorrectionMgr s_ColorCorrectionMgr; +CColorCorrectionMgr *g_pColorCorrectionMgr = &s_ColorCorrectionMgr; + + +//------------------------------------------------------------------------------ +// Constructor +//------------------------------------------------------------------------------ +CColorCorrectionMgr::CColorCorrectionMgr() +{ + m_nActiveWeightCount = 0; +} + + +//------------------------------------------------------------------------------ +// Creates, destroys color corrections +//------------------------------------------------------------------------------ +ClientCCHandle_t CColorCorrectionMgr::AddColorCorrection( const char *pName, const char *pFileName ) +{ + if ( !pFileName ) + { + pFileName = pName; + } + + CMatRenderContextPtr pRenderContext( g_pMaterialSystem ); + ColorCorrectionHandle_t ccHandle = pRenderContext->AddLookup( pName ); + if ( ccHandle ) + { + pRenderContext->LockLookup( ccHandle ); + pRenderContext->LoadLookup( ccHandle, pFileName ); + pRenderContext->UnlockLookup( ccHandle ); + } + else + { + Warning("Cannot find color correction lookup file: '%s'\n", pFileName ); + } + + return (ClientCCHandle_t)ccHandle; +} + +void CColorCorrectionMgr::RemoveColorCorrection( ClientCCHandle_t h ) +{ + if ( h != INVALID_CLIENT_CCHANDLE ) + { + CMatRenderContextPtr pRenderContext( g_pMaterialSystem ); + ColorCorrectionHandle_t ccHandle = (ColorCorrectionHandle_t)h; + pRenderContext->RemoveLookup( ccHandle ); + } +} + + +//------------------------------------------------------------------------------ +// Modify color correction weights +//------------------------------------------------------------------------------ +void CColorCorrectionMgr::SetColorCorrectionWeight( ClientCCHandle_t h, float flWeight ) +{ + if ( h != INVALID_CLIENT_CCHANDLE ) + { + CMatRenderContextPtr pRenderContext( g_pMaterialSystem ); + ColorCorrectionHandle_t ccHandle = (ColorCorrectionHandle_t)h; + pRenderContext->SetLookupWeight( ccHandle, flWeight ); + + // FIXME: NOTE! This doesn't work if the same handle has + // its weight set twice with no intervening calls to ResetColorCorrectionWeights + // which, at the moment, is true + if ( flWeight != 0.0f ) + { + ++m_nActiveWeightCount; + } + } +} + +void CColorCorrectionMgr::ResetColorCorrectionWeights() +{ + VPROF_("ResetColorCorrectionWeights", 2, VPROF_BUDGETGROUP_OTHER_UNACCOUNTED, false, 0); + // FIXME: Where should I put this? It needs to happen prior to SimulateEntities() + // which is where the client thinks for c_colorcorrection + c_colorcorrectionvolumes + // update the color correction weights. + CMatRenderContextPtr pRenderContext( g_pMaterialSystem ); + pRenderContext->ResetLookupWeights(); + m_nActiveWeightCount = 0; +} + +void CColorCorrectionMgr::SetResetable( ClientCCHandle_t h, bool bResetable ) +{ + // NOTE: Setting stuff to be not resettable doesn't work when in queued mode + // because the logic that sets m_nActiveWeightCount to 0 in ResetColorCorrectionWeights + // is no longer valid when stuff is not resettable. + Assert( bResetable || !g_pMaterialSystem->GetThreadMode() == MATERIAL_SINGLE_THREADED ); + if ( h != INVALID_CLIENT_CCHANDLE ) + { + CMatRenderContextPtr pRenderContext( g_pMaterialSystem ); + ColorCorrectionHandle_t ccHandle = (ColorCorrectionHandle_t)h; + pRenderContext->SetResetable( ccHandle, bResetable ); + } +} + + +//------------------------------------------------------------------------------ +// Is color correction active? +//------------------------------------------------------------------------------ +bool CColorCorrectionMgr::HasNonZeroColorCorrectionWeights() const +{ + return ( m_nActiveWeightCount != 0 ); +} diff --git a/src/src/game/client/colorcorrectionmgr.h b/src/src/game/client/colorcorrectionmgr.h new file mode 100644 index 0000000..e53dd06 --- /dev/null +++ b/src/src/game/client/colorcorrectionmgr.h @@ -0,0 +1,57 @@ +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// +// +// Purpose : Singleton manager for color correction on the client +// +// $NoKeywords: $ +//===========================================================================// + +#ifndef COLORCORRECTIONMGR_H +#define COLORCORRECTIONMGR_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "igamesystem.h" + + +//------------------------------------------------------------------------------ +// Purpose : Singleton manager for color correction on the client +//------------------------------------------------------------------------------ +DECLARE_POINTER_HANDLE( ClientCCHandle_t ); +#define INVALID_CLIENT_CCHANDLE ( (ClientCCHandle_t)0 ) + +class CColorCorrectionMgr : public CBaseGameSystem +{ + // Inherited from IGameSystemPerFrame +public: + virtual char const *Name() { return "Color Correction Mgr"; } + + // Other public methods +public: + CColorCorrectionMgr(); + + // Create, destroy color correction + ClientCCHandle_t AddColorCorrection( const char *pName, const char *pFileName = NULL ); + void RemoveColorCorrection( ClientCCHandle_t ); + + // Modify color correction weights + void SetColorCorrectionWeight( ClientCCHandle_t h, float flWeight ); + void ResetColorCorrectionWeights(); + void SetResetable( ClientCCHandle_t h, bool bResetable ); + + // Is color correction active? + bool HasNonZeroColorCorrectionWeights() const; + +private: + int m_nActiveWeightCount; +}; + + +//------------------------------------------------------------------------------ +// Singleton access +//------------------------------------------------------------------------------ +extern CColorCorrectionMgr *g_pColorCorrectionMgr; + + +#endif // COLORCORRECTIONMGR_H diff --git a/src/src/game/client/commentary_modelviewer.cpp b/src/src/game/client/commentary_modelviewer.cpp new file mode 100644 index 0000000..a659875 --- /dev/null +++ b/src/src/game/client/commentary_modelviewer.cpp @@ -0,0 +1,277 @@ +//========= Copyright © 1996-2006, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + + +#include "cbase.h" +#include "vgui/IInput.h" +#include +#include "commentary_modelviewer.h" +#include "iclientmode.h" +#include "baseviewport.h" + +DECLARE_BUILD_FACTORY( CCommentaryModelPanel ); + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CCommentaryModelPanel::CCommentaryModelPanel( vgui::Panel *parent, const char *name ) : CModelPanel( parent, name ) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CCommentaryModelViewer::CCommentaryModelViewer(IViewPort *pViewPort) : Frame(NULL, PANEL_COMMENTARY_MODELVIEWER ) +{ + m_pViewPort = pViewPort; + m_pModelPanel = NULL; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CCommentaryModelViewer::~CCommentaryModelViewer() +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CCommentaryModelViewer::ApplySchemeSettings( vgui::IScheme *pScheme ) +{ + BaseClass::ApplySchemeSettings( pScheme ); + + LoadControlSettings( "Resource/UI/CommentaryModelViewer.res" ); + + m_pModelPanel = dynamic_cast( FindChildByName( "modelpanel" ) ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CCommentaryModelViewer::PerformLayout( void ) +{ + int w,h; + GetParent()->GetSize( w, h ); + SetBounds(0,0,w,h); + + if ( m_pModelPanel ) + { + m_pModelPanel->SetBounds(0,0,w,h); + } + + BaseClass::PerformLayout(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CCommentaryModelViewer::SetModel( const char *pszName, const char *pszAttached ) +{ + if ( !m_pModelPanel ) + return; + + m_pModelPanel->SwapModel( pszName, pszAttached ); + + m_flYawSpeed = 0; + m_flZoomSpeed = 0; + m_bTranslating = false; + + m_vecResetPos = m_pModelPanel->m_pModelInfo->m_vecOriginOffset; + m_vecResetAngles = m_pModelPanel->m_pModelInfo->m_vecAbsAngles; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CCommentaryModelViewer::ShowPanel(bool bShow) +{ + if ( BaseClass::IsVisible() == bShow ) + return; + + if ( bShow ) + { + Activate(); + SetMouseInputEnabled( true ); + } + else + { + SetVisible( false ); + SetMouseInputEnabled( false ); + } + + m_pViewPort->ShowBackGround( bShow ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CCommentaryModelViewer::OnCommand( const char *command ) +{ + if ( Q_stricmp( command, "vguicancel" ) ) + { + engine->ClientCmd( const_cast( command ) ); + } + + Close(); + m_pViewPort->ShowBackGround( false ); + + BaseClass::OnCommand( command ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CCommentaryModelViewer::OnKeyCodePressed( vgui::KeyCode code ) +{ + if ( code == KEY_ENTER ) + { + Close(); + m_pViewPort->ShowBackGround( false ); + } + else if ( code == KEY_SPACE ) + { + m_bTranslating = !m_bTranslating; + } + else if ( code == KEY_R ) + { + m_pModelPanel->m_pModelInfo->m_vecOriginOffset = m_vecResetPos; + m_pModelPanel->m_pModelInfo->m_vecAbsAngles = m_vecResetAngles; + m_flYawSpeed = 0; + m_flZoomSpeed = 0; + + m_pModelPanel->ZoomToFrameDistance(); + } + else + { + BaseClass::OnKeyCodePressed( code ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CCommentaryModelViewer::OnThink( void ) +{ + HandleMovementInput(); + + BaseClass::OnThink(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CCommentaryModelViewer::HandleMovementInput( void ) +{ + bool bLeftDown = input()->IsKeyDown(KEY_LEFT); + bool bRightDown = input()->IsKeyDown(KEY_RIGHT); + bool bForwardDown = input()->IsKeyDown(KEY_UP); + bool bBackDown = input()->IsKeyDown(KEY_DOWN); + + float flAccel = 0.05; + + // Rotation around Z + if ( bLeftDown ) + { + if ( m_flYawSpeed > 0 ) + { + m_flYawSpeed = 0; + } + m_flYawSpeed = max(m_flYawSpeed-flAccel, -3.0); + } + else if ( bRightDown ) + { + if ( m_flYawSpeed < 0 ) + { + m_flYawSpeed = 0; + } + m_flYawSpeed = min(m_flYawSpeed+flAccel, 3.0); + } + if ( m_flYawSpeed != 0 ) + { + if ( m_bTranslating ) + { + m_pModelPanel->m_pModelInfo->m_vecOriginOffset.y = clamp( m_pModelPanel->m_pModelInfo->m_vecOriginOffset.y + m_flYawSpeed, -100, 100 ); + } + else + { + m_pModelPanel->m_pModelInfo->m_vecAbsAngles.y = anglemod( m_pModelPanel->m_pModelInfo->m_vecAbsAngles.y + m_flYawSpeed ); + } + + if ( !bLeftDown && !bRightDown ) + { + m_flYawSpeed = ( m_flYawSpeed > 0 ) ? max(0,m_flYawSpeed-0.1) : min(0,m_flYawSpeed+0.1); + } + } + + // Zooming + if ( bForwardDown ) + { + if ( m_flZoomSpeed > 0 ) + { + m_flZoomSpeed = 0; + } + m_flZoomSpeed = max(m_flZoomSpeed-flAccel, -3.0); + } + else if ( bBackDown ) + { + if ( m_flZoomSpeed < 0 ) + { + m_flZoomSpeed = 0; + } + m_flZoomSpeed = min(m_flZoomSpeed+flAccel, 3.0); + } + if ( m_flZoomSpeed != 0 ) + { + if ( m_bTranslating ) + { + m_pModelPanel->m_pModelInfo->m_vecOriginOffset.z = clamp( m_pModelPanel->m_pModelInfo->m_vecOriginOffset.z + m_flZoomSpeed, -100, 300 ); + } + else + { + float flZoomMin = m_pModelPanel->m_flFrameDistance * 0.75; + float flZoomMax = m_pModelPanel->m_flFrameDistance * 1.5; + m_pModelPanel->m_pModelInfo->m_vecOriginOffset.x = clamp( m_pModelPanel->m_pModelInfo->m_vecOriginOffset.x + m_flZoomSpeed, flZoomMin, flZoomMax ); + } + + if ( !bForwardDown && !bBackDown ) + { + m_flZoomSpeed = ( m_flZoomSpeed > 0 ) ? max(0,m_flZoomSpeed-0.1) : min(0,m_flZoomSpeed+0.1); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CommentaryShowModelViewer( const CCommand &args ) +{ + if ( args.ArgC() < 2 ) + { + ConMsg( "Usage: commentary_showmodelviewer \n" ); + return; + } + + CBaseViewport *pViewport = dynamic_cast( g_pClientMode->GetViewport() ); + if ( pViewport ) + { + IViewPortPanel *pCommentaryPanel = pViewport->FindPanelByName( PANEL_COMMENTARY_MODELVIEWER ); + if ( !pCommentaryPanel ) + { + pCommentaryPanel = pViewport->CreatePanelByName( PANEL_COMMENTARY_MODELVIEWER ); + pViewport->AddNewPanel( pCommentaryPanel, "PANEL_COMMENTARY_MODELVIEWER" ); + } + + if ( pCommentaryPanel ) + { + //((CCommentaryModelViewer*)pCommentaryPanel)->InvalidateLayout( false, true ); + ((CCommentaryModelViewer*)pCommentaryPanel)->SetModel( args[1], args[2] ); + pViewport->ShowPanel( pCommentaryPanel, true ); + } + } +} + +ConCommand commentary_showmodelviewer( "commentary_showmodelviewer", CommentaryShowModelViewer, "Display the commentary model viewer. Usage: commentary_showmodelviewer ", FCVAR_NONE ); diff --git a/src/src/game/client/commentary_modelviewer.h b/src/src/game/client/commentary_modelviewer.h new file mode 100644 index 0000000..4fa1d87 --- /dev/null +++ b/src/src/game/client/commentary_modelviewer.h @@ -0,0 +1,75 @@ +//========= Copyright © 1996-2006, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef COMMENTARY_MODELVIEWER_H +#define COMMENTARY_MODELVIEWER_H +#ifdef _WIN32 +#pragma once +#endif + +#include +#include +#include "basemodelpanel.h" + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CCommentaryModelPanel : public CModelPanel +{ +public: + DECLARE_CLASS_SIMPLE( CCommentaryModelPanel, CModelPanel ); + + CCommentaryModelPanel( vgui::Panel *parent, const char *name ); +}; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CCommentaryModelViewer : public vgui::Frame, public IViewPortPanel +{ + DECLARE_CLASS_SIMPLE( CCommentaryModelViewer, vgui::Frame ); +public: + CCommentaryModelViewer(IViewPort *pViewPort); + virtual ~CCommentaryModelViewer(); + + virtual void ApplySchemeSettings( vgui::IScheme *pScheme ); + virtual void PerformLayout( void ); + virtual void OnCommand( const char *command ); + virtual void OnKeyCodePressed( vgui::KeyCode code ); + virtual void OnThink( void ); + + void SetModel( const char *pszName, const char *pszAttached ); + + void HandleMovementInput( void ); + + // IViewPortPanel +public: + virtual const char *GetName( void ) { return PANEL_COMMENTARY_MODELVIEWER; } + virtual void SetData(KeyValues *data) {}; + virtual void Reset() {}; + virtual void Update() {}; + virtual bool NeedsUpdate( void ) { return false; } + virtual bool HasInputElements( void ) { return true; } + virtual void ShowPanel( bool bShow ); + + // both vgui::Frame and IViewPortPanel define these, so explicitly define them here as passthroughs to vgui + vgui::VPANEL GetVPanel( void ) { return BaseClass::GetVPanel(); } + virtual bool IsVisible() { return BaseClass::IsVisible(); } + virtual void SetParent( vgui::VPANEL parent ) { BaseClass::SetParent( parent ); } + +private: + IViewPort *m_pViewPort; + CCommentaryModelPanel *m_pModelPanel; + + Vector m_vecResetPos; + Vector m_vecResetAngles; + bool m_bTranslating; + float m_flYawSpeed; + float m_flZoomSpeed; +}; + +#endif // COMMENTARY_MODELVIEWER_H diff --git a/src/src/cl_dll/death.cpp b/src/src/game/client/death.cpp similarity index 96% rename from src/src/cl_dll/death.cpp rename to src/src/game/client/death.cpp index 9def93e..2391f83 100644 --- a/src/src/cl_dll/death.cpp +++ b/src/src/game/client/death.cpp @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include @@ -88,6 +88,7 @@ struct DeathNoticeItem { static int DEATHNOTICE_DISPLAY_TIME = 6; // Robin HACKHACK: HL2 doesn't use deathmsgs, so I just forced these down below our minimap. +// It should be positioned by TF2/HL2 separately, and TF2 should position it according to the minimap position #define DEATHNOTICE_TOP YRES( 140 ) // Was: 20 DeathNoticeItem rgDeathNoticeList[ MAX_DEATHNOTICES + 1 ]; @@ -156,8 +157,8 @@ void CHudDeathNotice::Paint() wchar_t victim[ 256 ]; wchar_t killer[ 256 ]; - vgui::localize()->ConvertANSIToUnicode( rgDeathNoticeList[i].szVictim, victim, sizeof( victim ) ); - vgui::localize()->ConvertANSIToUnicode( rgDeathNoticeList[i].szKiller, killer, sizeof( killer ) ); + g_pVGuiLocalize->ConvertANSIToUnicode( rgDeathNoticeList[i].szVictim, victim, sizeof( victim ) ); + g_pVGuiLocalize->ConvertANSIToUnicode( rgDeathNoticeList[i].szKiller, killer, sizeof( killer ) ); int len = UTIL_ComputeStringWidth( m_hTextFont, victim ); diff --git a/src/src/cl_dll/detailobjectsystem.cpp b/src/src/game/client/detailobjectsystem.cpp similarity index 60% rename from src/src/cl_dll/detailobjectsystem.cpp rename to src/src/game/client/detailobjectsystem.cpp index 6d77a5a..4575b94 100644 --- a/src/src/cl_dll/detailobjectsystem.cpp +++ b/src/src/game/client/detailobjectsystem.cpp @@ -1,4 +1,4 @@ -//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: Draws grasses and other small objects // @@ -6,6 +6,7 @@ // $NoKeywords: $ //===========================================================================// #include "cbase.h" +#include #include "DetailObjectSystem.h" #include "GameBspFile.h" #include "UtlBuffer.h" @@ -19,10 +20,11 @@ #include "materialsystem/IMesh.h" #include "model_types.h" #include "env_detail_controller.h" -#include "vstdlib/icommandline.h" +#include "tier0/icommandline.h" #include "c_world.h" -#if defined(DOD_DLL) || defined(CSTRIKE_DLL) +//Tony; add the SDK into this as well by default. +#if defined(DOD_DLL) || defined(CSTRIKE_DLL) || defined( SDK_DLL ) #define USE_DETAIL_SHAPES #endif @@ -75,6 +77,20 @@ struct DetailModelAdvInfo_t }; +class CDetailObjectSystemPerLeafData +{ + unsigned short m_FirstDetailProp; + unsigned short m_DetailPropCount; + int m_DetailPropRenderFrame; + + CDetailObjectSystemPerLeafData( void ) + { + m_FirstDetailProp = 0; + m_DetailPropCount = 0; + m_DetailPropRenderFrame = -1; + } +}; + //----------------------------------------------------------------------------- // Detail models //----------------------------------------------------------------------------- @@ -98,9 +114,11 @@ public: bool Init( int index, const Vector& org, const QAngle& angles, model_t* pModel, ColorRGBExp32 lighting, int lightstyle, unsigned char lightstylecount, int orientation ); - bool InitSprite( int index, const Vector& org, const QAngle& angles, unsigned short nSpriteIndex, - ColorRGBExp32 lighting, int lightstyle, unsigned char lightstylecount, int orientation, float flScale, - unsigned char type, unsigned char shapeAngle, unsigned char shapeSize, unsigned char swayAmount ); + bool InitSprite( int index, bool bFlipped, const Vector& org, const QAngle& angles, + unsigned short nSpriteIndex, + ColorRGBExp32 lighting, int lightstyle, unsigned char lightstylecount, + int orientation, float flScale, unsigned char type, + unsigned char shapeAngle, unsigned char shapeSize, unsigned char swayAmount ); void SetAlpha( unsigned char alpha ) { m_Alpha = alpha; } @@ -125,13 +143,16 @@ public: virtual const QAngle& GetRenderAngles( ); virtual const matrix3x4_t & RenderableToWorldTransform(); virtual bool ShouldDraw(); + virtual bool IsTwoPass( void ) { return false; } + virtual void OnThreadedDrawSetup() {} virtual bool IsTransparent( void ); virtual const model_t* GetModel( ) const; virtual int DrawModel( int flags ); virtual void ComputeFxBlend( ); virtual int GetFxBlend( ); virtual bool SetupBones( matrix3x4_t *pBoneToWorldOut, int nMaxBones, int boneMask, float currentTime ); - virtual void SetupWeights( void ); + virtual void SetupWeights( const matrix3x4_t *pBoneToWorld, int nFlexWeightCount, float *pFlexWeights, float *pFlexDelayedWeights ); + virtual bool UsesFlexDelayedWeights() { return false; } virtual void DoAnimationEvents( void ); virtual void GetRenderBounds( Vector& mins, Vector& maxs ); virtual IPVSNotify* GetPVSNotifyInterface(); @@ -139,7 +160,8 @@ public: virtual bool ShouldReceiveProjectedTextures( int flags ); virtual bool GetShadowCastDistance( float *pDist, ShadowType_t shadowType ) const { return false; } virtual bool GetShadowCastDirection( Vector *pDirection, ShadowType_t shadowType ) const { return false; } - virtual bool UsesFrameBufferTexture(); + virtual bool UsesPowerOfTwoFrameBufferTexture(); + virtual bool UsesFullFrameBufferTexture(); virtual bool LODTest() { return true; } virtual ClientShadowHandle_t GetShadowHandle() const; @@ -156,8 +178,9 @@ public: virtual int LookupAttachment( const char *pAttachmentName ) { return -1; } virtual bool GetAttachment( int number, matrix3x4_t &matrix ); virtual bool GetAttachment( int number, Vector &origin, QAngle &angles ); - virtual float * GetRenderClipPlane( void ) { return NULL; } - virtual int GetSkin( void ) { return 0; } + virtual float * GetRenderClipPlane() { return NULL; } + virtual int GetSkin() { return 0; } + virtual void RecordToolMessage() {} void GetColorModulation( float* color ); @@ -173,6 +196,7 @@ public: // Draw functions for the different types of sprite void DrawTypeSprite( CMeshBuilder &meshBuilder ); + #ifdef USE_DETAIL_SHAPES void DrawTypeShapeCross( CMeshBuilder &meshBuilder ); void DrawTypeShapeTri( CMeshBuilder &meshBuilder ); @@ -241,7 +265,7 @@ extern ConVar r_DrawDetailProps; //----------------------------------------------------------------------------- // Dictionary for detail sprites //----------------------------------------------------------------------------- -struct DetailPropSpriteDict_t +struct DetailPropSpriteDict_t { Vector2D m_UL; // Coordinate of upper left Vector2D m_LR; // Coordinate of lower right @@ -249,6 +273,78 @@ struct DetailPropSpriteDict_t Vector2D m_TexLR; // Texcoords of lower left }; +struct FastSpriteX4_t +{ + // mess with this structure without care and you'll be in a world of trouble. layout matters. + FourVectors m_Pos; + fltx4 m_HalfWidth; + fltx4 m_Height; + uint8 m_RGBColor[4][4]; + DetailPropSpriteDict_t *m_pSpriteDefs[4]; + + void ReplicateFirstEntryToOthers( void ) + { + m_HalfWidth = ReplicateX4( SubFloat( m_HalfWidth, 0 ) ); + m_Height = ReplicateX4( SubFloat( m_Height, 0 ) ); + + for( int i = 1; i < 4; i++ ) + for( int j = 0; j < 4; j++ ) + { + m_RGBColor[i][j] = m_RGBColor[0][j]; + } + m_Pos.x = ReplicateX4( SubFloat( m_Pos.x, 0 ) ); + m_Pos.y = ReplicateX4( SubFloat( m_Pos.y, 0 ) ); + m_Pos.z = ReplicateX4( SubFloat( m_Pos.z, 0 ) ); + } + +}; + + +struct FastSpriteQuadBuildoutBufferX4_t +{ + // mess with this structure without care and you'll be in a world of trouble. layout matters. + FourVectors m_Coords[4]; + uint8 m_RGBColor[4][4]; + fltx4 m_Alpha; + DetailPropSpriteDict_t *m_pSpriteDefs[4]; +}; + +struct FastSpriteQuadBuildoutBufferNonSIMDView_t +{ + // mess with this structure without care and you'll be in a world of trouble. layout matters. + float m_flX0[4], m_flY0[4], m_flZ0[4]; + float m_flX1[4], m_flY1[4], m_flZ1[4]; + float m_flX2[4], m_flY2[4], m_flZ2[4]; + float m_flX3[4], m_flY3[4], m_flZ3[4]; + + uint8 m_RGBColor[4][4]; + float m_Alpha[4]; + DetailPropSpriteDict_t *m_pSpriteDefs[4]; +}; + + +class CFastDetailLeafSpriteList : public CClientLeafSubSystemData +{ + friend class CDetailObjectSystem; + int m_nNumSprites; + int m_nNumSIMDSprites; // #sprites/4, rounded up + // simd pointers into larger array - don't free individually or you will be sad + FastSpriteX4_t *m_pSprites; + + // state for partially drawn sprite lists + int m_nNumPendingSprites; + int m_nStartSpriteIndex; + + CFastDetailLeafSpriteList( void ) + { + m_nNumPendingSprites = 0; + m_nStartSpriteIndex = 0; + } + +}; + + + //----------------------------------------------------------------------------- // Responsible for managing detail objects @@ -256,50 +352,54 @@ struct DetailPropSpriteDict_t class CDetailObjectSystem : public IDetailObjectSystem, public ISpatialLeafEnumerator { public: - virtual char const *Name() { return "DetailObjectSystem"; } + char const *Name() { return "DetailObjectSystem"; } // constructor, destructor CDetailObjectSystem(); - virtual ~CDetailObjectSystem(); + ~CDetailObjectSystem(); - virtual bool IsPerFrame() { return false; } + bool IsPerFrame() { return false; } // Init, shutdown - virtual bool Init() + bool Init() { m_flDefaultFadeStart = cl_detailfade.GetFloat(); m_flDefaultFadeEnd = cl_detaildist.GetFloat(); return true; } - virtual void Shutdown() {} + void PostInit() {} + void Shutdown() {} // Level init, shutdown - virtual void LevelInitPreEntity(); - virtual void LevelInitPostEntity(); - virtual void LevelShutdownPreEntity(); - virtual void LevelShutdownPostEntity(); + void LevelInitPreEntity(); + void LevelInitPostEntity(); + void LevelShutdownPreEntity(); + void LevelShutdownPostEntity(); - virtual void OnSave() {} - virtual void OnRestore() {} - virtual void SafeRemoveIfDesired() {} + void OnSave() {} + void OnRestore() {} + void SafeRemoveIfDesired() {} // Gets a particular detail object - virtual IClientRenderable* GetDetailModel( int idx ); + IClientRenderable* GetDetailModel( int idx ); // Prepares detail for rendering - virtual void BuildDetailObjectRenderLists( ); + void BuildDetailObjectRenderLists( const Vector &vViewOrigin ); // Renders all opaque detail objects in a particular set of leaves - virtual void RenderOpaqueDetailObjects( int nLeafCount, LeafIndex_t *pLeafList ); + void RenderOpaqueDetailObjects( int nLeafCount, LeafIndex_t *pLeafList ); // Renders all translucent detail objects in a particular set of leaves - virtual void RenderTranslucentDetailObjects( const Vector &viewOrigin, const Vector &viewForward, int nLeafCount, LeafIndex_t *pLeafList ); + void RenderTranslucentDetailObjects( const Vector &viewOrigin, const Vector &viewForward, const Vector &viewRight, const Vector &viewUp, int nLeafCount, LeafIndex_t *pLeafList ); // Renders all translucent detail objects in a particular leaf up to a particular point - virtual void RenderTranslucentDetailObjectsInLeaf( const Vector &viewOrigin, const Vector &viewForward, int nLeaf, const Vector *pVecClosestPoint ); + void RenderTranslucentDetailObjectsInLeaf( const Vector &viewOrigin, const Vector &viewForward, const Vector &viewRight, const Vector &viewUp, int nLeaf, const Vector *pVecClosestPoint ); + void RenderFastTranslucentDetailObjectsInLeaf( const Vector &viewOrigin, const Vector &viewForward, const Vector &viewRight, const Vector &viewUp, int nLeaf, const Vector *pVecClosestPoint ); + + // Call this before rendering translucent detail objects - virtual void BeginTranslucentDetailRendering( ); + void BeginTranslucentDetailRendering( ); // Method of ISpatialLeafEnumerator bool EnumerateLeaf( int leaf, int context ); @@ -315,9 +415,7 @@ private: struct EnumContext_t { - float m_MaxSqDist; - float m_FadeSqDist; - float m_FalloffFactor; + Vector m_vViewOrigin; int m_BuildWorldListNumber; }; @@ -327,25 +425,39 @@ private: float m_flDistance; }; - enum - { - MAX_SPRITES_PER_LEAF = 4096 - }; + int BuildOutSortedSprites( CFastDetailLeafSpriteList *pData, + Vector const &viewOrigin, + Vector const &viewForward, + Vector const &viewRight, + Vector const &viewUp ); + + void RenderFastSprites( const Vector &viewOrigin, const Vector &viewForward, const Vector &viewRight, const Vector &viewUp, int nLeafCount, LeafIndex_t const * pLeafList ); + + void UnserializeFastSprite( FastSpriteX4_t *pSpritex4, int nSubField, DetailObjectLump_t const &lump, bool bFlipped, Vector const &posOffset ); // Unserialization + void ScanForCounts( CUtlBuffer& buf, int *pNumOldStyleObjects, + int *pNumFastSpritesToAllocate, int *nMaxOldInLeaf, + int *nMaxFastInLeaf ) const; + void UnserializeModelDict( CUtlBuffer& buf ); void UnserializeDetailSprites( CUtlBuffer& buf ); void UnserializeModels( CUtlBuffer& buf ); void UnserializeModelLighting( CUtlBuffer& buf ); + Vector GetSpriteMiddleBottomPosition( DetailObjectLump_t const &lump ) const; // Count the number of detail sprites in the leaf list - int CountSpritesInLeafList( int nLeafCount, LeafIndex_t *pLeafList ); + int CountSpritesInLeafList( int nLeafCount, LeafIndex_t *pLeafList ) const; // Count the number of detail sprite quads in the leaf list - int CountSpriteQuadsInLeafList( int nLeafCount, LeafIndex_t *pLeafList ); + int CountSpriteQuadsInLeafList( int nLeafCount, LeafIndex_t *pLeafList ) const; + + int CountFastSpritesInLeafList( int nLeafCount, LeafIndex_t const *pLeafList, int *nMaxInLeaf ) const; + + void FreeSortBuffers( void ); // Sorts sprites in back-to-front order - static int __cdecl SortFunc( const void *arg1, const void *arg2 ); + static bool SortLessFunc( const SortInfo_t &left, const SortInfo_t &right ); int SortSpritesBackToFront( int nLeaf, const Vector &viewOrigin, const Vector &viewForward, SortInfo_t *pSortInfo ); // For fast detail object insertion @@ -354,7 +466,9 @@ private: CUtlVector m_DetailObjectDict; CUtlVector m_DetailObjects; CUtlVector m_DetailSpriteDict; + CUtlVector m_DetailSpriteDictFlipped; CUtlVector m_DetailLighting; + FastSpriteX4_t *m_pFastSpriteData; // Necessary to get sprites to batch correctly CMaterialReference m_DetailSpriteMaterial; @@ -364,10 +478,20 @@ private: int m_nSpriteCount; int m_nFirstSprite; int m_nSortedLeaf; - SortInfo_t m_pSortInfo[MAX_SPRITES_PER_LEAF]; + int m_nSortedFastLeaf; + SortInfo_t *m_pSortInfo; + SortInfo_t *m_pFastSortInfo; + FastSpriteQuadBuildoutBufferX4_t *m_pBuildoutBuffer; float m_flDefaultFadeStart; float m_flDefaultFadeEnd; + + + // pre calcs for the current render frame + float m_flCurMaxSqDist; + float m_flCurFadeSqDist; + float m_flCurFalloffFactor; + }; @@ -492,7 +616,12 @@ bool CDetailModel::ShouldReceiveProjectedTextures( int flags ) return false; } -bool CDetailModel::UsesFrameBufferTexture() +bool CDetailModel::UsesPowerOfTwoFrameBufferTexture() +{ + return false; +} + +bool CDetailModel::UsesFullFrameBufferTexture() { return false; } @@ -541,7 +670,7 @@ bool CDetailModel::SetupBones( matrix3x4_t *pBoneToWorldOut, int nMaxBones, int return true; } -void CDetailModel::SetupWeights( void ) +void CDetailModel::SetupWeights( const matrix3x4_t *pBoneToWorld, int nFlexWeightCount, float *pFlexWeights, float *pFlexDelayedWeights ) { } @@ -649,7 +778,7 @@ bool CDetailModel::Init( int index, const Vector& org, const QAngle& angles, return InitCommon( index, org, angles ); } -bool CDetailModel::InitSprite( int index, const Vector& org, const QAngle& angles, unsigned short nSpriteIndex, +bool CDetailModel::InitSprite( int index, bool bFlipped, const Vector& org, const QAngle& angles, unsigned short nSpriteIndex, ColorRGBExp32 lighting, int lightstyle, unsigned char lightstylecount, int orientation, float flScale, unsigned char type, unsigned char shapeAngle, unsigned char shapeSize, unsigned char swayAmount ) { @@ -680,7 +809,7 @@ bool CDetailModel::InitSprite( int index, const Vector& org, const QAngle& angle #endif - m_bFlipped = ( (index & 0x1) == 1 ); + m_bFlipped = bFlipped; return InitCommon( index, org, angles ); } @@ -1264,13 +1393,42 @@ void CDetailModel::DrawSwayingQuad( CMeshBuilder &meshBuilder, Vector vecOrigin, //----------------------------------------------------------------------------- // constructor, destructor //----------------------------------------------------------------------------- -CDetailObjectSystem::CDetailObjectSystem() : m_DetailSpriteDict( 0, 32 ), m_DetailObjectDict( 0, 32 ) +CDetailObjectSystem::CDetailObjectSystem() : m_DetailSpriteDict( 0, 32 ), m_DetailObjectDict( 0, 32 ), m_DetailSpriteDictFlipped( 0, 32 ) { - BuildExponentTable(); + m_pFastSpriteData = NULL; + m_pSortInfo = NULL; + m_pFastSortInfo = NULL; + m_pBuildoutBuffer = NULL; +} + +void CDetailObjectSystem::FreeSortBuffers( void ) +{ + if ( m_pSortInfo ) + { + MemAlloc_FreeAligned( m_pSortInfo ); + m_pSortInfo = NULL; + } + if ( m_pFastSortInfo ) + { + MemAlloc_FreeAligned( m_pFastSortInfo ); + m_pFastSortInfo = NULL; + } + if ( m_pBuildoutBuffer ) + { + MemAlloc_FreeAligned( m_pBuildoutBuffer ); + m_pBuildoutBuffer = NULL; + } } CDetailObjectSystem::~CDetailObjectSystem() { + if ( m_pFastSpriteData ) + { + MemAlloc_FreeAligned( m_pFastSpriteData ); + m_pFastSpriteData = NULL; + } + FreeSortBuffers(); + } @@ -1290,6 +1448,8 @@ void CDetailObjectSystem::LevelInitPreEntity() return; } + MEM_ALLOC_CREDIT(); + // Unserialize int size = engine->GameLumpSize( GAMELUMP_DETAIL_PROPS ); CUtlMemory fileMemory; @@ -1308,10 +1468,23 @@ void CDetailObjectSystem::LevelInitPreEntity() } } - if ( m_DetailObjects.Count() != 0 ) + if ( m_DetailObjects.Count() || m_DetailSpriteDict.Count() ) { // There are detail objects in the level, so precache the material PrecacheMaterial( DETAIL_SPRITE_MATERIAL ); + IMaterial *pMat = m_DetailSpriteMaterial; + // adjust for non-square textures (cropped) + float flRatio = pMat->GetMappingWidth() / pMat->GetMappingHeight(); + if ( flRatio > 1.0 ) + { + for( int i = 0; i= 0 ) { int i = m_DetailSpriteDict.AddToTail(); buf.Get( &m_DetailSpriteDict[i], sizeof(DetailSpriteDictLump_t) ); + int flipi = m_DetailSpriteDictFlipped.AddToTail(); + m_DetailSpriteDictFlipped[flipi] = m_DetailSpriteDict[i]; + swap( m_DetailSpriteDictFlipped[flipi].m_TexUL.x, m_DetailSpriteDictFlipped[flipi].m_TexLR.x ); } } @@ -1452,29 +1631,165 @@ void CDetailObjectSystem::UnserializeModelLighting( CUtlBuffer& buf ) } -//----------------------------------------------------------------------------- -// Unserialize all models -//----------------------------------------------------------------------------- -void CDetailObjectSystem::UnserializeModels( CUtlBuffer& buf ) +ConVar cl_detail_multiplier( "cl_detail_multiplier", "1", FCVAR_CHEAT, "extra details to create" ); + +#define SPRITE_MULTIPLIER ( cl_detail_multiplier.GetInt() ) + +ConVar cl_fastdetailsprites( "cl_fastdetailsprites", "1", FCVAR_CHEAT, "whether to use new detail sprite system"); + +static bool DetailObjectIsFastSprite( DetailObjectLump_t const & lump ) { - int firstDetailObject = 0; - int detailObjectCount = 0; + return ( + ( cl_fastdetailsprites.GetInt() ) && + ( lump.m_Type == DETAIL_PROP_TYPE_SPRITE ) && + ( lump.m_LightStyleCount == 0 ) && + ( lump.m_Orientation == 2 ) && + ( lump.m_ShapeAngle == 0 ) && + ( lump.m_ShapeSize == 0 ) && + ( lump.m_SwayAmount == 0 ) ); +} + + +void CDetailObjectSystem::ScanForCounts( CUtlBuffer& buf, + int *pNumOldStyleObjects, + int *pNumFastSpritesToAllocate, + int *nMaxNumOldSpritesInLeaf, + int *nMaxNumFastSpritesInLeaf + ) const +{ + int oldpos = buf.TellGet(); // we need to seek back + int count = buf.GetInt(); + + int nOld = 0; + int nFast = 0; int detailObjectLeaf = -1; - int count = buf.GetInt(); - m_DetailObjects.EnsureCapacity( count ); - + int nNumOldInLeaf = 0; + int nNumFastInLeaf = 0; + int nMaxOld = 0; + int nMaxFast = 0; while ( --count >= 0 ) { DetailObjectLump_t lump; buf.Get( &lump, sizeof(DetailObjectLump_t) ); + // We rely on the fact that details objects are sorted by leaf in the + // bsp file for this + if ( detailObjectLeaf != lump.m_Leaf ) + { + // need to pad nfast to next sse boundary + nFast += ( 0 - nFast ) & 3; + nMaxFast = max( nMaxFast, nNumFastInLeaf ); + nMaxOld = max( nMaxOld, nNumOldInLeaf ); + nNumOldInLeaf = 0; + nNumFastInLeaf = 0; + detailObjectLeaf = lump.m_Leaf; + + } + + if ( DetailObjectIsFastSprite( lump ) ) + { + nFast += SPRITE_MULTIPLIER; + nNumFastInLeaf += SPRITE_MULTIPLIER; + } + else + { + nOld += SPRITE_MULTIPLIER; + nNumOldInLeaf += SPRITE_MULTIPLIER; + } + } + + // need to pad nfast to next sse boundary + nFast += ( 0 - nFast ) & 3; + nMaxFast = max( nMaxFast, nNumFastInLeaf ); + nMaxOld = max( nMaxOld, nNumOldInLeaf ); + + buf.SeekGet( CUtlBuffer::SEEK_HEAD, oldpos ); + *pNumFastSpritesToAllocate = nFast; + *pNumOldStyleObjects = nOld; + nMaxFast = ( 3 + nMaxFast ) & ~3; + *nMaxNumOldSpritesInLeaf = nMaxOld; + *nMaxNumFastSpritesInLeaf = nMaxFast; + +} + +//----------------------------------------------------------------------------- +// Unserialize all models +//----------------------------------------------------------------------------- +void CDetailObjectSystem::UnserializeModels( CUtlBuffer& buf ) +{ + int firstDetailObject = 0; + int detailObjectCount = 0; + int detailObjectLeaf = -1; + + int nNumOldStyleObjects; + int nNumFastSpritesToAllocate; + int nMaxOldInLeaf; + int nMaxFastInLeaf; + ScanForCounts( buf, &nNumOldStyleObjects, &nNumFastSpritesToAllocate, &nMaxOldInLeaf, &nMaxFastInLeaf ); + + FreeSortBuffers(); + + if ( nMaxOldInLeaf ) + { + m_pSortInfo = reinterpret_cast ( + MemAlloc_AllocAligned( (3 + nMaxOldInLeaf ) * sizeof( SortInfo_t ), sizeof( fltx4 ) ) ); + } + if ( nMaxFastInLeaf ) + { + m_pFastSortInfo = reinterpret_cast ( + MemAlloc_AllocAligned( (3 + nMaxFastInLeaf ) * sizeof( SortInfo_t ), sizeof( fltx4 ) ) ); + + m_pBuildoutBuffer = reinterpret_cast ( + MemAlloc_AllocAligned( + ( 1 + nMaxFastInLeaf / 4 ) * sizeof( FastSpriteQuadBuildoutBufferX4_t ), + sizeof( fltx4 ) ) ); + } + + if ( nNumFastSpritesToAllocate ) + { + Assert( ( nNumFastSpritesToAllocate & 3 ) == 0 ); + Assert( ! m_pFastSpriteData ); // wtf? didn't free? + m_pFastSpriteData = reinterpret_cast ( + MemAlloc_AllocAligned( + ( nNumFastSpritesToAllocate >> 2 ) * sizeof( FastSpriteX4_t ), + sizeof( fltx4 ) ) ); + } + + m_DetailObjects.EnsureCapacity( nNumOldStyleObjects ); + + int count = buf.GetInt(); + + int nCurFastObject = 0; + int nNumFastObjectsInCurLeaf = 0; + FastSpriteX4_t *pCurFastSpriteOut = m_pFastSpriteData; + + bool bFlipped = true; + while ( --count >= 0 ) + { + bFlipped = !bFlipped; + DetailObjectLump_t lump; + buf.Get( &lump, sizeof(DetailObjectLump_t) ); + // We rely on the fact that details objects are sorted by leaf in the // bsp file for this if ( detailObjectLeaf != lump.m_Leaf ) { if (detailObjectLeaf != -1) { + if ( nNumFastObjectsInCurLeaf ) + { + CFastDetailLeafSpriteList *pNew = new CFastDetailLeafSpriteList; + pNew->m_nNumSprites = nNumFastObjectsInCurLeaf; + pNew->m_nNumSIMDSprites = ( 3 + nNumFastObjectsInCurLeaf ) >> 2; + pNew->m_pSprites = pCurFastSpriteOut; + pCurFastSpriteOut += pNew->m_nNumSIMDSprites; + ClientLeafSystem()->SetSubSystemDataInLeaf( + detailObjectLeaf, CLSUBSYSTEM_DETAILOBJECTS, pNew ); + // round to see boundary + nCurFastObject += ( 0 - nCurFastObject ) & 3; + nNumFastObjectsInCurLeaf = 0; + } ClientLeafSystem()->SetDetailObjectsInLeaf( detailObjectLeaf, firstDetailObject, detailObjectCount ); } @@ -1484,36 +1799,150 @@ void CDetailObjectSystem::UnserializeModels( CUtlBuffer& buf ) detailObjectCount = 0; } - if ( lump.m_Type == DETAIL_PROP_TYPE_MODEL ) + if ( DetailObjectIsFastSprite( lump ) ) { - if ( IsPC() ) + for( int i =0 ; i < SPRITE_MULTIPLIER ; i++) { - int newObj = m_DetailObjects.AddToTail(); - m_DetailObjects[newObj].Init( newObj, lump.m_Origin, lump.m_Angles, - m_DetailObjectDict[lump.m_DetailModel].m_pModel, lump.m_Lighting, - lump.m_LightStyles, lump.m_LightStyleCount, lump.m_Orientation ); - ++detailObjectCount; + FastSpriteX4_t *pSpritex4 = m_pFastSpriteData + (nCurFastObject >> 2 ); + int nSubField = ( nCurFastObject & 3 ); + Vector pos(0,0,0); + if ( i ) + { + pos += RandomVector( -50, 50 ); + pos.z = 0; + } + UnserializeFastSprite( pSpritex4, nSubField, lump, bFlipped, pos ); + if ( nSubField == 0 ) + pSpritex4->ReplicateFirstEntryToOthers(); // keep bad numbers out to prevent denormals, etc + nCurFastObject++; + nNumFastObjectsInCurLeaf++; } } else { - int newObj = m_DetailObjects.AddToTail(); - m_DetailObjects[newObj].InitSprite( newObj, lump.m_Origin, lump.m_Angles, - lump.m_DetailModel, lump.m_Lighting, - lump.m_LightStyles, lump.m_LightStyleCount, lump.m_Orientation, lump.m_flScale, - lump.m_Type, lump.m_ShapeAngle, lump.m_ShapeSize, lump.m_SwayAmount ); - ++detailObjectCount; + switch( lump.m_Type ) + { + case DETAIL_PROP_TYPE_MODEL: + { + int newObj = m_DetailObjects.AddToTail(); + m_DetailObjects[newObj].Init( + newObj, lump.m_Origin, lump.m_Angles, + m_DetailObjectDict[lump.m_DetailModel].m_pModel, lump.m_Lighting, + lump.m_LightStyles, lump.m_LightStyleCount, lump.m_Orientation ); + ++detailObjectCount; + } + break; + + case DETAIL_PROP_TYPE_SPRITE: + case DETAIL_PROP_TYPE_SHAPE_CROSS: + case DETAIL_PROP_TYPE_SHAPE_TRI: + { + for( int i=0;im_nNumSprites = nNumFastObjectsInCurLeaf; + pNew->m_nNumSIMDSprites = ( 3 + nNumFastObjectsInCurLeaf ) >> 2; + pNew->m_pSprites = pCurFastSpriteOut; + pCurFastSpriteOut += pNew->m_nNumSIMDSprites; + ClientLeafSystem()->SetSubSystemDataInLeaf( + detailObjectLeaf, CLSUBSYSTEM_DETAILOBJECTS, pNew ); + } ClientLeafSystem()->SetDetailObjectsInLeaf( detailObjectLeaf, - firstDetailObject, detailObjectCount ); + firstDetailObject, detailObjectCount ); } } +Vector CDetailObjectSystem::GetSpriteMiddleBottomPosition( DetailObjectLump_t const &lump ) const +{ + DetailPropSpriteDict_t &dict = s_DetailObjectSystem.DetailSpriteDict( lump.m_DetailModel ); + + Vector vecDir; + QAngle Angles; + + VectorSubtract( lump.m_Origin + Vector(0,-100,0), lump.m_Origin, vecDir ); + vecDir.z = 0.0f; + VectorAngles( vecDir, Angles ); + + Vector vecOrigin, dx, dy; + AngleVectors( Angles, NULL, &dx, &dy ); + + Vector2D ul, lr; + float scale = lump.m_flScale; + Vector2DMultiply( dict.m_UL, scale, ul ); + Vector2DMultiply( dict.m_LR, scale, lr ); + + VectorMA( lump.m_Origin, ul.x, dx, vecOrigin ); + VectorMA( vecOrigin, ul.y, dy, vecOrigin ); + dx *= (lr.x - ul.x); + dy *= (lr.y - ul.y); + + Vector2D texul, texlr; + texul = dict.m_TexUL; + texlr = dict.m_TexLR; + + return vecOrigin + dy + 0.5 * dx; +} + + +void CDetailObjectSystem::UnserializeFastSprite( FastSpriteX4_t *pSpritex4, int nSubField, DetailObjectLump_t const &lump, bool bFlipped, Vector const &posOffset ) +{ + Vector pos = lump.m_Origin + posOffset; + pos = GetSpriteMiddleBottomPosition( lump ) + posOffset; + + pSpritex4->m_Pos.X( nSubField ) = pos.x; + pSpritex4->m_Pos.Y( nSubField ) = pos.y; + pSpritex4->m_Pos.Z( nSubField ) = pos.z; + DetailPropSpriteDict_t *pSDef = &m_DetailSpriteDict[lump.m_DetailModel]; + + SubFloat( pSpritex4->m_HalfWidth, nSubField ) = 0.5 * lump.m_flScale * ( pSDef->m_LR.x - pSDef->m_UL.x ); + SubFloat( pSpritex4->m_Height, nSubField ) = lump.m_flScale * ( pSDef->m_LR.y - pSDef->m_UL.y ); + if ( !bFlipped ) + { + pSDef = &m_DetailSpriteDictFlipped[lump.m_DetailModel]; + } + // do packed color + ColorRGBExp32 rgbcolor = lump.m_Lighting; + float color[4]; + color[0] = TexLightToLinear( rgbcolor.r, rgbcolor.exponent ); + color[1] = TexLightToLinear( rgbcolor.g, rgbcolor.exponent ); + color[2] = TexLightToLinear( rgbcolor.b, rgbcolor.exponent ); + color[3] = 255; + engine->LinearToGamma( color, color ); + pSpritex4->m_RGBColor[nSubField][0] = 255.0 * color[0]; + pSpritex4->m_RGBColor[nSubField][1] = 255.0 * color[1]; + pSpritex4->m_RGBColor[nSubField][2] = 255.0 * color[2]; + pSpritex4->m_RGBColor[nSubField][3] = 255; + + pSpritex4->m_pSpriteDefs[nSubField] = pSDef; +} + + //----------------------------------------------------------------------------- // Renders all opaque detail objects in a particular set of leaves @@ -1527,7 +1956,7 @@ void CDetailObjectSystem::RenderOpaqueDetailObjects( int nLeafCount, LeafIndex_t //----------------------------------------------------------------------------- // Count the number of detail sprites in the leaf list //----------------------------------------------------------------------------- -int CDetailObjectSystem::CountSpritesInLeafList( int nLeafCount, LeafIndex_t *pLeafList ) +int CDetailObjectSystem::CountSpritesInLeafList( int nLeafCount, LeafIndex_t *pLeafList ) const { VPROF_BUDGET( "CDetailObjectSystem::CountSpritesInLeafList", VPROF_BUDGETGROUP_DETAILPROP_RENDERING ); int nPropCount = 0; @@ -1543,11 +1972,34 @@ int CDetailObjectSystem::CountSpritesInLeafList( int nLeafCount, LeafIndex_t *pL return nPropCount; } +//----------------------------------------------------------------------------- +// Count the number of fast sprites in the leaf list +//----------------------------------------------------------------------------- +int CDetailObjectSystem::CountFastSpritesInLeafList( int nLeafCount, LeafIndex_t const *pLeafList, + int *nMaxFoundInLeaf ) const +{ + VPROF_BUDGET( "CDetailObjectSystem::CountSpritesInLeafList", VPROF_BUDGETGROUP_DETAILPROP_RENDERING ); + int nCount = 0; + int nMax = 0; + for ( int i = 0; i < nLeafCount; ++i ) + { + CFastDetailLeafSpriteList *pData = reinterpret_cast< CFastDetailLeafSpriteList *> ( + ClientLeafSystem()->GetSubSystemDataInLeaf( pLeafList[i], CLSUBSYSTEM_DETAILOBJECTS ) ); + if ( pData ) + { + nCount += pData->m_nNumSprites; + nMax = max( nMax, pData->m_nNumSprites ); + } + } + *nMaxFoundInLeaf = ( nMax + 3 ) & ~3; // round up + return nCount; +} + //----------------------------------------------------------------------------- // Count the number of detail sprite quads in the leaf list //----------------------------------------------------------------------------- -int CDetailObjectSystem::CountSpriteQuadsInLeafList( int nLeafCount, LeafIndex_t *pLeafList ) +int CDetailObjectSystem::CountSpriteQuadsInLeafList( int nLeafCount, LeafIndex_t *pLeafList ) const { #ifdef USE_DETAIL_SHAPES VPROF_BUDGET( "CDetailObjectSystem::CountSpritesInLeafList", VPROF_BUDGETGROUP_DETAILPROP_RENDERING ); @@ -1571,21 +2023,18 @@ int CDetailObjectSystem::CountSpriteQuadsInLeafList( int nLeafCount, LeafIndex_t } +#define TREATASINT(x) ( *( ( (int32 const *)( &(x) ) ) ) ) + //----------------------------------------------------------------------------- // Sorts sprites in back-to-front order //----------------------------------------------------------------------------- -int __cdecl CDetailObjectSystem::SortFunc( const void *arg1, const void *arg2 ) +inline bool CDetailObjectSystem::SortLessFunc( const CDetailObjectSystem::SortInfo_t &left, const CDetailObjectSystem::SortInfo_t &right ) { - // Therefore, things that are farther away in front of us (has a greater + distance) - // need to appear at the front of the list, hence the somewhat misleading code below - float flDelta = ((SortInfo_t*)arg1)->m_flDistance - ((SortInfo_t*)arg2)->m_flDistance; - if ( flDelta > 0 ) - return -1; - if ( flDelta < 0 ) - return 1; - return 0; + return TREATASINT( left.m_flDistance ) > TREATASINT( right.m_flDistance ); +// return left.m_flDistance > right.m_flDistance; } + int CDetailObjectSystem::SortSpritesBackToFront( int nLeaf, const Vector &viewOrigin, const Vector &viewForward, SortInfo_t *pSortInfo ) { VPROF_BUDGET( "CDetailObjectSystem::SortSpritesBackToFront", VPROF_BUDGETGROUP_DETAILPROP_RENDERING ); @@ -1596,12 +2045,17 @@ int CDetailObjectSystem::SortSpritesBackToFront( int nLeaf, const Vector &viewOr C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer(); if ( pLocalPlayer ) { - flFactor = pLocalPlayer->GetFOVDistanceAdjustFactor(); + flFactor = 1.0 / pLocalPlayer->GetFOVDistanceAdjustFactor(); } - float flMaxSqDist = cl_detaildist.GetFloat() * cl_detaildist.GetFloat(); - float flFadeSqDist = cl_detaildist.GetFloat() - cl_detailfade.GetFloat(); - flMaxSqDist /= flFactor; - flFadeSqDist /= flFactor; + + float flMaxSqDist; + float flFadeSqDist; + float flDetailDist = cl_detaildist.GetFloat(); + + flMaxSqDist = flDetailDist * flDetailDist; + flFadeSqDist = flDetailDist - cl_detailfade.GetFloat(); + flMaxSqDist *= flFactor; + flFadeSqDist *= flFactor; if (flFadeSqDist > 0) { flFadeSqDist *= flFadeSqDist; @@ -1614,13 +2068,14 @@ int CDetailObjectSystem::SortSpritesBackToFront( int nLeaf, const Vector &viewOr Vector vecDelta; int nCount = 0; - for ( int j = 0; j < nDetailObjectCount; ++j ) + nDetailObjectCount += nFirstDetailObject; + for ( int j = nFirstDetailObject; j < nDetailObjectCount; ++j ) { - CDetailModel &model = m_DetailObjects[nFirstDetailObject + j]; + CDetailModel &model = m_DetailObjects[j]; Vector v; - VectorSubtract( model.GetRenderOrigin(), viewOrigin, v ); - float flSqDist = v.LengthSqr(); + VectorSubtract( model.GetRenderOrigin(), viewOrigin, vecDelta ); + float flSqDist = vecDelta.LengthSqr(); if ( flSqDist >= flMaxSqDist ) continue; @@ -1633,29 +2088,279 @@ int CDetailObjectSystem::SortSpritesBackToFront( int nLeaf, const Vector &viewOr model.SetAlpha( 255 ); } - // Perform screen alignment if necessary. - model.ComputeAngles(); - - if ( IsPC() && ( (model.GetType() == DETAIL_PROP_TYPE_MODEL) || (model.GetAlpha() == 0) ) ) + if ( (model.GetType() == DETAIL_PROP_TYPE_MODEL) || (model.GetAlpha() == 0) ) continue; - pSortInfo[nCount].m_nIndex = nFirstDetailObject + j; + // Perform screen alignment if necessary. + model.ComputeAngles(); + SortInfo_t *pSortInfoCurrent = &pSortInfo[nCount]; + + pSortInfoCurrent->m_nIndex = j; // Compute distance from the camera to each object - VectorSubtract( model.GetRenderOrigin(), viewOrigin, vecDelta ); - pSortInfo[nCount].m_flDistance = vecDelta.LengthSqr(); //DotProduct( viewForward, vecDelta ); + pSortInfoCurrent->m_flDistance = flSqDist; ++nCount; } - qsort( pSortInfo, nCount, sizeof(SortInfo_t), SortFunc ); + if ( nCount ) + { + VPROF( "CDetailObjectSystem::SortSpritesBackToFront -- Sort" ); + std::make_heap( pSortInfo, pSortInfo + nCount, SortLessFunc ); + std::sort_heap( pSortInfo, pSortInfo + nCount, SortLessFunc ); + } + return nCount; } +#define MAGIC_NUMBER (1<<23) +#ifdef BIG_ENDIAN +#define MANTISSA_LSB_OFFSET 3 +#else +#define MANTISSA_LSB_OFFSET 0 +#endif +static fltx4 Four_MagicNumbers={ MAGIC_NUMBER, MAGIC_NUMBER, MAGIC_NUMBER, MAGIC_NUMBER }; +static fltx4 Four_255s={ 255.0, 255.0, 255.0, 255.0 }; + +static __declspec(align(16)) int32 And255Mask[4]= {0xff,0xff,0xff,0xff}; +#define PIXMASK ( * ( reinterpret_cast< fltx4 *>( &And255Mask ) ) ) + +int CDetailObjectSystem::BuildOutSortedSprites( CFastDetailLeafSpriteList *pData, + Vector const &viewOrigin, + Vector const &viewForward, + Vector const &viewRight, + Vector const &viewUp ) +{ + // part 1 - do all vertex math, fading, etc into a buffer, using as much simd as we can + int nSIMDSprites = pData->m_nNumSIMDSprites; + FastSpriteX4_t const *pSprites = pData->m_pSprites; + SortInfo_t *pOut = m_pFastSortInfo; + FastSpriteQuadBuildoutBufferX4_t *pQuadBufferOut = m_pBuildoutBuffer; + int curidx = 0; + int nLastBfMask = 0; + + FourVectors vecViewPos; + vecViewPos.DuplicateVector( viewOrigin ); + fltx4 maxsqdist = ReplicateX4( m_flCurMaxSqDist ); + + fltx4 falloffFactor = ReplicateX4( 1.0/ ( m_flCurMaxSqDist - m_flCurFadeSqDist ) ); + fltx4 startFade = ReplicateX4( m_flCurFadeSqDist ); + + FourVectors vecUp; + vecUp.DuplicateVector(Vector(0,0,1) ); + FourVectors vecFwd; + vecFwd.DuplicateVector( viewForward ); + + do + { + // calculate alpha + FourVectors ofs = pSprites->m_Pos; + ofs -= vecViewPos; + fltx4 ofsDotFwd = ofs * vecFwd; + fltx4 distanceSquared = ofs * ofs; + nLastBfMask = TestSignSIMD( OrSIMD( ofsDotFwd, CmpGtSIMD( distanceSquared, maxsqdist ) ) ); // cull + if ( nLastBfMask != 0xf ) + { + FourVectors dx1; + dx1.x = fnegate( ofs.y ); + dx1.y = ( ofs.x ); + dx1.z = Four_Zeros; + dx1.VectorNormalizeFast(); + + FourVectors vecDx = dx1; + FourVectors vecDy = vecUp; + + FourVectors vecPos0 = pSprites->m_Pos; + + vecDx *= pSprites->m_HalfWidth; + vecDy *= pSprites->m_Height; + fltx4 alpha = MulSIMD( falloffFactor, SubSIMD( distanceSquared, startFade ) ); + alpha = SubSIMD( Four_Ones, MinSIMD( MaxSIMD( alpha, Four_Zeros), Four_Ones ) ); + + pQuadBufferOut->m_Alpha = AddSIMD( Four_MagicNumbers, + MulSIMD( Four_255s,alpha ) ); + + vecPos0 += vecDx; + pQuadBufferOut->m_Coords[0] = vecPos0; + vecPos0 -= vecDy; + pQuadBufferOut->m_Coords[1] = vecPos0; + vecPos0 -= vecDx; + vecPos0 -= vecDx; + pQuadBufferOut->m_Coords[2] = vecPos0; + vecPos0 += vecDy; + pQuadBufferOut->m_Coords[3] = vecPos0; + + fltx4 fetch4 = *( ( fltx4 *) ( &pSprites->m_pSpriteDefs[0] ) ); + *( (fltx4 *) ( & ( pQuadBufferOut->m_pSpriteDefs[0] ) ) ) = fetch4; + + fetch4 = *( ( fltx4 *) ( &pSprites->m_RGBColor[0][0] ) ); + *( (fltx4 *) ( & ( pQuadBufferOut->m_RGBColor[0][0] ) ) ) = fetch4; + + //!! bug!! store distance + // !! speed!! simd? + pOut[0].m_nIndex = curidx; + pOut[0].m_flDistance = SubFloat( distanceSquared, 0 ); + pOut[1].m_nIndex = curidx+1; + pOut[1].m_flDistance = SubFloat( distanceSquared, 1 ); + pOut[2].m_nIndex = curidx+2; + pOut[2].m_flDistance = SubFloat( distanceSquared, 2 ); + pOut[3].m_nIndex = curidx+3; + pOut[3].m_flDistance = SubFloat( distanceSquared, 3 ); + curidx += 4; + pOut += 4; + pQuadBufferOut++; + } + pSprites++; + } while( --nSIMDSprites ); + + // adjust count for tail + int nCount = pOut - m_pFastSortInfo; + if ( nLastBfMask != 0xf ) // if last not skipped + nCount -= ( 0 - pData->m_nNumSprites ) & 3; + + // part 2 - sort + if ( nCount ) + { + VPROF( "CDetailObjectSystem::SortSpritesBackToFront -- Sort" ); + std::make_heap( m_pFastSortInfo, m_pFastSortInfo + nCount, SortLessFunc ); + std::sort_heap( m_pFastSortInfo, m_pFastSortInfo + nCount, SortLessFunc ); + } + return nCount; +} + + +void CDetailObjectSystem::RenderFastSprites( const Vector &viewOrigin, const Vector &viewForward, const Vector &viewRight, const Vector &viewUp, int nLeafCount, LeafIndex_t const * pLeafList ) +{ + // Here, we must draw all detail objects back-to-front + // FIXME: Cache off a sorted list so we don't have to re-sort every frame + + // Count the total # of detail quads we possibly could render + int nMaxInLeaf; + + int nQuadCount = CountFastSpritesInLeafList( nLeafCount, pLeafList, &nMaxInLeaf ); + if ( nQuadCount == 0 ) + return; + if ( r_DrawDetailProps.GetInt() == 0 ) + return; + + + CMatRenderContextPtr pRenderContext( materials ); + pRenderContext->MatrixMode( MATERIAL_MODEL ); + pRenderContext->PushMatrix(); + pRenderContext->LoadIdentity(); + + IMaterial *pMaterial = m_DetailSpriteMaterial; + if ( ShouldDrawInWireFrameMode() || r_DrawDetailProps.GetInt() == 2 ) + { + pMaterial = m_DetailWireframeMaterial; + } + + CMeshBuilder meshBuilder; + IMesh *pMesh = pRenderContext->GetDynamicMesh( true, NULL, NULL, pMaterial ); + + int nMaxVerts, nMaxIndices; + pRenderContext->GetMaxToRender( pMesh, false, &nMaxVerts, &nMaxIndices ); + int nMaxQuadsToDraw = nMaxIndices / 6; + if ( nMaxQuadsToDraw > nMaxVerts / 4 ) + { + nMaxQuadsToDraw = nMaxVerts / 4; + } + + int nQuadsToDraw = min( nQuadCount, nMaxQuadsToDraw ); + int nQuadsRemaining = nQuadsToDraw; + + meshBuilder.Begin( pMesh, MATERIAL_QUADS, nQuadsToDraw ); + + + + // Sort detail sprites in each leaf independently; then render them + for ( int i = 0; i < nLeafCount; ++i ) + { + int nLeaf = pLeafList[i]; + + CFastDetailLeafSpriteList *pData = reinterpret_cast ( + ClientLeafSystem()->GetSubSystemDataInLeaf( nLeaf, CLSUBSYSTEM_DETAILOBJECTS ) ); + + if ( pData ) + { + Assert( pData->m_nNumSprites ); // ptr with no sprites? + + int nCount = BuildOutSortedSprites( pData, viewOrigin, viewForward, viewRight, viewUp ); + + // part 3 - stuff the sorted sprites into the vb + SortInfo_t const *pDraw = m_pFastSortInfo; + FastSpriteQuadBuildoutBufferNonSIMDView_t const *pQuadBuffer = + ( FastSpriteQuadBuildoutBufferNonSIMDView_t const *) m_pBuildoutBuffer; + + COMPILE_TIME_ASSERT( sizeof( FastSpriteQuadBuildoutBufferNonSIMDView_t ) == + sizeof( FastSpriteQuadBuildoutBufferX4_t ) ); + + while( nCount ) + { + if ( ! nQuadsRemaining ) // no room left? + { + meshBuilder.End(); + pMesh->Draw(); + nQuadsRemaining = nQuadsToDraw; + meshBuilder.Begin( pMesh, MATERIAL_QUADS, nQuadsToDraw ); + } + int nToDraw = min( nCount, nQuadsRemaining ); + nCount -= nToDraw; + nQuadsRemaining -= nToDraw; + while( nToDraw-- ) + { + // draw the sucker + int nSIMDIdx = pDraw->m_nIndex >> 2; + int nSubIdx = pDraw->m_nIndex & 3; + + FastSpriteQuadBuildoutBufferNonSIMDView_t const *pquad = pQuadBuffer+nSIMDIdx; + + // voodoo - since everything is in 4s, offset structure pointer by a couple of floats to handle sub-index + pquad = (FastSpriteQuadBuildoutBufferNonSIMDView_t const *) ( ( (int) ( pquad ) )+ ( nSubIdx << 2 ) ); + uint8 const *pColorsCasted = reinterpret_cast ( pquad->m_Alpha ); + + uint8 color[4]; + color[0] = pquad->m_RGBColor[0][0]; + color[1] = pquad->m_RGBColor[0][1]; + color[2] = pquad->m_RGBColor[0][2]; + color[3] = pColorsCasted[MANTISSA_LSB_OFFSET]; + + DetailPropSpriteDict_t *pDict = pquad->m_pSpriteDefs[0]; + + meshBuilder.Position3f( pquad->m_flX0[0], pquad->m_flY0[0], pquad->m_flZ0[0] ); + meshBuilder.Color4ubv( color ); + meshBuilder.TexCoord2f( 0, pDict->m_TexLR.x, pDict->m_TexLR.y ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Position3f( pquad->m_flX1[0], pquad->m_flY1[0], pquad->m_flZ1[0] ); + meshBuilder.Color4ubv( color ); + meshBuilder.TexCoord2f( 0, pDict->m_TexLR.x, pDict->m_TexUL.y ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Position3f( pquad->m_flX2[0], pquad->m_flY2[0], pquad->m_flZ2[0] ); + meshBuilder.Color4ubv( color ); + meshBuilder.TexCoord2f( 0, pDict->m_TexUL.x, pDict->m_TexUL.y ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Position3f( pquad->m_flX3[0], pquad->m_flY3[0], pquad->m_flZ3[0] ); + meshBuilder.Color4ubv( color ); + meshBuilder.TexCoord2f( 0, pDict->m_TexUL.x, pDict->m_TexLR.y ); + meshBuilder.AdvanceVertex(); + pDraw++; + } + } + } + } + meshBuilder.End(); + pMesh->Draw(); + pRenderContext->PopMatrix(); +} + + //----------------------------------------------------------------------------- // Renders all translucent detail objects in a particular set of leaves //----------------------------------------------------------------------------- -void CDetailObjectSystem::RenderTranslucentDetailObjects( const Vector &viewOrigin, const Vector &viewForward, int nLeafCount, LeafIndex_t *pLeafList ) +void CDetailObjectSystem::RenderTranslucentDetailObjects( const Vector &viewOrigin, const Vector &viewForward, const Vector &viewRight, const Vector &viewUp, int nLeafCount, LeafIndex_t *pLeafList ) { VPROF_BUDGET( "CDetailObjectSystem::RenderTranslucentDetailObjects", VPROF_BUDGETGROUP_DETAILPROP_RENDERING ); if (nLeafCount == 0) @@ -1665,6 +2370,8 @@ void CDetailObjectSystem::RenderTranslucentDetailObjects( const Vector &viewOrig Assert( m_nSpriteCount == m_nFirstSprite ); // Here, we must draw all detail objects back-to-front + RenderFastSprites( viewOrigin, viewForward, viewRight, viewUp, nLeafCount, pLeafList ); + // FIXME: Cache off a sorted list so we don't have to re-sort every frame // Count the total # of detail quads we possibly could render @@ -1672,9 +2379,10 @@ void CDetailObjectSystem::RenderTranslucentDetailObjects( const Vector &viewOrig if ( nQuadCount == 0 ) return; - materials->MatrixMode( MATERIAL_MODEL ); - materials->PushMatrix(); - materials->LoadIdentity(); + CMatRenderContextPtr pRenderContext( materials ); + pRenderContext->MatrixMode( MATERIAL_MODEL ); + pRenderContext->PushMatrix(); + pRenderContext->LoadIdentity(); IMaterial *pMaterial = m_DetailSpriteMaterial; if ( ShouldDrawInWireFrameMode() || r_DrawDetailProps.GetInt() == 2 ) @@ -1683,10 +2391,10 @@ void CDetailObjectSystem::RenderTranslucentDetailObjects( const Vector &viewOrig } CMeshBuilder meshBuilder; - IMesh *pMesh = materials->GetDynamicMesh( true, NULL, NULL, pMaterial ); + IMesh *pMesh = pRenderContext->GetDynamicMesh( true, NULL, NULL, pMaterial ); int nMaxVerts, nMaxIndices; - materials->GetMaxToRender( pMesh, false, &nMaxVerts, &nMaxIndices ); + pRenderContext->GetMaxToRender( pMesh, false, &nMaxVerts, &nMaxIndices ); int nMaxQuadsToDraw = nMaxIndices / 6; if ( nMaxQuadsToDraw > nMaxVerts / 4 ) { @@ -1710,7 +2418,7 @@ void CDetailObjectSystem::RenderTranslucentDetailObjects( const Vector &viewOrig ClientLeafSystem()->GetDetailObjectsInLeaf( nLeaf, nFirstDetailObject, nDetailObjectCount ); // Sort detail sprites in each leaf independently; then render them - SortInfo_t *pSortInfo = (SortInfo_t *)stackalloc( nDetailObjectCount * sizeof(SortInfo_t) ); + SortInfo_t *pSortInfo = m_pSortInfo; int nCount = SortSpritesBackToFront( nLeaf, viewOrigin, viewForward, pSortInfo ); for ( int j = 0; j < nCount; ++j ) @@ -1744,17 +2452,145 @@ void CDetailObjectSystem::RenderTranslucentDetailObjects( const Vector &viewOrig meshBuilder.End(); pMesh->Draw(); - materials->PopMatrix(); + pRenderContext->PopMatrix(); } +void CDetailObjectSystem::RenderFastTranslucentDetailObjectsInLeaf( const Vector &viewOrigin, const Vector &viewForward, const Vector &viewRight, const Vector &viewUp, int nLeaf, const Vector *pVecClosestPoint ) +{ + CFastDetailLeafSpriteList *pData = reinterpret_cast< CFastDetailLeafSpriteList *> ( + ClientLeafSystem()->GetSubSystemDataInLeaf( nLeaf, CLSUBSYSTEM_DETAILOBJECTS ) ); + if ( ! pData ) + return; + + if ( m_nSortedFastLeaf != nLeaf ) + { + m_nSortedFastLeaf = nLeaf; + pData->m_nNumPendingSprites = BuildOutSortedSprites( pData, viewOrigin, viewForward, viewRight, viewUp ); + pData->m_nStartSpriteIndex = 0; + } + if ( pData->m_nNumPendingSprites == 0 ) + return; + + float flMinDistance = 0.0f; + if ( pVecClosestPoint ) + { + Vector vecDelta; + VectorSubtract( *pVecClosestPoint, viewOrigin, vecDelta ); + flMinDistance = vecDelta.LengthSqr(); + } + + if ( m_pFastSortInfo[pData->m_nStartSpriteIndex].m_flDistance < flMinDistance ) + return; + + int nCount = pData->m_nNumPendingSprites; + + if ( r_DrawDetailProps.GetInt() == 0 ) + return; + + + CMatRenderContextPtr pRenderContext( materials ); + pRenderContext->MatrixMode( MATERIAL_MODEL ); + pRenderContext->PushMatrix(); + pRenderContext->LoadIdentity(); + + IMaterial *pMaterial = m_DetailSpriteMaterial; + if ( ShouldDrawInWireFrameMode() || r_DrawDetailProps.GetInt() == 2 ) + { + pMaterial = m_DetailWireframeMaterial; + } + + CMeshBuilder meshBuilder; + IMesh *pMesh = pRenderContext->GetDynamicMesh( true, NULL, NULL, pMaterial ); + + int nMaxVerts, nMaxIndices; + pRenderContext->GetMaxToRender( pMesh, false, &nMaxVerts, &nMaxIndices ); + int nMaxQuadsToDraw = nMaxIndices / 6; + if ( nMaxQuadsToDraw > nMaxVerts / 4 ) + { + nMaxQuadsToDraw = nMaxVerts / 4; + } + + int nQuadsToDraw = min( nCount, nMaxQuadsToDraw ); + int nQuadsRemaining = nQuadsToDraw; + + meshBuilder.Begin( pMesh, MATERIAL_QUADS, nQuadsToDraw ); + + SortInfo_t const *pDraw = m_pFastSortInfo + pData->m_nStartSpriteIndex; + + FastSpriteQuadBuildoutBufferNonSIMDView_t const *pQuadBuffer = + ( FastSpriteQuadBuildoutBufferNonSIMDView_t const *) m_pBuildoutBuffer; + + while( nCount && ( pDraw->m_flDistance >= flMinDistance ) ) + { + if ( ! nQuadsRemaining ) // no room left? + { + meshBuilder.End(); + pMesh->Draw(); + nQuadsRemaining = nQuadsToDraw; + meshBuilder.Begin( pMesh, MATERIAL_QUADS, nQuadsToDraw ); + } + int nToDraw = min( nCount, nQuadsRemaining ); + nCount -= nToDraw; + nQuadsRemaining -= nToDraw; + while( nToDraw-- ) + { + // draw the sucker + int nSIMDIdx = pDraw->m_nIndex >> 2; + int nSubIdx = pDraw->m_nIndex & 3; + + FastSpriteQuadBuildoutBufferNonSIMDView_t const *pquad = pQuadBuffer+nSIMDIdx; + + // voodoo - since everything is in 4s, offset structure pointer by a couple of floats to handle sub-index + pquad = (FastSpriteQuadBuildoutBufferNonSIMDView_t const *) ( ( (int) ( pquad ) )+ ( nSubIdx << 2 ) ); + uint8 const *pColorsCasted = reinterpret_cast ( pquad->m_Alpha ); + + uint8 color[4]; + color[0] = pquad->m_RGBColor[0][0]; + color[1] = pquad->m_RGBColor[0][1]; + color[2] = pquad->m_RGBColor[0][2]; + color[3] = pColorsCasted[MANTISSA_LSB_OFFSET]; + + DetailPropSpriteDict_t *pDict = pquad->m_pSpriteDefs[0]; + + meshBuilder.Position3f( pquad->m_flX0[0], pquad->m_flY0[0], pquad->m_flZ0[0] ); + meshBuilder.Color4ubv( color ); + meshBuilder.TexCoord2f( 0, pDict->m_TexLR.x, pDict->m_TexLR.y ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Position3f( pquad->m_flX1[0], pquad->m_flY1[0], pquad->m_flZ1[0] ); + meshBuilder.Color4ubv( color ); + meshBuilder.TexCoord2f( 0, pDict->m_TexLR.x, pDict->m_TexUL.y ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Position3f( pquad->m_flX2[0], pquad->m_flY2[0], pquad->m_flZ2[0] ); + meshBuilder.Color4ubv( color ); + meshBuilder.TexCoord2f( 0, pDict->m_TexUL.x, pDict->m_TexUL.y ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Position3f( pquad->m_flX3[0], pquad->m_flY3[0], pquad->m_flZ3[0] ); + meshBuilder.Color4ubv( color ); + meshBuilder.TexCoord2f( 0, pDict->m_TexUL.x, pDict->m_TexLR.y ); + meshBuilder.AdvanceVertex(); + pDraw++; + } + } + pData->m_nNumPendingSprites = nCount; + pData->m_nStartSpriteIndex = pDraw - m_pFastSortInfo; + + meshBuilder.End(); + pMesh->Draw(); + pRenderContext->PopMatrix(); +} + //----------------------------------------------------------------------------- // Renders a subset of the detail objects in a particular leaf (for interleaving with other translucent entities) //----------------------------------------------------------------------------- -void CDetailObjectSystem::RenderTranslucentDetailObjectsInLeaf( const Vector &viewOrigin, const Vector &viewForward, int nLeaf, const Vector *pVecClosestPoint ) +void CDetailObjectSystem::RenderTranslucentDetailObjectsInLeaf( const Vector &viewOrigin, const Vector &viewForward, const Vector &viewRight, const Vector &viewUp, int nLeaf, const Vector *pVecClosestPoint ) { VPROF_BUDGET( "CDetailObjectSystem::RenderTranslucentDetailObjectsInLeaf", VPROF_BUDGETGROUP_DETAILPROP_RENDERING ); + RenderFastTranslucentDetailObjectsInLeaf( viewOrigin, viewForward, viewRight, viewUp, nLeaf, pVecClosestPoint ); // We may have already sorted this leaf. If not, sort the leaf. if ( m_nSortedLeaf != nLeaf ) { @@ -1765,7 +2601,6 @@ void CDetailObjectSystem::RenderTranslucentDetailObjectsInLeaf( const Vector &vi // Count the total # of detail sprites we possibly could render LeafIndex_t nLeafIndex = nLeaf; int nSpriteCount = CountSpritesInLeafList( 1, &nLeafIndex ); - Assert( nSpriteCount <= MAX_SPRITES_PER_LEAF ); if (nSpriteCount == 0) return; @@ -1789,9 +2624,10 @@ void CDetailObjectSystem::RenderTranslucentDetailObjectsInLeaf( const Vector &vi if ( m_pSortInfo[m_nFirstSprite].m_flDistance < flMinDistance ) return; - materials->MatrixMode( MATERIAL_MODEL ); - materials->PushMatrix(); - materials->LoadIdentity(); + CMatRenderContextPtr pRenderContext( materials ); + pRenderContext->MatrixMode( MATERIAL_MODEL ); + pRenderContext->PushMatrix(); + pRenderContext->LoadIdentity(); IMaterial *pMaterial = m_DetailSpriteMaterial; if ( ShouldDrawInWireFrameMode() || r_DrawDetailProps.GetInt() == 2 ) @@ -1800,10 +2636,10 @@ void CDetailObjectSystem::RenderTranslucentDetailObjectsInLeaf( const Vector &vi } CMeshBuilder meshBuilder; - IMesh *pMesh = materials->GetDynamicMesh( true, NULL, NULL, pMaterial ); + IMesh *pMesh = pRenderContext->GetDynamicMesh( true, NULL, NULL, pMaterial ); int nMaxVerts, nMaxIndices; - materials->GetMaxToRender( pMesh, false, &nMaxVerts, &nMaxIndices ); + pRenderContext->GetMaxToRender( pMesh, false, &nMaxVerts, &nMaxIndices ); // needs to be * 4 since there are a max of 4 quads per detail object int nQuadCount = ( m_nSpriteCount - m_nFirstSprite ) * 4; @@ -1848,7 +2684,7 @@ void CDetailObjectSystem::RenderTranslucentDetailObjectsInLeaf( const Vector &vi meshBuilder.End(); pMesh->Draw(); - materials->PopMatrix(); + pRenderContext->PopMatrix(); } @@ -1865,39 +2701,36 @@ bool CDetailObjectSystem::EnumerateLeaf( int leaf, int context ) ClientLeafSystem()->DrawDetailObjectsInLeaf( leaf, pCtx->m_BuildWorldListNumber, firstDetailObject, detailObjectCount ); - if ( IsPC() ) + // Compute the translucency. Need to do it now cause we need to + // know that when we're rendering (opaque stuff is rendered first) + for ( int i = 0; i < detailObjectCount; ++i) { - // Compute the translucency. Need to do it now cause we need to - // know that when we're rendering (opaque stuff is rendered first) - for ( int i = 0; i < detailObjectCount; ++i) + // Calculate distance (badly) + CDetailModel& model = m_DetailObjects[firstDetailObject+i]; + VectorSubtract( model.GetRenderOrigin(), pCtx->m_vViewOrigin, v ); + + float sqDist = v.LengthSqr(); + + model.SetAlpha( 255 ); + if ( sqDist < m_flCurMaxSqDist ) { - // Calculate distance (badly) - CDetailModel& model = m_DetailObjects[firstDetailObject+i]; - VectorSubtract( model.GetRenderOrigin(), CurrentViewOrigin(), v ); - - float sqDist = v.LengthSqr(); - - if ( sqDist < pCtx->m_MaxSqDist ) + if ( sqDist > m_flCurFadeSqDist ) { - if ((pCtx->m_FadeSqDist > 0) && (sqDist > pCtx->m_FadeSqDist)) - { - model.SetAlpha( pCtx->m_FalloffFactor * (pCtx->m_MaxSqDist - sqDist ) ); - } - else - { - model.SetAlpha( 255 ); - } - - // Perform screen alignment if necessary. - model.ComputeAngles(); + model.SetAlpha( m_flCurFalloffFactor * ( m_flCurMaxSqDist - sqDist ) ); } else { - model.SetAlpha( 0 ); + model.SetAlpha( 255 ); } + + // Perform screen alignment if necessary. + model.ComputeAngles(); + } + else + { + model.SetAlpha( 0 ); } } - return true; } @@ -1905,7 +2738,7 @@ bool CDetailObjectSystem::EnumerateLeaf( int leaf, int context ) //----------------------------------------------------------------------------- // Gets called each view //----------------------------------------------------------------------------- -void CDetailObjectSystem::BuildDetailObjectRenderLists( ) +void CDetailObjectSystem::BuildDetailObjectRenderLists( const Vector &vViewOrigin ) { VPROF_BUDGET( "CDetailObjectSystem::BuildDetailObjectRenderLists", VPROF_BUDGETGROUP_DETAILPROP_RENDERING ); @@ -1913,50 +2746,50 @@ void CDetailObjectSystem::BuildDetailObjectRenderLists( ) return; // Don't bother doing any of this if the level doesn't have detail props. - if ( m_DetailObjects.Count() == 0 ) + if ( ( ! m_pFastSpriteData ) && ( m_DetailObjects.Count() == 0 ) ) return; EnumContext_t ctx; + ctx.m_vViewOrigin = vViewOrigin; ctx.m_BuildWorldListNumber = view->BuildWorldListsNumber(); - if ( IsPC() ) + // We need to recompute translucency information for all detail props + for (int i = m_DetailObjectDict.Size(); --i >= 0; ) { - // We need to recompute translucency information for all detail props - for (int i = m_DetailObjectDict.Size(); --i >= 0; ) + if (modelinfo->ModelHasMaterialProxy( m_DetailObjectDict[i].m_pModel )) { - if (modelinfo->ModelHasMaterialProxy( m_DetailObjectDict[i].m_pModel )) - { - modelinfo->RecomputeTranslucency( m_DetailObjectDict[i].m_pModel ); - } + modelinfo->RecomputeTranslucency( m_DetailObjectDict[i].m_pModel, 0, 0, NULL ); } - - float factor = 1.0f; - C_BasePlayer *local = C_BasePlayer::GetLocalPlayer(); - if ( local ) - { - factor = local->GetFOVDistanceAdjustFactor(); - } - - // Compute factors to optimize rendering of the detail models - ctx.m_MaxSqDist = cl_detaildist.GetFloat() * cl_detaildist.GetFloat(); - ctx.m_FadeSqDist = cl_detaildist.GetFloat() - cl_detailfade.GetFloat(); - - ctx.m_MaxSqDist /= factor; - ctx.m_FadeSqDist /= factor; - - if (ctx.m_FadeSqDist > 0) - { - ctx.m_FadeSqDist *= ctx.m_FadeSqDist; - } - else - { - ctx.m_FadeSqDist = 0; - } - ctx.m_FalloffFactor = 255.0f / (ctx.m_MaxSqDist - ctx.m_FadeSqDist); } + float factor = 1.0f; + C_BasePlayer *local = C_BasePlayer::GetLocalPlayer(); + if ( local ) + { + factor = local->GetFOVDistanceAdjustFactor(); + } + + // Compute factors to optimize rendering of the detail models + m_flCurMaxSqDist = cl_detaildist.GetFloat() * cl_detaildist.GetFloat(); + m_flCurFadeSqDist = cl_detaildist.GetFloat() - cl_detailfade.GetFloat(); + + m_flCurMaxSqDist /= factor; + m_flCurFadeSqDist /= factor; + + if ( m_flCurFadeSqDist > 0) + { + m_flCurFadeSqDist *= m_flCurFadeSqDist; + } + else + { + m_flCurFadeSqDist = 0; + } + m_flCurFadeSqDist = min( m_flCurFadeSqDist, m_flCurMaxSqDist -1 ); + m_flCurFalloffFactor = 255.0f / ( m_flCurMaxSqDist - m_flCurFadeSqDist ); + + ISpatialQuery* pQuery = engine->GetBSPTreeQuery(); pQuery->EnumerateLeavesInSphere( CurrentViewOrigin(), - cl_detaildist.GetFloat(), this, (int)&ctx ); + cl_detaildist.GetFloat(), this, (int)&ctx ); } diff --git a/src/src/cl_dll/detailobjectsystem.h b/src/src/game/client/detailobjectsystem.h similarity index 82% rename from src/src/cl_dll/detailobjectsystem.h rename to src/src/game/client/detailobjectsystem.h index b05f192..02b4bca 100644 --- a/src/src/cl_dll/detailobjectsystem.h +++ b/src/src/game/client/detailobjectsystem.h @@ -15,7 +15,7 @@ #include "IGameSystem.h" #include "IClientEntityInternal.h" #include "engine/IVModelRender.h" -#include "vector.h" +#include "mathlib/vector.h" #include "IVRenderView.h" struct model_t; @@ -31,7 +31,7 @@ public: virtual IClientRenderable* GetDetailModel( int idx ) = 0; // Gets called each view - virtual void BuildDetailObjectRenderLists( ) = 0; + virtual void BuildDetailObjectRenderLists( const Vector &vViewOrigin ) = 0; // Renders all opaque detail objects in a particular set of leaves virtual void RenderOpaqueDetailObjects( int nLeafCount, LeafIndex_t *pLeafList ) = 0; @@ -40,10 +40,10 @@ public: virtual void BeginTranslucentDetailRendering( ) = 0; // Renders all translucent detail objects in a particular set of leaves - virtual void RenderTranslucentDetailObjects( const Vector &viewOrigin, const Vector &viewForward, int nLeafCount, LeafIndex_t *pLeafList ) = 0; + virtual void RenderTranslucentDetailObjects( const Vector &viewOrigin, const Vector &viewForward, const Vector &viewRight, const Vector &viewUp, int nLeafCount, LeafIndex_t *pLeafList ) =0; // Renders all translucent detail objects in a particular leaf up to a particular point - virtual void RenderTranslucentDetailObjectsInLeaf( const Vector &viewOrigin, const Vector &viewForward, int nLeaf, const Vector *pVecClosestPoint ) = 0; + virtual void RenderTranslucentDetailObjectsInLeaf( const Vector &viewOrigin, const Vector &viewForward, const Vector &viewRight, const Vector &viewUp, int nLeaf, const Vector *pVecClosestPoint ) = 0; }; diff --git a/src/src/cl_dll/dummyproxy.cpp b/src/src/game/client/dummyproxy.cpp similarity index 96% rename from src/src/cl_dll/dummyproxy.cpp rename to src/src/game/client/dummyproxy.cpp index 9c10c42..1653b56 100644 --- a/src/src/cl_dll/dummyproxy.cpp +++ b/src/src/game/client/dummyproxy.cpp @@ -19,6 +19,7 @@ public: virtual bool Init( IMaterial *pMaterial, KeyValues *pKeyValues ); virtual void OnBind( void *pC_BaseEntity ); virtual void Release( void ) { delete this; } + virtual IMaterial *GetMaterial() { return NULL; } }; CDummyMaterialProxy::CDummyMaterialProxy() diff --git a/src/src/cl_dll/effectsclient.cpp b/src/src/game/client/effectsclient.cpp similarity index 99% rename from src/src/cl_dll/effectsclient.cpp rename to src/src/game/client/effectsclient.cpp index e37b7dd..bcd0dac 100644 --- a/src/src/cl_dll/effectsclient.cpp +++ b/src/src/game/client/effectsclient.cpp @@ -74,7 +74,7 @@ static CEffectsClient s_EffectClient; EXPOSE_SINGLE_INTERFACE_GLOBALVAR(CEffectsClient, IEffects, IEFFECTS_INTERFACE_VERSION, s_EffectClient); IEffects *g_pEffects = &s_EffectClient; -ConVar r_decals("r_decals","0"); +ConVar r_decals( "r_decals", "2048" ); //----------------------------------------------------------------------------- // constructor, destructor diff --git a/src/src/cl_dll/enginesprite.h b/src/src/game/client/enginesprite.h similarity index 98% rename from src/src/cl_dll/enginesprite.h rename to src/src/game/client/enginesprite.h index bc7c94b..f9737be 100644 --- a/src/src/cl_dll/enginesprite.h +++ b/src/src/game/client/enginesprite.h @@ -11,7 +11,7 @@ #pragma once #endif -#include "vector.h" +#include "mathlib/vector.h" #include "avi/iavi.h" diff --git a/src/src/cl_dll/entity_client_tools.cpp b/src/src/game/client/entity_client_tools.cpp similarity index 76% rename from src/src/cl_dll/entity_client_tools.cpp rename to src/src/game/client/entity_client_tools.cpp index 7aba266..fef86ba 100644 --- a/src/src/cl_dll/entity_client_tools.cpp +++ b/src/src/game/client/entity_client_tools.cpp @@ -9,6 +9,13 @@ #include "sprite.h" #include "enginesprite.h" #include "toolframework_client.h" +#include "particles/particles.h" +#include "particle_parse.h" +#include "rendertexture.h" + +#ifdef PORTAL + #include "portalrender.h" +#endif #pragma warning( disable: 4355 ) // warning C4355: 'this' : used in base member initializer list @@ -29,6 +36,7 @@ public: CClientTools(); virtual HTOOLHANDLE AttachToEntity( EntitySearchResult entityToAttach ); + virtual void DetachFromEntity( EntitySearchResult entityToDetach ); virtual bool IsValidHandle( HTOOLHANDLE handle ); virtual int GetNumRecordables(); @@ -41,6 +49,7 @@ public: virtual void SetEnabled( HTOOLHANDLE handle, bool enabled ); virtual void SetRecording( HTOOLHANDLE handle, bool recording ); + virtual bool ShouldRecord( HTOOLHANDLE handle ); virtual int GetModelIndex( HTOOLHANDLE handle ); virtual const char* GetModelName ( HTOOLHANDLE handle ); @@ -56,15 +65,19 @@ public: virtual bool DrawSprite( IClientRenderable *pRenderable, float scale, float frame, int rendermode, int renderfx, - const Color &color, int *pVisHandle ); + const Color &color, float flProxyRadius, int *pVisHandle ); virtual bool GetLocalPlayerEyePosition( Vector& org, QAngle& ang, float &fov ); virtual EntitySearchResult GetLocalPlayer(); virtual ClientShadowHandle_t CreateShadow( CBaseHandle h, int nFlags ); virtual void DestroyShadow( ClientShadowHandle_t h ); + virtual ClientShadowHandle_t CreateFlashlight( const FlashlightState_t &lightState ); + virtual void DestroyFlashlight( ClientShadowHandle_t h ); + virtual void UpdateFlashlightState( ClientShadowHandle_t h, const FlashlightState_t &flashlightState ); virtual void AddToDirtyShadowList( ClientShadowHandle_t h, bool force = false ); virtual void MarkRenderToTextureShadowDirty( ClientShadowHandle_t h ); + virtual void UpdateProjectedTexture( ClientShadowHandle_t h, bool bForce ); // Global toggle for recording virtual void EnableRecordingMode( bool bEnable ); @@ -90,6 +103,16 @@ public: virtual Vector GetAbsOrigin( HTOOLHANDLE handle ); virtual QAngle GetAbsAngles( HTOOLHANDLE handle ); + virtual void ReloadParticleDefintions( const char *pFileName, const void *pBufData, int nLen ); + + // Sends a mesage from the tool to the client + virtual void PostToolMessage( KeyValues *pKeyValues ); + + // Indicates whether the client should render particle systems + virtual void EnableParticleSystems( bool bEnable ); + + // Is the game rendering in 3rd person mode? + virtual bool IsRenderingThirdPerson() const; public: C_BaseEntity *LookupEntity( HTOOLHANDLE handle ); @@ -99,11 +122,6 @@ public: void OnEntityCreated( C_BaseEntity *pEntity ); private: - - void OnRemoveEntity( CBaseEntity *ent ); - - static int s_nNextHandle; - struct HToolEntry_t { HToolEntry_t() : m_Handle( 0 ) {} @@ -120,6 +138,8 @@ private: EHANDLE m_hEntity; }; + static int s_nNextHandle; + static bool HandleLessFunc( const HToolEntry_t& lhs, const HToolEntry_t& rhs ) { return lhs.m_Handle < rhs.m_Handle; @@ -128,18 +148,32 @@ private: CUtlRBTree< HToolEntry_t > m_Handles; CUtlVector< int > m_ActiveHandles; bool m_bInRecordingMode; - - bool m_bWTF; }; + +//----------------------------------------------------------------------------- +// Statics +//----------------------------------------------------------------------------- +int CClientTools::s_nNextHandle = 1; + + +//----------------------------------------------------------------------------- +// Singleton instance +//----------------------------------------------------------------------------- +static CClientTools s_ClientTools; +IClientTools *clienttools = &s_ClientTools; +EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CClientTools, IClientTools, VCLIENTTOOLS_INTERFACE_VERSION, s_ClientTools ); + + +//----------------------------------------------------------------------------- +// Constructor +//----------------------------------------------------------------------------- CClientTools::CClientTools() : m_Handles( 0, 0, HandleLessFunc ) { m_bInRecordingMode = false; cl_entitylist->AddListenerEntity( this ); } -int CClientTools::s_nNextHandle = 1; - //----------------------------------------------------------------------------- // Global toggle for recording @@ -154,6 +188,7 @@ bool CClientTools::IsInRecordingMode() const return m_bInRecordingMode; } + //----------------------------------------------------------------------------- // Trigger a temp entity //----------------------------------------------------------------------------- @@ -162,6 +197,7 @@ void CClientTools::TriggerTempEntity( KeyValues *pKeyValues ) te->TriggerTempEntity( pKeyValues ); } + //----------------------------------------------------------------------------- // get owning weapon (for viewmodels) //----------------------------------------------------------------------------- @@ -244,7 +280,7 @@ void CClientTools::SetRenderGroup( IClientRenderable *pRenderable, int renderGro } } -bool CClientTools::DrawSprite( IClientRenderable *pRenderable, float scale, float frame, int rendermode, int renderfx, const Color &color, int *pVisHandle ) +bool CClientTools::DrawSprite( IClientRenderable *pRenderable, float scale, float frame, int rendermode, int renderfx, const Color &color, float flProxyRadius, int *pVisHandle ) { Vector origin = pRenderable->GetRenderOrigin(); QAngle angles = pRenderable->GetRenderAngles(); @@ -269,7 +305,15 @@ bool CClientTools::DrawSprite( IClientRenderable *pRenderable, float scale, floa if (( rendermode == kRenderGlow ) || ( rendermode == kRenderWorldGlow )) { pixelvis_queryparams_t params; - params.Init( origin ); + if ( flProxyRadius != 0.0f ) + { + params.Init( origin, flProxyRadius ); + params.bSizeInScreenspace = true; + } + else + { + params.Init( origin ); + } float blend = oldBlend * StandardGlowBlend( params, ( pixelvis_handle_t* )pVisHandle, rendermode, renderfx, color.a(), &scale ); if ( blend <= 0.0f ) @@ -297,6 +341,7 @@ bool CClientTools::DrawSprite( IClientRenderable *pRenderable, float scale, floa HTOOLHANDLE CClientTools::AttachToEntity( EntitySearchResult entityToAttach ) { C_BaseEntity *ent = reinterpret_cast< C_BaseEntity * >( entityToAttach ); + Assert( ent ); if ( !ent ) return (HTOOLHANDLE)0; @@ -312,13 +357,12 @@ HTOOLHANDLE CClientTools::AttachToEntity( EntitySearchResult entityToAttach ) return (HTOOLHANDLE)newHandle.m_Handle; } -void CClientTools::OnRemoveEntity( C_BaseEntity *ent ) +void CClientTools::DetachFromEntity( EntitySearchResult entityToDetach ) { + C_BaseEntity *ent = reinterpret_cast< C_BaseEntity * >( entityToDetach ); + Assert( ent ); if ( !ent ) - { - Assert( 0 ); return; - } HTOOLHANDLE handle = ent->GetToolHandle(); ent->SetToolHandle( (HTOOLHANDLE)0 ); @@ -336,14 +380,6 @@ void CClientTools::OnRemoveEntity( C_BaseEntity *ent ) return; } - // Send deletion message to tool interface - if ( m_bInRecordingMode ) - { - KeyValues *kv = new KeyValues( "deleted" ); - ToolFramework_PostToolMessage( handle, kv ); - kv->deleteThis(); - } - m_Handles.RemoveAt( idx ); m_ActiveHandles.FindAndRemove( handle ); } @@ -436,6 +472,16 @@ void CClientTools::SetRecording( HTOOLHANDLE handle, bool recording ) } } +bool CClientTools::ShouldRecord( HTOOLHANDLE handle ) +{ + int idx = m_Handles.Find( HToolEntry_t( handle ) ); + if ( idx == m_Handles.InvalidIndex() ) + return false; + + HToolEntry_t &entry = m_Handles[ idx ]; + return entry.m_hEntity && entry.m_hEntity->ShouldRecordInTools(); +} + //----------------------------------------------------------------------------- // Purpose: @@ -504,29 +550,32 @@ bool CClientTools::IsValidHandle( HTOOLHANDLE handle ) void CClientTools::OnEntityDeleted( CBaseEntity *pEntity ) { - if ( pEntity && pEntity->GetToolHandle() != (HTOOLHANDLE)0 ) + HTOOLHANDLE handle = pEntity ? pEntity->GetToolHandle() : (HTOOLHANDLE)0; + if ( handle == (HTOOLHANDLE)0 ) + return; + + if ( m_bInRecordingMode ) { - OnRemoveEntity( pEntity ); + // Send deletion message to tool interface + KeyValues *kv = new KeyValues( "deleted" ); + ToolFramework_PostToolMessage( handle, kv ); + kv->deleteThis(); } + + DetachFromEntity( pEntity ); } void CClientTools::OnEntityCreated( CBaseEntity *pEntity ) { - // It won't have a HTOOLHANDLE since it's new!!! - if ( m_bInRecordingMode ) - { - // Send deletion message to tool interface - KeyValues *kv = new KeyValues( "created" ); - kv->SetPtr( "entity", pEntity ); - kv->SetInt( "index", pEntity->entindex() ); - kv->SetInt( "client", 1 ); - kv->SetString( "classname", pEntity->GetClassname() ); + if ( !m_bInRecordingMode ) + return; - HTOOLHANDLE h = AttachToEntity( pEntity ); - ToolFramework_PostToolMessage( h, kv ); + HTOOLHANDLE h = AttachToEntity( pEntity ); - kv->deleteThis(); - } + // Send deletion message to tool interface + KeyValues *kv = new KeyValues( "created" ); + ToolFramework_PostToolMessage( h, kv ); + kv->deleteThis(); } HTOOLHANDLE CClientTools::GetToolHandleForEntityByIndex( int entindex ) @@ -569,6 +618,21 @@ void CClientTools::DestroyShadow( ClientShadowHandle_t h ) g_pClientShadowMgr->DestroyShadow( h ); } +ClientShadowHandle_t CClientTools::CreateFlashlight( const FlashlightState_t &lightState ) +{ + return g_pClientShadowMgr->CreateFlashlight( lightState ); +} + +void CClientTools::DestroyFlashlight( ClientShadowHandle_t h ) +{ + g_pClientShadowMgr->DestroyFlashlight( h ); +} + +void CClientTools::UpdateFlashlightState( ClientShadowHandle_t h, const FlashlightState_t &lightState ) +{ + g_pClientShadowMgr->UpdateFlashlightState( h, lightState ); +} + void CClientTools::AddToDirtyShadowList( ClientShadowHandle_t h, bool force ) { g_pClientShadowMgr->AddToDirtyShadowList( h, force ); @@ -579,6 +643,11 @@ void CClientTools::MarkRenderToTextureShadowDirty( ClientShadowHandle_t h ) g_pClientShadowMgr->MarkRenderToTextureShadowDirty( h ); } +void CClientTools::UpdateProjectedTexture( ClientShadowHandle_t h, bool bForce ) +{ + g_pClientShadowMgr->UpdateProjectedTexture( h, bForce ); +} + int CClientTools::FindGlobalFlexcontroller( char const *name ) { return C_BaseFlex::AddGlobalFlexController( (char *)name ); @@ -648,6 +717,77 @@ QAngle CClientTools::GetAbsAngles( HTOOLHANDLE handle ) return vec3_angle; } -static CClientTools s_ClientTools; -IClientTools *clienttools = &s_ClientTools; -EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CClientTools, IClientTools, VCLIENTTOOLS_INTERFACE_VERSION, s_ClientTools ); + +//----------------------------------------------------------------------------- +// Sends a mesage from the tool to the client +//----------------------------------------------------------------------------- +void CClientTools::PostToolMessage( KeyValues *pKeyValues ) +{ + if ( !Q_stricmp( pKeyValues->GetName(), "QueryParticleManifest" ) ) + { + // NOTE: This cannot be done during particle system init because tools aren't set up at that point + CUtlVector files; + GetParticleManifest( files ); + int nCount = files.Count(); + for ( int i = 0; i < nCount; ++i ) + { + char pTemp[256]; + Q_snprintf( pTemp, sizeof(pTemp), "%d", i ); + KeyValues *pSubKey = pKeyValues->FindKey( pTemp, true ); + pSubKey->SetString( "file", files[i] ); + } + return; + } + + if ( !Q_stricmp( pKeyValues->GetName(), "QueryMonitorTexture" ) ) + { + pKeyValues->SetPtr( "texture", GetCameraTexture() ); + return; + } + +#ifdef PORTAL + if ( !Q_stricmp( pKeyValues->GetName(), "portals" ) ) + { + g_pPortalRender->HandlePortalPlaybackMessage( pKeyValues ); + return; + } + + if ( !Q_stricmp( pKeyValues->GetName(), "query CPortalRenderer" ) ) + { + pKeyValues->SetInt( "IsRenderingPortal", g_pPortalRender->IsRenderingPortal() ? 1 : 0 ); + return; + } +#endif +} + + +//----------------------------------------------------------------------------- +// Indicates whether the client should render particle systems +//----------------------------------------------------------------------------- +void CClientTools::EnableParticleSystems( bool bEnable ) +{ + ParticleMgr()->RenderParticleSystems( bEnable ); +} + + +//----------------------------------------------------------------------------- +// Is the game rendering in 3rd person mode? +//----------------------------------------------------------------------------- +bool CClientTools::IsRenderingThirdPerson() const +{ + return C_BasePlayer::ShouldDrawLocalPlayer(); +} + + +//----------------------------------------------------------------------------- +// Reload particle definitions +//----------------------------------------------------------------------------- +void CClientTools::ReloadParticleDefintions( const char *pFileName, const void *pBufData, int nLen ) +{ + // Remove all new effects, because we are going to free internal structures they point to + ParticleMgr()->RemoveAllNewEffects(); + + // FIXME: Use file name to determine if we care about this data + CUtlBuffer buf( pBufData, nLen, CUtlBuffer::READ_ONLY ); + g_pParticleSystemMgr->ReadParticleConfigFile( buf, true ); +} diff --git a/src/src/game/client/entityoriginmaterialproxy.cpp b/src/src/game/client/entityoriginmaterialproxy.cpp new file mode 100644 index 0000000..d7d40d5 --- /dev/null +++ b/src/src/game/client/entityoriginmaterialproxy.cpp @@ -0,0 +1,148 @@ +//========= Copyright © 1996-2006, Valve Corporation, All rights reserved. ============// +// +// Purpose: A base class for all material proxies in the client dll +// +// $NoKeywords: $ +//=============================================================================// + +#include "cbase.h" +// identifier was truncated to '255' characters in the debug information +//#pragma warning(disable: 4786) + +#include "ProxyEntity.h" +#include "materialsystem/IMaterialVar.h" + +class CEntityOriginMaterialProxy : public CEntityMaterialProxy +{ +public: + CEntityOriginMaterialProxy() + { + m_pMaterial = NULL; + m_pOriginVar = NULL; + } + virtual ~CEntityOriginMaterialProxy() + { + } + virtual bool Init( IMaterial *pMaterial, KeyValues *pKeyValues ) + { + m_pMaterial = pMaterial; + bool found; + m_pOriginVar = m_pMaterial->FindVar( "$entityorigin", &found ); + if( !found ) + { + m_pOriginVar = NULL; + return false; + } + return true; + } + virtual void OnBind( C_BaseEntity *pC_BaseEntity ) + { + const Vector &origin = pC_BaseEntity->GetAbsOrigin(); + m_pOriginVar->SetVecValue( origin.x, origin.y, origin.z ); + } + + virtual IMaterial *GetMaterial() + { + return m_pMaterial; + } + +protected: + IMaterial *m_pMaterial; + IMaterialVar *m_pOriginVar; +}; + +EXPOSE_INTERFACE( CEntityOriginMaterialProxy, IMaterialProxy, "EntityOrigin" IMATERIAL_PROXY_INTERFACE_VERSION ); + +//================================================================================================================= +// This is a last-minute hack to ship Orange Box on the 360! +//================================================================================================================= +class CEntityOriginAlyxMaterialProxy : public CEntityMaterialProxy +{ +public: + CEntityOriginAlyxMaterialProxy() + { + m_pMaterial = NULL; + m_pOriginVar = NULL; + } + virtual ~CEntityOriginAlyxMaterialProxy() + { + } + virtual bool Init( IMaterial *pMaterial, KeyValues *pKeyValues ) + { + m_pMaterial = pMaterial; + bool found; + m_pOriginVar = m_pMaterial->FindVar( "$entityorigin", &found ); + if( !found ) + { + m_pOriginVar = NULL; + return false; + } + return true; + } + virtual void OnBind( C_BaseEntity *pC_BaseEntity ) + { + const Vector &origin = pC_BaseEntity->GetAbsOrigin(); + m_pOriginVar->SetVecValue( origin.x - 15.0f, origin.y, origin.z ); + } + + virtual IMaterial *GetMaterial() + { + return m_pMaterial; + } + +protected: + IMaterial *m_pMaterial; + IMaterialVar *m_pOriginVar; +}; + +EXPOSE_INTERFACE( CEntityOriginAlyxMaterialProxy, IMaterialProxy, "EntityOriginAlyx" IMATERIAL_PROXY_INTERFACE_VERSION ); + +//================================================================================================================= +// This is a last-minute hack to ship Orange Box on the 360! +//================================================================================================================= +class CEp1IntroVortRefractMaterialProxy : public CEntityMaterialProxy +{ +public: + CEp1IntroVortRefractMaterialProxy() + { + m_pMaterial = NULL; + m_pOriginVar = NULL; + } + virtual ~CEp1IntroVortRefractMaterialProxy() + { + } + virtual bool Init( IMaterial *pMaterial, KeyValues *pKeyValues ) + { + m_pMaterial = pMaterial; + bool found; + m_pOriginVar = m_pMaterial->FindVar( "$refractamount", &found ); + if( !found ) + { + m_pOriginVar = NULL; + return false; + } + return true; + } + virtual void OnBind( C_BaseEntity *pC_BaseEntity ) + { + if ( m_pOriginVar != NULL) + { + float flTmp = ( 1.0f - m_pOriginVar->GetFloatValue() ); + flTmp *= flTmp; + flTmp *= flTmp; + flTmp = ( 1.0f - flTmp ) * 0.25f; + m_pOriginVar->SetFloatValue( flTmp ); + } + } + + virtual IMaterial *GetMaterial() + { + return m_pMaterial; + } + +protected: + IMaterial *m_pMaterial; + IMaterialVar *m_pOriginVar; +}; + +EXPOSE_INTERFACE( CEp1IntroVortRefractMaterialProxy, IMaterialProxy, "Ep1IntroVortRefract" IMATERIAL_PROXY_INTERFACE_VERSION ); diff --git a/src/src/game/client/episodic/c_npc_advisor.cpp b/src/src/game/client/episodic/c_npc_advisor.cpp new file mode 100644 index 0000000..76f3fc2 --- /dev/null +++ b/src/src/game/client/episodic/c_npc_advisor.cpp @@ -0,0 +1,251 @@ +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: Definition for client-side advisor. +// +//=====================================================================================// + + + +#include "cbase.h" +// this file contains the definitions for the message ID constants (eg ADVISOR_MSG_START_BEAM etc) +#include "npc_advisor_shared.h" + +#if NPC_ADVISOR_HAS_BEHAVIOR + +#include "particles_simple.h" +#include "citadel_effects_shared.h" +#include "particles_attractor.h" +#include "ClientEffectPrecacheSystem.h" +#include "c_te_effect_dispatch.h" + +#include "c_ai_basenpc.h" +#include "dlight.h" +#include "iefx.h" + + +//----------------------------------------------------------------------------- +// Purpose: unpack a networked entity index into a basehandle. +//----------------------------------------------------------------------------- +inline C_BaseEntity *IndexToEntity( int eindex ) +{ + return ClientEntityList().GetBaseEntityFromHandle(ClientEntityList().EntIndexToHandle(eindex)); +} + + + +#define ADVISOR_ELIGHT_CVARS 1 // enable/disable tuning advisor elight with console variables + +#if ADVISOR_ELIGHT_CVARS +ConVar advisor_elight_e("advisor_elight_e","3"); +ConVar advisor_elight_rfeet("advisor_elight_rfeet","52"); +#endif + + +/*! Client-side reflection of the advisor class. + */ +class C_NPC_Advisor : public C_AI_BaseNPC +{ + DECLARE_CLASS( C_NPC_Advisor, C_AI_BaseNPC ); + DECLARE_CLIENTCLASS(); + +public: + // Server to client message received + virtual void ReceiveMessage( int classID, bf_read &msg ); + virtual void ClientThink( void ); + +private: + /* + // broken into its own function so I can move it if necesasry + void Initialize(); + */ + + // start/stop beam particle effect from me to a pelting object + void StartBeamFX( C_BaseEntity *pOnEntity ); + void StopBeamFX( C_BaseEntity *pOnEntity ); + + void StartElight(); + void StopElight(); + + int m_ElightKey; // test using an elight to make the escape sequence more visible. 0 is invalid. + +}; + +IMPLEMENT_CLIENTCLASS_DT( C_NPC_Advisor, DT_NPC_Advisor, CNPC_Advisor ) + +END_RECV_TABLE() + +// Server to client message received +void C_NPC_Advisor::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 ADVISOR_MSG_START_BEAM: + { + int eindex = msg.ReadLong(); + StartBeamFX(IndexToEntity(eindex)); + } + break; + + case ADVISOR_MSG_STOP_BEAM: + { + int eindex = msg.ReadLong(); + StopBeamFX(IndexToEntity(eindex)); + + } + break; + + case ADVISOR_MSG_STOP_ALL_BEAMS: + { + ParticleProp()->StopEmission(); + } + break; + case ADVISOR_MSG_START_ELIGHT: + { + StartElight(); + } + break; + case ADVISOR_MSG_STOP_ELIGHT: + { + StopElight(); + } + break; + + default: + AssertMsg1( false, "Received unknown message %d", messageType); + } +} + +/// only use of the clientthink on the advisor is to update the elight +void C_NPC_Advisor::ClientThink( void ) +{ + // if the elight has gone away, bail out + if (m_ElightKey == 0) + { + SetNextClientThink( CLIENT_THINK_NEVER ); + return; + } + + // get the elight + dlight_t * el = effects->GetElightByKey(m_ElightKey); + if (!el) + { + // the elight has been invalidated. bail out. + m_ElightKey = 0; + + SetNextClientThink( CLIENT_THINK_NEVER ); + return; + } + else + { + el->origin = WorldSpaceCenter(); + +#if ADVISOR_ELIGHT_CVARS + el->color.exponent = advisor_elight_e.GetFloat(); + el->radius = advisor_elight_rfeet.GetFloat() * 12.0f; +#endif + } +} + +//----------------------------------------------------------------------------- +// Create a telekinetic beam effect from my head to an object +// TODO: use a point attachment. +//----------------------------------------------------------------------------- +void C_NPC_Advisor::StartBeamFX( C_BaseEntity *pOnEntity ) +{ + Assert(pOnEntity); + if (!pOnEntity) + return; + + CNewParticleEffect *pEffect = ParticleProp()->Create( "Advisor_Psychic_Beam", PATTACH_ABSORIGIN_FOLLOW ); + + Assert(pEffect); + if (!pEffect) return; + + ParticleProp()->AddControlPoint( pEffect, 1, pOnEntity, PATTACH_ABSORIGIN_FOLLOW ); +} + + +//----------------------------------------------------------------------------- +// terminate a telekinetic beam effect from my head to an object +//----------------------------------------------------------------------------- +void C_NPC_Advisor::StopBeamFX( C_BaseEntity *pOnEntity ) +{ + Assert(pOnEntity); + if (!pOnEntity) + return; + + ParticleProp()->StopParticlesInvolving( pOnEntity ); +} + + + + + + +void C_NPC_Advisor::StartElight() +{ + AssertMsg(m_ElightKey == 0 , "Advisor trying to create new elight on top of old one!"); + if ( m_ElightKey != 0 ) + { + Warning("Advisor tried to start his elight when it was already one.\n"); + } + else + { + m_ElightKey = LIGHT_INDEX_TE_DYNAMIC + this->entindex(); + dlight_t * el = effects->CL_AllocElight( m_ElightKey ); + + if ( el ) + { + // create an elight on top of me + el->origin = this->WorldSpaceCenter(); + + el->color.r = 235; + el->color.g = 255; + el->color.b = 255; + el->color.exponent = 3; + + el->radius = 52*12; + el->decay = 0.0f; + el->die = gpGlobals->curtime + 2000.0f; // 1000 just means " a long time " + + SetNextClientThink( CLIENT_THINK_ALWAYS ); + } + else + { // null out the light value + m_ElightKey = 0; + } + } +} + +void C_NPC_Advisor::StopElight() +{ + AssertMsg( m_ElightKey != 0, "Advisor tried to stop elight when none existed!"); + dlight_t * el; + // note: the following conditional sets el if not short-circuited + if ( m_ElightKey == 0 || (el = effects->GetElightByKey(m_ElightKey)) == NULL ) + { + Warning("Advisor tried to stop its elight when it had none.\n"); + } + else + { + // kill the elight by setting the die value to now + el->die = gpGlobals->curtime; + } +} + + +#endif + +/****************************************************** + * Tenser, said the Tensor. * + * Tenser, said the Tensor. * + * Tension, apprehension and dissension have begun. * + ******************************************************/ diff --git a/src/src/game/client/episodic/c_npc_puppet.cpp b/src/src/game/client/episodic/c_npc_puppet.cpp new file mode 100644 index 0000000..9c19414 --- /dev/null +++ b/src/src/game/client/episodic/c_npc_puppet.cpp @@ -0,0 +1,167 @@ +//====== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======= +// +// Purpose: +// +//============================================================================= + +#include "cbase.h" +#include "c_ai_basenpc.h" +#include "bone_setup.h" + +// Must be the last file included +#include "memdbgon.h" + + +extern ConVar r_sequence_debug; + +class C_NPC_Puppet : public C_AI_BaseNPC +{ + DECLARE_CLASS( C_NPC_Puppet, C_AI_BaseNPC ); +public: + + virtual void ClientThink( void ); + virtual void OnDataChanged( DataUpdateType_t updateType ); + virtual void BuildTransformations( CStudioHdr *pStudioHdr, Vector *pos, Quaternion q[], const matrix3x4_t& cameraTransform, int boneMask, CBoneBitList &boneComputed ); + virtual void AccumulateLayers( CStudioHdr *hdr, Vector pos[], Quaternion q[], float poseparam[], float currentTime, int boneMask ); + + EHANDLE m_hAnimationTarget; + int m_nTargetAttachment; + + DECLARE_CLIENTCLASS(); +}; + +IMPLEMENT_CLIENTCLASS_DT( C_NPC_Puppet, DT_NPC_Puppet, CNPC_Puppet ) + RecvPropEHandle( RECVINFO(m_hAnimationTarget) ), + RecvPropInt( RECVINFO(m_nTargetAttachment) ), +END_RECV_TABLE() + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_NPC_Puppet::OnDataChanged( DataUpdateType_t updateType ) +{ + BaseClass::OnDataChanged( updateType ); + + if ( updateType == DATA_UPDATE_CREATED ) + { + SetNextClientThink( CLIENT_THINK_ALWAYS ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: We need to slam our position! +//----------------------------------------------------------------------------- +void C_NPC_Puppet::BuildTransformations( CStudioHdr *pStudioHdr, Vector *pos, Quaternion q[], const matrix3x4_t& cameraTransform, int boneMask, CBoneBitList &boneComputed ) +{ + if ( m_hAnimationTarget && m_nTargetAttachment != -1 ) + { + C_BaseAnimating *pTarget = m_hAnimationTarget->GetBaseAnimating(); + if ( pTarget ) + { + matrix3x4_t matTarget; + pTarget->GetAttachment( m_nTargetAttachment, matTarget ); + + MatrixCopy( matTarget, GetBoneForWrite( 0 ) ); + boneComputed.ClearAll(); // FIXME: Why is this calculated already? + boneComputed.MarkBone( 0 ); + } + } + + // Call the baseclass + BaseClass::BuildTransformations( pStudioHdr, pos, q, cameraTransform, boneMask, boneComputed ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_NPC_Puppet::ClientThink( void ) +{ + if ( m_hAnimationTarget == NULL ) + return; + + C_BaseAnimating *pTarget = m_hAnimationTarget->GetBaseAnimating(); + if ( pTarget == NULL ) + return; + + int nTargetSequence = pTarget->GetSequence(); + const char *pSequenceName = pTarget->GetSequenceName( nTargetSequence ); + + int nSequence = LookupSequence( pSequenceName ); + if ( nSequence >= 0 ) + { + if ( nSequence != GetSequence() ) + { + SetSequence( nSequence ); + UpdateVisibility(); + } + + SetCycle( pTarget->GetCycle() ); + SetPlaybackRate( pTarget->GetPlaybackRate() ); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_NPC_Puppet::AccumulateLayers( CStudioHdr *hdr, Vector pos[], Quaternion q[], float poseparam[], float currentTime, int boneMask ) +{ + if ( m_hAnimationTarget == NULL ) + return; + + C_BaseAnimatingOverlay *pTarget = dynamic_cast( m_hAnimationTarget->GetBaseAnimating() ); + if ( pTarget == NULL ) + return; + + // resort the layers + int layer[MAX_OVERLAYS]; + int i; + for (i = 0; i < MAX_OVERLAYS; i++) + { + layer[i] = MAX_OVERLAYS; + } + for (i = 0; i < pTarget->m_AnimOverlay.Count(); i++) + { + if (pTarget->m_AnimOverlay[i].m_nOrder < MAX_OVERLAYS) + { + layer[pTarget->m_AnimOverlay[i].m_nOrder] = i; + } + } + + int j; + for (j = 0; j < MAX_OVERLAYS; j++) + { + i = layer[ j ]; + if (i < pTarget->m_AnimOverlay.Count()) + { + float fWeight = pTarget->m_AnimOverlay[i].m_flWeight; + + if (fWeight > 0) + { + const char *pSequenceName = pTarget->GetSequenceName( pTarget->m_AnimOverlay[i].m_nSequence ); + + int nSequence = LookupSequence( pSequenceName ); + if ( nSequence >= 0 ) + { + float fCycle = pTarget->m_AnimOverlay[ i ].m_flCycle; + + fCycle = ClampCycle( fCycle, IsSequenceLooping( nSequence ) ); + + if (fWeight > 1) + fWeight = 1; + + AccumulatePose( hdr, NULL, pos, q, nSequence, fCycle, poseparam, boneMask, fWeight, currentTime ); + +#if _DEBUG + if (Q_stristr( hdr->pszName(), r_sequence_debug.GetString()) != NULL) + { + DevMsgRT( "%6.2f : %30s : %5.3f : %4.2f : %1d\n", currentTime, hdr->pSeqdesc( nSequence ).pszLabel(), fCycle, fWeight, i ); + } +#endif + + } + } + } + } +} + diff --git a/src/src/cl_dll/episodic/c_prop_coreball.cpp b/src/src/game/client/episodic/c_prop_coreball.cpp similarity index 100% rename from src/src/cl_dll/episodic/c_prop_coreball.cpp rename to src/src/game/client/episodic/c_prop_coreball.cpp diff --git a/src/src/game/client/episodic/c_prop_scalable.cpp b/src/src/game/client/episodic/c_prop_scalable.cpp new file mode 100644 index 0000000..3a6b35a --- /dev/null +++ b/src/src/game/client/episodic/c_prop_scalable.cpp @@ -0,0 +1,196 @@ +//====== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======= +// +// Purpose: +// +//============================================================================= + +#include "cbase.h" + +class C_PropScalable : public C_BaseAnimating +{ + DECLARE_CLASS( C_PropScalable, C_BaseAnimating ); + DECLARE_CLIENTCLASS(); + DECLARE_DATADESC(); + +public: + + C_PropScalable(); + + virtual void ApplyBoneMatrixTransform( matrix3x4_t& transform ); + virtual void GetRenderBounds( Vector &theMins, Vector &theMaxs ); + + // Must be available to proxy functions + float m_flScaleX; + float m_flScaleY; + float m_flScaleZ; + + float m_flLerpTimeX; + float m_flLerpTimeY; + float m_flLerpTimeZ; + + float m_flGoalTimeX; + float m_flGoalTimeY; + float m_flGoalTimeZ; + + float m_flCurrentScale[3]; + bool m_bRunningScale[3]; + float m_flTargetScale[3]; + +private: + + void CalculateScale( void ); + float m_nCalcFrame; // Frame the last calculation was made at +}; + +void RecvProxy_ScaleX( const CRecvProxyData *pData, void *pStruct, void *pOut ) +{ + C_PropScalable *pCoreData = (C_PropScalable *) pStruct; + + pCoreData->m_flScaleX = pData->m_Value.m_Float; + + if ( pCoreData->m_bRunningScale[0] == true ) + { + pCoreData->m_flTargetScale[0] = pCoreData->m_flCurrentScale[0]; + } +} + +void RecvProxy_ScaleY( const CRecvProxyData *pData, void *pStruct, void *pOut ) +{ + C_PropScalable *pCoreData = (C_PropScalable *) pStruct; + + pCoreData->m_flScaleY = pData->m_Value.m_Float; + + if ( pCoreData->m_bRunningScale[1] == true ) + { + pCoreData->m_flTargetScale[1] = pCoreData->m_flCurrentScale[1]; + } +} + +void RecvProxy_ScaleZ( const CRecvProxyData *pData, void *pStruct, void *pOut ) +{ + C_PropScalable *pCoreData = (C_PropScalable *) pStruct; + + pCoreData->m_flScaleZ = pData->m_Value.m_Float; + + if ( pCoreData->m_bRunningScale[2] == true ) + { + pCoreData->m_flTargetScale[2] = pCoreData->m_flCurrentScale[2]; + } +} + +IMPLEMENT_CLIENTCLASS_DT( C_PropScalable, DT_PropScalable, CPropScalable ) + RecvPropFloat( RECVINFO( m_flScaleX ), 0, RecvProxy_ScaleX ), + RecvPropFloat( RECVINFO( m_flScaleY ), 0, RecvProxy_ScaleY ), + RecvPropFloat( RECVINFO( m_flScaleZ ), 0, RecvProxy_ScaleZ ), + + RecvPropFloat( RECVINFO( m_flLerpTimeX ) ), + RecvPropFloat( RECVINFO( m_flLerpTimeY ) ), + RecvPropFloat( RECVINFO( m_flLerpTimeZ ) ), + + RecvPropFloat( RECVINFO( m_flGoalTimeX ) ), + RecvPropFloat( RECVINFO( m_flGoalTimeY ) ), + RecvPropFloat( RECVINFO( m_flGoalTimeZ ) ), +END_RECV_TABLE() + + +BEGIN_DATADESC( C_PropScalable ) + DEFINE_AUTO_ARRAY( m_flTargetScale, FIELD_FLOAT ), + DEFINE_AUTO_ARRAY( m_bRunningScale, FIELD_BOOLEAN ), +END_DATADESC() + +C_PropScalable::C_PropScalable( void ) +{ + m_flTargetScale[0] = 1.0f; + m_flTargetScale[1] = 1.0f; + m_flTargetScale[2] = 1.0f; + + m_bRunningScale[0] = false; + m_bRunningScale[1] = false; + m_bRunningScale[2] = false; + + m_nCalcFrame = 0; +} + +//----------------------------------------------------------------------------- +// Purpose: Calculates the scake of the object once per frame +//----------------------------------------------------------------------------- +void C_PropScalable::CalculateScale( void ) +{ + // Don't bother to calculate this for a second time in the same frame + if ( m_nCalcFrame == gpGlobals->framecount ) + return; + + // Mark that we cached this value for the frame + m_nCalcFrame = gpGlobals->framecount; + + float flVal[3] = { m_flTargetScale[0], m_flTargetScale[1], m_flTargetScale[2] }; + float *flTargetScale[3] = { &m_flTargetScale[0], &m_flTargetScale[1], &m_flTargetScale[2] }; + float flScale[3] = { m_flScaleX, m_flScaleY, m_flScaleZ }; + float flLerpTime[3] = { m_flLerpTimeX, m_flLerpTimeY, m_flLerpTimeZ }; + float flGoalTime[3] = { m_flGoalTimeX, m_flGoalTimeY, m_flGoalTimeZ }; + bool *bRunning[3] = { &m_bRunningScale[0], &m_bRunningScale[1], &m_bRunningScale[2] }; + + for ( int i = 0; i < 3; i++ ) + { + if ( *flTargetScale[i] != flScale[i] ) + { + float deltaTime = (float)( gpGlobals->curtime - flGoalTime[i]) / flLerpTime[i]; + float flRemapVal = SimpleSplineRemapValClamped( deltaTime, 0.0f, 1.0f, *flTargetScale[i], flScale[i] ); + + *bRunning[i] = true; + + if ( deltaTime >= 1.0f ) + { + *flTargetScale[i] = flScale[i]; + *bRunning[i] = false; + } + + flVal[i] = flRemapVal; + m_flCurrentScale[i] = flVal[i]; + } + else + { + m_flCurrentScale[i] = m_flTargetScale[i]; + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: Scales the bones based on the current scales +//----------------------------------------------------------------------------- +void C_PropScalable::ApplyBoneMatrixTransform( matrix3x4_t& transform ) +{ + BaseClass::ApplyBoneMatrixTransform( transform ); + + // Find the scale for this frame + CalculateScale(); + + VectorScale( transform[0], m_flCurrentScale[0], transform[0] ); + VectorScale( transform[1], m_flCurrentScale[1], transform[1] ); + VectorScale( transform[2], m_flCurrentScale[2], transform[2] ); + + UpdateVisibility(); +} + +//----------------------------------------------------------------------------- +// Purpose: Ensures the render bounds match the scales +//----------------------------------------------------------------------------- +void C_PropScalable::GetRenderBounds( Vector &theMins, Vector &theMaxs ) +{ + BaseClass::GetRenderBounds( theMins, theMaxs ); + + // Find the scale for this frame + CalculateScale(); + + // Extend our render bounds to encompass the scaled object + theMins.x *= m_flCurrentScale[0]; + theMins.y *= m_flCurrentScale[1]; + theMins.z *= m_flCurrentScale[2]; + + theMaxs.x *= m_flCurrentScale[0]; + theMaxs.y *= m_flCurrentScale[1]; + theMaxs.z *= m_flCurrentScale[2]; + + Assert( theMins.IsValid() && theMaxs.IsValid() ); + +} diff --git a/src/src/game/client/episodic/c_vehicle_jeep_episodic.cpp b/src/src/game/client/episodic/c_vehicle_jeep_episodic.cpp new file mode 100644 index 0000000..b258815 --- /dev/null +++ b/src/src/game/client/episodic/c_vehicle_jeep_episodic.cpp @@ -0,0 +1,133 @@ +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include "c_prop_vehicle.h" +#include "c_vehicle_jeep.h" +#include "movevars_shared.h" +#include "view.h" +#include "flashlighteffect.h" +#include "c_baseplayer.h" +#include "c_te_effect_dispatch.h" +#include "hl2_vehicle_radar.h" +#include "usermessages.h" +#include "hud_radar.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +//============================================================================= +// +// Client-side Episodic Jeep (Jalopy) Class +// +class C_PropJeepEpisodic : public C_PropJeep +{ + + DECLARE_CLASS( C_PropJeepEpisodic, C_PropJeep ); + +public: + DECLARE_CLIENTCLASS(); + +public: + C_PropJeepEpisodic(); + + void OnEnteredVehicle( C_BasePlayer *pPlayer ); + void Simulate( void ); + +public: + int m_iNumRadarContacts; + Vector m_vecRadarContactPos[ RADAR_MAX_CONTACTS ]; + int m_iRadarContactType[ RADAR_MAX_CONTACTS ]; +}; +C_PropJeepEpisodic *g_pJalopy = NULL; + +IMPLEMENT_CLIENTCLASS_DT( C_PropJeepEpisodic, DT_CPropJeepEpisodic, CPropJeepEpisodic ) + //CNetworkVar( int, m_iNumRadarContacts ); + RecvPropInt( RECVINFO(m_iNumRadarContacts) ), + + //CNetworkArray( Vector, m_vecRadarContactPos, RADAR_MAX_CONTACTS ); + RecvPropArray( RecvPropVector(RECVINFO(m_vecRadarContactPos[0])), m_vecRadarContactPos ), + + //CNetworkArray( int, m_iRadarContactType, RADAR_MAX_CONTACTS ); + RecvPropArray( RecvPropInt( RECVINFO(m_iRadarContactType[0] ) ), m_iRadarContactType ), + +END_RECV_TABLE() + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void __MsgFunc_UpdateJalopyRadar(bf_read &msg) +{ + // Radar code here! + if( !GetHudRadar() ) + return; + + // Sometimes we update more quickly when we need to track something in high resolution. + // Usually we do not, so default to false. + GetHudRadar()->m_bUseFastUpdate = false; + + for( int i = 0 ; i < g_pJalopy->m_iNumRadarContacts ; i++ ) + { + if( g_pJalopy->m_iRadarContactType[i] == RADAR_CONTACT_DOG ) + { + GetHudRadar()->m_bUseFastUpdate = true; + break; + } + } + + float flContactTimeToLive; + + if( GetHudRadar()->m_bUseFastUpdate ) + { + flContactTimeToLive = RADAR_UPDATE_FREQUENCY_FAST; + } + else + { + flContactTimeToLive = RADAR_UPDATE_FREQUENCY; + } + + for( int i = 0 ; i < g_pJalopy->m_iNumRadarContacts ; i++ ) + { + GetHudRadar()->AddRadarContact( g_pJalopy->m_vecRadarContactPos[i], g_pJalopy->m_iRadarContactType[i], flContactTimeToLive ); + } +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +C_PropJeepEpisodic::C_PropJeepEpisodic() +{ + if( g_pJalopy == NULL ) + { + usermessages->HookMessage( "UpdateJalopyRadar", __MsgFunc_UpdateJalopyRadar ); + } + + g_pJalopy = this; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_PropJeepEpisodic::Simulate( void ) +{ + // Keep trying to hook to the radar. + if( GetHudRadar() != NULL ) + { + // This is not our ideal long-term solution. This will only work if you only have + // one jalopy in a given level. The Jalopy and the Radar Screen are currently both + // assumed to be singletons. This is appropriate for EP2, however. (sjb) + GetHudRadar()->SetVehicle( this ); + } + + BaseClass::Simulate(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_PropJeepEpisodic::OnEnteredVehicle( C_BasePlayer *pPlayer ) +{ + BaseClass::OnEnteredVehicle( pPlayer ); +} diff --git a/src/src/game/client/episodic/c_vort_charge_token.cpp b/src/src/game/client/episodic/c_vort_charge_token.cpp new file mode 100644 index 0000000..d89f2f1 --- /dev/null +++ b/src/src/game/client/episodic/c_vort_charge_token.cpp @@ -0,0 +1,600 @@ +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=====================================================================================// + +#include "cbase.h" +#include "particles_simple.h" +#include "citadel_effects_shared.h" +#include "particles_attractor.h" +#include "iefx.h" +#include "dlight.h" +#include "ClientEffectPrecacheSystem.h" +#include "c_te_effect_dispatch.h" +#include "fx_quad.h" + +#include "c_ai_basenpc.h" + +// For material proxy +#include "ProxyEntity.h" +#include "materialsystem/IMaterial.h" +#include "materialsystem/IMaterialVar.h" + +#define NUM_INTERIOR_PARTICLES 8 + +#define DLIGHT_RADIUS (150.0f) +#define DLIGHT_MINLIGHT (40.0f/255.0f) + +class C_NPC_Vortigaunt : public C_AI_BaseNPC +{ + DECLARE_CLASS( C_NPC_Vortigaunt, C_AI_BaseNPC ); + DECLARE_CLIENTCLASS(); + +public: + virtual void OnDataChanged( DataUpdateType_t updateType ); + virtual void ClientThink( void ); + virtual void ReceiveMessage( int classID, bf_read &msg ); + +public: + bool m_bIsBlue; ///< wants to fade to blue + float m_flBlueEndFadeTime; ///< when to end fading from one skin to another + + bool m_bIsBlack; ///< wants to fade to black (networked) + float m_flBlackFade; ///< [0.00 .. 1.00] where 1.00 is all black. Locally interpolated. +}; + +IMPLEMENT_CLIENTCLASS_DT( C_NPC_Vortigaunt, DT_NPC_Vortigaunt, CNPC_Vortigaunt ) + RecvPropTime( RECVINFO(m_flBlueEndFadeTime ) ), + RecvPropBool( RECVINFO(m_bIsBlue) ), + RecvPropBool( RECVINFO(m_bIsBlack) ), +END_RECV_TABLE() + + +#define VORTIGAUNT_BLUE_FADE_TIME 2.25f // takes this long to fade from green to blue or back +#define VORT_BLACK_FADE_TIME 2.2f // time to interpolate up or down in fading to black + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : updateType - +//----------------------------------------------------------------------------- +void C_NPC_Vortigaunt::OnDataChanged( DataUpdateType_t updateType ) +{ + BaseClass::OnDataChanged( updateType ); + + // start thinking if we need to fade. + if ( m_flBlackFade != (m_bIsBlack ? 1.0f : 0.0f) ) + { + SetNextClientThink( CLIENT_THINK_ALWAYS ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_NPC_Vortigaunt::ClientThink( void ) +{ + // Don't update if our frame hasn't moved forward (paused) + if ( gpGlobals->frametime <= 0.0f ) + return; + + if ( m_bIsBlack ) + { + // are we done? + if ( m_flBlackFade >= 1.0f ) + { + m_flBlackFade = 1.0f; + SetNextClientThink( CLIENT_THINK_NEVER ); + } + else // interpolate there + { + float lerpQuant = gpGlobals->frametime / VORT_BLACK_FADE_TIME; + m_flBlackFade += lerpQuant; + if ( m_flBlackFade > 1.0f ) + { + m_flBlackFade = 1.0f; + } + } + } + else + { + // are we done? + if ( m_flBlackFade <= 0.0f ) + { + m_flBlackFade = 0.0f; + SetNextClientThink( CLIENT_THINK_NEVER ); + } + else // interpolate there + { + float lerpQuant = gpGlobals->frametime / VORT_BLACK_FADE_TIME; + m_flBlackFade -= lerpQuant; + if ( m_flBlackFade < 0.0f ) + { + m_flBlackFade = 0.0f; + } + } + } +} + +// FIXME: Move to shared code! +#define VORTFX_ZAPBEAM 0 +#define VORTFX_ARMBEAM 1 + +//----------------------------------------------------------------------------- +// Purpose: Receive messages from the server +//----------------------------------------------------------------------------- +void C_NPC_Vortigaunt::ReceiveMessage( int classID, bf_read &msg ) +{ + // Is the message for a sub-class? + if ( classID != GetClientClass()->m_ClassID ) + { + BaseClass::ReceiveMessage( classID, msg ); + return; + } + + int messageType = msg.ReadByte(); + switch( messageType ) + { + case VORTFX_ZAPBEAM: + { + // Find our attachment point + unsigned char nAttachment = msg.ReadByte(); + + // Get our attachment position + Vector vecStart; + QAngle vecAngles; + GetAttachment( nAttachment, vecStart, vecAngles ); + + // Get the final position we'll strike + Vector vecEndPos; + msg.ReadBitVec3Coord( vecEndPos ); + + // Place a beam between the two points + CNewParticleEffect *pEffect = ParticleProp()->Create( "vortigaunt_beam", PATTACH_POINT_FOLLOW, nAttachment ); + if ( pEffect ) + { + pEffect->SetControlPoint( 0, vecStart ); + pEffect->SetControlPoint( 1, vecEndPos ); + } + } + break; + + case VORTFX_ARMBEAM: + { + int nIndex = msg.ReadLong(); + C_BaseEntity *pEnt = ClientEntityList().GetBaseEntityFromHandle( ClientEntityList().EntIndexToHandle( nIndex ) ); + + if ( pEnt ) + { + unsigned char nAttachment = msg.ReadByte(); + Vector vecEndPos; + msg.ReadBitVec3Coord( vecEndPos ); + + Vector vecNormal; + msg.ReadBitVec3Normal( vecNormal ); + + CNewParticleEffect *pEffect = pEnt->ParticleProp()->Create( "vortigaunt_beam_charge", PATTACH_POINT_FOLLOW, nAttachment ); + if ( pEffect ) + { + // Set the control point's angles to be the surface normal we struct + Vector vecRight, vecUp; + VectorVectors( vecNormal, vecRight, vecUp ); + pEffect->SetControlPointOrientation( 1, vecNormal, vecRight, vecUp ); + pEffect->SetControlPoint( 1, vecEndPos ); + } + } + } + break; + default: + AssertMsg1( false, "Received unknown message %d", messageType); + } +} + +class C_VortigauntChargeToken : public C_BaseEntity +{ + DECLARE_CLASS( C_VortigauntChargeToken, C_BaseEntity ); + DECLARE_CLIENTCLASS(); + +public: + virtual void UpdateOnRemove( void ); + virtual void ClientThink( void ); + virtual void NotifyShouldTransmit( ShouldTransmitState_t state ); + virtual void OnDataChanged( DataUpdateType_t type ); + + // For RecvProxy handlers + float m_flFadeOutTime; + float m_flFadeOutStart; + +private: + bool SetupEmitters( void ); + + bool m_bFadeOut; + CNewParticleEffect *m_hEffect; + dlight_t *m_pDLight; +}; + +void RecvProxy_FadeOutDuration( const CRecvProxyData *pData, void *pStruct, void *pOut ) +{ + C_VortigauntChargeToken *pVortToken = (C_VortigauntChargeToken *) pStruct; + Assert( pOut == &pVortToken->m_flFadeOutTime ); + + pVortToken->m_flFadeOutStart = gpGlobals->curtime; + pVortToken->m_flFadeOutTime = ( pData->m_Value.m_Float - gpGlobals->curtime ); +} + +IMPLEMENT_CLIENTCLASS_DT( C_VortigauntChargeToken, DT_VortigauntChargeToken, CVortigauntChargeToken ) + RecvPropBool( RECVINFO( m_bFadeOut ) ), +END_RECV_TABLE() + +void C_VortigauntChargeToken::UpdateOnRemove( void ) +{ + if ( m_hEffect ) + { + m_hEffect->StopEmission(); + m_hEffect = NULL; + } + + if ( m_pDLight != NULL ) + { + m_pDLight->die = gpGlobals->curtime; + } +} + +//----------------------------------------------------------------------------- +// Purpose: Change our transmission state +//----------------------------------------------------------------------------- +void C_VortigauntChargeToken::NotifyShouldTransmit( ShouldTransmitState_t state ) +{ + BaseClass::NotifyShouldTransmit( state ); + + // Turn off + if ( state == SHOULDTRANSMIT_END ) + { + if ( m_hEffect ) + { + m_hEffect->StopEmission(); + m_hEffect = NULL; + } + } + + // Turn on + if ( state == SHOULDTRANSMIT_START ) + { + m_hEffect = ParticleProp()->Create( "vortigaunt_charge_token", PATTACH_ABSORIGIN_FOLLOW ); + m_hEffect->SetControlPointEntity( 0, this ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_VortigauntChargeToken::OnDataChanged( DataUpdateType_t type ) +{ + if ( m_bFadeOut ) + { + if ( m_hEffect ) + { + m_hEffect->StopEmission(); + m_hEffect = NULL; + } + } + + BaseClass::OnDataChanged( type ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_VortigauntChargeToken::ClientThink( void ) +{ + // + // -- DLight + // + + if ( m_pDLight != NULL ) + { + m_pDLight->origin = GetAbsOrigin(); + m_pDLight->radius = DLIGHT_RADIUS; + } +} + +//============================================================================= +// +// Dispel Effect +// +//============================================================================= + +class C_VortigauntEffectDispel : public C_BaseEntity +{ + DECLARE_CLASS( C_VortigauntEffectDispel, C_BaseEntity ); + DECLARE_CLIENTCLASS(); + +public: + virtual void UpdateOnRemove( void ); + virtual void ClientThink( void ); + virtual void NotifyShouldTransmit( ShouldTransmitState_t state ); + virtual void OnDataChanged( DataUpdateType_t type ); + + // For RecvProxy handlers + float m_flFadeOutTime; + float m_flFadeOutStart; + +private: + bool SetupEmitters( void ); + + CNewParticleEffect *m_hEffect; + bool m_bFadeOut; + dlight_t *m_pDLight; +}; + +void RecvProxy_DispelFadeOutDuration( const CRecvProxyData *pData, void *pStruct, void *pOut ) +{ + C_VortigauntEffectDispel *pVortToken = (C_VortigauntEffectDispel *) pStruct; + Assert( pOut == &pVortToken->m_flFadeOutTime ); + + pVortToken->m_flFadeOutStart = gpGlobals->curtime; + pVortToken->m_flFadeOutTime = ( pData->m_Value.m_Float - gpGlobals->curtime ); +} + +IMPLEMENT_CLIENTCLASS_DT( C_VortigauntEffectDispel, DT_VortigauntEffectDispel, CVortigauntEffectDispel ) + RecvPropBool( RECVINFO( m_bFadeOut ) ), +END_RECV_TABLE() + +void C_VortigauntEffectDispel::UpdateOnRemove( void ) +{ + if ( m_hEffect ) + { + m_hEffect->StopEmission(); + m_hEffect = NULL; + } + + if ( m_pDLight != NULL ) + { + m_pDLight->die = gpGlobals->curtime; + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_VortigauntEffectDispel::OnDataChanged( DataUpdateType_t type ) +{ + if ( m_bFadeOut ) + { + if ( m_hEffect ) + { + m_hEffect->StopEmission(); + m_hEffect = NULL; + } + } + + BaseClass::OnDataChanged( type ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_VortigauntEffectDispel::NotifyShouldTransmit( ShouldTransmitState_t state ) +{ + BaseClass::NotifyShouldTransmit( state ); + + // Turn off + if ( state == SHOULDTRANSMIT_END ) + { + if ( m_hEffect ) + { + m_hEffect->StopEmission(); + m_hEffect = NULL; + } + } + + // Turn on + if ( state == SHOULDTRANSMIT_START ) + { + m_hEffect = ParticleProp()->Create( "vortigaunt_hand_glow", PATTACH_ABSORIGIN_FOLLOW ); + m_hEffect->SetControlPointEntity( 0, this ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Create our emitter +//----------------------------------------------------------------------------- +bool C_VortigauntEffectDispel::SetupEmitters( void ) +{ + m_pDLight = NULL; + +#ifndef _X360 + m_pDLight = effects->CL_AllocDlight ( index ); + m_pDLight->origin = GetAbsOrigin(); + m_pDLight->color.r = 64; + m_pDLight->color.g = 255; + m_pDLight->color.b = 64; + m_pDLight->radius = 0; + m_pDLight->minlight = DLIGHT_MINLIGHT; + m_pDLight->die = FLT_MAX; +#endif // _X360 + + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_VortigauntEffectDispel::ClientThink( void ) +{ + if ( m_pDLight != NULL ) + { + m_pDLight->origin = GetAbsOrigin(); + m_pDLight->radius = DLIGHT_RADIUS; + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void DispelCallback( const CEffectData &data ) +{ + // Kaboom! + Vector startPos = data.m_vOrigin + Vector(0,0,16); + Vector endPos = data.m_vOrigin + Vector(0,0,-64); + + trace_t tr; + UTIL_TraceLine( startPos, endPos, MASK_SOLID_BRUSHONLY, NULL, COLLISION_GROUP_NONE, &tr ); + + if ( tr.fraction < 1.0f ) + { + //Add a ripple quad to the surface + FX_AddQuad( tr.endpos + ( tr.plane.normal * 8.0f ), + Vector( 0, 0, 1 ), + 64.0f, + 600.0f, + 0.8f, + 1.0f, // start alpha + 0.0f, // end alpha + 0.3f, + random->RandomFloat( 0, 360 ), + 0.0f, + Vector( 0.5f, 1.0f, 0.5f ), + 0.75f, + "effects/ar2_altfire1b", + (FXQUAD_BIAS_SCALE|FXQUAD_BIAS_ALPHA|FXQUAD_COLOR_FADE) ); + + //Add a ripple quad to the surface + FX_AddQuad( tr.endpos + ( tr.plane.normal * 8.0f ), + Vector( 0, 0, 1 ), + 16.0f, + 300.0f, + 0.9f, + 1.0f, // start alpha + 0.0f, // end alpha + 0.9f, + random->RandomFloat( 0, 360 ), + 0.0f, + Vector( 0.5f, 1.0f, 0.5f ), + 1.25f, + "effects/rollerglow", + (FXQUAD_BIAS_SCALE|FXQUAD_BIAS_ALPHA) ); + } +} + +DECLARE_CLIENT_EFFECT( "VortDispel", DispelCallback ); + +//----------------------------------------------------------------------------- +// Purpose: Used for emissive lightning layer on vort +//----------------------------------------------------------------------------- +class CVortEmissiveProxy : public CEntityMaterialProxy +{ +public: + CVortEmissiveProxy( void ); + virtual ~CVortEmissiveProxy( void ); + virtual bool Init( IMaterial *pMaterial, KeyValues* pKeyValues ); + virtual void OnBind( C_BaseEntity *pC_BaseEntity ); + virtual IMaterial * GetMaterial(); + +private: + + IMaterialVar *m_pMatEmissiveStrength; + IMaterialVar *m_pMatDetailBlendStrength; +}; + +//----------------------------------------------------------------------------- +CVortEmissiveProxy::CVortEmissiveProxy( void ) +{ + m_pMatEmissiveStrength = NULL; + m_pMatDetailBlendStrength = NULL; +} + +CVortEmissiveProxy::~CVortEmissiveProxy( void ) +{ + // Do nothing +} + +//----------------------------------------------------------------------------- +bool CVortEmissiveProxy::Init( IMaterial *pMaterial, KeyValues* pKeyValues ) +{ + Assert( pMaterial ); + + // Need to get the material var + bool bFound; + m_pMatEmissiveStrength = pMaterial->FindVar( "$emissiveblendstrength", &bFound ); + + if ( bFound ) + { + // Optional + bool bFound2; + m_pMatDetailBlendStrength = pMaterial->FindVar( "$detailblendfactor", &bFound2 ); + } + + return bFound; +} + +//----------------------------------------------------------------------------- +void CVortEmissiveProxy::OnBind( C_BaseEntity *pEnt ) +{ + C_NPC_Vortigaunt *pVort = dynamic_cast(pEnt); + + float flBlendValue; + + if (pVort) + { + // do we need to crossfade? + if (gpGlobals->curtime < pVort->m_flBlueEndFadeTime) + { + // will be 0 when fully faded and 1 when not faded at all: + float fadeRatio = (pVort->m_flBlueEndFadeTime - gpGlobals->curtime) / VORTIGAUNT_BLUE_FADE_TIME; + if (pVort->m_bIsBlue) + { + fadeRatio = 1.0f - fadeRatio; + } + flBlendValue = clamp( fadeRatio, 0.0f, 1.0f ); + } + else // no crossfade + { + flBlendValue = pVort->m_bIsBlue ? 1.0f : 0.0f; + } + + // ALEX VLACHOS: + // The following variable varies on [0 .. 1]. 0.0 means the vort wants to be his normal + // color. 1.0 means he wants to be all black. It is interpolated in the + // C_NPC_Vortigaunt::ClientThink() function. + // + // pVort->m_flBlackFade + } + else + { // if you bind this proxy to anything non-vort (eg a ragdoll) it's always green + flBlendValue = 0.0f; + } + + + /* + // !!! Change me !!! I'm using a clamped sin wave for debugging + float flBlendValue = sinf( gpGlobals->curtime * 4.0f ) * 0.75f + 0.25f; + + // Clamp 0-1 + flBlendValue = ( flBlendValue < 0.0f ) ? 0.0f : ( flBlendValue > 1.0f ) ? 1.0f : flBlendValue; + */ + + if( m_pMatEmissiveStrength != NULL ) + { + m_pMatEmissiveStrength->SetFloatValue( flBlendValue ); + } + + if( m_pMatDetailBlendStrength != NULL ) + { + m_pMatDetailBlendStrength->SetFloatValue( flBlendValue ); + } +} + +//----------------------------------------------------------------------------- +IMaterial *CVortEmissiveProxy::GetMaterial() +{ + if ( m_pMatEmissiveStrength != NULL ) + return m_pMatEmissiveStrength->GetOwningMaterial(); + else if ( m_pMatDetailBlendStrength != NULL ) + return m_pMatDetailBlendStrength->GetOwningMaterial(); + else + return NULL; +} + +EXPOSE_INTERFACE( CVortEmissiveProxy, IMaterialProxy, "VortEmissive" IMATERIAL_PROXY_INTERFACE_VERSION ); diff --git a/src/src/cl_dll/episodic/c_weapon_hopwire.cpp b/src/src/game/client/episodic/c_weapon_hopwire.cpp similarity index 96% rename from src/src/cl_dll/episodic/c_weapon_hopwire.cpp rename to src/src/game/client/episodic/c_weapon_hopwire.cpp index cae8e71..b1baa48 100644 --- a/src/src/cl_dll/episodic/c_weapon_hopwire.cpp +++ b/src/src/game/client/episodic/c_weapon_hopwire.cpp @@ -106,7 +106,7 @@ void C_HopwireExplosion::AddParticles( void ) offset = GetRenderOrigin() + RandomVector( -256.0f, 256.0f ); - sParticle = (SimpleParticle *) m_pAttractorEmitter->AddParticle( sizeof(SimpleParticle), m_pAttractorEmitter->GetPMaterial( "effects/fleck_cement1" ), offset ); + sParticle = (SimpleParticle *) m_pAttractorEmitter->AddParticle( sizeof(SimpleParticle), g_Mat_Fleck_Cement[0], offset ); if ( sParticle == NULL ) return; @@ -175,10 +175,6 @@ void C_HopwireExplosion::AddParticles( void ) vecDustColor.y = 0.3f; vecDustColor.z = 0.25f; - PMaterialHandle hMaterial[2]; - hMaterial[0] = m_pSimpleEmitter->GetPMaterial("particle/particle_smokegrenade"); - hMaterial[1] = m_pSimpleEmitter->GetPMaterial("particle/particle_noisesphere"); - Vector color; int numRingSprites = 8; @@ -204,7 +200,7 @@ void C_HopwireExplosion::AddParticles( void ) offset = ( RandomVector( -4.0f, 4.0f ) + tr.endpos ) + ( forward * 512.0f ); - sParticle = (SimpleParticle *) m_pSimpleEmitter->AddParticle( sizeof(SimpleParticle), hMaterial[random->RandomInt(0,1)], offset ); + sParticle = (SimpleParticle *) m_pSimpleEmitter->AddParticle( sizeof(SimpleParticle), g_Mat_DustPuff[random->RandomInt(0,1)], offset ); if ( sParticle != NULL ) { @@ -264,7 +260,8 @@ int C_HopwireExplosion::DrawModel( int flags ) { AddParticles(); - materials->Flush(); + CMatRenderContextPtr pRenderContext( materials ); + pRenderContext->Flush(); UpdateRefractTexture(); IMaterial *pMat = materials->FindMaterial( "effects/strider_pinch_dudv", TEXTURE_GROUP_CLIENT_EFFECTS ); @@ -275,7 +272,7 @@ int C_HopwireExplosion::DrawModel( int flags ) IMaterialVar *pVar = pMat->FindVar( "$refractamount", NULL ); pVar->SetFloatValue( refract ); - materials->Bind( pMat, (IClientRenderable*)this ); + pRenderContext->Bind( pMat, (IClientRenderable*)this ); float sin1 = sinf( gpGlobals->curtime * 10 ); float sin2 = sinf( gpGlobals->curtime ); diff --git a/src/src/game/client/episodic/episodic_screenspaceeffects.cpp b/src/src/game/client/episodic/episodic_screenspaceeffects.cpp new file mode 100644 index 0000000..eb65926 --- /dev/null +++ b/src/src/game/client/episodic/episodic_screenspaceeffects.cpp @@ -0,0 +1,463 @@ +// +// Episodic screen-space effects +// + +#include "cbase.h" +#include "screenspaceeffects.h" +#include "rendertexture.h" +#include "materialsystem/imaterialsystemhardwareconfig.h" +#include "materialsystem/imaterialsystem.h" +#include "materialsystem/imaterialvar.h" +#include "cdll_client_int.h" +#include "materialsystem/itexture.h" +#include "keyvalues.h" +#include "ClientEffectPrecacheSystem.h" + +#include "episodic_screenspaceeffects.h" + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +#ifdef _X360 +#define STUN_TEXTURE "_rt_FullFrameFB2" +#else +#define STUN_TEXTURE "_rt_WaterRefraction" +#endif + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CStunEffect::Init( void ) +{ + m_flDuration = 0.0f; + m_flFinishTime = 0.0f; + m_bUpdateView = true; + + KeyValues *pVMTKeyValues = new KeyValues( "UnlitGeneric" ); + pVMTKeyValues->SetString( "$basetexture", STUN_TEXTURE ); + m_EffectMaterial.Init( "__stuneffect", TEXTURE_GROUP_CLIENT_EFFECTS, pVMTKeyValues ); + m_StunTexture.Init( STUN_TEXTURE, TEXTURE_GROUP_CLIENT_EFFECTS ); +} + +void CStunEffect::Shutdown( void ) +{ + m_EffectMaterial.Shutdown(); + m_StunTexture.Shutdown(); +} + +//------------------------------------------------------------------------------ +// Purpose: Pick up changes in our parameters +//------------------------------------------------------------------------------ +void CStunEffect::SetParameters( KeyValues *params ) +{ + if( params->FindKey( "duration" ) ) + { + m_flDuration = params->GetFloat( "duration" ); + m_flFinishTime = gpGlobals->curtime + m_flDuration; + m_bUpdateView = true; + } +} + +//----------------------------------------------------------------------------- +// Purpose: Render the effect +//----------------------------------------------------------------------------- +void CStunEffect::Render( int x, int y, int w, int h ) +{ + // Make sure we're ready to play this effect + if ( m_flFinishTime < gpGlobals->curtime ) + return; + + CMatRenderContextPtr pRenderContext( materials ); + + // Set ourselves to the proper rendermode + pRenderContext->MatrixMode( MATERIAL_VIEW ); + pRenderContext->PushMatrix(); + pRenderContext->LoadIdentity(); + pRenderContext->MatrixMode( MATERIAL_PROJECTION ); + pRenderContext->PushMatrix(); + pRenderContext->LoadIdentity(); + + // Draw the texture if we're using it + if ( m_bUpdateView ) + { + // Save off this pass + Rect_t srcRect; + srcRect.x = x; + srcRect.y = y; + srcRect.width = w; + srcRect.height = h; + pRenderContext->CopyRenderTargetToTextureEx( m_StunTexture, 0, &srcRect, NULL ); + m_bUpdateView = false; + } + + float flEffectPerc = ( m_flFinishTime - gpGlobals->curtime ) / m_flDuration; + + float viewOffs = ( flEffectPerc * 32.0f ) * ( cos( gpGlobals->curtime * 40.0f ) * sin( gpGlobals->curtime * 17.0f ) ); + float vX = x + viewOffs; + + if ( g_pMaterialSystemHardwareConfig->GetDXSupportLevel() >= 80 ) + { + if ( g_pMaterialSystemHardwareConfig->GetHDRType() == HDR_TYPE_NONE ) + { + m_EffectMaterial->ColorModulate( 1.0f, 1.0f, 1.0f ); + } + else + { + // This is a stupid fix, but I don't have time to do a cleaner implementation. Since + // the introblur.vmt material uses unlit generic, it will tone map, so I need to undo the tone mapping + // using color modulate. The proper fix would be to use a different material type that + // supports alpha blending but not tone mapping, which I don't think exists. Whatever. This works when + // the tone mapping scalar is less than 1.0, which it is in the cases it's used in game. + float flUnTonemap = pow( 1.0f / pRenderContext->GetToneMappingScaleLinear().x, 1.0f / 2.2f ); + m_EffectMaterial->ColorModulate( flUnTonemap, flUnTonemap, flUnTonemap ); + } + + // Set alpha blend value + float flOverlayAlpha = clamp( ( 150.0f / 255.0f ) * flEffectPerc, 0.0f, 1.0f ); + m_EffectMaterial->AlphaModulate( flOverlayAlpha ); + + // Draw full screen alpha-blended quad + pRenderContext->DrawScreenSpaceRectangle( m_EffectMaterial, 0, 0, w, h, + vX, 0, (m_StunTexture->GetActualWidth()-1)+vX, (m_StunTexture->GetActualHeight()-1), + m_StunTexture->GetActualWidth(), m_StunTexture->GetActualHeight() ); + } + + // Save off this pass + Rect_t srcRect; + srcRect.x = x; + srcRect.y = y; + srcRect.width = w; + srcRect.height = h; + pRenderContext->CopyRenderTargetToTextureEx( m_StunTexture, 0, &srcRect, NULL ); + + // Restore our state + pRenderContext->MatrixMode( MATERIAL_VIEW ); + pRenderContext->PopMatrix(); + pRenderContext->MatrixMode( MATERIAL_PROJECTION ); + pRenderContext->PopMatrix(); +} + +// ================================================================================================================ +// +// Ep 1. Intro blur +// +// ================================================================================================================ + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CEP1IntroEffect::Init( void ) +{ + m_flDuration = 0.0f; + m_flFinishTime = 0.0f; + m_bUpdateView = true; + m_bFadeOut = false; + + KeyValues *pVMTKeyValues = new KeyValues( "UnlitGeneric" ); + pVMTKeyValues->SetString( "$basetexture", STUN_TEXTURE ); + m_EffectMaterial.Init( "__ep1introeffect", TEXTURE_GROUP_CLIENT_EFFECTS, pVMTKeyValues ); + m_StunTexture.Init( STUN_TEXTURE, TEXTURE_GROUP_CLIENT_EFFECTS ); +} + +void CEP1IntroEffect::Shutdown( void ) +{ + m_EffectMaterial.Shutdown(); + m_StunTexture.Shutdown(); +} + + +//------------------------------------------------------------------------------ +// Purpose: Pick up changes in our parameters +//------------------------------------------------------------------------------ +void CEP1IntroEffect::SetParameters( KeyValues *params ) +{ + if( params->FindKey( "duration" ) ) + { + m_flDuration = params->GetFloat( "duration" ); + m_flFinishTime = gpGlobals->curtime + m_flDuration; + } + + if( params->FindKey( "fadeout" ) ) + { + m_bFadeOut = ( params->GetInt( "fadeout" ) == 1 ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Get the alpha value depending on various factors and time +//----------------------------------------------------------------------------- +inline unsigned char CEP1IntroEffect::GetFadeAlpha( void ) +{ + // Find our percentage between fully "on" and "off" in the pulse range + float flEffectPerc = ( m_flDuration == 0.0f ) ? 0.0f : ( m_flFinishTime - gpGlobals->curtime ) / m_flDuration; + flEffectPerc = clamp( flEffectPerc, 0.0f, 1.0f ); + + if ( m_bFadeOut ) + { + // HDR requires us to be more subtle, or we get uber-brightening + if ( g_pMaterialSystemHardwareConfig->GetHDRType() != HDR_TYPE_NONE ) + return (unsigned char) clamp( 50.0f * flEffectPerc, 0.0f, 50.0f ); + + // Non-HDR + return (unsigned char) clamp( 64.0f * flEffectPerc, 0.0f, 64.0f ); + } + else + { + // HDR requires us to be more subtle, or we get uber-brightening + if ( g_pMaterialSystemHardwareConfig->GetHDRType() != HDR_TYPE_NONE ) + return (unsigned char) clamp( 64.0f * flEffectPerc, 50.0f, 64.0f ); + + // Non-HDR + return (unsigned char) clamp( 128.0f * flEffectPerc, 64.0f, 128.0f ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Render the effect +//----------------------------------------------------------------------------- +void CEP1IntroEffect::Render( int x, int y, int w, int h ) +{ + if ( ( m_flFinishTime == 0 ) || ( IsEnabled() == false ) ) + return; + + CMatRenderContextPtr pRenderContext( materials ); + + // Set ourselves to the proper rendermode + pRenderContext->MatrixMode( MATERIAL_VIEW ); + pRenderContext->PushMatrix(); + pRenderContext->LoadIdentity(); + pRenderContext->MatrixMode( MATERIAL_PROJECTION ); + pRenderContext->PushMatrix(); + pRenderContext->LoadIdentity(); + + // Draw the texture if we're using it + if ( m_bUpdateView ) + { + // Save off this pass + Rect_t srcRect; + srcRect.x = x; + srcRect.y = y; + srcRect.width = w; + srcRect.height = h; + pRenderContext->CopyRenderTargetToTextureEx( m_StunTexture, 0, &srcRect, NULL ); + m_bUpdateView = false; + } + + byte overlaycolor[4] = { 255, 255, 255, 0 }; + + // Get our fade value depending on our fade duration + overlaycolor[3] = GetFadeAlpha(); + if ( g_pMaterialSystemHardwareConfig->UsesSRGBCorrectBlending() ) + { + // For DX10 cards, alpha blending happens in linear space, so try to adjust by hacking alpha to 50% + overlaycolor[3] *= 0.7f; + } + + // Disable overself if we're done fading out + if ( m_bFadeOut && overlaycolor[3] == 0 ) + { + // Takes effect next frame (we don't want to hose our matrix stacks here) + g_pScreenSpaceEffects->DisableScreenSpaceEffect( "episodic_intro" ); + m_bUpdateView = true; + } + + // Calculate some wavey noise to jitter the view by + float vX = 2.0f * -fabs( cosf( gpGlobals->curtime ) * cosf( gpGlobals->curtime * 6.0 ) ); + float vY = 2.0f * cosf( gpGlobals->curtime ) * cosf( gpGlobals->curtime * 5.0 ); + + // Scale percentage + float flScalePerc = 0.02f + ( 0.01f * cosf( gpGlobals->curtime * 2.0f ) * cosf( gpGlobals->curtime * 0.5f ) ); + + // Scaled offsets for the UVs (as texels) + float flUOffset = ( m_StunTexture->GetActualWidth() - 1 ) * flScalePerc * 0.5f; + float flVOffset = ( m_StunTexture->GetActualHeight() - 1 ) * flScalePerc * 0.5f; + + // New UVs with scaling offsets + float flU1 = flUOffset; + float flU2 = ( m_StunTexture->GetActualWidth() - 1 ) - flUOffset; + float flV1 = flVOffset; + float flV2 = ( m_StunTexture->GetActualHeight() - 1 ) - flVOffset; + + // Draw the "zoomed" overlay + pRenderContext->DrawScreenSpaceRectangle( m_EffectMaterial, vX, vY, w, h, + flU1, flV1, + flU2, flV2, + m_StunTexture->GetActualWidth(), m_StunTexture->GetActualHeight() ); + + render->ViewDrawFade( overlaycolor, m_EffectMaterial ); + + // Save off this pass + Rect_t srcRect; + srcRect.x = x; + srcRect.y = y; + srcRect.width = w; + srcRect.height = h; + pRenderContext->CopyRenderTargetToTextureEx( m_StunTexture, 0, &srcRect, NULL ); + + // Restore our state + pRenderContext->MatrixMode( MATERIAL_VIEW ); + pRenderContext->PopMatrix(); + pRenderContext->MatrixMode( MATERIAL_PROJECTION ); + pRenderContext->PopMatrix(); +} + +// ================================================================================================================ +// +// Ep 2. Groggy-player view +// +// ================================================================================================================ + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CEP2StunEffect::Init( void ) +{ + m_flDuration = 0.0f; + m_flFinishTime = 0.0f; + m_bUpdateView = true; + m_bFadeOut = false; + + KeyValues *pVMTKeyValues = new KeyValues( "UnlitGeneric" ); + pVMTKeyValues->SetString( "$basetexture", STUN_TEXTURE ); + m_EffectMaterial.Init( "__ep2stuneffect", TEXTURE_GROUP_CLIENT_EFFECTS, pVMTKeyValues ); + m_StunTexture.Init( STUN_TEXTURE, TEXTURE_GROUP_CLIENT_EFFECTS ); +} + +void CEP2StunEffect::Shutdown( void ) +{ + m_EffectMaterial.Shutdown(); + m_StunTexture.Shutdown(); +} + +//------------------------------------------------------------------------------ +// Purpose: Pick up changes in our parameters +//------------------------------------------------------------------------------ +void CEP2StunEffect::SetParameters( KeyValues *params ) +{ + if( params->FindKey( "duration" ) ) + { + m_flDuration = params->GetFloat( "duration" ); + m_flFinishTime = gpGlobals->curtime + m_flDuration; + } + + if( params->FindKey( "fadeout" ) ) + { + m_bFadeOut = ( params->GetInt( "fadeout" ) == 1 ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Get the alpha value depending on various factors and time +//----------------------------------------------------------------------------- +inline unsigned char CEP2StunEffect::GetFadeAlpha( void ) +{ + // Find our percentage between fully "on" and "off" in the pulse range + float flEffectPerc = ( m_flDuration == 0.0f ) ? 0.0f : ( m_flFinishTime - gpGlobals->curtime ) / m_flDuration; + flEffectPerc = clamp( flEffectPerc, 0.0f, 1.0f ); + + if ( m_bFadeOut ) + { + // HDR requires us to be more subtle, or we get uber-brightening + if ( g_pMaterialSystemHardwareConfig->GetHDRType() != HDR_TYPE_NONE ) + return (unsigned char) clamp( 50.0f * flEffectPerc, 0.0f, 50.0f ); + + // Non-HDR + return (unsigned char) clamp( 64.0f * flEffectPerc, 0.0f, 64.0f ); + } + else + { + // HDR requires us to be more subtle, or we get uber-brightening + if ( g_pMaterialSystemHardwareConfig->GetHDRType() != HDR_TYPE_NONE ) + return (unsigned char) clamp( 164.0f * flEffectPerc, 128.0f, 164.0f ); + + // Non-HDR + return (unsigned char) clamp( 164.0f * flEffectPerc, 128.0f, 164.0f ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Render the effect +//----------------------------------------------------------------------------- +void CEP2StunEffect::Render( int x, int y, int w, int h ) +{ + if ( ( m_flFinishTime == 0 ) || ( IsEnabled() == false ) ) + return; + + CMatRenderContextPtr pRenderContext( materials ); + + // Set ourselves to the proper rendermode + pRenderContext->MatrixMode( MATERIAL_VIEW ); + pRenderContext->PushMatrix(); + pRenderContext->LoadIdentity(); + pRenderContext->MatrixMode( MATERIAL_PROJECTION ); + pRenderContext->PushMatrix(); + pRenderContext->LoadIdentity(); + + if ( m_bUpdateView ) + { + // Save off this pass + Rect_t srcRect; + srcRect.x = x; + srcRect.y = y; + srcRect.width = w; + srcRect.height = h; + pRenderContext->CopyRenderTargetToTextureEx( m_StunTexture, 0, &srcRect, NULL ); + m_bUpdateView = false; + } + + byte overlaycolor[4] = { 255, 255, 255, 0 }; + + // Get our fade value depending on our fade duration + overlaycolor[3] = GetFadeAlpha(); + + // Disable overself if we're done fading out + if ( m_bFadeOut && overlaycolor[3] == 0 ) + { + // Takes effect next frame (we don't want to hose our matrix stacks here) + g_pScreenSpaceEffects->DisableScreenSpaceEffect( "ep2_groggy" ); + m_bUpdateView = true; + } + + // Calculate some wavey noise to jitter the view by + float vX = 4.0f * cosf( gpGlobals->curtime ) * cosf( gpGlobals->curtime * 6.0 ); + float vY = 2.0f * cosf( gpGlobals->curtime ) * cosf( gpGlobals->curtime * 5.0 ); + + float flBaseScale = 0.2f + 0.005f * sinf( gpGlobals->curtime * 4.0f ); + + // Scale percentage + float flScalePerc = flBaseScale + ( 0.01f * cosf( gpGlobals->curtime * 2.0f ) * cosf( gpGlobals->curtime * 0.5f ) ); + + // Scaled offsets for the UVs (as texels) + float flUOffset = ( m_StunTexture->GetActualWidth() - 1 ) * flScalePerc * 0.5f; + float flVOffset = ( m_StunTexture->GetActualHeight() - 1 ) * flScalePerc * 0.5f; + + // New UVs with scaling offsets + float flU1 = flUOffset; + float flU2 = ( m_StunTexture->GetActualWidth() - 1 ) - flUOffset; + float flV1 = flVOffset; + float flV2 = ( m_StunTexture->GetActualHeight() - 1 ) - flVOffset; + + // Draw the "zoomed" overlay + pRenderContext->DrawScreenSpaceRectangle( m_EffectMaterial, vX, vY, w, h, + flU1, flV1, + flU2, flV2, + m_StunTexture->GetActualWidth(), m_StunTexture->GetActualHeight() ); + + render->ViewDrawFade( overlaycolor, m_EffectMaterial ); + + // Save off this pass + Rect_t srcRect; + srcRect.x = x; + srcRect.y = y; + srcRect.width = w; + srcRect.height = h; + pRenderContext->CopyRenderTargetToTextureEx( m_StunTexture, 0, &srcRect, NULL ); + + // Restore our state + pRenderContext->MatrixMode( MATERIAL_VIEW ); + pRenderContext->PopMatrix(); + pRenderContext->MatrixMode( MATERIAL_PROJECTION ); + pRenderContext->PopMatrix(); +} diff --git a/src/src/game/client/episodic/episodic_screenspaceeffects.h b/src/src/game/client/episodic/episodic_screenspaceeffects.h new file mode 100644 index 0000000..cc5bb41 --- /dev/null +++ b/src/src/game/client/episodic/episodic_screenspaceeffects.h @@ -0,0 +1,119 @@ +//====== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======= +// +// Purpose: +// +//============================================================================= + +#ifndef EPISODIC_SCREENSPACEEFFECTS_H +#define EPISODIC_SCREENSPACEEFFECTS_H +#ifdef _WIN32 +#pragma once +#endif + +#include "screenspaceeffects.h" + +class CStunEffect : public IScreenSpaceEffect +{ +public: + CStunEffect( void ) : + m_flDuration( 0.0f ), + m_flFinishTime( 0.0f ), + m_bUpdateView( true ) {} + + virtual void Init( void ); + virtual void Shutdown( void ); + virtual void SetParameters( KeyValues *params ); + virtual void Enable( bool bEnable ) {}; + virtual bool IsEnabled( ) { return true; } + + virtual void Render( int x, int y, int w, int h ); + +private: + CTextureReference m_StunTexture; + CMaterialReference m_EffectMaterial; + float m_flDuration; + float m_flFinishTime; + bool m_bUpdateView; +}; + +ADD_SCREENSPACE_EFFECT( CStunEffect, episodic_stun ); + +// +// EP1 Intro Blur +// + +class CEP1IntroEffect : public IScreenSpaceEffect +{ +public: + CEP1IntroEffect( void ) : + m_flDuration( 0.0f ), + m_flFinishTime( 0.0f ), + m_bUpdateView( true ), + m_bEnabled( false ), + m_bFadeOut( false ) {} + + virtual void Init( void ); + virtual void Shutdown( void ); + virtual void SetParameters( KeyValues *params ); + virtual void Enable( bool bEnable ) { m_bEnabled = bEnable; } + virtual bool IsEnabled( ) { return m_bEnabled; } + + virtual void Render( int x, int y, int w, int h ); + +private: + + inline unsigned char GetFadeAlpha( void ); + + CTextureReference m_StunTexture; + CMaterialReference m_EffectMaterial; + float m_flDuration; + float m_flFinishTime; + bool m_bUpdateView; + bool m_bEnabled; + bool m_bFadeOut; +}; + +ADD_SCREENSPACE_EFFECT( CEP1IntroEffect, episodic_intro ); + +// +// EP2 Player Stunned Effect +// + +// +// EP1 Intro Blur +// + +class CEP2StunEffect : public IScreenSpaceEffect +{ +public: + CEP2StunEffect( void ) : + m_flDuration( 0.0f ), + m_flFinishTime( 0.0f ), + m_bUpdateView( true ), + m_bEnabled( false ), + m_bFadeOut( false ) {} + + virtual void Init( void ); + virtual void Shutdown( void ); + virtual void SetParameters( KeyValues *params ); + virtual void Enable( bool bEnable ) { m_bEnabled = bEnable; } + virtual bool IsEnabled( ) { return m_bEnabled; } + + virtual void Render( int x, int y, int w, int h ); + +private: + + inline unsigned char GetFadeAlpha( void ); + + CTextureReference m_StunTexture; + CMaterialReference m_EffectMaterial; + float m_flDuration; + float m_flFinishTime; + bool m_bUpdateView; + bool m_bEnabled; + bool m_bFadeOut; +}; + +ADD_SCREENSPACE_EFFECT( CEP2StunEffect, ep2_groggy ); + +#endif // EPISODIC_SCREENSPACEEFFECTS_H diff --git a/src/src/game/client/episodic/flesh_internal_material_proxy.cpp b/src/src/game/client/episodic/flesh_internal_material_proxy.cpp new file mode 100644 index 0000000..9c70da1 --- /dev/null +++ b/src/src/game/client/episodic/flesh_internal_material_proxy.cpp @@ -0,0 +1,225 @@ +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +// Purpose: +// +// $NoKeywords: $ +//=====================================================================================// +#include "cbase.h" +#include "ProxyEntity.h" +#include "materialsystem/IMaterial.h" +#include "materialsystem/IMaterialVar.h" +#include "debugoverlay_shared.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +class C_FleshEffectTarget; +void AddFleshProxyTarget( C_FleshEffectTarget *pTarget ); +void RemoveFleshProxy( C_FleshEffectTarget *pTarget ); + +//============================================================================= +// +// Flesh effect target (used for orchestrating the "Invisible Alyx" moment +// +//============================================================================= + +class C_FleshEffectTarget : public C_BaseEntity +{ + DECLARE_CLASS( C_FleshEffectTarget, C_BaseEntity ); + +public: + float GetRadius( void ) + { + if ( m_flScaleTime <= 0.0f ) + return m_flRadius; + + float dt = ( gpGlobals->curtime - m_flScaleStartTime ); + if ( dt >= m_flScaleTime ) + return m_flRadius; + + return SimpleSplineRemapVal( ( dt / m_flScaleTime ), 0.0f, 1.0f, m_flStartRadius, m_flRadius ); + } + + virtual void Release( void ) + { + // Remove us from the list of targets + RemoveFleshProxy( this ); + } + + virtual void OnDataChanged( DataUpdateType_t updateType ) + { + BaseClass::OnDataChanged( updateType ); + + if ( updateType == DATA_UPDATE_CREATED ) + { + // Add us to the list of flesh proxy targets + AddFleshProxyTarget( this ); + } + } + + float m_flRadius; + float m_flStartRadius; + float m_flScaleStartTime; + float m_flScaleTime; + + DECLARE_CLIENTCLASS(); +}; + +void RecvProxy_FleshEffect_Radius( const CRecvProxyData *pData, void *pStruct, void *pOut ) +{ + C_FleshEffectTarget *pTarget = (C_FleshEffectTarget *) pStruct; + float flRadius = pData->m_Value.m_Float; + + //If changed, update our internal information + if ( pTarget->m_flRadius != flRadius ) + { + pTarget->m_flStartRadius = pTarget->m_flRadius; + pTarget->m_flScaleStartTime = gpGlobals->curtime; + } + + pTarget->m_flRadius = flRadius; +} + +IMPLEMENT_CLIENTCLASS_DT( C_FleshEffectTarget, DT_FleshEffectTarget, CFleshEffectTarget ) + RecvPropFloat( RECVINFO(m_flRadius), 0, RecvProxy_FleshEffect_Radius ), + RecvPropFloat( RECVINFO(m_flScaleTime) ), +END_RECV_TABLE() + +CUtlVector< C_FleshEffectTarget * > g_FleshProxyTargets; + +void AddFleshProxyTarget( C_FleshEffectTarget *pTarget ) +{ + // Take it! + g_FleshProxyTargets.AddToTail( pTarget ); +} + +void RemoveFleshProxy( C_FleshEffectTarget *pTarget ) +{ + int nIndex = g_FleshProxyTargets.Find( pTarget ); + if ( nIndex != g_FleshProxyTargets.InvalidIndex() ) + { + g_FleshProxyTargets.Remove( nIndex ); + } +} + +// $sineVar : name of variable that controls the FleshInterior level (float) +class CFleshInteriorMaterialProxy : public CEntityMaterialProxy +{ +public: + CFleshInteriorMaterialProxy(); + virtual ~CFleshInteriorMaterialProxy(); + virtual bool Init( IMaterial *pMaterial, KeyValues *pKeyValues ); + virtual void OnBind( C_BaseEntity *pEntity ); + virtual IMaterial *GetMaterial(); + +private: + IMaterialVar *m_pMaterialParamFleshEffectCenterRadius1; + IMaterialVar *m_pMaterialParamFleshEffectCenterRadius2; + IMaterialVar *m_pMaterialParamFleshEffectCenterRadius3; + IMaterialVar *m_pMaterialParamFleshEffectCenterRadius4; + IMaterialVar *m_pMaterialParamFleshGlobalOpacity; + IMaterialVar *m_pMaterialParamFleshSubsurfaceTint; +}; + +CFleshInteriorMaterialProxy::CFleshInteriorMaterialProxy() +{ + m_pMaterialParamFleshEffectCenterRadius1 = NULL; + m_pMaterialParamFleshEffectCenterRadius2 = NULL; + m_pMaterialParamFleshEffectCenterRadius3 = NULL; + m_pMaterialParamFleshEffectCenterRadius4 = NULL; + m_pMaterialParamFleshGlobalOpacity = NULL; + m_pMaterialParamFleshSubsurfaceTint = NULL; +} + +CFleshInteriorMaterialProxy::~CFleshInteriorMaterialProxy() +{ + // Do nothing +} + +bool CFleshInteriorMaterialProxy::Init( IMaterial *pMaterial, KeyValues *pKeyValues ) +{ + bool bFoundVar = false; + + m_pMaterialParamFleshEffectCenterRadius1 = pMaterial->FindVar( "$FleshEffectCenterRadius1", &bFoundVar, false ); + if ( bFoundVar == false) + return false; + + m_pMaterialParamFleshEffectCenterRadius2 = pMaterial->FindVar( "$FleshEffectCenterRadius2", &bFoundVar, false ); + if ( bFoundVar == false) + return false; + + m_pMaterialParamFleshEffectCenterRadius3 = pMaterial->FindVar( "$FleshEffectCenterRadius3", &bFoundVar, false ); + if ( bFoundVar == false) + return false; + + m_pMaterialParamFleshEffectCenterRadius4 = pMaterial->FindVar( "$FleshEffectCenterRadius4", &bFoundVar, false ); + if ( bFoundVar == false) + return false; + + m_pMaterialParamFleshGlobalOpacity = pMaterial->FindVar( "$FleshGlobalOpacity", &bFoundVar, false ); + if ( bFoundVar == false) + return false; + + m_pMaterialParamFleshSubsurfaceTint = pMaterial->FindVar( "$FleshSubsurfaceTint", &bFoundVar, false ); + if ( bFoundVar == false) + return false; + + return true; +} + +void CFleshInteriorMaterialProxy::OnBind( C_BaseEntity *pEnt ) +{ + IMaterialVar *pParams[] = + { + m_pMaterialParamFleshEffectCenterRadius1, + m_pMaterialParamFleshEffectCenterRadius2, + m_pMaterialParamFleshEffectCenterRadius3, + m_pMaterialParamFleshEffectCenterRadius4 + }; + + float vEffectCenterRadius[4]; + for ( int i = 0; i < ARRAYSIZE( pParams ); i++ ) + { + if ( i < g_FleshProxyTargets.Count() ) + { + // Setup the target + if ( g_FleshProxyTargets[i]->IsAbsQueriesValid() == false ) + continue; + + Vector vecAbsOrigin = g_FleshProxyTargets[i]->GetAbsOrigin(); + vEffectCenterRadius[0] = vecAbsOrigin.x; + vEffectCenterRadius[1] = vecAbsOrigin.y; + vEffectCenterRadius[2] = vecAbsOrigin.z; + vEffectCenterRadius[3] = g_FleshProxyTargets[i]->GetRadius(); + } + else + { + // Clear the target + vEffectCenterRadius[0] = vEffectCenterRadius[1] = vEffectCenterRadius[2] = vEffectCenterRadius[3] = 0.0f; + } + + // Set the value either way + pParams[i]->SetVecValue( vEffectCenterRadius, 4 ); + } + + // Subsurface texture. NOTE: This texture bleeds through the color of the flesh texture so expect + // to have to set this brighter than white to really see the subsurface texture glow through. + if ( m_pMaterialParamFleshSubsurfaceTint != NULL ) + { + float vSubsurfaceTintColor[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; + + // !!! Test code. REPLACE ME! + // vSubsurfaceTintColor[0] = vSubsurfaceTintColor[1] = vSubsurfaceTintColor[2] = sinf( gpGlobals->curtime * 3.0f ) + 1.0f; // * 0.5f + 0.5f; + + m_pMaterialParamFleshSubsurfaceTint->SetVecValue( vSubsurfaceTintColor, 4 ); + } +} + +IMaterial *CFleshInteriorMaterialProxy::GetMaterial() +{ + if ( m_pMaterialParamFleshEffectCenterRadius1 == NULL) + return NULL; + + return m_pMaterialParamFleshEffectCenterRadius1->GetOwningMaterial(); +} + +EXPOSE_INTERFACE( CFleshInteriorMaterialProxy, IMaterialProxy, "FleshInterior" IMATERIAL_PROXY_INTERFACE_VERSION ); diff --git a/src/src/cl_dll/flashlighteffect.cpp b/src/src/game/client/flashlighteffect.cpp similarity index 50% rename from src/src/cl_dll/flashlighteffect.cpp rename to src/src/game/client/flashlighteffect.cpp index e773e20..8753056 100644 --- a/src/src/cl_dll/flashlighteffect.cpp +++ b/src/src/game/client/flashlighteffect.cpp @@ -1,8 +1,8 @@ -//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: // -//=============================================================================// +//===========================================================================// #include "cbase.h" #include "flashlighteffect.h" @@ -11,31 +11,48 @@ #include "iviewrender.h" #include "view.h" #include "engine/ivdebugoverlay.h" +#include "tier0/vprof.h" +#include "tier1/KeyValues.h" +#include "toolframework_client.h" -#ifdef HL2_EPISODIC - #include "c_basehlplayer.h" +#ifdef HL2_CLIENT_DLL +#include "c_basehlplayer.h" +#endif // HL2_CLIENT_DLL + +#if defined( _X360 ) +extern ConVar r_flashlightdepthres; +#else +extern ConVar r_flashlightdepthres; #endif - // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" -void r_newflashlightCallback_f( ConVar *var, char const *pOldString ); +extern ConVar r_flashlightdepthtexture; + +void r_newflashlightCallback_f( IConVar *pConVar, const char *pOldString, float flOldValue ); static ConVar r_newflashlight( "r_newflashlight", "1", FCVAR_CHEAT, "", r_newflashlightCallback_f ); +static ConVar r_swingflashlight( "r_swingflashlight", "1", FCVAR_CHEAT ); static ConVar r_flashlightlockposition( "r_flashlightlockposition", "0", FCVAR_CHEAT ); static ConVar r_flashlightfov( "r_flashlightfov", "45.0", FCVAR_CHEAT ); static ConVar r_flashlightoffsetx( "r_flashlightoffsetx", "10.0", FCVAR_CHEAT ); static ConVar r_flashlightoffsety( "r_flashlightoffsety", "-20.0", FCVAR_CHEAT ); static ConVar r_flashlightoffsetz( "r_flashlightoffsetz", "24.0", FCVAR_CHEAT ); -static ConVar r_flashlightnear( "r_flashlightnear", "1.0", FCVAR_CHEAT ); +static ConVar r_flashlightnear( "r_flashlightnear", "4.0", FCVAR_CHEAT ); static ConVar r_flashlightfar( "r_flashlightfar", "750.0", FCVAR_CHEAT ); static ConVar r_flashlightconstant( "r_flashlightconstant", "0.0", FCVAR_CHEAT ); static ConVar r_flashlightlinear( "r_flashlightlinear", "100.0", FCVAR_CHEAT ); static ConVar r_flashlightquadratic( "r_flashlightquadratic", "0.0", FCVAR_CHEAT ); static ConVar r_flashlightvisualizetrace( "r_flashlightvisualizetrace", "0", FCVAR_CHEAT ); +static ConVar r_flashlightambient( "r_flashlightambient", "0.0", FCVAR_CHEAT ); +static ConVar r_flashlightshadowatten( "r_flashlightshadowatten", "0.35", FCVAR_CHEAT ); +static ConVar r_flashlightladderdist( "r_flashlightladderdist", "40.0", FCVAR_CHEAT ); +static ConVar mat_slopescaledepthbias_shadowmap( "mat_slopescaledepthbias_shadowmap", "16", FCVAR_CHEAT ); +static ConVar mat_depthbias_shadowmap( "mat_depthbias_shadowmap", "0.0005", FCVAR_CHEAT ); -void r_newflashlightCallback_f( ConVar *var, char const *pOldString ) + +void r_newflashlightCallback_f( IConVar *pConVar, const char *pOldString, float flOldValue ) { if( engine->GetDXSupportLevel() < 70 ) { @@ -60,6 +77,15 @@ CFlashlightEffect::CFlashlightEffect(int nEntIndex) { r_newflashlight.SetValue( 0 ); } + + if ( g_pMaterialSystemHardwareConfig->SupportsBorderColor() ) + { + m_FlashlightTexture.Init( "effects/flashlight_border", TEXTURE_GROUP_OTHER, true ); + } + else + { + m_FlashlightTexture.Init( "effects/flashlight001", TEXTURE_GROUP_OTHER, true ); + } } @@ -105,131 +131,188 @@ public: // Test against the vehicle too? // FLASHLIGHTFIXME: how do you know that you are actually inside of the vehicle? C_BaseEntity *pEntity = EntityFromEntityHandle( pServerEntity ); - if( pEntity && - ( dynamic_cast( pEntity ) != NULL ) || - ( dynamic_cast( pEntity ) != NULL ) || + if ( !pEntity ) + return true; + + if ( ( dynamic_cast( pEntity ) != NULL ) || + ( dynamic_cast( pEntity ) != NULL ) || pEntity->GetCollisionGroup() == COLLISION_GROUP_DEBRIS || pEntity->GetCollisionGroup() == COLLISION_GROUP_INTERACTIVE_DEBRIS ) { return false; } - else - { - return true; - } + + return true; } }; //----------------------------------------------------------------------------- // Purpose: Do the headlight //----------------------------------------------------------------------------- -void CFlashlightEffect::UpdateLightNew(const Vector &vecPos, const Vector &vecForward, const Vector &vecRight, const Vector &vecUp) +void CFlashlightEffect::UpdateLightNew(const Vector &vecPos, const Vector &vecForward, const Vector &vecRight, const Vector &vecUp ) { + VPROF_BUDGET( "CFlashlightEffect::UpdateLightNew", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING ); + FlashlightState_t state; - Vector end = vecPos + r_flashlightoffsety.GetFloat() * vecUp; + // We will lock some of the flashlight params if player is on a ladder, to prevent oscillations due to the trace-rays + bool bPlayerOnLadder = ( C_BasePlayer::GetLocalPlayer()->GetMoveType() == MOVETYPE_LADDER ); + + const float flEpsilon = 0.1f; // Offset flashlight position along vecUp + const float flDistCutoff = 128.0f; + const float flDistDrag = 0.2; - trace_t pmEye, pmEyeBack; CTraceFilterSkipPlayerAndViewModel traceFilter; + float flOffsetY = r_flashlightoffsety.GetFloat(); - UTIL_TraceHull( vecPos, end, Vector( -4, -4, -4 ), Vector ( 4, 4, 4 ), MASK_SOLID & ~(CONTENTS_HITBOX), &traceFilter, &pmEye ); - - if ( pmEye.fraction != 1.0f ) + if( r_swingflashlight.GetBool() ) { - end = vecPos; + // This projects the view direction backwards, attempting to raise the vertical + // offset of the flashlight, but only when the player is looking down. + Vector vecSwingLight = vecPos + vecForward * -12.0f; + if( vecSwingLight.z > vecPos.z ) + { + flOffsetY += (vecSwingLight.z - vecPos.z); + } } + Vector vOrigin = vecPos + flOffsetY * vecUp; + + // Not on ladder...trace a hull + if ( !bPlayerOnLadder ) + { + trace_t pmOriginTrace; + UTIL_TraceHull( vecPos, vOrigin, Vector(-4, -4, -4), Vector(4, 4, 4), MASK_SOLID & ~(CONTENTS_HITBOX), &traceFilter, &pmOriginTrace ); + + if ( pmOriginTrace.DidHit() ) + { + vOrigin = vecPos; + } + } + else // on ladder...skip the above hull trace + { + vOrigin = vecPos; + } + + // Now do a trace along the flashlight direction to ensure there is nothing within range to pull back from int iMask = MASK_OPAQUE_AND_NPCS; iMask &= ~CONTENTS_HITBOX; iMask |= CONTENTS_WINDOW; - // Trace a line outward, skipping the player model and the view model. - //Eye -> EyeForward - UTIL_TraceHull( end, vecPos + vecForward * r_flashlightfar.GetFloat(), Vector( -4, -4, -4 ), Vector ( 4, 4, 4 ), iMask, &traceFilter, &pmEye ); - UTIL_TraceHull( end, vecPos - vecForward * 128, Vector( -4, -4, -4 ), Vector ( 4, 4, 4 ), iMask, &traceFilter, &pmEyeBack ); + Vector vTarget = vecPos + vecForward * r_flashlightfar.GetFloat(); - float flDist; - float flLength = (pmEye.endpos - end).Length(); + // Work with these local copies of the basis for the rest of the function + Vector vDir = vTarget - vOrigin; + Vector vRight = vecRight; + Vector vUp = vecUp; + VectorNormalize( vDir ); + VectorNormalize( vRight ); + VectorNormalize( vUp ); - if ( flLength <= 128 ) - { - flDist = ( ( 1.0f - ( flLength / 128 ) ) * 128.0f ); - } - else - { - flDist = 0.0f; - } + // Orthonormalize the basis, since the flashlight texture projection will require this later... + vUp -= DotProduct( vDir, vUp ) * vDir; + VectorNormalize( vUp ); + vRight -= DotProduct( vDir, vRight ) * vDir; + VectorNormalize( vRight ); + vRight -= DotProduct( vUp, vRight ) * vUp; + VectorNormalize( vRight ); + AssertFloatEquals( DotProduct( vDir, vRight ), 0.0f, 1e-3 ); + AssertFloatEquals( DotProduct( vDir, vUp ), 0.0f, 1e-3 ); + AssertFloatEquals( DotProduct( vRight, vUp ), 0.0f, 1e-3 ); - m_flDistMod = Lerp( 0.3f, m_flDistMod, flDist ); - - float flMaxDist = (pmEyeBack.endpos - end).Length(); - if( m_flDistMod > flMaxDist ) - m_flDistMod = flMaxDist; - - Vector vStartPos = end; - Vector vEndPos = pmEye.endpos; - Vector vDir = vEndPos - vStartPos; - - VectorNormalize( vDir ); - - if ( vDir == vec3_origin ) - { - vDir = vecForward; - } - - vStartPos = vStartPos - vDir * m_flDistMod; + trace_t pmDirectionTrace; + UTIL_TraceHull( vOrigin, vTarget, Vector( -4, -4, -4 ), Vector( 4, 4, 4 ), iMask, &traceFilter, &pmDirectionTrace ); if ( r_flashlightvisualizetrace.GetBool() == true ) { - debugoverlay->AddBoxOverlay( vEndPos, Vector( -4, -4, -4 ), Vector( 4, 4, 4 ), QAngle( 0, 0, 0 ), 0, 0, 255, 16, 0 ); - debugoverlay->AddLineOverlay( vStartPos, vEndPos, 255, 0, 0, false, 0 ); + debugoverlay->AddBoxOverlay( pmDirectionTrace.endpos, Vector( -4, -4, -4 ), Vector( 4, 4, 4 ), QAngle( 0, 0, 0 ), 0, 0, 255, 16, 0 ); + debugoverlay->AddLineOverlay( vOrigin, pmDirectionTrace.endpos, 255, 0, 0, false, 0 ); } - state.m_vecLightOrigin = vStartPos; - state.m_vecLightDirection = vDir; + float flDist = (pmDirectionTrace.endpos - vOrigin).Length(); + if ( flDist < flDistCutoff ) + { + // We have an intersection with our cutoff range + // Determine how far to pull back, then trace to see if we are clear + float flPullBackDist = bPlayerOnLadder ? r_flashlightladderdist.GetFloat() : flDistCutoff - flDist; // Fixed pull-back distance if on ladder + m_flDistMod = Lerp( flDistDrag, m_flDistMod, flPullBackDist ); + + if ( !bPlayerOnLadder ) + { + trace_t pmBackTrace; + UTIL_TraceHull( vOrigin, vOrigin - vDir*(flPullBackDist-flEpsilon), Vector( -4, -4, -4 ), Vector( 4, 4, 4 ), iMask, &traceFilter, &pmBackTrace ); + if( pmBackTrace.DidHit() ) + { + // We have an intersection behind us as well, so limit our m_flDistMod + float flMaxDist = (pmBackTrace.endpos - vOrigin).Length() - flEpsilon; + if( m_flDistMod > flMaxDist ) + m_flDistMod = flMaxDist; + } + } + } + else + { + m_flDistMod = Lerp( flDistDrag, m_flDistMod, 0.0f ); + } + vOrigin = vOrigin - vDir * m_flDistMod; + + state.m_vecLightOrigin = vOrigin; + + BasisToQuaternion( vDir, vRight, vUp, state.m_quatOrientation ); state.m_fQuadraticAtten = r_flashlightquadratic.GetFloat(); bool bFlicker = false; #ifdef HL2_EPISODIC - C_BaseHLPlayer *pPlayer = (C_BaseHLPlayer *)C_BasePlayer::GetLocalPlayer(); - if ( pPlayer && pPlayer->m_HL2Local.m_flSuitPower <= 10.0f ) + if ( pPlayer ) { - float flScale = SimpleSplineRemapVal( pPlayer->m_HL2Local.m_flSuitPower, 10.0f, 4.8f, 1.0f, 0.0f ); - flScale = clamp( flScale, 0.0f, 1.0f ); - - if ( flScale < 0.35f ) + float flBatteryPower = ( pPlayer->m_HL2Local.m_flFlashBattery >= 0.0f ) ? ( pPlayer->m_HL2Local.m_flFlashBattery ) : pPlayer->m_HL2Local.m_flSuitPower; + if ( flBatteryPower <= 10.0f ) { - float flFlicker = cosf( gpGlobals->curtime * 6.0f ) * sinf( gpGlobals->curtime * 15.0f ); - - if ( flFlicker > 0.25f && flFlicker < 0.75f ) - { - // On - state.m_fLinearAtten = r_flashlightlinear.GetFloat() * flScale; + float flScale; + if ( flBatteryPower >= 0.0f ) + { + flScale = ( flBatteryPower <= 4.5f ) ? SimpleSplineRemapVal( flBatteryPower, 4.5f, 0.0f, 1.0f, 0.0f ) : 1.0f; } else { - // Off - state.m_fLinearAtten = 0.0f; + flScale = SimpleSplineRemapVal( flBatteryPower, 10.0f, 4.8f, 1.0f, 0.0f ); } - } - else - { - float flNoise = cosf( gpGlobals->curtime * 7.0f ) * sinf( gpGlobals->curtime * 25.0f ); - state.m_fLinearAtten = r_flashlightlinear.GetFloat() * flScale + 1.5f * flNoise; - } + + flScale = clamp( flScale, 0.0f, 1.0f ); - state.m_fHorizontalFOVDegrees = r_flashlightfov.GetFloat() - ( 16.0f * (1.0f-flScale) ); - state.m_fVerticalFOVDegrees = r_flashlightfov.GetFloat() - ( 16.0f * (1.0f-flScale) ); - - bFlicker = true; + if ( flScale < 0.35f ) + { + float flFlicker = cosf( gpGlobals->curtime * 6.0f ) * sinf( gpGlobals->curtime * 15.0f ); + + if ( flFlicker > 0.25f && flFlicker < 0.75f ) + { + // On + state.m_fLinearAtten = r_flashlightlinear.GetFloat() * flScale; + } + else + { + // Off + state.m_fLinearAtten = 0.0f; + } + } + else + { + float flNoise = cosf( gpGlobals->curtime * 7.0f ) * sinf( gpGlobals->curtime * 25.0f ); + state.m_fLinearAtten = r_flashlightlinear.GetFloat() * flScale + 1.5f * flNoise; + } + + state.m_fHorizontalFOVDegrees = r_flashlightfov.GetFloat() - ( 16.0f * (1.0f-flScale) ); + state.m_fVerticalFOVDegrees = r_flashlightfov.GetFloat() - ( 16.0f * (1.0f-flScale) ); + + bFlicker = true; + } } +#endif // HL2_EPISODIC -#endif - if ( bFlicker == false ) { state.m_fLinearAtten = r_flashlightlinear.GetFloat(); @@ -238,10 +321,22 @@ void CFlashlightEffect::UpdateLightNew(const Vector &vecPos, const Vector &vecFo } state.m_fConstantAtten = r_flashlightconstant.GetFloat(); - state.m_Color.Init( 1.0f, 1.0f, 1.0f ); - state.m_NearZ = r_flashlightnear.GetFloat(); + state.m_Color[0] = 1.0f; + state.m_Color[1] = 1.0f; + state.m_Color[2] = 1.0f; + state.m_Color[3] = r_flashlightambient.GetFloat(); + state.m_NearZ = r_flashlightnear.GetFloat() + m_flDistMod; // Push near plane out so that we don't clip the world when the flashlight pulls back state.m_FarZ = r_flashlightfar.GetFloat(); - + state.m_bEnableShadows = r_flashlightdepthtexture.GetBool(); + state.m_flShadowMapResolution = r_flashlightdepthres.GetInt(); + + state.m_pSpotlightTexture = m_FlashlightTexture; + state.m_nSpotlightTextureFrame = 0; + + state.m_flShadowAtten = r_flashlightshadowatten.GetFloat(); + state.m_flShadowSlopeScaleDepthBias = mat_slopescaledepthbias_shadowmap.GetFloat(); + state.m_flShadowDepthBias = mat_depthbias_shadowmap.GetFloat(); + if( m_FlashlightHandle == CLIENTSHADOW_INVALID_HANDLE ) { m_FlashlightHandle = g_pClientShadowMgr->CreateFlashlight( state ); @@ -258,6 +353,19 @@ void CFlashlightEffect::UpdateLightNew(const Vector &vecPos, const Vector &vecFo // Kill the old flashlight method if we have one. LightOffOld(); + +#ifndef NO_TOOLFRAMEWORK + if ( clienttools->IsInRecordingMode() ) + { + KeyValues *msg = new KeyValues( "FlashlightState" ); + msg->SetFloat( "time", gpGlobals->curtime ); + msg->SetInt( "entindex", m_nEntIndex ); + msg->SetInt( "flashlightHandle", m_FlashlightHandle ); + msg->SetPtr( "flashlightState", &state ); + ToolFramework_PostToolMessage( HTOOLHANDLE_INVALID, msg ); + msg->deleteThis(); + } +#endif } //----------------------------------------------------------------------------- @@ -333,6 +441,19 @@ void CFlashlightEffect::UpdateLight(const Vector &vecPos, const Vector &vecDir, //----------------------------------------------------------------------------- void CFlashlightEffect::LightOffNew() { +#ifndef NO_TOOLFRAMEWORK + if ( clienttools->IsInRecordingMode() ) + { + KeyValues *msg = new KeyValues( "FlashlightState" ); + msg->SetFloat( "time", gpGlobals->curtime ); + msg->SetInt( "entindex", m_nEntIndex ); + msg->SetInt( "flashlightHandle", m_FlashlightHandle ); + msg->SetPtr( "flashlightState", NULL ); + ToolFramework_PostToolMessage( HTOOLHANDLE_INVALID, msg ); + msg->deleteThis(); + } +#endif + // Clear out the light if( m_FlashlightHandle != CLIENTSHADOW_INVALID_HANDLE ) { @@ -378,27 +499,32 @@ void CHeadlightEffect::UpdateLight( const Vector &vecPos, const Vector &vecDir, return; FlashlightState_t state; - state.m_vecLightDirection = vecDir; + Vector basisX, basisY, basisZ; + basisX = vecDir; + basisY = vecRight; + basisZ = vecUp; + VectorNormalize(basisX); + VectorNormalize(basisY); + VectorNormalize(basisZ); + + BasisToQuaternion( basisX, basisY, basisZ, state.m_quatOrientation ); - Vector end = vecPos + vecRight + vecUp + vecDir; - - VectorNormalize( state.m_vecLightDirection ); - - // Trace a line outward, skipping the player model and the view model. - trace_t pm; - CTraceFilterSkipPlayerAndViewModel traceFilter; - UTIL_TraceLine( vecPos, end, MASK_ALL, &traceFilter, &pm ); - VectorCopy( pm.endpos, state.m_vecLightOrigin ); - pm.endpos -= vecDir * 4.0f; - - state.m_fHorizontalFOVDegrees = 90.0f; - state.m_fVerticalFOVDegrees = 75.0f; - state.m_fQuadraticAtten = 0.0f; - state.m_fLinearAtten = 0.0f; - state.m_fConstantAtten = 1.0f; - state.m_Color.Init( 1.0f, 1.0f, 1.0f ); + state.m_vecLightOrigin = vecPos; + + state.m_fHorizontalFOVDegrees = 45.0f; + state.m_fVerticalFOVDegrees = 30.0f; + state.m_fQuadraticAtten = r_flashlightquadratic.GetFloat(); + state.m_fLinearAtten = r_flashlightlinear.GetFloat(); + state.m_fConstantAtten = r_flashlightconstant.GetFloat(); + state.m_Color[0] = 1.0f; + state.m_Color[1] = 1.0f; + state.m_Color[2] = 1.0f; + state.m_Color[3] = r_flashlightambient.GetFloat(); state.m_NearZ = r_flashlightnear.GetFloat(); state.m_FarZ = r_flashlightfar.GetFloat(); + state.m_bEnableShadows = true; + state.m_pSpotlightTexture = m_FlashlightTexture; + state.m_nSpotlightTextureFrame = 0; if( GetFlashlightHandle() == CLIENTSHADOW_INVALID_HANDLE ) { diff --git a/src/src/cl_dll/flashlighteffect.h b/src/src/game/client/flashlighteffect.h similarity index 94% rename from src/src/cl_dll/flashlighteffect.h rename to src/src/game/client/flashlighteffect.h index b079b41..6b69e71 100644 --- a/src/src/cl_dll/flashlighteffect.h +++ b/src/src/game/client/flashlighteffect.h @@ -28,7 +28,7 @@ public: ClientShadowHandle_t GetFlashlightHandle( void ) { return m_FlashlightHandle; } void SetFlashlightHandle( ClientShadowHandle_t Handle ) { m_FlashlightHandle = Handle; } -private: +protected: void LightOff(); void LightOffOld(); @@ -44,6 +44,9 @@ private: // Vehicle headlight dynamic light pointer dlight_t *m_pPointLight; float m_flDistMod; + + // Texture for flashlight + CTextureReference m_FlashlightTexture; }; class CHeadlightEffect : public CFlashlightEffect diff --git a/src/src/cl_dll/fontabc.h b/src/src/game/client/fontabc.h similarity index 100% rename from src/src/cl_dll/fontabc.h rename to src/src/game/client/fontabc.h diff --git a/src/src/cl_dll/functionproxy.cpp b/src/src/game/client/functionproxy.cpp similarity index 95% rename from src/src/cl_dll/functionproxy.cpp rename to src/src/game/client/functionproxy.cpp index 12263a4..3ec51ae 100644 --- a/src/src/cl_dll/functionproxy.cpp +++ b/src/src/game/client/functionproxy.cpp @@ -148,20 +148,21 @@ bool CResultProxy::Init( IMaterial *pMaterial, KeyValues *pKeyValues ) void CResultProxy::SetFloatResult( float result ) { if (m_pResult->GetType() == MATERIAL_VAR_TYPE_VECTOR) - { - float v[4]; - int vecSize = m_pResult->VectorSize(); + { if ( m_ResultVecComp >= 0 ) { - m_pResult->GetVecValue( v, vecSize ); - v[m_ResultVecComp] = result; + m_pResult->SetVecComponentValue( result, m_ResultVecComp ); } else { + float v[4]; + int vecSize = m_pResult->VectorSize(); + for (int i = 0; i < vecSize; ++i) v[i] = result; - } - m_pResult->SetVecValue( v, vecSize ); + + m_pResult->SetVecValue( v, vecSize ); + } } else { @@ -175,6 +176,11 @@ C_BaseEntity *CResultProxy::BindArgToEntity( void *pArg ) return pRend->GetIClientUnknown()->GetBaseEntity(); } +IMaterial *CResultProxy::GetMaterial() +{ + return m_pResult->GetOwningMaterial(); +} + //----------------------------------------------------------------------------- // diff --git a/src/src/cl_dll/functionproxy.h b/src/src/game/client/functionproxy.h similarity index 98% rename from src/src/cl_dll/functionproxy.h rename to src/src/game/client/functionproxy.h index 5cbb05c..d8a8df2 100644 --- a/src/src/cl_dll/functionproxy.h +++ b/src/src/game/client/functionproxy.h @@ -43,6 +43,7 @@ public: virtual ~CResultProxy(); virtual bool Init( IMaterial *pMaterial, KeyValues *pKeyValues ); virtual void Release( void ) { delete this; } + virtual IMaterial *GetMaterial(); protected: C_BaseEntity *BindArgToEntity( void *pArg ); diff --git a/src/src/cl_dll/fx.cpp b/src/src/game/client/fx.cpp similarity index 95% rename from src/src/cl_dll/fx.cpp rename to src/src/game/client/fx.cpp index 03b4880..d2064c5 100644 --- a/src/src/cl_dll/fx.cpp +++ b/src/src/game/client/fx.cpp @@ -30,6 +30,7 @@ #include "tier0/memdbgon.h" //Precahce the effects +#ifndef TF_CLIENT_DLL CLIENTEFFECT_REGISTER_BEGIN( PrecacheMuzzleFlash ) CLIENTEFFECT_MATERIAL( "effects/muzzleflash1" ) CLIENTEFFECT_MATERIAL( "effects/muzzleflash2" ) @@ -38,11 +39,13 @@ CLIENTEFFECT_MATERIAL( "effects/muzzleflash4" ) CLIENTEFFECT_MATERIAL( "effects/bluemuzzle" ) CLIENTEFFECT_MATERIAL( "effects/gunshipmuzzle" ) CLIENTEFFECT_MATERIAL( "effects/gunshiptracer" ) +CLIENTEFFECT_MATERIAL( "effects/huntertracer" ) CLIENTEFFECT_MATERIAL( "sprites/physcannon_bluelight2" ) CLIENTEFFECT_MATERIAL( "effects/combinemuzzle1" ) CLIENTEFFECT_MATERIAL( "effects/combinemuzzle2" ) CLIENTEFFECT_MATERIAL( "effects/combinemuzzle2_nocull" ) CLIENTEFFECT_REGISTER_END() +#endif //Whether or not we should emit a dynamic light ConVar muzzleflash_light( "muzzleflash_light", "1", FCVAR_ARCHIVE ); @@ -298,6 +301,12 @@ void FX_MuzzleEffectAttached( VPROF_BUDGET( "FX_MuzzleEffect", VPROF_BUDGETGROUP_PARTICLE_RENDERING ); CSmartPtr pSimple = CLocalSpaceEmitter::Create( "MuzzleFlash", hEntity, attachmentIndex ); + Assert( pSimple ); + if ( pSimple == NULL ) + return; + + // Lock our bounding box + pSimple->GetBinding().SetBBox( -( Vector( 16, 16, 16 ) * scale ), ( Vector( 16, 16, 16 ) * scale ) ); SimpleParticle *pParticle; Vector forward(1,0,0), offset; @@ -322,7 +331,7 @@ void FX_MuzzleEffectAttached( { offset = (forward * (i*2.0f*scale)); - pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), pSimple->GetPMaterial( VarArgs( "effects/muzzleflash%d", random->RandomInt(1,4) ) ), offset ); + pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Mat_SMG_Muzzleflash[random->RandomInt(0,3)], offset ); if ( pParticle == NULL ) return; @@ -370,7 +379,7 @@ void FX_MuzzleEffectAttached( // NOTE: Particle system destruction message will be sent by the particle effect itself. int nId = pSimple->AllocateToolParticleEffectId(); - KeyValues *msg = new KeyValues( "ParticleSystem_Create" ); + KeyValues *msg = new KeyValues( "OldParticleSystem_Create" ); msg->SetString( "name", "FX_MuzzleEffectAttached" ); msg->SetInt( "id", nId ); msg->SetFloat( "time", gpGlobals->curtime ); @@ -622,7 +631,7 @@ public: void CreateSpurtParticles( void ) { SimpleParticle *pParticle; - PMaterialHandle hMaterial = GetPMaterial( "particle/particle_smokegrenade" ); + // PMaterialHandle hMaterial = GetPMaterial( "particle/particle_smokegrenade" ); Vector vecOrigin = m_vSortOrigin; IClientRenderable *pRenderable = ClientEntityList().GetClientRenderableFromHandle(m_hEntity); @@ -637,7 +646,7 @@ public: int numParticles = RandomInt( 1,2 ); for ( int i = 0; i < numParticles; i++ ) { - pParticle = (SimpleParticle *) AddParticle( sizeof( SimpleParticle ), hMaterial, vecOrigin ); + pParticle = (SimpleParticle *) AddParticle( sizeof( SimpleParticle ), g_Mat_DustPuff[0], vecOrigin ); if ( pParticle == NULL ) break; @@ -920,6 +929,40 @@ void FX_StriderTracer( Vector& start, Vector& end, int velocity, bool makeWhiz ) } +//----------------------------------------------------------------------------- +// Purpose: +// Input : start - +// end - +// velocity - +// makeWhiz - +//----------------------------------------------------------------------------- +void FX_HunterTracer( Vector& start, Vector& end, int velocity, bool makeWhiz ) +{ + VPROF_BUDGET( "FX_HunterTracer", VPROF_BUDGETGROUP_PARTICLE_RENDERING ); + Vector vNear, dStart, dEnd, shotDir; + float totalDist; + + // Get out shot direction and length + VectorSubtract( end, start, shotDir ); + totalDist = VectorNormalize( shotDir ); + + // Make short tracers in close quarters + // float flMinLength = min( totalDist, 128.0f ); + // float flMaxLength = min( totalDist, 128.0f ); + + float length = 128.0f;//random->RandomFloat( flMinLength, flMaxLength ); + float life = ( totalDist + length ) / velocity; // NOTENOTE: We want the tail to finish its run as well + + // Add it + FX_AddDiscreetLine( start, shotDir, velocity*0.5f, length, totalDist, 2.0f, life, "effects/huntertracer" ); + + if( makeWhiz ) + { + FX_TracerSound( start, end, TRACER_TYPE_STRIDER ); + } +} + + //----------------------------------------------------------------------------- // Purpose: // Input : start - diff --git a/src/src/cl_dll/fx.h b/src/src/game/client/fx.h similarity index 85% rename from src/src/cl_dll/fx.h rename to src/src/game/client/fx.h index e5afd46..d77e4cf 100644 --- a/src/src/cl_dll/fx.h +++ b/src/src/game/client/fx.h @@ -1,18 +1,18 @@ -//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: // // $Workfile: $ // $Date: $ // $NoKeywords: $ -//=============================================================================// +//===========================================================================// #if !defined( FX_H ) #define FX_H #ifdef _WIN32 #pragma once #endif -#include "vector.h" +#include "mathlib/vector.h" #include "particles_simple.h" #include "c_pixel_visibility.h" @@ -45,6 +45,7 @@ void FX_DebrisFlecks( const Vector& origin, trace_t *trace, char materialType, i void FX_Tracer( Vector& start, Vector& end, int velocity, bool makeWhiz = true ); void FX_GunshipTracer( Vector& start, Vector& end, int velocity, bool makeWhiz = true ); void FX_StriderTracer( Vector& start, Vector& end, int velocity, bool makeWhiz = true ); +void FX_HunterTracer( Vector& start, Vector& end, int velocity, bool makeWhiz = true ); void FX_PlayerTracer( Vector& start, Vector& end ); void FX_BulletPass( Vector& start, Vector& end ); void FX_MetalSpark( const Vector &position, const Vector &direction, const Vector &surfaceNormal, int iScale = 1 ); @@ -59,6 +60,7 @@ void FX_MicroExplosion( Vector &position, Vector &normal ); void FX_Explosion( Vector& origin, Vector& normal, char materialType ); void FX_ConcussiveExplosion( Vector& origin, Vector& normal ); void FX_DustImpact( const Vector &origin, trace_t *tr, int iScale ); +void FX_DustImpact( const Vector &origin, trace_t *tr, float flScale ); void FX_MuzzleEffect( const Vector &origin, const QAngle &angles, float scale, ClientEntityHandle_t hEntity, unsigned char *pFlashColor = NULL, bool bOneFrame = false ); void FX_MuzzleEffectAttached( float scale, ClientEntityHandle_t hEntity, int attachmentIndex, unsigned char *pFlashColor = NULL, bool bOneFrame = false ); void FX_StriderMuzzleEffect( const Vector &origin, const QAngle &angles, float scale, ClientEntityHandle_t hEntity, unsigned char *pFlashColor = NULL ); @@ -93,4 +95,15 @@ public: void FX_Tesla( const CTeslaInfo &teslaInfo ); extern ConVar r_decals; -#endif // FX_H \ No newline at end of file +extern void FX_CacheMaterialHandles( void ); + +extern PMaterialHandle g_Mat_Fleck_Wood[2]; +extern PMaterialHandle g_Mat_Fleck_Cement[2]; +extern PMaterialHandle g_Mat_Fleck_Antlion[2]; +extern PMaterialHandle g_Mat_Fleck_Tile[2]; +extern PMaterialHandle g_Mat_DustPuff[2]; +extern PMaterialHandle g_Mat_BloodPuff[2]; +extern PMaterialHandle g_Mat_Fleck_Glass[2]; +extern PMaterialHandle g_Mat_SMG_Muzzleflash[4]; +extern PMaterialHandle g_Mat_Combine_Muzzleflash[3]; +#endif // FX_H diff --git a/src/src/cl_dll/fx_blood.cpp b/src/src/game/client/fx_blood.cpp similarity index 80% rename from src/src/cl_dll/fx_blood.cpp rename to src/src/game/client/fx_blood.cpp index a4929de..2660fb9 100644 --- a/src/src/cl_dll/fx_blood.cpp +++ b/src/src/game/client/fx_blood.cpp @@ -16,8 +16,11 @@ #include "fx_quad.h" #include "engine/IVDebugOverlay.h" #include "shareddefs.h" +#include "fx.h" #include "fx_blood.h" #include "effect_color_tables.h" +#include "particle_simple3D.h" +#include "particle_parse.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -309,7 +312,7 @@ void FX_BloodBulletImpact( const Vector &origin, const Vector &normal, float sca //Find area ambient light color and use it to tint smoke Vector worldLight = WorldGetLightForPoint( origin, true ); - if ( IsPC() && gpGlobals->maxClients > 1 ) + if ( gpGlobals->maxClients > 1 ) { worldLight = Vector( 1.0, 1.0, 1.0 ); r = 96; @@ -460,6 +463,27 @@ void FX_BloodBulletImpact( const Vector &origin, const Vector &normal, float sca //C_BaseEntity::EmitSound( filter, SOUND_FROM_WORLD, CHAN_VOICE, "Physics.WaterSplash", 1.0, ATTN_NORM, 0, 100, &origin ); } +// FIXME: This will be simplified when the initializer can take color parameters as an input +// For now, we use different systems + +struct ParticleForBlood_t +{ + int nColor; + const char *lpszParticleSystemName; +}; + +ParticleForBlood_t bloodCallbacks[] = +{ + { BLOOD_COLOR_RED, "blood_impact_red_01" }, + { BLOOD_COLOR_GREEN, "blood_impact_green_01" }, + { BLOOD_COLOR_YELLOW, "blood_impact_yellow_01" }, +#if defined( HL2_EPISODIC ) + { BLOOD_COLOR_ANTLION, "blood_impact_antlion_01" }, // FIXME: Move to Base HL2 + { BLOOD_COLOR_ZOMBIE, "blood_impact_zombie_01" }, // FIXME: Move to Base HL2 + { BLOOD_COLOR_ANTLION_WORKER, "blood_impact_antlion_worker_01" }, +#endif // HL2_EPISODIC +}; + //----------------------------------------------------------------------------- // Purpose: Intercepts the blood spray message. //----------------------------------------------------------------------------- @@ -477,14 +501,91 @@ DECLARE_CLIENT_EFFECT( "bloodspray", BloodSprayCallback ); //----------------------------------------------------------------------------- void BloodImpactCallback( const CEffectData & data ) { - Vector vecPosition; - vecPosition = data.m_vOrigin; - - // Fetch the blood color. - colorentry_t color; - GetBloodColor( data.m_nColor, color ); + bool bFoundBlood = false; - FX_BloodBulletImpact( vecPosition, data.m_vNormal, data.m_flScale, color.r, color.g, color.b ); + // Find which sort of blood we are + for ( int i = 0; i < ARRAYSIZE( bloodCallbacks ); i++ ) + { + if ( bloodCallbacks[i].nColor == data.m_nColor ) + { + QAngle vecAngles; + VectorAngles( -data.m_vNormal, vecAngles ); + DispatchParticleEffect( bloodCallbacks[i].lpszParticleSystemName, data.m_vOrigin, vecAngles ); + bFoundBlood = true; + break; + } + } + + if ( bFoundBlood == false ) + { + Vector vecPosition; + vecPosition = data.m_vOrigin; + + // Fetch the blood color. + colorentry_t color; + GetBloodColor( data.m_nColor, color ); + + FX_BloodBulletImpact( vecPosition, data.m_vNormal, data.m_flScale, color.r, color.g, color.b ); + } } DECLARE_CLIENT_EFFECT( "BloodImpact", BloodImpactCallback ); + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void HunterDamageCallback( const CEffectData &data ) +{ + CSmartPtr pGlassEmitter = CSimple3DEmitter::Create( "HunterDamage" ); + if ( pGlassEmitter == NULL ) + return; + + pGlassEmitter->SetSortOrigin( data.m_vOrigin ); + + // Handle increased scale + const float flMaxSpeed = 400.0f; + const float flMinSpeed = 50.0f; + float flAngularSpray = 1.0f; + + // Setup our collision information + pGlassEmitter->m_ParticleCollision.Setup( data.m_vOrigin, &data.m_vNormal, flAngularSpray, flMinSpeed, flMaxSpeed, 600.0f, 0.2f ); + + Vector dir, end; + + int numFlecks = 32; + + Particle3D *pFleckParticle; + Vector spawnOffset; + + //Dump out flecks + for ( int i = 0; i < numFlecks; i++ ) + { + spawnOffset = data.m_vOrigin + RandomVector( -32.0f, 32.0f ); + pFleckParticle = (Particle3D *) pGlassEmitter->AddParticle( sizeof(Particle3D), g_Mat_Fleck_Antlion[random->RandomInt(0,1)], spawnOffset ); + + if ( pFleckParticle == NULL ) + break; + + pFleckParticle->m_flLifeRemaining = random->RandomFloat( 2.0f, 3.0f ); + + dir[0] = data.m_vNormal[0] + random->RandomFloat( -flAngularSpray, flAngularSpray ); + dir[1] = data.m_vNormal[1] + random->RandomFloat( -flAngularSpray, flAngularSpray ); + dir[2] = data.m_vNormal[2] + random->RandomFloat( -flAngularSpray, flAngularSpray ); + + pFleckParticle->m_uchSize = random->RandomInt( 3, 8 ); + + pFleckParticle->m_vecVelocity = dir * random->RandomFloat( flMinSpeed, flMaxSpeed); + + pFleckParticle->m_vAngles = RandomAngle( 0, 360 ); + pFleckParticle->m_flAngSpeed = random->RandomFloat( -800, 800 ); + + unsigned char color = 255; + pFleckParticle->m_uchFrontColor[0] = color; + pFleckParticle->m_uchFrontColor[1] = color; + pFleckParticle->m_uchFrontColor[2] = color; + pFleckParticle->m_uchBackColor[0] = color * 0.25f; + pFleckParticle->m_uchBackColor[1] = color * 0.25f; + pFleckParticle->m_uchBackColor[2] = color * 0.25f; + } +} + +DECLARE_CLIENT_EFFECT( "HunterDamage", HunterDamageCallback ); diff --git a/src/src/cl_dll/fx_blood.h b/src/src/game/client/fx_blood.h similarity index 100% rename from src/src/cl_dll/fx_blood.h rename to src/src/game/client/fx_blood.h diff --git a/src/src/cl_dll/fx_cube.cpp b/src/src/game/client/fx_cube.cpp similarity index 94% rename from src/src/cl_dll/fx_cube.cpp rename to src/src/game/client/fx_cube.cpp index 71ce464..58d183b 100644 --- a/src/src/cl_dll/fx_cube.cpp +++ b/src/src/game/client/fx_cube.cpp @@ -49,7 +49,8 @@ public: Vector color; VectorScale( m_vColor, shade, color ); - IMesh *pMesh = materials->GetDynamicMesh(); + CMatRenderContextPtr pRenderContext( materials ); + IMesh *pMesh = pRenderContext->GetDynamicMesh(); CMeshBuilder builder; builder.Begin(pMesh, MATERIAL_TRIANGLE_STRIP, 2); @@ -80,8 +81,9 @@ public: virtual void Draw( double frametime ) { + CMatRenderContextPtr pRenderContext( materials ); // Draw it. - materials->Bind( m_pMaterial ); + pRenderContext->Bind( m_pMaterial ); Vector vLightDir(-1,-2,-3); VectorNormalize( vLightDir ); diff --git a/src/src/cl_dll/fx_discreetline.cpp b/src/src/game/client/fx_discreetline.cpp similarity index 96% rename from src/src/cl_dll/fx_discreetline.cpp rename to src/src/game/client/fx_discreetline.cpp index d1f9b8e..25cb6cf 100644 --- a/src/src/cl_dll/fx_discreetline.cpp +++ b/src/src/game/client/fx_discreetline.cpp @@ -108,6 +108,8 @@ void CFXDiscreetLine::Draw( double frametime ) CMeshBuilder meshBuilder; IMesh *pMesh; + CMatRenderContextPtr pRenderContext( materials ); + // Better, more visible tracers if ( tracer_extra.GetBool() ) { @@ -133,9 +135,9 @@ void CFXDiscreetLine::Draw( double frametime ) } //Bind the material - pMesh = materials->GetDynamicMesh( true, NULL, NULL, m_pMaterial ); + pMesh = pRenderContext->GetDynamicMesh( true, NULL, NULL, m_pMaterial ); - meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 ); + meshBuilder.Begin( pMesh, MATERIAL_QUADS, 2 ); float color = (int) 255.0f * flAlpha; @@ -203,7 +205,7 @@ void CFXDiscreetLine::Draw( double frametime ) else { //Bind the material - pMesh = materials->GetDynamicMesh( true, NULL, NULL, m_pMaterial ); + pMesh = pRenderContext->GetDynamicMesh( true, NULL, NULL, m_pMaterial ); meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 ); diff --git a/src/src/cl_dll/fx_discreetline.h b/src/src/game/client/fx_discreetline.h similarity index 97% rename from src/src/cl_dll/fx_discreetline.h rename to src/src/game/client/fx_discreetline.h index b4b0e2b..5ffd652 100644 --- a/src/src/cl_dll/fx_discreetline.h +++ b/src/src/game/client/fx_discreetline.h @@ -17,7 +17,7 @@ #pragma once #endif -#include "vector.h" +#include "mathlib/vector.h" #include "clientsideeffects.h" class IMaterial; diff --git a/src/src/cl_dll/fx_envelope.cpp b/src/src/game/client/fx_envelope.cpp similarity index 100% rename from src/src/cl_dll/fx_envelope.cpp rename to src/src/game/client/fx_envelope.cpp diff --git a/src/src/cl_dll/fx_envelope.h b/src/src/game/client/fx_envelope.h similarity index 100% rename from src/src/cl_dll/fx_envelope.h rename to src/src/game/client/fx_envelope.h diff --git a/src/src/cl_dll/fx_explosion.cpp b/src/src/game/client/fx_explosion.cpp similarity index 98% rename from src/src/cl_dll/fx_explosion.cpp rename to src/src/game/client/fx_explosion.cpp index ba3c6ea..5e0d357 100644 --- a/src/src/cl_dll/fx_explosion.cpp +++ b/src/src/game/client/fx_explosion.cpp @@ -227,7 +227,7 @@ void C_BaseExplosionEffect::CreateCore( void ) if ( m_Material_Smoke == NULL ) { - m_Material_Smoke = pSimple->GetPMaterial( "particle/particle_noisesphere" ); + m_Material_Smoke = g_Mat_DustPuff[1]; } //FIXME: Better sampling area @@ -268,6 +268,9 @@ void C_BaseExplosionEffect::CreateCore( void ) { pParticle->m_flLifetime = 0.0f; + #ifdef INVASION_CLIENT_DLL + pParticle->m_flDieTime = random->RandomFloat( 0.5f, 1.0f ); + #endif #ifdef _XBOX pParticle->m_flDieTime = 1.0f; #else @@ -324,7 +327,11 @@ void C_BaseExplosionEffect::CreateCore( void ) { pParticle->m_flLifetime = 0.0f; + #ifdef INVASION_CLIENT_DLL pParticle->m_flDieTime = random->RandomFloat( 0.5f, 1.0f ); + #else + pParticle->m_flDieTime = random->RandomFloat( 0.5f, 1.0f ); + #endif pParticle->m_vecVelocity.Random( -spread, spread ); pParticle->m_vecVelocity += ( m_vecDirection * random->RandomFloat( 1.0f, 6.0f ) ); @@ -368,6 +375,7 @@ void C_BaseExplosionEffect::CreateCore( void ) Vector forward; +#ifndef INVASION_CLIENT_DLL #ifndef _XBOX int numRingSprites = 32; @@ -421,7 +429,7 @@ void C_BaseExplosionEffect::CreateCore( void ) pParticle->m_flRollDelta = random->RandomFloat( -8.0f, 8.0f ); } } - +#endif } #ifndef _XBOX @@ -620,23 +628,13 @@ void C_BaseExplosionEffect::CreateDebris( void ) // Vector offset; - - CSmartPtr fleckEmitter = CFleckParticles::Create( "CreateDebris 2", m_vecOrigin ); + CSmartPtr fleckEmitter = CFleckParticles::Create( "CreateDebris 2", m_vecOrigin, Vector(128,128,128) ); if ( !fleckEmitter ) return; - fleckEmitter->SetSortOrigin( m_vecOrigin ); - // Setup our collision information fleckEmitter->m_ParticleCollision.Setup( m_vecOrigin, &m_vecDirection, 0.9f, 512, 1024, 800, 0.5f ); - // Limit our bbox - fleckEmitter->GetBinding().SetBBox( m_vecOrigin - Vector(128,128,128), m_vecOrigin + Vector(128,128,128) ); - - // FIXME: Cache? - PMaterialHandle hMaterialArray[2]; - hMaterialArray[0] = fleckEmitter->GetPMaterial( "effects/fleck_cement1" ); - hMaterialArray[1] = fleckEmitter->GetPMaterial( "effects/fleck_cement2" ); #ifdef _XBOX int numFlecks = random->RandomInt( 8, 16 ); @@ -654,7 +652,7 @@ void C_BaseExplosionEffect::CreateDebris( void ) offset[1] += random->RandomFloat( -8.0f, 8.0f ); offset[2] += random->RandomFloat( -8.0f, 8.0f ); - FleckParticle *pParticle = (FleckParticle *) fleckEmitter->AddParticle( sizeof(FleckParticle), hMaterialArray[random->RandomInt(0,1)], offset ); + FleckParticle *pParticle = (FleckParticle *) fleckEmitter->AddParticle( sizeof(FleckParticle), g_Mat_Fleck_Cement[random->RandomInt(0,1)], offset ); if ( pParticle == NULL ) break; @@ -1115,7 +1113,12 @@ void C_WaterExplosionEffect::CreateDebris( void ) { pParticle->m_flLifetime = 0.0f; +#ifdef INVASION_CLIENT_DLL + pParticle->m_flDieTime = random->RandomFloat( 0.5f, 1.0f ); +#else pParticle->m_flDieTime = random->RandomFloat( 2.0f, 3.0f ); +#endif + pParticle->m_vecVelocity.Random( -spread, spread ); pParticle->m_vecVelocity += ( m_vecDirection * random->RandomFloat( 1.0f, 6.0f ) ); diff --git a/src/src/cl_dll/fx_explosion.h b/src/src/game/client/fx_explosion.h similarity index 100% rename from src/src/cl_dll/fx_explosion.h rename to src/src/game/client/fx_explosion.h diff --git a/src/src/game/client/fx_fleck.cpp b/src/src/game/client/fx_fleck.cpp new file mode 100644 index 0000000..1818b5b --- /dev/null +++ b/src/src/game/client/fx_fleck.cpp @@ -0,0 +1,239 @@ +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "FX_Fleck.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + + +// enable this to have the fleck_merge cvar as well as the current system count displayed as it changes (for profiling) +#define REPORT_MERGED_FLECKS 0 + +// +// class PARTICLE_MERGE +//{ +//public: +// bool MergeParticleSystems( CFleckParticles *pSystem, const char *pEffectName, const Vector ¢er, const Vector &extents ) +// { merge; return true; } +//}; + +// a singly linked list through all particle effects of a specific type +// with a specific rule for sharing them. +// Needs a hook to the particle effect's constructor/destructor and factory method +// The factory needs to support optionally merging the new particles into a previously built particle effect +// this cuts down on lots of scene management overhead as well as rendering/batch overhead +template< class PARTICLE_EFFECT, class PARTICLE_MERGE > +class CParticleMergeList +{ +public: + CParticleMergeList() : m_pHead(NULL) {} + void AddParticleSystem( PARTICLE_EFFECT *pSystem ); + void RemoveParticleSystem( PARTICLE_EFFECT *pRemove ); + PARTICLE_EFFECT *FindAndMergeParticleSystem( const char *pEffectName, const Vector ¢er, const Vector &extents ); + bool MergeParticleSystems( PARTICLE_EFFECT *pSystem, const char *pEffectName, const Vector ¢er, const Vector &extents ); +private: + PARTICLE_EFFECT *m_pHead; + PARTICLE_MERGE m_merge; +}; + +#if REPORT_MERGED_FLECKS +ConVar fleck_merge("fleck_merge","1"); +int g_PCount = 0; +#endif + +template< class PARTICLE_EFFECT, class PARTICLE_MERGE > +void CParticleMergeList::AddParticleSystem( PARTICLE_EFFECT *pSystem ) +{ +#if REPORT_MERGED_FLECKS + g_PCount++; + Msg("PS: %d\n", g_PCount); +#endif + pSystem->m_pNextParticleSystem = m_pHead; + m_pHead = pSystem; +} + +template< class PARTICLE_EFFECT, class PARTICLE_MERGE > +void CParticleMergeList::RemoveParticleSystem( PARTICLE_EFFECT *pRemove ) +{ +#if REPORT_MERGED_FLECKS + g_PCount--; + Msg("PS: %d\n", g_PCount); +#endif + PARTICLE_EFFECT **pPrev = &m_pHead; + PARTICLE_EFFECT *pCur = *pPrev; + while ( pCur ) + { + if ( pCur == pRemove ) + { + *pPrev = pCur->m_pNextParticleSystem; + return; + } + pPrev = &pCur->m_pNextParticleSystem; + pCur = *pPrev; + } +} + +template< class PARTICLE_EFFECT, class PARTICLE_MERGE > +PARTICLE_EFFECT *CParticleMergeList::FindAndMergeParticleSystem( const char *pEffectName, const Vector ¢er, const Vector &extents ) +{ +#if REPORT_MERGED_FLECKS + if ( !fleck_merge.GetBool() ) + return NULL; +#endif + + for ( PARTICLE_EFFECT *pMerge = m_pHead; pMerge != NULL; pMerge = pMerge->m_pNextParticleSystem ) + { + if ( m_merge.MergeParticleSystems( pMerge, pEffectName, center, extents ) ) + return pMerge; + } + return NULL; +} + +// merge anything within 10 feet +const float MAX_RADIUS_BBOX_MERGE = 120.0f; + +template< class PARTICLE_EFFECT > +class CMergeSameNameBbox +{ +public: + bool MergeParticleSystems( PARTICLE_EFFECT *pSystem, const char *pEffectName, const Vector ¢er, const Vector &extents ) + { + // by default, match names + if ( !Q_stricmp(pSystem->GetEffectName(), pEffectName) ) + { + Vector mins, maxs; + pSystem->GetBinding().GetWorldspaceBounds( &mins, &maxs ); + AddPointToBounds( center - extents, mins, maxs ); + AddPointToBounds( center + extents, mins, maxs ); + Vector size = maxs - mins; + float radius = size.Length(); + if ( radius < MAX_RADIUS_BBOX_MERGE ) + { + pSystem->GetBinding().SetBBox( mins, maxs ); + // put sort origin at center of the new box + Vector sortOrigin = 0.5f * (mins+maxs); + pSystem->SetSortOrigin(sortOrigin); + return true; + } + } + return false; + } +}; + +CParticleMergeList< CFleckParticles, CMergeSameNameBbox > g_FleckMergeList; + +// +// CFleckParticles +// +CSmartPtr CFleckParticles::Create( const char *pDebugName, const Vector &vCenter, const Vector &extents ) +{ + CFleckParticles *pMerge = g_FleckMergeList.FindAndMergeParticleSystem( pDebugName, vCenter, extents ); + if ( pMerge ) + return pMerge; + + CFleckParticles *pRet = new CFleckParticles( pDebugName ); + if ( pRet ) + { + pRet->GetBinding().SetBBox( vCenter - extents, vCenter + extents ); + pRet->SetSortOrigin(vCenter); + } + return pRet; +} + + +CFleckParticles::CFleckParticles( const char *pDebugName ) : CSimpleEmitter( pDebugName ), m_pNextParticleSystem(NULL) +{ + g_FleckMergeList.AddParticleSystem(this); +} + +CFleckParticles::~CFleckParticles() +{ + g_FleckMergeList.RemoveParticleSystem(this); +} + +//----------------------------------------------------------------------------- +// Purpose: Test for surrounding collision surfaces for quick collision testing for the particle system +// Input : &origin - starting position +// *dir - direction of movement (if NULL, will do a point emission test in four directions) +// angularSpread - looseness of the spread +// minSpeed - minimum speed +// maxSpeed - maximum speed +// gravity - particle gravity for the sytem +// dampen - dampening amount on collisions +// flags - extra information +//----------------------------------------------------------------------------- +void CFleckParticles::Setup( const Vector &origin, const Vector *direction, float angularSpread, float minSpeed, float maxSpeed, float gravity, float dampen, int flags ) +{ + //See if we've specified a direction + m_ParticleCollision.Setup( origin, direction, angularSpread, minSpeed, maxSpeed, gravity, dampen ); +} + + +void CFleckParticles::RenderParticles( CParticleRenderIterator *pIterator ) +{ + const FleckParticle *pParticle = (const FleckParticle*)pIterator->GetFirst(); + while ( pParticle ) + { + Vector tPos; + TransformParticle( ParticleMgr()->GetModelView(), pParticle->m_Pos, tPos ); + float sortKey = (int) tPos.z; + + Vector color; + color[0] = pParticle->m_uchColor[0] / 255.0f; + color[1] = pParticle->m_uchColor[1] / 255.0f; + color[2] = pParticle->m_uchColor[2] / 255.0f; + //Render it + RenderParticle_ColorSizeAngle( + pIterator->GetParticleDraw(), + tPos, + color, + 1.0f - (pParticle->m_flLifetime / pParticle->m_flDieTime), + pParticle->m_uchSize, + pParticle->m_flRoll ); + + pParticle = (const FleckParticle*)pIterator->GetNext( sortKey ); + } +} + + +void CFleckParticles::SimulateParticles( CParticleSimulateIterator *pIterator ) +{ + FleckParticle *pParticle = (FleckParticle*)pIterator->GetFirst(); + while ( pParticle ) + { + const float timeDelta = pIterator->GetTimeDelta(); + + //Should this particle die? + pParticle->m_flLifetime += timeDelta; + + if ( pParticle->m_flLifetime >= pParticle->m_flDieTime ) + { + pIterator->RemoveParticle( pParticle ); + } + else + { + pParticle->m_flRoll += pParticle->m_flRollDelta * timeDelta; + + //Simulate the movement with collision + trace_t trace; + m_ParticleCollision.MoveParticle( pParticle->m_Pos, pParticle->m_vecVelocity, &pParticle->m_flRollDelta, timeDelta, &trace ); + + // If we're in solid, then stop moving + if ( trace.allsolid ) + { + pParticle->m_vecVelocity = vec3_origin; + pParticle->m_flRollDelta = 0.0f; + } + } + + pParticle = (FleckParticle*)pIterator->GetNext(); + } +} + + diff --git a/src/src/cl_dll/fx_fleck.h b/src/src/game/client/fx_fleck.h similarity index 89% rename from src/src/cl_dll/fx_fleck.h rename to src/src/game/client/fx_fleck.h index 51a916b..430e876 100644 --- a/src/src/cl_dll/fx_fleck.h +++ b/src/src/game/client/fx_fleck.h @@ -43,8 +43,9 @@ class CFleckParticles : public CSimpleEmitter { public: - CFleckParticles( const char *pDebugName ) : CSimpleEmitter( pDebugName ) {} - static CSmartPtr Create( const char *pDebugName, const Vector &vCenter ); + CFleckParticles( const char *pDebugName ); + ~CFleckParticles(); + static CSmartPtr Create( const char *pDebugName, const Vector &vCenter, const Vector &extents ); virtual void RenderParticles( CParticleRenderIterator *pIterator ); virtual void SimulateParticles( CParticleSimulateIterator *pIterator ); @@ -54,6 +55,7 @@ public: CParticleCollision m_ParticleCollision; + CFleckParticles *m_pNextParticleSystem; private: CFleckParticles( const CFleckParticles & ); // not defined, not accessible }; diff --git a/src/src/cl_dll/fx_impact.cpp b/src/src/game/client/fx_impact.cpp similarity index 70% rename from src/src/cl_dll/fx_impact.cpp rename to src/src/game/client/fx_impact.cpp index 36f1d06..ca1b404 100644 --- a/src/src/cl_dll/fx_impact.cpp +++ b/src/src/game/client/fx_impact.cpp @@ -1,8 +1,8 @@ -//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: // -//=============================================================================// +//===========================================================================// #include "cbase.h" #include "decals.h" #include "materialsystem/IMaterialVar.h" @@ -11,6 +11,8 @@ #include "fx_impact.h" #include "view.h" #include "engine/IStaticPropMgr.h" +#include "c_impact_effects.h" +#include "tier0/vprof.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -95,6 +97,8 @@ DECLARE_CLIENT_EFFECT( "RagdollImpact", RagdollImpactCallback ); //----------------------------------------------------------------------------- bool Impact( Vector &vecOrigin, Vector &vecStart, int iMaterial, int iDamageType, int iHitbox, C_BaseEntity *pEntity, trace_t &tr, int nFlags, int maxLODToDecal ) { + VPROF( "Impact" ); + Assert ( pEntity ); // Clear out the trace @@ -183,12 +187,111 @@ char const *GetImpactDecal( C_BaseEntity *pEntity, int iMaterial, int iDamageTyp //----------------------------------------------------------------------------- // Purpose: Perform custom effects based on the Decal index //----------------------------------------------------------------------------- +static ConVar cl_new_impact_effects( "cl_new_impact_effects", "0" ); + +struct ImpactEffect_t +{ + const char *m_pName; + const char *m_pNameNoFlecks; +}; + +static ImpactEffect_t s_pImpactEffect[26] = +{ + { "impact_antlion", NULL }, // CHAR_TEX_ANTLION + { NULL, NULL }, // CHAR_TEX_BLOODYFLESH + { "impact_concrete", "impact_concrete_noflecks" }, // CHAR_TEX_CONCRETE + { "impact_dirt", NULL }, // CHAR_TEX_DIRT + { NULL, NULL }, // CHAR_TEX_EGGSHELL + { NULL, NULL }, // CHAR_TEX_FLESH + { NULL, NULL }, // CHAR_TEX_GRATE + { NULL, NULL }, // CHAR_TEX_ALIENFLESH + { NULL, NULL }, // CHAR_TEX_CLIP + { NULL, NULL }, // CHAR_TEX_UNUSED + { NULL, NULL }, // CHAR_TEX_UNUSED + { NULL, NULL }, // CHAR_TEX_PLASTIC + { "impact_metal", NULL }, // CHAR_TEX_METAL + { "impact_dirt", NULL }, // CHAR_TEX_SAND + { NULL, NULL }, // CHAR_TEX_FOLIAGE + { "impact_computer", NULL }, // CHAR_TEX_COMPUTER + { NULL, NULL }, // CHAR_TEX_UNUSED + { NULL, NULL }, // CHAR_TEX_UNUSED + { NULL, NULL }, // CHAR_TEX_SLOSH + { "impact_concrete", "impact_concrete_noflecks" }, // CHAR_TEX_TILE + { NULL, NULL }, // CHAR_TEX_UNUSED + { "impact_metal", NULL }, // CHAR_TEX_VENT + { "impact_wood", "impact_wood_noflecks" }, // CHAR_TEX_WOOD + { NULL, NULL }, // CHAR_TEX_UNUSED + { "impact_glass", NULL }, // CHAR_TEX_GLASS + { "warp_shield_impact", NULL }, // CHAR_TEX_WARPSHIELD +}; + +static void SetImpactControlPoint( CNewParticleEffect *pEffect, int nPoint, const Vector &vecImpactPoint, const Vector &vecForward, C_BaseEntity *pEntity ) +{ + Vector vecImpactY, vecImpactZ; + VectorVectors( vecForward, vecImpactY, vecImpactZ ); + vecImpactY *= -1.0f; + + pEffect->SetControlPoint( nPoint, vecImpactPoint ); + pEffect->SetControlPointOrientation( nPoint, vecForward, vecImpactY, vecImpactZ ); + pEffect->SetControlPointEntity( nPoint, pEntity ); +} + +static void PerformNewCustomEffects( const Vector &vecOrigin, trace_t &tr, const Vector &shotDir, int iMaterial, int iScale, int nFlags ) +{ + bool bNoFlecks = !r_drawflecks.GetBool(); + if ( !bNoFlecks ) + { + bNoFlecks = ( ( nFlags & FLAGS_CUSTIOM_EFFECTS_NOFLECKS ) != 0 ); + } + + // Compute the impact effect name + const ImpactEffect_t &effect = s_pImpactEffect[ iMaterial - 'A' ]; + const char *pImpactName = effect.m_pName; + if ( bNoFlecks && effect.m_pNameNoFlecks ) + { + pImpactName = effect.m_pNameNoFlecks; + } + if ( !pImpactName ) + return; + + CSmartPtr pEffect = CNewParticleEffect::Create( NULL, pImpactName ); + if ( !pEffect->IsValid() ) + return; + + Vector vecReflect; + float flDot = DotProduct( shotDir, tr.plane.normal ); + VectorMA( shotDir, -2.0f * flDot, tr.plane.normal, vecReflect ); + + Vector vecShotBackward; + VectorMultiply( shotDir, -1.0f, vecShotBackward ); + + Vector vecImpactPoint = ( tr.fraction != 1.0f ) ? tr.endpos : vecOrigin; + Assert( VectorsAreEqual( vecOrigin, tr.endpos, 1e-1 ) ); + + SetImpactControlPoint( pEffect.GetObject(), 0, vecImpactPoint, tr.plane.normal, tr.m_pEnt ); + SetImpactControlPoint( pEffect.GetObject(), 1, vecImpactPoint, vecReflect, tr.m_pEnt ); + SetImpactControlPoint( pEffect.GetObject(), 2, vecImpactPoint, vecShotBackward, tr.m_pEnt ); + pEffect->SetControlPoint( 3, Vector( iScale, iScale, iScale ) ); + if ( pEffect->m_pDef->ReadsControlPoint( 4 ) ) + { + Vector vecColor; + GetColorForSurface( &tr, &vecColor ); + pEffect->SetControlPoint( 4, vecColor ); + } +} + void PerformCustomEffects( const Vector &vecOrigin, trace_t &tr, const Vector &shotDir, int iMaterial, int iScale, int nFlags ) { // Throw out the effect if any of these are true if ( tr.surface.flags & (SURF_SKY|SURF_NODRAW|SURF_HINT|SURF_SKIP) ) return; + if ( cl_new_impact_effects.GetInt() ) + { + PerformNewCustomEffects( vecOrigin, tr, shotDir, iMaterial, iScale, nFlags ); + return; + } + bool bNoFlecks = !r_drawflecks.GetBool(); if ( !bNoFlecks ) { @@ -230,6 +333,12 @@ void PerformCustomEffects( const Vector &vecOrigin, trace_t &tr, const Vector &s g_pEffects->Sparks( offset ); } + else if ( iMaterial == CHAR_TEX_WARPSHIELD ) + { + QAngle vecAngles; + VectorAngles( -shotDir, vecAngles ); + DispatchParticleEffect( "warp_shield_impact", vecOrigin, vecAngles ); + } } //----------------------------------------------------------------------------- @@ -238,6 +347,7 @@ void PerformCustomEffects( const Vector &vecOrigin, trace_t &tr, const Vector &s //----------------------------------------------------------------------------- void PlayImpactSound( CBaseEntity *pEntity, trace_t &tr, Vector &vecServerOrigin, int nServerSurfaceProp ) { + VPROF( "PlayImpactSound" ); surfacedata_t *pdata; Vector vecOrigin; diff --git a/src/src/cl_dll/fx_impact.h b/src/src/game/client/fx_impact.h similarity index 100% rename from src/src/cl_dll/fx_impact.h rename to src/src/game/client/fx_impact.h diff --git a/src/src/cl_dll/fx_interpvalue.cpp b/src/src/game/client/fx_interpvalue.cpp similarity index 100% rename from src/src/cl_dll/fx_interpvalue.cpp rename to src/src/game/client/fx_interpvalue.cpp diff --git a/src/src/cl_dll/fx_interpvalue.h b/src/src/game/client/fx_interpvalue.h similarity index 100% rename from src/src/cl_dll/fx_interpvalue.h rename to src/src/game/client/fx_interpvalue.h diff --git a/src/src/cl_dll/fx_line.cpp b/src/src/game/client/fx_line.cpp similarity index 95% rename from src/src/cl_dll/fx_line.cpp rename to src/src/game/client/fx_line.cpp index b9c964b..8ff9ef7 100644 --- a/src/src/cl_dll/fx_line.cpp +++ b/src/src/game/client/fx_line.cpp @@ -54,8 +54,10 @@ void CFXLine::Draw( double frametime ) VectorNormalize( cross ); + CMatRenderContextPtr pRenderContext( materials ); + //Bind the material - IMesh* pMesh = materials->GetDynamicMesh( true, NULL, NULL, m_FXData.m_pMaterial ); + IMesh* pMesh = pRenderContext->GetDynamicMesh( true, NULL, NULL, m_FXData.m_pMaterial ); CMeshBuilder meshBuilder; @@ -152,8 +154,10 @@ void FX_DrawLine( const Vector &start, const Vector &end, float scale, IMaterial VectorNormalize( cross ); + CMatRenderContextPtr pRenderContext( materials ); + //Bind the material - IMesh* pMesh = materials->GetDynamicMesh( true, NULL, NULL, pMaterial ); + IMesh* pMesh = pRenderContext->GetDynamicMesh( true, NULL, NULL, pMaterial ); CMeshBuilder meshBuilder; Vector tmp; @@ -213,8 +217,10 @@ void FX_DrawLineFade( const Vector &start, const Vector &end, float scale, IMate VectorNormalize( cross ); + CMatRenderContextPtr pRenderContext( materials ); + //Bind the material - IMesh* pMesh = materials->GetDynamicMesh( true, NULL, NULL, pMaterial ); + IMesh* pMesh = pRenderContext->GetDynamicMesh( true, NULL, NULL, pMaterial ); CMeshBuilder meshBuilder; Vector tmp; diff --git a/src/src/cl_dll/fx_line.h b/src/src/game/client/fx_line.h similarity index 100% rename from src/src/cl_dll/fx_line.h rename to src/src/game/client/fx_line.h diff --git a/src/src/cl_dll/fx_quad.cpp b/src/src/game/client/fx_quad.cpp similarity index 94% rename from src/src/cl_dll/fx_quad.cpp rename to src/src/game/client/fx_quad.cpp index 5f0f87a..7100721 100644 --- a/src/src/cl_dll/fx_quad.cpp +++ b/src/src/game/client/fx_quad.cpp @@ -63,8 +63,10 @@ void CFXQuad::Draw( double frametime ) float alpha = m_FXData.m_flStartAlpha + ( ( m_FXData.m_flEndAlpha - m_FXData.m_flStartAlpha ) * alphaTimePerc ); alpha = clamp( alpha, 0.0f, 1.0f ); + CMatRenderContextPtr pRenderContext( materials ); + //Bind the material - IMesh* pMesh = materials->GetDynamicMesh( true, NULL, NULL, m_FXData.m_pMaterial ); + IMesh* pMesh = pRenderContext->GetDynamicMesh( true, NULL, NULL, m_FXData.m_pMaterial ); CMeshBuilder meshBuilder; meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 ); @@ -80,6 +82,14 @@ void CFXQuad::Draw( double frametime ) color[0] = m_FXData.m_Color[0]; color[1] = m_FXData.m_Color[1]; color[2] = m_FXData.m_Color[2]; + + if ( m_FXData.m_uiFlags & FXQUAD_COLOR_FADE ) + { + color[0] *= alpha; + color[1] *= alpha; + color[2] *= alpha; + } + color[3] = alpha; VectorVectors( m_FXData.m_vecNormal, vRight, vUp ); diff --git a/src/src/cl_dll/fx_quad.h b/src/src/game/client/fx_quad.h similarity index 95% rename from src/src/cl_dll/fx_quad.h rename to src/src/game/client/fx_quad.h index b8c3b5d..56830f2 100644 --- a/src/src/cl_dll/fx_quad.h +++ b/src/src/game/client/fx_quad.h @@ -18,6 +18,7 @@ // Flags #define FXQUAD_BIAS_SCALE 0x0001 //Bias the scale's interpolation function #define FXQUAD_BIAS_ALPHA 0x0002 //Bias the alpha's interpolation function +#define FXQUAD_COLOR_FADE 0x0004 //Blend the color towards black via the alpha (overcomes additive ignoring alpha) struct FXQuadData_t { diff --git a/src/src/cl_dll/fx_shelleject.cpp b/src/src/game/client/fx_shelleject.cpp similarity index 100% rename from src/src/cl_dll/fx_shelleject.cpp rename to src/src/game/client/fx_shelleject.cpp diff --git a/src/src/cl_dll/fx_sparks.cpp b/src/src/game/client/fx_sparks.cpp similarity index 98% rename from src/src/cl_dll/fx_sparks.cpp rename to src/src/game/client/fx_sparks.cpp index debc587..de9bb21 100644 --- a/src/src/cl_dll/fx_sparks.cpp +++ b/src/src/game/client/fx_sparks.cpp @@ -37,6 +37,8 @@ CLIENTEFFECT_REGISTER_END() PMaterialHandle g_Material_Spark = NULL; +static ConVar fx_drawmetalspark( "fx_drawmetalspark", "1", FCVAR_DEVELOPMENTONLY, "Draw metal spark effects." ); + //----------------------------------------------------------------------------- // Purpose: // Input : &pos - @@ -490,7 +492,7 @@ void FX_ElectricSpark( const Vector &pos, int nMagnitude, int nTrailLength, cons sOffs[1] = pos[1] + random->RandomFloat( -4.0f, 4.0f ); sOffs[2] = pos[2]; - sParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), pSimple->GetPMaterial( "particle/particle_noisesphere" ), sOffs ); + sParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Mat_DustPuff[1], sOffs ); if ( sParticle == NULL ) return; @@ -616,6 +618,10 @@ void FX_MetalScrape( Vector &position, Vector &normal ) void FX_MetalSpark( const Vector &position, const Vector &direction, const Vector &surfaceNormal, int iScale ) { VPROF_BUDGET( "FX_MetalSpark", VPROF_BUDGETGROUP_PARTICLE_RENDERING ); + + if ( !fx_drawmetalspark.GetBool() ) + return; + // // Emitted particles // @@ -1107,24 +1113,21 @@ void FX_Explosion( Vector& origin, Vector& normal, char materialType ) // Only create dirt chunks on concrete/world if ( materialType == 'C' || materialType == 'W' ) { - CSmartPtr fleckEmitter = CFleckParticles::Create( "FX_Explosion 10", offset ); + CSmartPtr fleckEmitter = CFleckParticles::Create( "FX_Explosion 10", offset, Vector(5,5,5) ); if ( !fleckEmitter ) return; - fleckEmitter->SetSortOrigin( offset ); - // Setup our collision information fleckEmitter->m_ParticleCollision.Setup( offset, &normal, EXPLOSION_FLECK_ANGULAR_SPRAY, EXPLOSION_FLECK_MIN_SPEED, EXPLOSION_FLECK_MAX_SPEED, EXPLOSION_FLECK_GRAVITY, EXPLOSION_FLECK_DAMPEN ); - PMaterialHandle hMaterialArray[2]; + PMaterialHandle *hMaterialArray; switch ( materialType ) { case 'C': case 'c': default: - hMaterialArray[0] = fleckEmitter->GetPMaterial( "effects/fleck_cement1" ); - hMaterialArray[1] = fleckEmitter->GetPMaterial( "effects/fleck_cement2" ); + hMaterialArray = g_Mat_Fleck_Cement; break; } @@ -1156,7 +1159,7 @@ void FX_Explosion( Vector& origin, Vector& normal, char materialType ) // Large sphere bursts CSmartPtr pSimpleEmitter = CSimpleEmitter::Create( "FX_Explosion 1" ); - PMaterialHandle hSphereMaterial = pSimpleEmitter->GetPMaterial( "particle/particle_noisesphere" );; + PMaterialHandle hSphereMaterial = g_Mat_DustPuff[1]; Vector vecBurstOrigin = offset + normal * 8.0; pSimpleEmitter->SetSortOrigin( vecBurstOrigin ); SimpleParticle *pSphereParticle = (SimpleParticle *) pSimpleEmitter->AddParticle( sizeof(SimpleParticle), hSphereMaterial, vecBurstOrigin ); @@ -1209,10 +1212,9 @@ void FX_Explosion( Vector& origin, Vector& normal, char materialType ) // Create a couple of big, floating smoke clouds CSmartPtr pSmokeEmitter = CSimpleEmitter::Create( "FX_Explosion 2" ); pSmokeEmitter->SetSortOrigin( offset ); - hSphereMaterial = pSmokeEmitter->GetPMaterial( "particle/particle_noisesphere" ); for ( i = 0; i < 2; i++ ) { - SimpleParticle *pParticle = (SimpleParticle *) pSmokeEmitter->AddParticle( sizeof(SimpleParticle), hSphereMaterial, offset ); + SimpleParticle *pParticle = (SimpleParticle *) pSmokeEmitter->AddParticle( sizeof(SimpleParticle), g_Mat_DustPuff[1], offset ); if ( pParticle == NULL ) break; @@ -1254,12 +1256,11 @@ void FX_ConcussiveExplosion( Vector &origin, Vector &normal ) CSmartPtr pSmokeEmitter = CSimpleEmitter::Create( "FX_ConcussiveExplosion 1" ); pSmokeEmitter->SetSortOrigin( offset ); - PMaterialHandle hSphereMaterial = pSmokeEmitter->GetPMaterial( "particle/particle_noisesphere" ); //Quick moving sprites for ( i = 0; i < 16; i++ ) { - SimpleParticle *pParticle = (SimpleParticle *) pSmokeEmitter->AddParticle( sizeof(SimpleParticle), hSphereMaterial, offset ); + SimpleParticle *pParticle = (SimpleParticle *) pSmokeEmitter->AddParticle( sizeof(SimpleParticle), g_Mat_DustPuff[1], offset ); if ( pParticle == NULL ) return; @@ -1288,7 +1289,7 @@ void FX_ConcussiveExplosion( Vector &origin, Vector &normal ) //Slow lingering sprites for ( i = 0; i < 2; i++ ) { - SimpleParticle *pParticle = (SimpleParticle *) pSmokeEmitter->AddParticle( sizeof(SimpleParticle), hSphereMaterial, offset ); + SimpleParticle *pParticle = (SimpleParticle *) pSmokeEmitter->AddParticle( sizeof(SimpleParticle), g_Mat_DustPuff[1], offset ); if ( pParticle == NULL ) return; diff --git a/src/src/cl_dll/fx_sparks.h b/src/src/game/client/fx_sparks.h similarity index 100% rename from src/src/cl_dll/fx_sparks.h rename to src/src/game/client/fx_sparks.h diff --git a/src/src/cl_dll/fx_staticline.cpp b/src/src/game/client/fx_staticline.cpp similarity index 97% rename from src/src/cl_dll/fx_staticline.cpp rename to src/src/game/client/fx_staticline.cpp index 1623af2..8250066 100644 --- a/src/src/cl_dll/fx_staticline.cpp +++ b/src/src/game/client/fx_staticline.cpp @@ -67,8 +67,10 @@ void CFXStaticLine::Draw( double frametime ) VectorNormalize( cross ); + CMatRenderContextPtr pRenderContext( materials ); + //Bind the material - IMesh* pMesh = materials->GetDynamicMesh( true, NULL, NULL, m_pMaterial ); + IMesh* pMesh = pRenderContext->GetDynamicMesh( true, NULL, NULL, m_pMaterial ); CMeshBuilder meshBuilder; meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 ); diff --git a/src/src/cl_dll/fx_staticline.h b/src/src/game/client/fx_staticline.h similarity index 97% rename from src/src/cl_dll/fx_staticline.h rename to src/src/game/client/fx_staticline.h index 4272b7b..b7beb04 100644 --- a/src/src/cl_dll/fx_staticline.h +++ b/src/src/game/client/fx_staticline.h @@ -15,7 +15,7 @@ #pragma once #endif -#include "vector.h" +#include "mathlib/vector.h" class IMaterial; diff --git a/src/src/cl_dll/fx_tracer.cpp b/src/src/game/client/fx_tracer.cpp similarity index 70% rename from src/src/cl_dll/fx_tracer.cpp rename to src/src/game/client/fx_tracer.cpp index bd9346a..71db29b 100644 --- a/src/src/cl_dll/fx_tracer.cpp +++ b/src/src/game/client/fx_tracer.cpp @@ -8,6 +8,7 @@ #include "c_te_effect_dispatch.h" #include "basecombatweapon_shared.h" #include "baseviewmodel_shared.h" +#include "particles_new.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -35,10 +36,14 @@ Vector GetTracerOrigin( const CEffectData &data ) return vecStart; C_BaseEntity *pEnt = data.GetEntity(); -#ifdef HL2MP - if ( pEnt && pEnt->IsDormant() ) - return vecStart; -#endif + + // This check should probably be for all multiplayer games, investigate later + // 10/09/2008: It should. + if ( gpGlobals->maxClients > 1 ) + { + if ( pEnt && pEnt->IsDormant() ) + return vecStart; + } C_BaseCombatWeapon *pWpn = dynamic_cast( pEnt ); if ( pWpn && pWpn->IsCarriedByLocalPlayer() ) @@ -107,6 +112,47 @@ void TracerCallback( const CEffectData &data ) DECLARE_CLIENT_EFFECT( "Tracer", TracerCallback ); +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void ParticleTracerCallback( const CEffectData &data ) +{ + C_BasePlayer *player = C_BasePlayer::GetLocalPlayer(); + if ( !player ) + return; + + // Grab the data + Vector vecStart = GetTracerOrigin( data ); + Vector vecEnd = data.m_vOrigin; + + // Adjust view model tracers + C_BaseEntity *pEntity = data.GetEntity(); + if ( data.entindex() && data.entindex() == player->index ) + { + QAngle vangles; + Vector vforward, vright, vup; + + engine->GetViewAngles( vangles ); + AngleVectors( vangles, &vforward, &vright, &vup ); + + VectorMA( data.m_vStart, 4, vright, vecStart ); + vecStart[2] -= 0.5f; + } + + // Create the particle effect + QAngle vecAngles; + Vector vecToEnd = vecEnd - vecStart; + VectorNormalize(vecToEnd); + VectorAngles( vecToEnd, vecAngles ); + DispatchParticleEffect( data.m_nHitBox, vecStart, vecEnd, vecAngles, pEntity ); + + if ( data.m_fFlags & TRACER_FLAG_WHIZ ) + { + FX_TracerSound( vecStart, vecEnd, TRACER_TYPE_DEFAULT ); + } +} + +DECLARE_CLIENT_EFFECT( "ParticleTracer", ParticleTracerCallback ); //----------------------------------------------------------------------------- // Purpose: diff --git a/src/src/cl_dll/fx_trail.cpp b/src/src/game/client/fx_trail.cpp similarity index 100% rename from src/src/cl_dll/fx_trail.cpp rename to src/src/game/client/fx_trail.cpp diff --git a/src/src/cl_dll/fx_trail.h b/src/src/game/client/fx_trail.h similarity index 100% rename from src/src/cl_dll/fx_trail.h rename to src/src/game/client/fx_trail.h diff --git a/src/src/cl_dll/fx_water.cpp b/src/src/game/client/fx_water.cpp similarity index 98% rename from src/src/cl_dll/fx_water.cpp rename to src/src/game/client/fx_water.cpp index 68aff98..9b9f4db 100644 --- a/src/src/cl_dll/fx_water.cpp +++ b/src/src/game/client/fx_water.cpp @@ -24,7 +24,6 @@ CLIENTEFFECT_REGISTER_BEGIN( PrecacheEffectSplash ) CLIENTEFFECT_MATERIAL( "effects/splash1" ) CLIENTEFFECT_MATERIAL( "effects/splash2" ) CLIENTEFFECT_MATERIAL( "effects/splash4" ) -CLIENTEFFECT_MATERIAL( "effects/splashwake1" ) CLIENTEFFECT_MATERIAL( "effects/slime1" ) CLIENTEFFECT_REGISTER_END() @@ -295,6 +294,8 @@ void FX_GunshotSlimeSplash( const Vector &origin, const Vector &normal, float sc VPROF_BUDGET( "FX_GunshotSlimeSplash", VPROF_BUDGETGROUP_PARTICLE_RENDERING ); +#if 0 + float colorRamp; float flScale = min( 1.0f, scale / 8.0f ); @@ -407,6 +408,25 @@ void FX_GunshotSlimeSplash( const Vector &origin, const Vector &normal, float sc pParticle->m_flRoll = random->RandomInt( 0, 360 ); pParticle->m_flRollDelta = random->RandomFloat( -4.0f, 4.0f ); } + +#else + + QAngle vecAngles; + VectorAngles( normal, vecAngles ); + if ( scale < 2.0f ) + { + DispatchParticleEffect( "slime_splash_01", origin, vecAngles ); + } + else if ( scale < 4.0f ) + { + DispatchParticleEffect( "slime_splash_02", origin, vecAngles ); + } + else + { + DispatchParticleEffect( "slime_splash_03", origin, vecAngles ); + } + +#endif //Play a sound CLocalPlayerFilter filter; diff --git a/src/src/cl_dll/fx_water.h b/src/src/game/client/fx_water.h similarity index 100% rename from src/src/cl_dll/fx_water.h rename to src/src/game/client/fx_water.h diff --git a/src/src/game/client/game_controls/basemodel_panel.cpp b/src/src/game/client/game_controls/basemodel_panel.cpp new file mode 100644 index 0000000..4e73042 --- /dev/null +++ b/src/src/game/client/game_controls/basemodel_panel.cpp @@ -0,0 +1,527 @@ +//====== Copyright © 1996-2008, Valve Corporation, All rights reserved. ======= +// +// Purpose: +// +//============================================================================= + +#include "cbase.h" +#include "basemodel_panel.h" +#include "activitylist.h" +#include "animation.h" +#include "vgui/iinput.h" +#include "matsys_controls/manipulator.h" + +using namespace vgui; +DECLARE_BUILD_FACTORY( CBaseModelPanel ); + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CBaseModelPanel::CBaseModelPanel( vgui::Panel *pParent, const char *pName ): BaseClass( pParent, pName ) +{ + m_bForcePos = false; + m_bMousePressed = false; + m_bAllowRotation = false; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CBaseModelPanel::~CBaseModelPanel() +{ +} + +//----------------------------------------------------------------------------- +// Purpose: Load in the model portion of the panel's resource file. +//----------------------------------------------------------------------------- +void CBaseModelPanel::ApplySettings( KeyValues *inResourceData ) +{ + BaseClass::ApplySettings( inResourceData ); + + // Grab and set the camera FOV. + float flFOV = GetCameraFOV(); + m_BMPResData.m_flFOV = inResourceData->GetInt( "fov", flFOV ); + SetCameraFOV( m_BMPResData.m_flFOV ); + + // Do we allow rotation on these panels. + m_bAllowRotation = ( inResourceData->GetInt( "allow_rot", 0 ) == 1 ); + + // Parse our resource file and apply all necessary updates to the MDL. + for ( KeyValues *pData = inResourceData->GetFirstSubKey() ; pData != NULL ; pData = pData->GetNextKey() ) + { + if ( !Q_stricmp( pData->GetName(), "model" ) ) + { + ParseModelResInfo( pData ); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CBaseModelPanel::ParseModelResInfo( KeyValues *inResourceData ) +{ + m_bForcePos = ( inResourceData->GetInt( "force_pos", 0 ) == 1 ); + m_BMPResData.m_pszModelName = ReadAndAllocStringValue( inResourceData, "modelname" ); + m_BMPResData.m_pszModelName_HWM = ReadAndAllocStringValue( inResourceData, "modelname_hwm" ); + m_BMPResData.m_pszVCD = ReadAndAllocStringValue( inResourceData, "vcd" ); + m_BMPResData.m_angModelPoseRot.Init( inResourceData->GetFloat( "angles_x", 0.0f ), inResourceData->GetFloat( "angles_y", 0.0f ), inResourceData->GetFloat( "angles_z", 0.0f ) ); + m_BMPResData.m_vecOriginOffset.Init( inResourceData->GetFloat( "origin_x", 110.0 ), inResourceData->GetFloat( "origin_y", 5.0 ), inResourceData->GetFloat( "origin_z", 5.0 ) ); + m_BMPResData.m_vecFramedOriginOffset.Init( inResourceData->GetFloat( "frame_origin_x", 110.0 ), inResourceData->GetFloat( "frame_origin_y", 5.0 ), inResourceData->GetFloat( "frame_origin_z", 5.0 ) ); + m_BMPResData.m_vecViewportOffset.Init(); + m_BMPResData.m_nSkin = inResourceData->GetInt( "skin", -1 ); + m_BMPResData.m_bUseSpotlight = ( inResourceData->GetInt( "spotlight", 0 ) == 1 ); + + m_angPlayer = m_BMPResData.m_angModelPoseRot; + m_vecPlayerPos = m_BMPResData.m_vecOriginOffset; + + for ( KeyValues *pData = inResourceData->GetFirstSubKey(); pData != NULL; pData = pData->GetNextKey() ) + { + if ( !Q_stricmp( pData->GetName(), "animation" ) ) + { + ParseModelAnimInfo( pData ); + } + else if ( !Q_stricmp( pData->GetName(), "attached_model" ) ) + { + ParseModelAttachInfo( pData ); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CBaseModelPanel::ParseModelAnimInfo( KeyValues *inResourceData ) +{ + if ( !inResourceData ) + return; + + int iAnim = m_BMPResData.m_aAnimations.AddToTail(); + if ( iAnim == m_BMPResData.m_aAnimations.InvalidIndex() ) + return; + + m_BMPResData.m_aAnimations[iAnim].m_pszName = ReadAndAllocStringValue( inResourceData, "name" ); + m_BMPResData.m_aAnimations[iAnim].m_pszSequence = ReadAndAllocStringValue( inResourceData, "sequence" ); + m_BMPResData.m_aAnimations[iAnim].m_pszActivity = ReadAndAllocStringValue( inResourceData, "activity" ); + m_BMPResData.m_aAnimations[iAnim].m_bDefault = ( inResourceData->GetInt( "default", 0 ) == 1 ); + + for ( KeyValues *pAnimData = inResourceData->GetFirstSubKey(); pAnimData != NULL; pAnimData = pAnimData->GetNextKey() ) + { + if ( !Q_stricmp( pAnimData->GetName(), "pose_parameters" ) ) + { + m_BMPResData.m_aAnimations[iAnim].m_pPoseParameters = pAnimData->MakeCopy(); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CBaseModelPanel::ParseModelAttachInfo( KeyValues *inResourceData ) +{ + if ( !inResourceData ) + return; + + int iAttach = m_BMPResData.m_aAttachModels.AddToTail(); + if ( iAttach == m_BMPResData.m_aAttachModels.InvalidIndex() ) + return; + + m_BMPResData.m_aAttachModels[iAttach].m_pszModelName = ReadAndAllocStringValue( inResourceData, "modelname" ); + m_BMPResData.m_aAttachModels[iAttach].m_nSkin = inResourceData->GetInt( "skin", -1 ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CBaseModelPanel::SetupModelDefaults( void ) +{ + SetupModelAnimDefaults(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CBaseModelPanel::SetupModelAnimDefaults( void ) +{ + // Verify that we have animations for this model. + int nAnimCount = m_BMPResData.m_aAnimations.Count(); + if ( nAnimCount == 0 ) + return; + + // Find the default animation if one exists. + int iIndex = FindDefaultAnim(); + if ( iIndex == -1 ) + return; + + SetModelAnim( iIndex ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +int CBaseModelPanel::FindDefaultAnim( void ) +{ + int iIndex = -1; + + int nAnimCount = m_BMPResData.m_aAnimations.Count(); + for ( int iAnim = 0; iAnim < nAnimCount; ++iAnim ) + { + if ( m_BMPResData.m_aAnimations[iAnim].m_bDefault ) + return iAnim; + } + + return iIndex; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +int CBaseModelPanel::FindAnimByName( const char *pszName ) +{ + int iIndex = -1; + + int nAnimCount = m_BMPResData.m_aAnimations.Count(); + for ( int iAnim = 0; iAnim < nAnimCount; ++iAnim ) + { + if ( !Q_stricmp( m_BMPResData.m_aAnimations[iAnim].m_pszName, pszName ) ) + return iAnim; + } + + return iIndex; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +int CBaseModelPanel::FindSequenceFromActivity( CStudioHdr *pStudioHdr, const char *pszActivity ) +{ + if ( !pStudioHdr ) + return -1; + + for ( int iSeq = 0; iSeq < pStudioHdr->GetNumSeq(); ++iSeq ) + { + mstudioseqdesc_t &seqDesc = pStudioHdr->pSeqdesc( iSeq ); + if ( !stricmp( seqDesc.pszActivityName(), pszActivity ) ) + { + return iSeq; + } + } + + return -1; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CBaseModelPanel::SetModelAnim( int iAnim ) +{ + int nAnimCount = m_BMPResData.m_aAnimations.Count(); + if ( nAnimCount == 0 || !m_BMPResData.m_aAnimations.IsValidIndex( iAnim ) ) + return; + + MDLCACHE_CRITICAL_SECTION(); + + // Get the studio header of the root model. + studiohdr_t *pStudioHdr = m_RootMDL.m_MDL.GetStudioHdr(); + if ( !pStudioHdr ) + return; + + CStudioHdr studioHdr( pStudioHdr, g_pMDLCache ); + + // Do we have an activity or a sequence? + int iSequence = ACT_INVALID; + if ( m_BMPResData.m_aAnimations[iAnim].m_pszActivity && m_BMPResData.m_aAnimations[iAnim].m_pszActivity[0] ) + { + iSequence = FindSequenceFromActivity( &studioHdr, m_BMPResData.m_aAnimations[iAnim].m_pszActivity ); + } + else if ( m_BMPResData.m_aAnimations[iAnim].m_pszSequence && m_BMPResData.m_aAnimations[iAnim].m_pszSequence[0] ) + { + iSequence = LookupSequence( &studioHdr, m_BMPResData.m_aAnimations[iAnim].m_pszSequence ); + } + + if ( iSequence != ACT_INVALID ) + { + SetSequence( iSequence ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CBaseModelPanel::SetMDL( MDLHandle_t handle ) +{ + MDLCACHE_CRITICAL_SECTION(); + studiohdr_t *pHdr = g_pMDLCache->GetStudioHdr( handle ); + + if ( pHdr ) + { + // SetMDL will cause the base CMdl code to set our localtoglobal indices if they aren't set. + // We set them up here so that they're left alone by that code. + CStudioHdr studioHdr( pHdr, g_pMDLCache ); + if (studioHdr.numflexcontrollers() > 0 && studioHdr.pFlexcontroller( LocalFlexController_t(0) )->localToGlobal == -1) + { + for (LocalFlexController_t i = LocalFlexController_t(0); i < studioHdr.numflexcontrollers(); i++) + { + int j = C_BaseFlex::AddGlobalFlexController( studioHdr.pFlexcontroller( i )->pszName() ); + studioHdr.pFlexcontroller( i )->localToGlobal = j; + } + } + } + + BaseClass::SetMDL( handle ); + + SetupModelDefaults(); + + // Need to invalidate the layout so the panel will adjust is LookAt for the new model. + InvalidateLayout(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CBaseModelPanel::SetMDL( const char *pMDLName ) +{ + BaseClass::SetMDL( pMDLName ); + + // Need to invalidate the layout so the panel will adjust is LookAt for the new model. +// InvalidateLayout(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CBaseModelPanel::PerformLayout() +{ + BaseClass::PerformLayout(); + + if ( m_bForcePos ) + { + ResetCameraPivot(); + SetCameraOffset( Vector( 0.0f, 0.0f, 0.0f ) ); + SetCameraPositionAndAngles( vec3_origin, vec3_angle ); + SetModelAnglesAndPosition( m_angPlayer, m_vecPlayerPos ); + } + + // Center and fill the frame with the model? + if ( m_bStartFramed ) + { + Vector vecBoundsMin, vecBoundsMax; + if ( GetBoundingBox( vecBoundsMin, vecBoundsMax ) ) + { + LookAtBounds( vecBoundsMin, vecBoundsMax ); + } + } +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CBaseModelPanel::OnKeyCodePressed ( vgui::KeyCode code ) +{ + return; +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CBaseModelPanel::OnKeyCodeReleased( vgui::KeyCode code ) +{ + return; +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CBaseModelPanel::OnMousePressed ( vgui::MouseCode code ) +{ + if ( !m_bAllowRotation ) + return; + + RequestFocus(); + + EnableMouseCapture( true, code ); + + // Warp the mouse to the center of the screen + int width, height; + GetSize( width, height ); + int x = width / 2; + int y = height / 2; + + int xpos = x; + int ypos = y; + LocalToScreen( xpos, ypos ); + input()->SetCursorPos( xpos, ypos ); + + m_nManipStartX = xpos; + m_nManipStartY = ypos; + + m_bMousePressed = true; +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CBaseModelPanel::OnMouseReleased( vgui::MouseCode code ) +{ + if ( !m_bAllowRotation ) + return; + + EnableMouseCapture( false ); + m_bMousePressed = false; +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CBaseModelPanel::OnCursorMoved( int x, int y ) +{ + if ( !m_bAllowRotation ) + return; + + if ( m_bMousePressed ) + { + WarpMouse( x, y ); + + int xpos, ypos; + input()->GetCursorPos( xpos, ypos ); + + // Only want the x delta. + float flDelta = xpos - m_nManipStartX; + + // Apply the delta and rotate the player. + m_angPlayer.y += flDelta; + if ( m_angPlayer.y > 360.0f ) + { + m_angPlayer.y = m_angPlayer.y - 360.0f; + } + else if ( m_angPlayer.y < -360.0f ) + { + m_angPlayer.y = m_angPlayer.y + 360.0f; + } + + SetModelAnglesAndPosition( m_angPlayer, m_vecPlayerPos ); + } +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CBaseModelPanel::OnMouseWheeled( int delta ) +{ + return; +} + +//----------------------------------------------------------------------------- +// Purpose: Set the camera to a distance that allows the object to fill the model panel. +//----------------------------------------------------------------------------- +void CBaseModelPanel::LookAtBounds( const Vector &vecBoundsMin, const Vector &vecBoundsMax ) +{ + // Get the model space render bounds. + Vector vecMin = vecBoundsMin; + Vector vecMax = vecBoundsMax; + Vector vecCenter = ( vecMax + vecMin ) * 0.5f; + vecMin -= vecCenter; + vecMax -= vecCenter; + + // Get the bounds points and transform them by the desired model panel rotation. + Vector aBoundsPoints[8]; + aBoundsPoints[0].Init( vecMax.x, vecMax.y, vecMax.z ); + aBoundsPoints[1].Init( vecMin.x, vecMax.y, vecMax.z ); + aBoundsPoints[2].Init( vecMax.x, vecMin.y, vecMax.z ); + aBoundsPoints[3].Init( vecMin.x, vecMin.y, vecMax.z ); + aBoundsPoints[4].Init( vecMax.x, vecMax.y, vecMin.z ); + aBoundsPoints[5].Init( vecMin.x, vecMax.y, vecMin.z ); + aBoundsPoints[6].Init( vecMax.x, vecMin.y, vecMin.z ); + aBoundsPoints[7].Init( vecMin.x, vecMin.y, vecMin.z ); + + // Translated center point (offset from camera center). + Vector vecTranslateCenter = -vecCenter; + + // Build the rotation matrix. + matrix3x4_t matRotation; + AngleMatrix( m_BMPResData.m_angModelPoseRot, matRotation ); + + Vector aXFormPoints[8]; + for ( int iPoint = 0; iPoint < 8; ++iPoint ) + { + VectorTransform( aBoundsPoints[iPoint], matRotation, aXFormPoints[iPoint] ); + } + + Vector vecXFormCenter; + VectorTransform( -vecTranslateCenter, matRotation, vecXFormCenter ); + + int w, h; + GetSize( w, h ); + float flW = (float)w; + float flH = (float)h; + + float flFOVx = DEG2RAD( m_BMPResData.m_flFOV * 0.5f ); + float flFOVy = CalcFovY( ( m_BMPResData.m_flFOV * 0.5f ), flW/flH ); + flFOVy = DEG2RAD( flFOVy ); + + float flTanFOVx = tan( flFOVx ); + float flTanFOVy = tan( flFOVy ); + + // Find the max value of x, y, or z + Vector2D dist[8]; + float flDist = 0.0f; + for ( int iPoint = 0; iPoint < 8; ++iPoint ) + { + float flDistY = fabs( aXFormPoints[iPoint].y / flTanFOVx ) - aXFormPoints[iPoint].x; + float flDistZ = fabs( aXFormPoints[iPoint].z / flTanFOVy ) - aXFormPoints[iPoint].x; + dist[iPoint].x = flDistY; + dist[iPoint].y = flDistZ; + float flTestDist = max( flDistZ, flDistY ); + flDist = max( flDist, flTestDist ); + } + + // Screen space points. + Vector2D aScreenPoints[8]; + Vector aCameraPoints[8]; + for ( int iPoint = 0; iPoint < 8; ++iPoint ) + { + aCameraPoints[iPoint] = aXFormPoints[iPoint]; + aCameraPoints[iPoint].x += flDist; + + aScreenPoints[iPoint].x = aCameraPoints[iPoint].y / ( flTanFOVx * aCameraPoints[iPoint].x ); + aScreenPoints[iPoint].y = aCameraPoints[iPoint].z / ( flTanFOVy * aCameraPoints[iPoint].x ); + + aScreenPoints[iPoint].x = ( aScreenPoints[iPoint].x * 0.5f + 0.5f ) * flW; + aScreenPoints[iPoint].y = ( aScreenPoints[iPoint].y * 0.5f + 0.5f ) * flH; + } + + // Find the min/max and center of the 2D bounding box of the object. + Vector2D vecScreenMin( 99999.0f, 99999.0f ), vecScreenMax( -99999.0f, -99999.0f ); + for ( int iPoint = 0; iPoint < 8; ++iPoint ) + { + vecScreenMin.x = min( vecScreenMin.x, aScreenPoints[iPoint].x ); + vecScreenMin.y = min( vecScreenMin.y, aScreenPoints[iPoint].y ); + vecScreenMax.x = max( vecScreenMax.x, aScreenPoints[iPoint].x ); + vecScreenMax.y = max( vecScreenMax.y, aScreenPoints[iPoint].y ); + } + + // Offset the model to the be the correct distance away from the camera. + Vector vecModelPos; + vecModelPos.x = flDist - vecXFormCenter.x; + vecModelPos.y = -vecXFormCenter.y; + vecModelPos.z = -vecXFormCenter.z; + SetModelAnglesAndPosition( m_BMPResData.m_angModelPoseRot, vecModelPos ); + + // Back project to figure out the camera offset to center the model. + Vector2D vecPanelCenter( ( flW * 0.5f ), ( flH * 0.5f ) ); + Vector2D vecScreenCenter = ( vecScreenMax + vecScreenMin ) * 0.5f; + + Vector2D vecPanelCenterCamera, vecScreenCenterCamera; + vecPanelCenterCamera.x = ( ( vecPanelCenter.x / flW ) * 2.0f ) - 0.5f; + vecPanelCenterCamera.y = ( ( vecPanelCenter.y / flH ) * 2.0f ) - 0.5f; + vecPanelCenterCamera.x *= ( flTanFOVx * flDist ); + vecPanelCenterCamera.y *= ( flTanFOVy * flDist ); + vecScreenCenterCamera.x = ( ( vecScreenCenter.x / flW ) * 2.0f ) - 0.5f; + vecScreenCenterCamera.y = ( ( vecScreenCenter.y / flH ) * 2.0f ) - 0.5f; + vecScreenCenterCamera.x *= ( flTanFOVx * flDist ); + vecScreenCenterCamera.y *= ( flTanFOVy * flDist ); + + Vector2D vecCameraOffset( 0.0f, 0.0f ); + vecCameraOffset.x = vecPanelCenterCamera.x - vecScreenCenterCamera.x; + vecCameraOffset.y = vecPanelCenterCamera.y - vecScreenCenterCamera.y; + + // Clear the camera pivot and set position matrix. + ResetCameraPivot(); + SetCameraOffset( Vector( 0.0f, -vecCameraOffset.x, -vecCameraOffset.y ) ); + UpdateCameraTransform(); +} + diff --git a/src/src/game/client/game_controls/basemodel_panel.h b/src/src/game/client/game_controls/basemodel_panel.h new file mode 100644 index 0000000..87d9172 --- /dev/null +++ b/src/src/game/client/game_controls/basemodel_panel.h @@ -0,0 +1,209 @@ +//====== Copyright © 1996-2008, Valve Corporation, All rights reserved. ======= +// +// Purpose: +// +//============================================================================= +#ifndef BASEMODEL_PANEL_H +#define BASEMODEL_PANEL_H +#ifdef _WIN32 +#pragma once +#endif + +#include "matsys_controls/mdlpanel.h" + +//----------------------------------------------------------------------------- +// Resource file data used in posing the model inside of the model panel. +//----------------------------------------------------------------------------- +struct BMPResAnimData_t +{ + const char *m_pszName; + const char *m_pszSequence; + const char *m_pszActivity; + KeyValues *m_pPoseParameters; + bool m_bDefault; + + BMPResAnimData_t() + { + m_pszName = NULL; + m_pszSequence = NULL; + m_pszActivity = NULL; + m_pPoseParameters = NULL; + m_bDefault = false; + } + + ~BMPResAnimData_t() + { + if ( m_pszName && m_pszName[0] ) + { + delete [] m_pszName; + m_pszName = NULL; + } + + if ( m_pszSequence && m_pszSequence[0] ) + { + delete [] m_pszSequence; + m_pszSequence = NULL; + } + + if ( m_pszActivity && m_pszActivity[0] ) + { + delete [] m_pszActivity; + m_pszActivity = NULL; + } + + if ( m_pPoseParameters ) + { + m_pPoseParameters->deleteThis(); + m_pPoseParameters = NULL; + } + } +}; + +struct BMPResAttachData_t +{ + const char *m_pszModelName; + int m_nSkin; + + BMPResAttachData_t() + { + m_pszModelName = NULL; + m_nSkin = 0; + } + + ~BMPResAttachData_t() + { + if ( m_pszModelName && m_pszModelName[0] ) + { + delete [] m_pszModelName; + m_pszModelName = NULL; + } + } +}; + +struct BMPResData_t +{ + float m_flFOV; + + const char *m_pszModelName; + const char *m_pszModelName_HWM; + const char *m_pszVCD; + QAngle m_angModelPoseRot; + Vector m_vecOriginOffset; + Vector m_vecFramedOriginOffset; + Vector2D m_vecViewportOffset; + int m_nSkin; + bool m_bUseSpotlight; + + CUtlVector m_aAnimations; + CUtlVector m_aAttachModels; + + BMPResData_t() + { + m_flFOV = 0.0f; + + m_pszModelName = NULL; + m_pszModelName_HWM = NULL; + m_pszVCD = NULL; + m_angModelPoseRot.Init(); + m_vecOriginOffset.Init(); + m_vecFramedOriginOffset.Init(); + m_vecViewportOffset.Init(); + m_nSkin = 0; + m_bUseSpotlight = false; + } + + ~BMPResData_t() + { + if ( m_pszModelName && m_pszModelName[0] ) + { + delete [] m_pszModelName; + m_pszModelName = NULL; + } + + if ( m_pszModelName_HWM && m_pszModelName_HWM[0] ) + { + delete [] m_pszModelName_HWM; + m_pszModelName_HWM = NULL; + } + + if ( m_pszVCD && m_pszVCD[0] ) + { + delete [] m_pszVCD; + m_pszVCD = NULL; + } + + m_aAnimations.Purge(); + m_aAttachModels.Purge(); + } +}; + +//----------------------------------------------------------------------------- +// Base Model Panel +// +// ...vgui::Panel |--> vgui +// +->vgui::EditablePanel | +// +->PotterWheelPanel |--> matsys_controls +// +->MDLPanel | +// +->BaseModelPanel |--> game_controls, client.dll +// +//----------------------------------------------------------------------------- +class CBaseModelPanel : public CMDLPanel +{ + DECLARE_CLASS_SIMPLE( CBaseModelPanel, CMDLPanel ); + +public: + + // Constructor, Destructor. + CBaseModelPanel( vgui::Panel *pParent, const char *pName ); + virtual ~CBaseModelPanel(); + + // Overridden mdlpanel.h + virtual void SetMDL( MDLHandle_t handle ); + virtual void SetMDL( const char *pMDLName ); + + // Overridden methods of vgui::Panel + virtual void ApplySettings( KeyValues *inResourceData ); + virtual void PerformLayout(); + + // Animaiton. + int FindDefaultAnim( void ); + int FindAnimByName( const char *pszName ); + void SetModelAnim( int iAnim ); + + // Manipulation. + virtual void OnKeyCodePressed ( vgui::KeyCode code ); + virtual void OnKeyCodeReleased( vgui::KeyCode code ); + virtual void OnMousePressed ( vgui::MouseCode code ); + virtual void OnMouseReleased( vgui::MouseCode code ); + virtual void OnCursorMoved( int x, int y ); + virtual void OnMouseWheeled( int delta ); + +private: + + // Resource file data. + void ParseModelResInfo( KeyValues *inResourceData ); + void ParseModelAnimInfo( KeyValues *inResourceData ); + void ParseModelAttachInfo( KeyValues *inResourceData ); + + void SetupModelDefaults( void ); + void SetupModelAnimDefaults( void ); + + void LookAtBounds( const Vector &vecBoundsMin, const Vector &vecBoundsMax ); + + int FindSequenceFromActivity( CStudioHdr *pStudioHdr, const char *pszActivity ); + +private: + + BMPResData_t m_BMPResData; // Base model panel data set in the .res file. + QAngle m_angPlayer; + Vector m_vecPlayerPos; + bool m_bForcePos; + bool m_bMousePressed; + bool m_bAllowRotation; + + // VGUI script accessible variables. + CPanelAnimationVar( bool, m_bStartFramed, "start_framed", "0" ); + CPanelAnimationVar( bool, m_bDisableManipulation, "disable_manipulation", "0" ); +}; + +#endif // BASEMODEL_PANEL_H \ No newline at end of file diff --git a/src/src/game/client/game_controls/basemodelpanel.cpp b/src/src/game/client/game_controls/basemodelpanel.cpp new file mode 100644 index 0000000..3d3e22a --- /dev/null +++ b/src/src/game/client/game_controls/basemodelpanel.cpp @@ -0,0 +1,880 @@ +//========= Copyright © 1996-2006, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + + +#include "cbase.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "materialsystem/imaterialsystem.h" +#include "engine/ivmodelinfo.h" + +#include "c_sceneentity.h" +#include "gamestringpool.h" +#include "model_types.h" +#include "view_shared.h" +#include "view.h" +#include "ivrenderview.h" +#include "iefx.h" +#include "dlight.h" +#include "activitylist.h" + +#include "basemodelpanel.h" + +bool UseHWMorphModels(); + + +using namespace vgui; + +DECLARE_BUILD_FACTORY( CModelPanel ); + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CModelPanel::CModelPanel( vgui::Panel *pParent, const char *pName ) : vgui::EditablePanel( pParent, pName ) +{ + m_nFOV = 54; + m_hModel = NULL; + m_pModelInfo = NULL; + m_hScene = NULL; + m_iDefaultAnimation = 0; + m_bPanelDirty = true; + m_bStartFramed = false; + m_bAllowOffscreen = false; + + ListenForGameEvent( "game_newmap" ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CModelPanel::~CModelPanel() +{ + if ( m_pModelInfo ) + { + delete m_pModelInfo; + m_pModelInfo = NULL; + } + + DeleteVCDData(); + DeleteModelData(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CModelPanel::ApplySettings( KeyValues *inResourceData ) +{ + BaseClass::ApplySettings( inResourceData ); + + m_nFOV = inResourceData->GetInt( "fov", 54 ); + m_bStartFramed = inResourceData->GetInt( "start_framed", false ); + m_bAllowOffscreen = inResourceData->GetInt( "allow_offscreen", false ); + + // do we have a valid "model" section in the .res file? + for ( KeyValues *pData = inResourceData->GetFirstSubKey() ; pData != NULL ; pData = pData->GetNextKey() ) + { + if ( !Q_stricmp( pData->GetName(), "model" ) ) + { + ParseModelInfo( pData ); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CModelPanel::ParseModelInfo( KeyValues *inResourceData ) +{ + // delete any current info + if ( m_pModelInfo ) + { + delete m_pModelInfo; + m_pModelInfo = NULL; + } + + m_pModelInfo = new CModelPanelModelInfo; + + if ( !m_pModelInfo ) + return; + + m_pModelInfo->m_pszModelName = ReadAndAllocStringValue( inResourceData, "modelname" ); + m_pModelInfo->m_pszModelName_HWM = ReadAndAllocStringValue( inResourceData, "modelname_hwm" ); + m_pModelInfo->m_nSkin = inResourceData->GetInt( "skin", -1 ); + m_pModelInfo->m_vecAbsAngles.Init( inResourceData->GetFloat( "angles_x", 0.0 ), inResourceData->GetFloat( "angles_y", 0.0 ), inResourceData->GetFloat( "angles_z", 0.0 ) ); + m_pModelInfo->m_vecOriginOffset.Init( inResourceData->GetFloat( "origin_x", 110.0 ), inResourceData->GetFloat( "origin_y", 5.0 ), inResourceData->GetFloat( "origin_z", 5.0 ) ); + m_pModelInfo->m_vecFramedOriginOffset.Init( inResourceData->GetFloat( "frame_origin_x", 110.0 ), inResourceData->GetFloat( "frame_origin_y", 5.0 ), inResourceData->GetFloat( "frame_origin_z", 5.0 ) ); + m_pModelInfo->m_pszVCD = ReadAndAllocStringValue( inResourceData, "vcd" ); + m_pModelInfo->m_bUseSpotlight = ( inResourceData->GetInt( "spotlight", 0 ) == 1 ); + m_pModelInfo->m_vecViewportOffset.Init(); + + for ( KeyValues *pData = inResourceData->GetFirstSubKey(); pData != NULL; pData = pData->GetNextKey() ) + { + if ( !Q_stricmp( pData->GetName(), "animation" ) ) + { + OnAddAnimation( pData ); + } + else if ( !Q_stricmp( pData->GetName(), "attached_model" ) ) + { + CModelPanelAttachedModelInfo *pAttachedModelInfo = new CModelPanelAttachedModelInfo; + + if ( pAttachedModelInfo ) + { + pAttachedModelInfo->m_pszModelName = ReadAndAllocStringValue( pData, "modelname" ); + pAttachedModelInfo->m_nSkin = pData->GetInt( "skin", -1 ); + + m_pModelInfo->m_AttachedModelsInfo.AddToTail( pAttachedModelInfo ); + } + } + } + + m_bPanelDirty = true; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CModelPanel::OnAddAnimation( KeyValues *pData ) +{ + if ( !pData ) + return; + + CModelPanelModelAnimation *pAnimation = new CModelPanelModelAnimation; + + if ( pAnimation ) + { + pAnimation->m_pszName = ReadAndAllocStringValue( pData, "name" ); + pAnimation->m_pszSequence = ReadAndAllocStringValue( pData, "sequence" ); + pAnimation->m_pszActivity = ReadAndAllocStringValue( pData, "activity" ); + pAnimation->m_bDefault = ( pData->GetInt( "default", 0 ) == 1 ); + + for ( KeyValues *pAnimData = pData->GetFirstSubKey(); pAnimData != NULL; pAnimData = pAnimData->GetNextKey() ) + { + if ( !Q_stricmp( pAnimData->GetName(), "pose_parameters" ) ) + { + pAnimation->m_pPoseParameters = pAnimData->MakeCopy(); + } + } + + m_pModelInfo->m_Animations.AddToTail( pAnimation ); + if ( pAnimation->m_bDefault ) + { + m_iDefaultAnimation = m_pModelInfo->m_Animations.Find( pAnimation ); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CModelPanel::FireGameEvent( IGameEvent * event ) +{ + const char *type = event->GetName(); + + if ( Q_strcmp( type, "game_newmap" ) == 0 ) + { + // force the models to re-setup themselves + m_bPanelDirty = true; + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CModelPanel::SetDefaultAnimation( const char *pszName ) +{ + if ( m_pModelInfo ) + { + for ( int i = 0; i < m_pModelInfo->m_Animations.Count(); i++ ) + { + if ( m_pModelInfo->m_Animations[i] && m_pModelInfo->m_Animations[i]->m_pszName ) + { + if ( !Q_stricmp( m_pModelInfo->m_Animations[i]->m_pszName, pszName ) ) + { + m_iDefaultAnimation = i; + return; + } + } + } + } + + Assert( 0 ); +} + +//----------------------------------------------------------------------------- +// Purpose: Replaces the current model with a new one, without changing the camera settings +//----------------------------------------------------------------------------- +void CModelPanel::SwapModel( const char *pszName, const char *pszAttached ) +{ + if ( !m_pModelInfo || !pszName || !pszName[0] ) + return; + + int len = Q_strlen( pszName ) + 1; + char *pAlloced = new char[ len ]; + Assert( pAlloced ); + Q_strncpy( pAlloced, pszName, len ); + m_pModelInfo->m_pszModelName = pAlloced; + + ClearAttachedModelInfos(); + + if ( pszAttached ) + { + CModelPanelAttachedModelInfo *pAttachedModelInfo = new CModelPanelAttachedModelInfo; + if ( pAttachedModelInfo ) + { + len = Q_strlen( pszAttached ) + 1; + pAlloced = new char[ len ]; + Assert( pAlloced ); + Q_strncpy( pAlloced, pszAttached, len ); + pAttachedModelInfo->m_pszModelName = pAlloced; + pAttachedModelInfo->m_nSkin = 0; + + m_pModelInfo->m_AttachedModelsInfo.AddToTail( pAttachedModelInfo ); + } + } + + m_bPanelDirty = true; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CModelPanel::DeleteVCDData( void ) +{ + if ( m_hScene.Get() ) + { + m_hScene->StopClientOnlyScene(); + + m_hScene->Remove(); + m_hScene = NULL; + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CModelPanel::SetupVCD( void ) +{ + if ( !m_pModelInfo ) + return; + + DeleteVCDData(); + + C_SceneEntity *pEnt = new class C_SceneEntity; + + if ( !pEnt ) + return; + + if ( pEnt->InitializeAsClientEntity( "", RENDER_GROUP_OTHER ) == false ) + { + // we failed to initialize this entity so just return gracefully + pEnt->Remove(); + return; + } + + // setup the handle + m_hScene = pEnt; + + // setup the scene + pEnt->SetupClientOnlyScene( m_pModelInfo->m_pszVCD, m_hModel, true ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CModelPanel::ClearAttachedModelInfos( void ) +{ + if ( m_pModelInfo ) + { + m_pModelInfo->m_AttachedModelsInfo.PurgeAndDeleteElements(); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CModelPanel::DeleteModelData( void ) +{ + if ( m_hModel.Get() ) + { + m_hModel->Remove(); + m_hModel = NULL; + m_flFrameDistance = 0; + } + + for ( int i = 0 ; i < m_AttachedModels.Count() ; i++ ) + { + if ( m_AttachedModels[i].Get() ) + { + m_AttachedModels[i]->Remove(); + } + m_AttachedModels.Remove( i ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +const char *CModelPanel::GetModelName( void ) +{ + if ( !m_pModelInfo ) + return NULL; + + // check to see if we want to use a HWM model + if ( UseHWMorphModels() ) + { + // do we have a valid HWM model filename + if ( m_pModelInfo->m_pszModelName_HWM && ( Q_strlen( m_pModelInfo->m_pszModelName_HWM ) > 0 ) ) + { + // does the file exist + model_t *pModel = (model_t *)engine->LoadModel( m_pModelInfo->m_pszModelName_HWM ); + if ( pModel ) + { + return m_pModelInfo->m_pszModelName_HWM; + } + } + } + + return m_pModelInfo->m_pszModelName; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CModelPanel::SetupModel( void ) +{ + if ( !m_pModelInfo ) + return; + + MDLCACHE_CRITICAL_SECTION(); + + // remove any current models we're using + DeleteModelData(); + + const char *pszModelName = GetModelName(); + if ( !pszModelName || !pszModelName[0] ) + return; + + // create the new model + CModelPanelModel *pEnt = new CModelPanelModel; + + if ( !pEnt ) + return; + + if ( pEnt->InitializeAsClientEntity( pszModelName, RENDER_GROUP_OPAQUE_ENTITY ) == false ) + { + // we failed to initialize this entity so just return gracefully + pEnt->Remove(); + return; + } + + // setup the handle + m_hModel = pEnt; + + pEnt->DontRecordInTools(); + pEnt->AddEffects( EF_NODRAW ); // don't let the renderer draw the model normally + + if ( m_pModelInfo->m_nSkin >= 0 ) + { + pEnt->m_nSkin = m_pModelInfo->m_nSkin; + } + + // do we have any animation information? + if ( m_pModelInfo->m_Animations.Count() > 0 && m_pModelInfo->m_Animations.IsValidIndex( m_iDefaultAnimation ) ) + { + CModelPanelModelAnimation *pAnim = m_pModelInfo->m_Animations[ m_iDefaultAnimation ]; + int sequence = ACT_INVALID; + if ( pAnim->m_pszActivity && pAnim->m_pszActivity[0] ) + { + Activity activity = (Activity)ActivityList_IndexForName( pAnim->m_pszActivity ); + sequence = pEnt->SelectWeightedSequence( activity ); + } + else if ( pAnim->m_pszSequence && pAnim->m_pszSequence[0] ) + { + sequence = pEnt->LookupSequence( pAnim->m_pszSequence ); + } + if ( sequence != ACT_INVALID ) + { + pEnt->ResetSequence( sequence ); + pEnt->SetCycle( 0 ); + + if ( pAnim->m_pPoseParameters ) + { + for ( KeyValues *pData = pAnim->m_pPoseParameters->GetFirstSubKey(); pData != NULL; pData = pData->GetNextKey() ) + { + const char *pName = pData->GetName(); + float flValue = pData->GetFloat(); + + pEnt->SetPoseParameter( pName, flValue ); + } + } + + pEnt->m_flAnimTime = gpGlobals->curtime; + } + } + + // setup any attached models + for ( int i = 0 ; i < m_pModelInfo->m_AttachedModelsInfo.Count() ; i++ ) + { + CModelPanelAttachedModelInfo *pInfo = m_pModelInfo->m_AttachedModelsInfo[i]; + C_BaseAnimating *pTemp = new C_BaseAnimating; + + if ( pTemp ) + { + if ( pTemp->InitializeAsClientEntity( pInfo->m_pszModelName, RENDER_GROUP_OPAQUE_ENTITY ) == false ) + { + // we failed to initialize this model so just skip it + pTemp->Remove(); + continue; + } + + pTemp->DontRecordInTools(); + pTemp->AddEffects( EF_NODRAW ); // don't let the renderer draw the model normally + pTemp->FollowEntity( m_hModel.Get() ); // attach to parent model + + if ( pInfo->m_nSkin >= 0 ) + { + pTemp->m_nSkin = pInfo->m_nSkin; + } + + pTemp->m_flAnimTime = gpGlobals->curtime; + m_AttachedModels.AddToTail( pTemp ); + } + } + + CalculateFrameDistance(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CModelPanel::InitCubeMaps() +{ + ITexture *pCubemapTexture; + + // Deal with the default cubemap + if ( g_pMaterialSystemHardwareConfig->GetHDREnabled() ) + { + pCubemapTexture = materials->FindTexture( "editor/cubemap.hdr", NULL, true ); + m_DefaultHDREnvCubemap.Init( pCubemapTexture ); + } + else + { + pCubemapTexture = materials->FindTexture( "editor/cubemap", NULL, true ); + m_DefaultEnvCubemap.Init( pCubemapTexture ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CModelPanel::Paint() +{ + BaseClass::Paint(); + + C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer(); + + if ( !pLocalPlayer || !m_pModelInfo ) + return; + + MDLCACHE_CRITICAL_SECTION(); + + if ( m_bPanelDirty ) + { + InitCubeMaps(); + + SetupModel(); + + // are we trying to play a VCD? + if ( Q_strlen( m_pModelInfo->m_pszVCD ) > 0 ) + { + SetupVCD(); + } + + m_bPanelDirty = false; + } + + if ( !m_hModel.Get() ) + return; + + int i = 0; + int x, y, w, h; + + GetBounds( x, y, w, h ); + ParentLocalToScreen( x, y ); + + if ( !m_bAllowOffscreen && x < 0 ) + { + // prevent x from being pushed off the left side of the screen + // for modes like 1280 x 1024 (prevents model from being drawn in the panel) + x = 0; + } + + Vector vecExtraModelOffset( 0, 0, 0 ); + float flWidthRatio = engine->GetScreenAspectRatio() / ( 4.0f / 3.0f ); + + // is this a player model? + if ( Q_strstr( GetModelName(), "models/player/" ) ) + { + // need to know if the ratio is not 4/3 + // HACK! HACK! to get our player models to appear the way they do in 4/3 if we're using other aspect ratios + if ( flWidthRatio > 1.05f ) + { + vecExtraModelOffset.Init( -60, 0, 0 ); + } + else if ( flWidthRatio < 0.95f ) + { + vecExtraModelOffset.Init( 15, 0, 0 ); + } + } + + m_hModel->SetAbsOrigin( m_pModelInfo->m_vecOriginOffset + vecExtraModelOffset ); + m_hModel->SetAbsAngles( QAngle( m_pModelInfo->m_vecAbsAngles.x, m_pModelInfo->m_vecAbsAngles.y, m_pModelInfo->m_vecAbsAngles.z ) ); + + // do we have a valid sequence? + if ( m_hModel->GetSequence() != -1 ) + { + m_hModel->FrameAdvance( gpGlobals->frametime ); + } + + // Now draw it. + CViewSetup view; + view.x = x + m_pModelInfo->m_vecViewportOffset.x; + view.y = y + m_pModelInfo->m_vecViewportOffset.y; + view.width = w; + view.height = h; + + view.m_bOrtho = false; + + // scale the FOV for aspect ratios other than 4/3 + view.fov = ScaleFOVByWidthRatio( m_nFOV, flWidthRatio ); + + view.origin = vec3_origin; + view.angles.Init(); + view.zNear = VIEW_NEARZ; + view.zFar = 1000; + + CMatRenderContextPtr pRenderContext( materials ); + + // Not supported by queued material system - doesn't appear to be necessary +// ITexture *pLocalCube = pRenderContext->GetLocalCubemap(); + + if ( g_pMaterialSystemHardwareConfig->GetHDREnabled() ) + { + pRenderContext->BindLocalCubemap( m_DefaultHDREnvCubemap ); + } + else + { + pRenderContext->BindLocalCubemap( m_DefaultEnvCubemap ); + } + + pRenderContext->SetLightingOrigin( vec3_origin ); + pRenderContext->SetAmbientLight( 0.4, 0.4, 0.4 ); + + static Vector white[6] = + { + Vector( 0.4, 0.4, 0.4 ), + Vector( 0.4, 0.4, 0.4 ), + Vector( 0.4, 0.4, 0.4 ), + Vector( 0.4, 0.4, 0.4 ), + Vector( 0.4, 0.4, 0.4 ), + Vector( 0.4, 0.4, 0.4 ), + }; + + g_pStudioRender->SetAmbientLightColors( white ); + g_pStudioRender->SetLocalLights( 0, NULL ); + + if ( m_pModelInfo->m_bUseSpotlight ) + { + Vector vecMins, vecMaxs; + m_hModel->GetRenderBounds( vecMins, vecMaxs ); + LightDesc_t spotLight( vec3_origin + Vector( 0, 0, 200 ), Vector( 1, 1, 1 ), m_hModel->GetAbsOrigin() + Vector( 0, 0, ( vecMaxs.z - vecMins.z ) * 0.75 ), 0.035, 0.873 ); + g_pStudioRender->SetLocalLights( 1, &spotLight ); + } + + Frustum dummyFrustum; + render->Push3DView( view, 0, NULL, dummyFrustum ); + + modelrender->SuppressEngineLighting( true ); + float color[3] = { 1.0f, 1.0f, 1.0f }; + render->SetColorModulation( color ); + render->SetBlend( 1.0f ); + m_hModel->DrawModel( STUDIO_RENDER ); + + for ( i = 0 ; i < m_AttachedModels.Count() ; i++ ) + { + if ( m_AttachedModels[i].Get() ) + { + m_AttachedModels[i]->DrawModel( STUDIO_RENDER ); + } + } + + modelrender->SuppressEngineLighting( false ); + + render->PopView( dummyFrustum ); + + pRenderContext->BindLocalCubemap( NULL ); + + /* + vgui::surface()->DrawSetColor( Color(0,0,0,255) ); + vgui::surface()->DrawOutlinedRect( 0,0, GetWide(), GetTall() ); + */ + +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +int CModelPanel::FindAnimByName( const char *pszName ) +{ + // first try to find the sequence using pszName as the friendly name + for ( int iIndex = 0 ; iIndex < m_pModelInfo->m_Animations.Count() ; iIndex++ ) + { + CModelPanelModelAnimation *pAnimation = m_pModelInfo->m_Animations[ iIndex ]; + if ( FStrEq( pAnimation->m_pszName, pszName ) ) + return iIndex; + } + + return -1; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CModelPanel::SetSequence( const char *pszName ) +{ + bool bRetVal = false; + const char *pszAnim = NULL; + + MDLCACHE_CRITICAL_SECTION(); + + if ( m_pModelInfo ) + { + int iIndex = FindAnimByName(pszName); + if ( iIndex != -1 ) + { + pszAnim = m_pModelInfo->m_Animations[iIndex]->m_pszSequence; + } + else + { + // if not, just use the passed name as the sequence + pszAnim = pszName; + } + + if ( m_hModel.Get() ) + { + int sequence = m_hModel->LookupSequence( pszAnim ); + if ( sequence != ACT_INVALID ) + { + m_hModel->ResetSequence( sequence ); + m_hModel->SetCycle( 0 ); + + bRetVal = true; + } + } + } + + return bRetVal; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CModelPanel::OnSetAnimation( KeyValues *data ) +{ + // If there's no model, these commands will be ignored. + Assert(m_hModel); + + if ( data ) + { + const char *pszAnimation = data->GetString( "animation", "" ); + const char *pszActivity = data->GetString( "activity", "" ); + if ( pszActivity && pszActivity[0] ) + { + if ( m_hModel ) + { + int iIndex = FindAnimByName(pszActivity); + if ( iIndex != -1 ) + { + pszActivity = m_pModelInfo->m_Animations[iIndex]->m_pszActivity; + } + + Activity activity = (Activity)ActivityList_IndexForName( pszActivity ); + int sequence = m_hModel->SelectWeightedSequence( activity ); + if ( sequence != ACT_INVALID ) + { + m_hModel->ResetSequence( sequence ); + m_hModel->SetCycle( 0 ); + } + } + } + else + { + SetSequence( pszAnimation ); + } + } +} + +void CModelPanel::CalculateFrameDistanceInternal( const model_t *pModel ) +{ + // Get the model space render bounds. + Vector vecMin, vecMax; + modelinfo->GetModelRenderBounds( pModel, vecMin, vecMax ); + Vector vecCenter = ( vecMax + vecMin ) * 0.5f; + vecMin -= vecCenter; + vecMax -= vecCenter; + + // Get the bounds points and transform them by the desired model panel rotation. + Vector aBoundsPoints[8]; + aBoundsPoints[0].Init( vecMax.x, vecMax.y, vecMax.z ); + aBoundsPoints[1].Init( vecMin.x, vecMax.y, vecMax.z ); + aBoundsPoints[2].Init( vecMax.x, vecMin.y, vecMax.z ); + aBoundsPoints[3].Init( vecMin.x, vecMin.y, vecMax.z ); + aBoundsPoints[4].Init( vecMax.x, vecMax.y, vecMin.z ); + aBoundsPoints[5].Init( vecMin.x, vecMax.y, vecMin.z ); + aBoundsPoints[6].Init( vecMax.x, vecMin.y, vecMin.z ); + aBoundsPoints[7].Init( vecMin.x, vecMin.y, vecMin.z ); + + // Translated center point (offset from camera center). + Vector vecTranslateCenter = -vecCenter; + + // Build the rotation matrix. + QAngle angPanelAngles( m_pModelInfo->m_vecAbsAngles.x, m_pModelInfo->m_vecAbsAngles.y, m_pModelInfo->m_vecAbsAngles.z ); + matrix3x4_t matRotation; + AngleMatrix( angPanelAngles, matRotation ); + + Vector aXFormPoints[8]; + for ( int iPoint = 0; iPoint < 8; ++iPoint ) + { + VectorTransform( aBoundsPoints[iPoint], matRotation, aXFormPoints[iPoint] ); + } + + Vector vecXFormCenter; + VectorTransform( -vecTranslateCenter, matRotation, vecXFormCenter ); + + int w, h; + GetSize( w, h ); + float flW = (float)w; + float flH = (float)h; + + float flFOVx = DEG2RAD( m_nFOV * 0.5f ); + float flFOVy = CalcFovY( ( m_nFOV * 0.5f ), flW/flH ); + flFOVy = DEG2RAD( flFOVy ); + + float flTanFOVx = tan( flFOVx ); + float flTanFOVy = tan( flFOVy ); + + // Find the max value of x, y, or z + float flDist = 0.0f; + for ( int iPoint = 0; iPoint < 8; ++iPoint ) + { + float flDistZ = fabs( aXFormPoints[iPoint].z / flTanFOVy - aXFormPoints[iPoint].x ); + float flDistY = fabs( aXFormPoints[iPoint].y / flTanFOVx - aXFormPoints[iPoint].x ); + float flTestDist = max( flDistZ, flDistY ); + flDist = max( flDist, flTestDist ); + } + + // Scale the object down by 10%. + flDist *= 1.10f; + + // Add the framing offset. + vecXFormCenter += m_pModelInfo->m_vecFramedOriginOffset; + + // Zoom to the frame distance + m_pModelInfo->m_vecOriginOffset.x = flDist - vecXFormCenter.x; + m_pModelInfo->m_vecOriginOffset.y = -vecXFormCenter.y; + m_pModelInfo->m_vecOriginOffset.z = -vecXFormCenter.z; + + // Screen space points. + Vector2D aScreenPoints[8]; + Vector aCameraPoints[8]; + for ( int iPoint = 0; iPoint < 8; ++iPoint ) + { + aCameraPoints[iPoint] = aXFormPoints[iPoint]; + aCameraPoints[iPoint].x += flDist; + + aScreenPoints[iPoint].x = aCameraPoints[iPoint].y / ( flTanFOVx * aCameraPoints[iPoint].x ); + aScreenPoints[iPoint].y = aCameraPoints[iPoint].z / ( flTanFOVy * aCameraPoints[iPoint].x ); + + aScreenPoints[iPoint].x = ( aScreenPoints[iPoint].x * 0.5f + 0.5f ) * flW; + aScreenPoints[iPoint].y = ( aScreenPoints[iPoint].y * 0.5f + 0.5f ) * flH; + } + + // Find the min/max and center of the 2D bounding box of the object. + Vector2D vecScreenMin( 99999.0f, 99999.0f ), vecScreenMax( -99999.0f, -99999.0f ); + for ( int iPoint = 0; iPoint < 8; ++iPoint ) + { + vecScreenMin.x = min( vecScreenMin.x, aScreenPoints[iPoint].x ); + vecScreenMin.y = min( vecScreenMin.y, aScreenPoints[iPoint].y ); + vecScreenMax.x = max( vecScreenMax.x, aScreenPoints[iPoint].x ); + vecScreenMax.y = max( vecScreenMax.y, aScreenPoints[iPoint].y ); + } + + vecScreenMin.x = clamp( vecScreenMin.x, 0.0f, flW ); + vecScreenMin.y = clamp( vecScreenMin.y, 0.0f, flH ); + vecScreenMax.x = clamp( vecScreenMax.x, 0.0f, flW ); + vecScreenMax.y = clamp( vecScreenMax.y, 0.0f, flH ); + + // Offset the view port based on the calculated model 2D center and the center of the viewport. + Vector2D vecScreenCenter = ( vecScreenMax + vecScreenMin ) * 0.5f; + m_pModelInfo->m_vecViewportOffset.x = -( ( flW * 0.5f ) - vecScreenCenter.x ); + m_pModelInfo->m_vecViewportOffset.y = -( ( flH * 0.5f ) - vecScreenCenter.y ); +} + +//----------------------------------------------------------------------------- +// Purpose: Calculates the distance the camera should be at to frame the model on the screen. +//----------------------------------------------------------------------------- +void CModelPanel::CalculateFrameDistance( void ) +{ + m_flFrameDistance = 0; + if ( !m_hModel ) + return; + + // Compute a bounding radius for the model + const model_t *mod = modelinfo->GetModel( m_hModel->GetModelIndex() ); + if ( !mod ) + return; + + if ( m_bStartFramed ) + { + CalculateFrameDistanceInternal( mod ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Moves the camera forward/backward along the current view angle to +// frame the model on the screen. +//----------------------------------------------------------------------------- +void CModelPanel::ZoomToFrameDistance( void ) +{ + if ( !m_flFrameDistance || !m_hModel ) + return; + + const model_t *mod = modelinfo->GetModel( m_hModel->GetModelIndex() ); + if ( !mod ) + return; + + // Move the model to the midpoint + Vector mins, maxs, vecModelCenter; + modelinfo->GetModelRenderBounds( mod, mins, maxs ); + VectorLerp( mins, maxs, 0.5f, vecModelCenter ); + + vecModelCenter += m_pModelInfo->m_vecFramedOriginOffset; + + // Zoom to the frame distance + m_pModelInfo->m_vecOriginOffset.x = m_flFrameDistance; + m_pModelInfo->m_vecOriginOffset.y = -vecModelCenter.y; + m_pModelInfo->m_vecOriginOffset.z = -vecModelCenter.z; +} + diff --git a/src/src/game/client/game_controls/basemodelpanel.h b/src/src/game/client/game_controls/basemodelpanel.h new file mode 100644 index 0000000..acef7da --- /dev/null +++ b/src/src/game/client/game_controls/basemodelpanel.h @@ -0,0 +1,232 @@ +//========= Copyright © 1996-2006, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef BASEMODELPANEL_H +#define BASEMODELPANEL_H +#ifdef _WIN32 +#pragma once +#endif + +#include +#include +#include +#include "gameeventlistener.h" +#include "KeyValues.h" + +class C_SceneEntity; + + +class CModelPanelModel : public C_BaseFlex +{ +public: + CModelPanelModel(){} + DECLARE_CLASS( CModelPanelModel, C_BaseFlex ); + + virtual bool IsMenuModel() const{ return true; } +}; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CModelPanelModelAnimation +{ +public: + CModelPanelModelAnimation() + { + m_pszName = NULL; + m_pszSequence = NULL; + m_pszActivity = NULL; + m_pPoseParameters = NULL; + m_bDefault = false; + } + + ~CModelPanelModelAnimation() + { + if ( m_pszName && m_pszName[0] ) + { + delete [] m_pszName; + m_pszName = NULL; + } + + if ( m_pszSequence && m_pszSequence[0] ) + { + delete [] m_pszSequence; + m_pszSequence = NULL; + } + + if ( m_pszActivity && m_pszActivity[0] ) + { + delete [] m_pszActivity; + m_pszActivity = NULL; + } + + if ( m_pPoseParameters ) + { + m_pPoseParameters->deleteThis(); + m_pPoseParameters = NULL; + } + } + +public: + const char *m_pszName; + const char *m_pszSequence; + const char *m_pszActivity; + KeyValues *m_pPoseParameters; + bool m_bDefault; +}; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CModelPanelAttachedModelInfo +{ +public: + CModelPanelAttachedModelInfo() + { + m_pszModelName = NULL; + m_nSkin = 0; + } + + ~CModelPanelAttachedModelInfo() + { + if ( m_pszModelName && m_pszModelName[0] ) + { + delete [] m_pszModelName; + m_pszModelName = NULL; + } + } + +public: + const char *m_pszModelName; + int m_nSkin; +}; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CModelPanelModelInfo +{ +public: + CModelPanelModelInfo() + { + m_pszModelName = NULL; + m_pszModelName_HWM = NULL; + m_nSkin = -1; + m_vecAbsAngles.Init(); + m_vecOriginOffset.Init(); + m_vecFramedOriginOffset.Init(); + m_bUseSpotlight = false; + } + + ~CModelPanelModelInfo() + { + if ( m_pszModelName && m_pszModelName[0] ) + { + delete [] m_pszModelName; + m_pszModelName = NULL; + } + + if ( m_pszModelName_HWM && m_pszModelName_HWM[0] ) + { + delete [] m_pszModelName_HWM; + m_pszModelName_HWM = NULL; + } + + if ( m_pszVCD && m_pszVCD[0] ) + { + delete [] m_pszVCD; + m_pszVCD = NULL; + } + + m_Animations.PurgeAndDeleteElements(); + m_AttachedModelsInfo.PurgeAndDeleteElements(); + } + +public: + const char *m_pszModelName; + const char *m_pszModelName_HWM; + int m_nSkin; + const char *m_pszVCD; + Vector m_vecAbsAngles; + Vector m_vecOriginOffset; + Vector2D m_vecViewportOffset; + Vector m_vecFramedOriginOffset; + bool m_bUseSpotlight; + + CUtlVector m_Animations; + CUtlVector m_AttachedModelsInfo; +}; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CModelPanel : public vgui::EditablePanel, public CGameEventListener +{ +public: + DECLARE_CLASS_SIMPLE( CModelPanel, vgui::EditablePanel ); + + CModelPanel( vgui::Panel *parent, const char *name ); + virtual ~CModelPanel(); + + virtual void Paint(); + virtual void ApplySettings( KeyValues *inResourceData ); + virtual void DeleteVCDData( void ); + virtual void DeleteModelData( void ); + + virtual void SetFOV( int nFOV ){ m_nFOV = nFOV; } + virtual void SetPanelDirty( void ){ m_bPanelDirty = true; } + virtual bool SetSequence( const char *pszSequence ); + + MESSAGE_FUNC_PARAMS( OnAddAnimation, "AddAnimation", data ); + MESSAGE_FUNC_PARAMS( OnSetAnimation, "SetAnimation", data ); + + void SetDefaultAnimation( const char *pszName ); + void SwapModel( const char *pszName, const char *pszAttached = NULL ); + + virtual void ParseModelInfo( KeyValues *inResourceData ); + + void ClearAttachedModelInfos( void ); + + void CalculateFrameDistance( void ); + void ZoomToFrameDistance( void ); + +public: // IGameEventListener: + virtual void FireGameEvent( IGameEvent * event ); + +protected: + virtual void SetupModel( void ); + virtual void SetupVCD( void ); + virtual const char *GetModelName( void ); + +private: + void InitCubeMaps(); + int FindAnimByName( const char *pszName ); + void CalculateFrameDistanceInternal( const model_t *pModel ); + +public: + int m_nFOV; + float m_flFrameDistance; + bool m_bStartFramed; + CModelPanelModelInfo *m_pModelInfo; + + CHandle m_hModel; + CUtlVector > m_AttachedModels; + + CHandle m_hScene; + +private: + bool m_bPanelDirty; + int m_iDefaultAnimation; + + bool m_bAllowOffscreen; + + CTextureReference m_DefaultEnvCubemap; + CTextureReference m_DefaultHDREnvCubemap; +}; + + +#endif // BASEMODELPANEL_H diff --git a/src/src/cl_dll/game_controls/baseviewport.cpp b/src/src/game/client/game_controls/baseviewport.cpp similarity index 78% rename from src/src/cl_dll/game_controls/baseviewport.cpp rename to src/src/game/client/game_controls/baseviewport.cpp index 15f0d0c..330d579 100644 --- a/src/src/cl_dll/game_controls/baseviewport.cpp +++ b/src/src/game/client/game_controls/baseviewport.cpp @@ -27,8 +27,8 @@ #include #include #include +#include -#include // K_ENTER, ... define #include // sub dialogs @@ -40,6 +40,7 @@ #include "mapoverview.h" #include "hud.h" #include "NavProgress.h" +#include "commentary_modelviewer.h" // our definition #include "baseviewport.h" @@ -54,6 +55,7 @@ IViewPort *gViewPortInterface = NULL; vgui::Panel *g_lastPanel = NULL; // used for mouseover buttons, keeps track of the last active panel +vgui::Button *g_lastButton = NULL; // used for mouseover buttons, keeps track of the last active button using namespace vgui; ConVar hud_autoreloadscript("hud_autoreloadscript", "0", FCVAR_NONE, "Automatically reloads the animation script each time one is ran"); @@ -65,10 +67,10 @@ CON_COMMAND( showpanel, "Shows a viewport panel " ) if ( !gViewPortInterface ) return; - if ( engine->Cmd_Argc() != 2 ) + if ( args.ArgC() != 2 ) return; - gViewPortInterface->ShowPanel( engine->Cmd_Argv( 1 ), true ); + gViewPortInterface->ShowPanel( args[ 1 ], true ); } CON_COMMAND( hidepanel, "Hides a viewport panel " ) @@ -76,10 +78,10 @@ CON_COMMAND( hidepanel, "Hides a viewport panel " ) if ( !gViewPortInterface ) return; - if ( engine->Cmd_Argc() != 2 ) + if ( args.ArgC() != 2 ) return; - gViewPortInterface->ShowPanel( engine->Cmd_Argv( 1 ), false ); + gViewPortInterface->ShowPanel( args[ 1 ], false ); } /* global helper functions @@ -101,6 +103,41 @@ bool Helper_LoadFile( IBaseFileSystem *pFileSystem, const char *pFilename, CUtlV return true; } */ +//----------------------------------------------------------------------------- +// Purpose: +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CBaseViewport::LoadHudAnimations( void ) +{ + const char *HUDANIMATION_MANIFEST_FILE = "scripts/hudanimations_manifest.txt"; + KeyValues *manifest = new KeyValues( HUDANIMATION_MANIFEST_FILE ); + if ( manifest->LoadFromFile( g_pFullFileSystem, HUDANIMATION_MANIFEST_FILE, "GAME" ) == false ) + { + manifest->deleteThis(); + return false; + } + + bool bClearScript = true; + + // Load each file defined in the text + for ( KeyValues *sub = manifest->GetFirstSubKey(); sub != NULL; sub = sub->GetNextKey() ) + { + if ( !Q_stricmp( sub->GetName(), "file" ) ) + { + // Add it + if ( m_pAnimController->SetScriptFile( GetVPanel(), sub->GetString(), bClearScript ) == false ) + { + Assert( 0 ); + } + + bClearScript = false; + continue; + } + } + + manifest->deleteThis(); + return true; +} //================================================================ CBaseViewport::CBaseViewport() : vgui::EditablePanel( NULL, "CBaseViewport") @@ -128,10 +165,17 @@ CBaseViewport::CBaseViewport() : vgui::EditablePanel( NULL, "CBaseViewport") // create our animation controller m_pAnimController->SetScheme(scheme); m_pAnimController->SetProportional(true); - if (!m_pAnimController->SetScriptFile( GetVPanel(), "scripts/HudAnimations.txt")) + + // Attempt to load all hud animations + if ( LoadHudAnimations() == false ) { - Assert(0); + // Fall back to just the main + if ( m_pAnimController->SetScriptFile( GetVPanel(), "scripts/HudAnimations.txt", true ) == false ) + { + Assert(0); + } } + m_OldSize[ 0 ] = m_OldSize[ 1 ] = -1; } @@ -156,19 +200,27 @@ void CBaseViewport::OnScreenSizeChanged(int iOldWide, int iOldTall) #ifndef _XBOX vgui::ipanel()->MoveToBack( m_pBackGround->GetVPanel() ); // really send it to the back #endif + + // hide all panels when reconnecting + ShowPanel( PANEL_ALL, false ); + + if ( engine->IsHLTV() ) + { + ShowPanel( PANEL_SPECGUI, true ); + } } void CBaseViewport::CreateDefaultPanels( void ) { #ifndef _XBOX - AddNewPanel( CreatePanelByName( PANEL_SCOREBOARD ) ); - AddNewPanel( CreatePanelByName( PANEL_INFO ) ); - AddNewPanel( CreatePanelByName( PANEL_SPECGUI ) ); - AddNewPanel( CreatePanelByName( PANEL_SPECMENU ) ); - AddNewPanel( CreatePanelByName( PANEL_NAV_PROGRESS ) ); - // AddNewPanel( CreatePanelByName( PANEL_TEAM ) ); - // AddNewPanel( CreatePanelByName( PANEL_CLASS ) ); - // AddNewPanel( CreatePanelByName( PANEL_BUY ) ); + AddNewPanel( CreatePanelByName( PANEL_SCOREBOARD ), "PANEL_SCOREBOARD" ); + AddNewPanel( CreatePanelByName( PANEL_INFO ), "PANEL_INFO" ); + AddNewPanel( CreatePanelByName( PANEL_SPECGUI ), "PANEL_SPECGUI" ); + AddNewPanel( CreatePanelByName( PANEL_SPECMENU ), "PANEL_SPECMENU" ); + AddNewPanel( CreatePanelByName( PANEL_NAV_PROGRESS ), "PANEL_NAV_PROGRESS" ); + // AddNewPanel( CreatePanelByName( PANEL_TEAM ), "PANEL_TEAM" ); + // AddNewPanel( CreatePanelByName( PANEL_CLASS ), "PANEL_CLASS" ); + // AddNewPanel( CreatePanelByName( PANEL_BUY ), "PANEL_BUY" ); #endif } @@ -222,16 +274,21 @@ IViewPortPanel* CBaseViewport::CreatePanelByName(const char *szPanelName) newpanel = new CNavProgress( this ); } #endif + + if ( Q_strcmp(PANEL_COMMENTARY_MODELVIEWER, szPanelName) == 0 ) + { + newpanel = new CCommentaryModelViewer( this ); + } return newpanel; } -bool CBaseViewport::AddNewPanel( IViewPortPanel* pPanel ) +bool CBaseViewport::AddNewPanel( IViewPortPanel* pPanel, char const *pchDebugName ) { if ( !pPanel ) { - DevMsg("CBaseViewport::AddNewPanel: NULL panel.\n" ); + DevMsg("CBaseViewport::AddNewPanel(%s): NULL panel.\n", pchDebugName ); return false; } @@ -261,6 +318,41 @@ IViewPortPanel* CBaseViewport::FindPanelByName(const char *szPanelName) return NULL; } +void CBaseViewport::PostMessageToPanel( IViewPortPanel* pPanel, KeyValues *pKeyValues ) +{ + PostMessage( pPanel->GetVPanel(), pKeyValues ); +} + +void CBaseViewport::PostMessageToPanel( const char *pName, KeyValues *pKeyValues ) +{ + if ( Q_strcmp( pName, PANEL_ALL ) == 0 ) + { + for (int i=0; i< m_Panels.Count(); i++ ) + { + PostMessageToPanel( m_Panels[i], pKeyValues ); + } + + return; + } + + IViewPortPanel * panel = NULL; + + if ( Q_strcmp( pName, PANEL_ACTIVE ) == 0 ) + { + panel = m_pActivePanel; + } + else + { + panel = FindPanelByName( pName ); + } + + if ( !panel ) + return; + + PostMessageToPanel( panel, pKeyValues ); +} + + void CBaseViewport::ShowPanel( const char *pName, bool state ) { if ( Q_strcmp( pName, PANEL_ALL ) == 0 ) @@ -301,7 +393,7 @@ void CBaseViewport::ShowPanel( IViewPortPanel* pPanel, bool state ) if ( engine->IsPlayingDemo() && !engine->IsHLTV() ) return; - if ( (m_pActivePanel != NULL) && (m_pActivePanel != pPanel) ) + if ( (m_pActivePanel != NULL) && (m_pActivePanel != pPanel) && (m_pActivePanel->IsVisible()) ) { // store a pointer to the currently active panel // so we can restore it later @@ -373,6 +465,8 @@ CBaseViewport::~CBaseViewport() m_pBackGround = NULL; #endif RemoveAllPanels(); + + gameeventmanager->RemoveListener( this ); } @@ -497,19 +591,19 @@ void CBaseViewport::OnThink() void CBaseViewport::SetParent(vgui::VPANEL parent) { EditablePanel::SetParent( parent ); + // force ourselves to be proportional - when we set our parent above, if our new + // parent happened to be non-proportional (such as the vgui root panel), we got + // slammed to be nonproportional + EditablePanel::SetProportional( true ); + #ifndef _XBOX m_pBackGround->SetParent( (vgui::VPANEL)parent ); #endif - for (int i=0; i< m_Panels.Count(); i++ ) - { - m_Panels[i]->SetParent( parent ); - } + + // set proportionality on animation controller + m_pAnimController->SetProportional( true ); m_bHasParent = (parent != 0); - - // restore proportionality on animation controller - // TODO: should all panels be restored to being proportional? - m_pAnimController->SetProportional( true ); } //----------------------------------------------------------------------------- @@ -563,15 +657,19 @@ void CBaseViewport::ReloadScheme(const char *fromFile) } // Force a reload - if ( !m_pAnimController->SetScriptFile( GetVPanel(), "scripts/HudAnimations.txt", true) ) + if ( LoadHudAnimations() == false ) { - Assert( 0 ); + // Fall back to just the main + if ( m_pAnimController->SetScriptFile( GetVPanel(), "scripts/HudAnimations.txt", true ) == false ) + { + Assert(0); + } } SetProportional( true ); // reload the .res file from disk - LoadControlSettings("scripts/HudLayout.res"); + LoadControlSettings( "scripts/HudLayout.res" ); gHUD.RefreshHudTextures(); diff --git a/src/src/cl_dll/game_controls/baseviewport.h b/src/src/game/client/game_controls/baseviewport.h similarity index 92% rename from src/src/cl_dll/game_controls/baseviewport.h rename to src/src/game/client/game_controls/baseviewport.h index 5499eaa..a6d1fd2 100644 --- a/src/src/cl_dll/game_controls/baseviewport.h +++ b/src/src/game/client/game_controls/baseviewport.h @@ -9,7 +9,7 @@ #define TEAMFORTRESSVIEWPORT_H // viewport interface for the rest of the dll -#include +#include #include // a vector based queue template to manage our VGUI menu queue #include @@ -40,9 +40,10 @@ public: virtual void ShowPanel( const char *pName, bool state ); virtual void ShowPanel( IViewPortPanel* pPanel, bool state ); - virtual bool AddNewPanel( IViewPortPanel* pPanel ); + virtual bool AddNewPanel( IViewPortPanel* pPanel, char const *pchDebugName ); virtual void CreateDefaultPanels( void ); virtual void UpdateAllPanels( void ); + virtual void PostMessageToPanel( const char *pName, KeyValues *pKeyValues ); virtual void Start( IGameUIFuncs *pGameUIFuncs, IGameEventManager2 *pGameEventManager ); virtual void SetParent(vgui::VPANEL parent); @@ -74,6 +75,9 @@ public: // IGameEventListener: protected: + + bool LoadHudAnimations( void ); + #ifndef _XBOX class CBackGroundPanel : public vgui::Frame { @@ -121,6 +125,7 @@ protected: virtual void Paint(); virtual void OnThink(); virtual void OnScreenSizeChanged(int iOldWide, int iOldTall); + void PostMessageToPanel( IViewPortPanel* pPanel, KeyValues *pKeyValues ); protected: IGameUIFuncs* m_GameuiFuncs; // for key binding details diff --git a/src/src/cl_dll/game_controls/buymenu.cpp b/src/src/game/client/game_controls/buymenu.cpp similarity index 100% rename from src/src/cl_dll/game_controls/buymenu.cpp rename to src/src/game/client/game_controls/buymenu.cpp diff --git a/src/src/cl_dll/game_controls/buymenu.h b/src/src/game/client/game_controls/buymenu.h similarity index 97% rename from src/src/cl_dll/game_controls/buymenu.h rename to src/src/game/client/game_controls/buymenu.h index d30ebc8..4e2c686 100644 --- a/src/src/cl_dll/game_controls/buymenu.h +++ b/src/src/game/client/game_controls/buymenu.h @@ -12,7 +12,7 @@ #endif #include -#include +#include class CBuySubMenu; diff --git a/src/src/cl_dll/game_controls/buysubmenu.cpp b/src/src/game/client/game_controls/buysubmenu.cpp similarity index 99% rename from src/src/cl_dll/game_controls/buysubmenu.cpp rename to src/src/game/client/game_controls/buysubmenu.cpp index 649b67a..bc34910 100644 --- a/src/src/cl_dll/game_controls/buysubmenu.cpp +++ b/src/src/game/client/game_controls/buysubmenu.cpp @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include "MouseOverPanelButton.h" diff --git a/src/src/cl_dll/game_controls/buysubmenu.h b/src/src/game/client/game_controls/buysubmenu.h similarity index 100% rename from src/src/cl_dll/game_controls/buysubmenu.h rename to src/src/game/client/game_controls/buysubmenu.h diff --git a/src/src/cl_dll/game_controls/classmenu.cpp b/src/src/game/client/game_controls/classmenu.cpp similarity index 81% rename from src/src/cl_dll/game_controls/classmenu.cpp rename to src/src/game/client/game_controls/classmenu.cpp index 171c93d..980ca0f 100644 --- a/src/src/cl_dll/game_controls/classmenu.cpp +++ b/src/src/game/client/game_controls/classmenu.cpp @@ -29,7 +29,11 @@ #ifndef _XBOX extern IGameUIFuncs *gameuifuncs; // for key binding details #endif -#include +#include + +#if defined( TF_CLIENT_DLL ) +#include "item_inventory.h" +#endif // TF_CLIENT_DLL #include // MAX_PATH define @@ -38,7 +42,13 @@ extern IGameUIFuncs *gameuifuncs; // for key binding details using namespace vgui; -ConVar hud_classautokill( "hud_classautokill", "1", FCVAR_CLIENTDLL | FCVAR_ARCHIVE, "Automatically kill player after choosing a new playerclass." ); +#ifdef TF_CLIENT_DLL +#define HUD_CLASSAUTOKILL_FLAGS ( FCVAR_CLIENTDLL | FCVAR_ARCHIVE | FCVAR_USERINFO ) +#else +#define HUD_CLASSAUTOKILL_FLAGS ( FCVAR_CLIENTDLL | FCVAR_ARCHIVE ) +#endif // !TF_CLIENT_DLL + +ConVar hud_classautokill( "hud_classautokill", "1", HUD_CLASSAUTOKILL_FLAGS, "Automatically kill player after choosing a new playerclass." ); //----------------------------------------------------------------------------- // Purpose: Constructor @@ -46,7 +56,7 @@ ConVar hud_classautokill( "hud_classautokill", "1", FCVAR_CLIENTDLL | FCVAR_ARCH CClassMenu::CClassMenu(IViewPort *pViewPort) : Frame(NULL, PANEL_CLASS) { m_pViewPort = pViewPort; - m_iScoreBoardKey = -1; // this is looked up in Activate() + m_iScoreBoardKey = BUTTON_CODE_INVALID; // this is looked up in Activate() m_iTeam = 0; // initialize dialog @@ -73,7 +83,7 @@ CClassMenu::CClassMenu(IViewPort *pViewPort) : Frame(NULL, PANEL_CLASS) CClassMenu::CClassMenu(IViewPort *pViewPort, const char *panelName) : Frame(NULL, panelName) { m_pViewPort = pViewPort; - m_iScoreBoardKey = -1; // this is looked up in Activate() + m_iScoreBoardKey = BUTTON_CODE_INVALID; // this is looked up in Activate() m_iTeam = 0; // initialize dialog @@ -156,27 +166,36 @@ void CClassMenu::Reset() //----------------------------------------------------------------------------- // Purpose: Called when the user picks a class //----------------------------------------------------------------------------- -void CClassMenu::OnCommand( const char *command) +void CClassMenu::OnCommand( const char *command ) { if ( Q_stricmp( command, "vguicancel" ) ) { +#if defined( TF_CLIENT_DLL ) + // PREITEMHACK: Until Steam has the loadout backend up, just tell the server + // what we're using before we pick a class. + if ( !Q_strnicmp( command, "joinclass", 9 ) ) + { + InventoryManager()->UpdateServerLoadout(); + } +#endif + engine->ClientCmd( const_cast( command ) ); -#ifndef CSTRIKE_DLL +#if !defined( CSTRIKE_DLL ) && !defined( TF_CLIENT_DLL ) // They entered a command to change their class, kill them so they spawn with // the new class right away if ( hud_classautokill.GetBool() ) { engine->ClientCmd( "kill" ); } -#endif // !CSTRIKE_DLL +#endif // !CSTRIKE_DLL && !TF_CLIENT_DLL } - + Close(); gViewPortInterface->ShowBackGround( false ); - BaseClass::OnCommand(command); + BaseClass::OnCommand( command ); } //----------------------------------------------------------------------------- @@ -202,9 +221,9 @@ void CClassMenu::ShowPanel(bool bShow) } } - if ( m_iScoreBoardKey < 0 ) + if ( m_iScoreBoardKey == BUTTON_CODE_INVALID ) { - m_iScoreBoardKey = gameuifuncs->GetEngineKeyCodeForBind( "showscores" ); + m_iScoreBoardKey = gameuifuncs->GetButtonCodeForBind( "showscores" ); } } else @@ -248,11 +267,10 @@ void CClassMenu::SetVisibleButton(const char *textEntryName, bool state) void CClassMenu::OnKeyCodePressed(KeyCode code) { - int lastPressedEngineKey = engine->GetLastPressedEngineKey(); - - if ( m_iScoreBoardKey >= 0 && m_iScoreBoardKey == lastPressedEngineKey ) + if ( m_iScoreBoardKey != BUTTON_CODE_INVALID && m_iScoreBoardKey == code ) { gViewPortInterface->ShowPanel( PANEL_SCOREBOARD, true ); + gViewPortInterface->PostMessageToPanel( PANEL_SCOREBOARD, new KeyValues( "PollHideCode", "code", code ) ); } else { diff --git a/src/src/cl_dll/game_controls/classmenu.h b/src/src/game/client/game_controls/classmenu.h similarity index 97% rename from src/src/cl_dll/game_controls/classmenu.h rename to src/src/game/client/game_controls/classmenu.h index fe7cd49..afa0962 100644 --- a/src/src/cl_dll/game_controls/classmenu.h +++ b/src/src/game/client/game_controls/classmenu.h @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include "mouseoverpanelbutton.h" @@ -68,7 +68,7 @@ protected: void OnCommand( const char *command ); IViewPort *m_pViewPort; - int m_iScoreBoardKey; + ButtonCode_t m_iScoreBoardKey; int m_iTeam; vgui::EditablePanel *m_pPanel; diff --git a/src/src/cl_dll/game_controls/clientscoreboarddialog.cpp b/src/src/game/client/game_controls/clientscoreboarddialog.cpp similarity index 63% rename from src/src/cl_dll/game_controls/clientscoreboarddialog.cpp rename to src/src/game/client/game_controls/clientscoreboarddialog.cpp index acd5121..afee384 100644 --- a/src/src/cl_dll/game_controls/clientscoreboarddialog.cpp +++ b/src/src/game/client/game_controls/clientscoreboarddialog.cpp @@ -1,9 +1,9 @@ -//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: // // $NoKeywords: $ -//=============================================================================// +//===========================================================================// #include "cbase.h" #include @@ -12,8 +12,10 @@ #include #include #include - +#include "IGameUIFuncs.h" // for key bindings +#include "inputsystem/iinputsystem.h" #include "clientscoreboarddialog.h" +#include #include #include @@ -26,26 +28,28 @@ #include #include -#include +#include #include -//#include "voice_status.h" -//#include "Friends/IFriendsUser.h" +#include "vgui_avatarimage.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" -// extern vars -//extern IFriendsUser *g_pFriendsUser; - using namespace vgui; +bool AvatarIndexLessFunc( const int &lhs, const int &rhs ) +{ + return lhs < rhs; +} + //----------------------------------------------------------------------------- // Purpose: Constructor //----------------------------------------------------------------------------- -CClientScoreBoardDialog::CClientScoreBoardDialog(IViewPort *pViewPort) : Frame( NULL, PANEL_SCOREBOARD ) +CClientScoreBoardDialog::CClientScoreBoardDialog(IViewPort *pViewPort) : EditablePanel( NULL, PANEL_SCOREBOARD ) { m_iPlayerIndexSymbol = KeyValuesSystem()->GetSymbolForString("playerIndex"); + m_nCloseKey = BUTTON_CODE_INVALID; //memset(s_VoiceImage, 0x0, sizeof( s_VoiceImage )); TrackerImage = 0; @@ -55,10 +59,6 @@ CClientScoreBoardDialog::CClientScoreBoardDialog(IViewPort *pViewPort) : Frame( SetProportional(true); SetKeyBoardInputEnabled(false); SetMouseInputEnabled(false); - SetSizeable(false); - - // hide the system buttons - SetTitleBarVisible( false ); // set the scheme before any child control is created SetScheme("ClientScheme"); @@ -73,16 +73,67 @@ CClientScoreBoardDialog::CClientScoreBoardDialog(IViewPort *pViewPort) : Frame( m_HLTVSpectators = 0; // update scoreboard instantly if on of these events occure - gameeventmanager->AddListener(this, "hltv_status", false ); - gameeventmanager->AddListener(this, "server_spawn", false ); + ListenForGameEvent( "hltv_status" ); + ListenForGameEvent( "server_spawn" ); + + m_pImageList = NULL; + + m_mapAvatarsToImageList.SetLessFunc( AvatarIndexLessFunc ); + m_mapAvatarsToImageList.RemoveAll(); + memset( &m_iImageAvatars, 0, sizeof(int) * (MAX_PLAYERS+1) ); } //----------------------------------------------------------------------------- -// Purpose: Destructor +// Purpose: Constructor //----------------------------------------------------------------------------- CClientScoreBoardDialog::~CClientScoreBoardDialog() { - gameeventmanager->RemoveListener(this); + if ( NULL != m_pImageList ) + { + delete m_pImageList; + m_pImageList = NULL; + } +} + +//----------------------------------------------------------------------------- +// Call every frame +//----------------------------------------------------------------------------- +void CClientScoreBoardDialog::OnThink() +{ + BaseClass::OnThink(); + + // NOTE: this is necessary because of the way input works. + // If a key down message is sent to vgui, then it will get the key up message + // Sometimes the scoreboard is activated by other vgui menus, + // sometimes by console commands. In the case where it's activated by + // other vgui menus, we lose the key up message because this panel + // doesn't accept keyboard input. It *can't* accept keyboard input + // because another feature of the dialog is that if it's triggered + // from within the game, you should be able to still run around while + // the scoreboard is up. That feature is impossible if this panel accepts input. + // because if a vgui panel is up that accepts input, it prevents the engine from + // receiving that input. So, I'm stuck with a polling solution. + // + // Close key is set to non-invalid when something other than a keybind + // brings the scoreboard up, and it's set to invalid as soon as the + // dialog becomes hidden. + if ( m_nCloseKey != BUTTON_CODE_INVALID ) + { + if ( !g_pInputSystem->IsButtonDown( m_nCloseKey ) ) + { + m_nCloseKey = BUTTON_CODE_INVALID; + gViewPortInterface->ShowPanel( PANEL_SCOREBOARD, false ); + GetClientVoiceMgr()->StopSquelchMode(); + } + } +} + +//----------------------------------------------------------------------------- +// Called by vgui panels that activate the client scoreboard +//----------------------------------------------------------------------------- +void CClientScoreBoardDialog::OnPollHideCode( int code ) +{ + m_nCloseKey = (ButtonCode_t)code; } //----------------------------------------------------------------------------- @@ -113,36 +164,54 @@ void CClientScoreBoardDialog::InitScoreboardSections() void CClientScoreBoardDialog::ApplySchemeSettings( IScheme *pScheme ) { BaseClass::ApplySchemeSettings( pScheme ); - ImageList *imageList = new ImageList(false); -// s_VoiceImage[0] = 0; // index 0 is always blank -// s_VoiceImage[CVoiceStatus::VOICE_NEVERSPOKEN] = imageList->AddImage(scheme()->GetImage("gfx/vgui/640_speaker1", true)); -// s_VoiceImage[CVoiceStatus::VOICE_NOTTALKING] = imageList->AddImage(scheme()->GetImage("gfx/vgui/640_speaker2", true)); -// s_VoiceImage[CVoiceStatus::VOICE_TALKING] = imageList->AddImage(scheme()->GetImage( "gfx/vgui/640_speaker3", true)); -// s_VoiceImage[CVoiceStatus::VOICE_BANNED] = imageList->AddImage(scheme()->GetImage("gfx/vgui/640_voiceblocked", true)); - -// TrackerImage = imageList->AddImage(scheme()->GetImage("gfx/vgui/640_scoreboardtracker", true)); + if ( m_pImageList ) + delete m_pImageList; + m_pImageList = new ImageList( false ); + + m_mapAvatarsToImageList.RemoveAll(); + memset( &m_iImageAvatars, 0, sizeof(int) * (MAX_PLAYERS+1) ); + + PostApplySchemeSettings( pScheme ); +} + +//----------------------------------------------------------------------------- +// Purpose: Does dialog-specific customization after applying scheme settings. +//----------------------------------------------------------------------------- +void CClientScoreBoardDialog::PostApplySchemeSettings( vgui::IScheme *pScheme ) +{ // resize the images to our resolution - for (int i = 0; i < imageList->GetImageCount(); i++ ) + for (int i = 0; i < m_pImageList->GetImageCount(); i++ ) { int wide, tall; - imageList->GetImage(i)->GetSize(wide, tall); - imageList->GetImage(i)->SetSize(scheme()->GetProportionalScaledValueEx( GetScheme(),wide), scheme()->GetProportionalScaledValueEx( GetScheme(),tall)); + m_pImageList->GetImage(i)->GetSize(wide, tall); + m_pImageList->GetImage(i)->SetSize(scheme()->GetProportionalScaledValueEx( GetScheme(),wide), scheme()->GetProportionalScaledValueEx( GetScheme(),tall)); } - m_pPlayerList->SetImageList(imageList, false); + m_pPlayerList->SetImageList( m_pImageList, false ); m_pPlayerList->SetVisible( true ); // light up scoreboard a bit SetBgColor( Color( 0,0,0,0) ); } - //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CClientScoreBoardDialog::ShowPanel(bool bShow) { + // Catch the case where we call ShowPanel before ApplySchemeSettings, eg when + // going from windowed <-> fullscreen + if ( m_pImageList == NULL ) + { + InvalidateLayout( true, true ); + } + + if ( !bShow ) + { + m_nCloseKey = BUTTON_CODE_INVALID; + } + if ( BaseClass::IsVisible() == bShow ) return; @@ -150,8 +219,8 @@ void CClientScoreBoardDialog::ShowPanel(bool bShow) { Reset(); Update(); - - Activate(); + SetVisible( true ); + MoveToFront(); } else { @@ -161,8 +230,6 @@ void CClientScoreBoardDialog::ShowPanel(bool bShow) } } - - void CClientScoreBoardDialog::FireGameEvent( IGameEvent *event ) { const char * type = event->GetName(); @@ -183,8 +250,8 @@ void CClientScoreBoardDialog::FireGameEvent( IGameEvent *event ) if ( control ) { PostMessage( control, new KeyValues( "SetText", "text", hostname ) ); + control->MoveToFront(); } - control->MoveToFront(); } if( IsVisible() ) @@ -194,9 +261,7 @@ void CClientScoreBoardDialog::FireGameEvent( IGameEvent *event ) bool CClientScoreBoardDialog::NeedsUpdate( void ) { - return (m_fNextUpdateTime < gpGlobals->curtime); - - + return (m_fNextUpdateTime < gpGlobals->curtime); } //----------------------------------------------------------------------------- @@ -214,6 +279,7 @@ void CClientScoreBoardDialog::Update( void ) // grow the scoreboard to fit all the players int wide, tall; m_pPlayerList->GetContentSize(wide, tall); + tall += GetAdditionalHeight(); wide = GetWide(); if (m_iDesiredHeight < tall) { @@ -237,6 +303,7 @@ void CClientScoreBoardDialog::Update( void ) //----------------------------------------------------------------------------- void CClientScoreBoardDialog::UpdateTeamInfo() { +// TODO: work out a sorting algorithm for team display for TF2 } //----------------------------------------------------------------------------- @@ -257,13 +324,12 @@ void CClientScoreBoardDialog::UpdatePlayerInfo() // add the player to the list KeyValues *playerData = new KeyValues("data"); GetPlayerScoreInfo( i, playerData ); + UpdatePlayerAvatar( i, playerData ); - const char *oldName = playerData->GetString("name",""); - int bufsize = strlen(oldName) * 2 + 1; - char *newName = (char *)_alloca( bufsize ); + char newName[MAX_PLAYER_NAME_LENGTH]; - UTIL_MakeSafeName( oldName, newName, bufsize ); + UTIL_MakeSafeName( oldName, newName, MAX_PLAYER_NAME_LENGTH ); playerData->SetString("name", newName); @@ -319,8 +385,6 @@ void CClientScoreBoardDialog::AddHeader() m_pPlayerList->AddColumnToSection(m_iSectionId, "frags", "#PlayerScore", 0, scheme()->GetProportionalScaledValueEx( GetScheme(),SCORE_WIDTH) ); m_pPlayerList->AddColumnToSection(m_iSectionId, "deaths", "#PlayerDeath", 0, scheme()->GetProportionalScaledValueEx( GetScheme(),DEATH_WIDTH) ); m_pPlayerList->AddColumnToSection(m_iSectionId, "ping", "#PlayerPing", 0, scheme()->GetProportionalScaledValueEx( GetScheme(),PING_WIDTH) ); -// m_pPlayerList->AddColumnToSection(m_iSectionId, "voice", "#PlayerVoice", SectionedListPanel::COLUMN_IMAGE | SectionedListPanel::COLUMN_CENTER, scheme()->GetProportionalScaledValueEx( GetScheme(),VOICE_WIDTH) ); -// m_pPlayerList->AddColumnToSection(m_iSectionId, "tracker", "#PlayerTracker", SectionedListPanel::COLUMN_IMAGE, scheme()->GetProportionalScaledValueEx( GetScheme(),FRIENDS_WIDTH) ); } //----------------------------------------------------------------------------- @@ -336,21 +400,27 @@ void CClientScoreBoardDialog::AddSection(int teamType, int teamNumber) return; // setup the team name - wchar_t *teamName = localize()->Find( gr->GetTeamName(teamNumber) ); + wchar_t *teamName = g_pVGuiLocalize->Find( gr->GetTeamName(teamNumber) ); wchar_t name[64]; wchar_t string1[1024]; if (!teamName) { - localize()->ConvertANSIToUnicode(gr->GetTeamName(teamNumber), name, sizeof(name)); + g_pVGuiLocalize->ConvertANSIToUnicode(gr->GetTeamName(teamNumber), name, sizeof(name)); teamName = name; } - localize()->ConstructString( string1, sizeof( string1 ), localize()->Find("#Player"), 2, teamName ); + g_pVGuiLocalize->ConstructString( string1, sizeof( string1 ), g_pVGuiLocalize->Find("#Player"), 2, teamName ); m_pPlayerList->AddSection(m_iSectionId, "", StaticPlayerSortFunc); - m_pPlayerList->AddColumnToSection(m_iSectionId, "name", string1, 0, scheme()->GetProportionalScaledValueEx( GetScheme(),NAME_WIDTH) ); + // Avatars are always displayed at 32x32 regardless of resolution + if ( ShowAvatars() ) + { + m_pPlayerList->AddColumnToSection( m_iSectionId, "avatar", "", SectionedListPanel::COLUMN_IMAGE | SectionedListPanel::COLUMN_RIGHT, m_iAvatarWidth ); + } + + m_pPlayerList->AddColumnToSection(m_iSectionId, "name", string1, 0, scheme()->GetProportionalScaledValueEx( GetScheme(),NAME_WIDTH) - m_iAvatarWidth ); m_pPlayerList->AddColumnToSection(m_iSectionId, "frags", "", 0, scheme()->GetProportionalScaledValueEx( GetScheme(),SCORE_WIDTH) ); m_pPlayerList->AddColumnToSection(m_iSectionId, "deaths", "", 0, scheme()->GetProportionalScaledValueEx( GetScheme(),DEATH_WIDTH) ); m_pPlayerList->AddColumnToSection(m_iSectionId, "ping", "", 0, scheme()->GetProportionalScaledValueEx( GetScheme(),PING_WIDTH) ); @@ -358,7 +428,13 @@ void CClientScoreBoardDialog::AddSection(int teamType, int teamNumber) else if ( teamType == TYPE_SPECTATORS ) { m_pPlayerList->AddSection(m_iSectionId, ""); - m_pPlayerList->AddColumnToSection(m_iSectionId, "name", "#Spectators", 0, scheme()->GetProportionalScaledValueEx( GetScheme(),NAME_WIDTH)); + + // Avatars are always displayed at 32x32 regardless of resolution + if ( ShowAvatars() ) + { + m_pPlayerList->AddColumnToSection( m_iSectionId, "avatar", "", SectionedListPanel::COLUMN_IMAGE | SectionedListPanel::COLUMN_RIGHT, m_iAvatarWidth ); + } + m_pPlayerList->AddColumnToSection(m_iSectionId, "name", "#Spectators", 0, scheme()->GetProportionalScaledValueEx( GetScheme(),NAME_WIDTH) - m_iAvatarWidth ); m_pPlayerList->AddColumnToSection(m_iSectionId, "frags", "", 0, scheme()->GetProportionalScaledValueEx( GetScheme(),SCORE_WIDTH) ); } } @@ -408,20 +484,55 @@ bool CClientScoreBoardDialog::GetPlayerScoreInfo(int playerIndex, KeyValues *kv) kv->SetString("name", gr->GetPlayerName( playerIndex ) ); kv->SetInt("playerIndex", playerIndex); -// kv->SetInt("voice", s_VoiceImage[GetClientVoice()->GetSpeakerStatus( playerIndex - 1) ]); + return true; +} -/* // setup the tracker column - if (g_pFriendsUser) +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CClientScoreBoardDialog::UpdatePlayerAvatar( int playerIndex, KeyValues *kv ) +{ + // Update their avatar + if ( kv && ShowAvatars() && steamapicontext->SteamFriends() && steamapicontext->SteamUtils() ) { - unsigned int trackerID = gEngfuncs.GetTrackerIDForPlayer(row); - - if (g_pFriendsUser->IsBuddy(trackerID) && trackerID != g_pFriendsUser->GetFriendsID()) + player_info_t pi; + if ( engine->GetPlayerInfo( playerIndex, &pi ) ) { - kv->SetInt("tracker",TrackerImage); + if ( pi.friendsID ) + { + CSteamID steamIDForPlayer( pi.friendsID, 1, steamapicontext->SteamUtils()->GetConnectedUniverse(), k_EAccountTypeIndividual ); + + // See if the avatar's changed + int iAvatar = steamapicontext->SteamFriends()->GetFriendAvatar( steamIDForPlayer ); + if ( m_iImageAvatars[playerIndex] != iAvatar ) + { + m_iImageAvatars[playerIndex] = iAvatar; + + // Now see if we already have that avatar in our list + int iIndex = m_mapAvatarsToImageList.Find( iAvatar ); + if ( iIndex == m_mapAvatarsToImageList.InvalidIndex() ) + { + CAvatarImage *pImage = new CAvatarImage(); + pImage->SetAvatarSteamID( steamIDForPlayer ); + pImage->SetAvatarSize( 32, 32 ); // Deliberately non scaling + int iImageIndex = m_pImageList->AddImage( pImage ); + + m_mapAvatarsToImageList.Insert( iAvatar, iImageIndex ); + } + } + + int iIndex = m_mapAvatarsToImageList.Find( iAvatar ); + + if ( iIndex != m_mapAvatarsToImageList.InvalidIndex() ) + { + kv->SetInt( "avatar", m_mapAvatarsToImageList[iIndex] ); + + CAvatarImage *pAvIm = (CAvatarImage *)m_pImageList->GetImage( m_mapAvatarsToImageList[iIndex] ); + pAvIm->UpdateFriendStatus(); + } + } } } -*/ - return true; } //----------------------------------------------------------------------------- @@ -454,9 +565,6 @@ int CClientScoreBoardDialog::FindItemIDForPlayerIndex(int playerIndex) return -1; } - - - //----------------------------------------------------------------------------- // Purpose: Sets the text of a control by name //----------------------------------------------------------------------------- @@ -469,3 +577,13 @@ void CClientScoreBoardDialog::MoveLabelToFront(const char *textEntryName) } } +//----------------------------------------------------------------------------- +// Purpose: Center the dialog on the screen. (vgui has this method on +// Frame, but we're an EditablePanel, need to roll our own.) +//----------------------------------------------------------------------------- +void CClientScoreBoardDialog::MoveToCenterOfScreen() +{ + int wx, wy, ww, wt; + surface()->GetWorkspaceBounds(wx, wy, ww, wt); + SetPos((ww - GetWide()) / 2, (wt - GetTall()) / 2); +} diff --git a/src/src/cl_dll/game_controls/clientscoreboarddialog.h b/src/src/game/client/game_controls/clientscoreboarddialog.h similarity index 63% rename from src/src/cl_dll/game_controls/clientscoreboarddialog.h rename to src/src/game/client/game_controls/clientscoreboarddialog.h index 85acca5..7ecbaa2 100644 --- a/src/src/cl_dll/game_controls/clientscoreboarddialog.h +++ b/src/src/game/client/game_controls/clientscoreboarddialog.h @@ -11,23 +11,24 @@ #pragma once #endif -#include -#include -#include +#include +#include +#include "gameeventlistener.h" #define TYPE_NOTEAM 0 // NOTEAM must be zero :) #define TYPE_TEAM 1 // a section for a single team -#define TYPE_SPECTATORS 2 // a section for a spectator group -#define TYPE_BLANK 3 +#define TYPE_PLAYERS 2 +#define TYPE_SPECTATORS 3 // a section for a spectator group +#define TYPE_BLANK 4 //----------------------------------------------------------------------------- // Purpose: Game ScoreBoard //----------------------------------------------------------------------------- -class CClientScoreBoardDialog : public vgui::Frame, public IViewPortPanel, public IGameEventListener2 +class CClientScoreBoardDialog : public vgui::EditablePanel, public IViewPortPanel, public CGameEventListener { private: - DECLARE_CLASS_SIMPLE( CClientScoreBoardDialog, vgui::Frame ); + DECLARE_CLASS_SIMPLE( CClientScoreBoardDialog, vgui::EditablePanel ); protected: // column widths at 640 @@ -36,7 +37,7 @@ protected: public: CClientScoreBoardDialog( IViewPort *pViewPort ); - virtual ~CClientScoreBoardDialog(); + ~CClientScoreBoardDialog(); virtual const char *GetName( void ) { return PANEL_SCOREBOARD; } virtual void SetData(KeyValues *data) {}; @@ -46,6 +47,8 @@ public: virtual bool HasInputElements( void ) { return true; } virtual void ShowPanel( bool bShow ); + virtual bool ShowAvatars() { return IsPC(); } + // both vgui::Frame and IViewPortPanel define these, so explicitly define them here as passthroughs to vgui vgui::VPANEL GetVPanel( void ) { return BaseClass::GetVPanel(); } virtual bool IsVisible() { return BaseClass::IsVisible(); } @@ -53,23 +56,29 @@ public: // IGameEventListener interface: virtual void FireGameEvent( IGameEvent *event); - + virtual void UpdatePlayerAvatar( int playerIndex, KeyValues *kv ); + protected: + MESSAGE_FUNC_INT( OnPollHideCode, "PollHideCode", code ); + // functions to override virtual bool GetPlayerScoreInfo(int playerIndex, KeyValues *outPlayerInfo); virtual void InitScoreboardSections(); virtual void UpdateTeamInfo(); virtual void UpdatePlayerInfo(); - + virtual void OnThink(); virtual void AddHeader(); // add the start header of the scoreboard virtual void AddSection(int teamType, int teamNumber); // add a new section header for a team + virtual int GetAdditionalHeight() { return 0; } // sorts players within a section static bool StaticPlayerSortFunc(vgui::SectionedListPanel *list, int itemID1, int itemID2); virtual void ApplySchemeSettings(vgui::IScheme *pScheme); + virtual void PostApplySchemeSettings( vgui::IScheme *pScheme ); + // finds the player in the scoreboard int FindItemIDForPlayerIndex(int playerIndex); @@ -81,15 +90,27 @@ protected: int s_VoiceImage[5]; int TrackerImage; int m_HLTVSpectators; + float m_fNextUpdateTime; void MoveLabelToFront(const char *textEntryName); + void MoveToCenterOfScreen(); + + vgui::ImageList *m_pImageList; + int m_iImageAvatars[MAX_PLAYERS+1]; + CUtlMap m_mapAvatarsToImageList; + + CPanelAnimationVar( int, m_iAvatarWidth, "avatar_width", "34" ); // Avatar width doesn't scale with resolution + CPanelAnimationVarAliasType( int, m_iNameWidth, "name_width", "136", "proportional_int" ); + CPanelAnimationVarAliasType( int, m_iClassWidth, "class_width", "35", "proportional_int" ); + CPanelAnimationVarAliasType( int, m_iScoreWidth, "score_width", "35", "proportional_int" ); + CPanelAnimationVarAliasType( int, m_iDeathWidth, "death_width", "35", "proportional_int" ); + CPanelAnimationVarAliasType( int, m_iPingWidth, "ping_width", "23", "proportional_int" ); private: int m_iPlayerIndexSymbol; int m_iDesiredHeight; IViewPort *m_pViewPort; - float m_fNextUpdateTime; - + ButtonCode_t m_nCloseKey; // methods diff --git a/src/src/cl_dll/game_controls/commandmenu.cpp b/src/src/game/client/game_controls/commandmenu.cpp similarity index 93% rename from src/src/cl_dll/game_controls/commandmenu.cpp rename to src/src/game/client/game_controls/commandmenu.cpp index 1ab4e20..cbfe3a5 100644 --- a/src/src/cl_dll/game_controls/commandmenu.cpp +++ b/src/src/game/client/game_controls/commandmenu.cpp @@ -1,9 +1,9 @@ -//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: // // $NoKeywords: $ -//=============================================================================// +//===========================================================================// #include "cbase.h" #include @@ -35,7 +35,7 @@ bool CommandMenu::LoadFromFile( const char * fileName) // load menu from KeyValu { KeyValues * kv = new KeyValues(fileName); - if ( !kv->LoadFromFile( vgui::filesystem(), fileName, "GAME" ) ) + if ( !kv->LoadFromFile( g_pFullFileSystem, fileName, "GAME" ) ) return false; bool ret = LoadFromKeyValues( kv ); @@ -61,18 +61,18 @@ void CommandMenu::OnMessage(const KeyValues *params, VPANEL fromPanel) if ( text[0] ) { - ConVar * convar = (ConVar*) cvar->FindVar( text ); - if ( convar ) + ConVarRef convar( text ); + if ( convar.IsValid() ) { - // toggel cvar + // toggle cvar - if ( convar->GetInt() ) + if ( convar.GetInt() ) { - convar->SetValue( 0 ); + convar.SetValue( 0 ); } else { - convar->SetValue( 1 ); + convar.SetValue( 1 ); } UpdateMenu(); @@ -213,11 +213,11 @@ void CommandMenu::UpdateMenu() if ( text[0] ) { // set toggle state equal to cvar state - ConVar * convar = (ConVar*) cvar->FindVar( text ); + ConVarRef convar( text ); - if ( convar ) + if ( convar.IsValid() ) { - menuitem.menu->SetMenuItemChecked( menuitem.itemnr, convar->GetBool() ); + menuitem.menu->SetMenuItemChecked( menuitem.itemnr, convar.GetBool() ); } } } diff --git a/src/src/cl_dll/game_controls/commandmenu.h b/src/src/game/client/game_controls/commandmenu.h similarity index 87% rename from src/src/cl_dll/game_controls/commandmenu.h rename to src/src/game/client/game_controls/commandmenu.h index e6943b0..5a8a414 100644 --- a/src/src/cl_dll/game_controls/commandmenu.h +++ b/src/src/game/client/game_controls/commandmenu.h @@ -1,11 +1,4 @@ -//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// -// -// Purpose: -// -// $NoKeywords: $ -// -//=============================================================================// - //========= Copyright © 1996-2003, Valve LLC, All rights reserved. ============ +//========= Copyright © 1996-2003, Valve LLC, All rights reserved. ============ // // Purpose: // @@ -17,7 +10,7 @@ #define COMMANDMENU_H #include -#include +#include #include #include "UtlStack.h" #include "UtlVector.h" diff --git a/src/src/game/client/game_controls/iconpanel.cpp b/src/src/game/client/game_controls/iconpanel.cpp new file mode 100644 index 0000000..797a87c --- /dev/null +++ b/src/src/game/client/game_controls/iconpanel.cpp @@ -0,0 +1,68 @@ +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include "iconpanel.h" +#include "KeyValues.h" + +DECLARE_BUILD_FACTORY( CIconPanel ); + +CIconPanel::CIconPanel( vgui::Panel *parent, const char *name ) : vgui::Panel( parent, name ) +{ + m_szIcon[0] = '\0'; + m_icon = NULL; + m_bScaleImage = false; +} + +void CIconPanel::ApplySettings( KeyValues *inResourceData ) +{ + Q_strncpy( m_szIcon, inResourceData->GetString( "icon", "" ), sizeof( m_szIcon ) ); + + m_icon = gHUD.GetIcon( m_szIcon ); + + m_bScaleImage = inResourceData->GetInt("scaleImage", 0); + + BaseClass::ApplySettings( inResourceData ); +} + +void CIconPanel::SetIcon( const char *szIcon ) +{ + Q_strncpy( m_szIcon, szIcon, sizeof(m_szIcon) ); + + m_icon = gHUD.GetIcon( m_szIcon ); +} + +void CIconPanel::Paint() +{ + BaseClass::Paint(); + + if ( m_icon ) + { + int x, y, w, h; + GetBounds( x, y, w, h ); + + if ( m_bScaleImage ) + { + m_icon->DrawSelf( 0, 0, w, h, m_IconColor ); + } + else + { + m_icon->DrawSelf( 0, 0, m_IconColor ); + } + } +} + +void CIconPanel::ApplySchemeSettings( vgui::IScheme *pScheme ) +{ + BaseClass::ApplySchemeSettings( pScheme ); + + if ( m_szIcon[0] != '\0' ) + { + m_icon = gHUD.GetIcon( m_szIcon ); + } + + SetFgColor( pScheme->GetColor( "FgColor", Color( 255, 255, 255, 255 ) ) ); +} diff --git a/src/src/game/client/game_controls/iconpanel.h b/src/src/game/client/game_controls/iconpanel.h new file mode 100644 index 0000000..13834a4 --- /dev/null +++ b/src/src/game/client/game_controls/iconpanel.h @@ -0,0 +1,41 @@ +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef ICONPANEL_H +#define ICONPANEL_H +#ifdef _WIN32 +#pragma once +#endif + +#include + +using namespace vgui; + +class CIconPanel : public vgui::Panel +{ + DECLARE_CLASS_SIMPLE( CIconPanel, vgui::Panel ); + +public: + CIconPanel( vgui::Panel *parent, const char *name ); + + void Init( void ); + virtual void Paint(); + virtual void ApplySettings( KeyValues *inResourceData ); + virtual void ApplySchemeSettings( vgui::IScheme *pScheme ); + + void SetIcon( const char *szIcon ); + +private: + CHudTexture *m_icon; + char m_szIcon[128]; + + bool m_bScaleImage; + + CPanelAnimationVar( Color, m_IconColor, "iconColor", "255 255 255 255" ); +}; + +#endif //ICONPANEL_H \ No newline at end of file diff --git a/src/src/game/client/game_controls/imagemouseoverbutton.h b/src/src/game/client/game_controls/imagemouseoverbutton.h new file mode 100644 index 0000000..ff9dcba --- /dev/null +++ b/src/src/game/client/game_controls/imagemouseoverbutton.h @@ -0,0 +1,262 @@ +//========= Copyright © 1996-2006, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef IMAGE_MOUSE_OVER_BUTTON_H +#define IMAGE_MOUSE_OVER_BUTTON_H + +#include "vgui/isurface.h" +#include "mouseoverpanelbutton.h" + +//=============================================== +// CImageMouseOverButton - used for class images +//=============================================== + +template +class CImageMouseOverButton : public MouseOverButton +{ +private: + //DECLARE_CLASS_SIMPLE( CImageMouseOverButton, MouseOverButton ); + +public: + CImageMouseOverButton( vgui::Panel *parent, const char *panelName, T *templatePanel ); + + virtual void ApplySettings( KeyValues *inResourceData ); + virtual void ApplySchemeSettings( vgui::IScheme *pScheme ); + virtual void OnSizeChanged( int newWide, int newTall ); + + void RecalculateImageSizes( void ); + void SetActiveImage( const char *imagename ); + void SetInactiveImage( const char *imagename ); + void SetActiveImage( vgui::IImage *image ); + void SetInactiveImage( vgui::IImage *image ); + +public: + virtual void Paint(); + virtual void ShowPage( void ); + virtual void HidePage( void ); + +private: + vgui::IImage *m_pActiveImage; + char *m_pszActiveImageName; + + vgui::IImage *m_pInactiveImage; + char *m_pszInactiveImageName; + + bool m_bScaleImage; +}; + +template +CImageMouseOverButton::CImageMouseOverButton( vgui::Panel *parent, const char *panelName, T *templatePanel ) : + MouseOverButton( parent, panelName, templatePanel ) +{ + m_pszActiveImageName = NULL; + m_pszInactiveImageName = NULL; + + m_pActiveImage = NULL; + m_pInactiveImage = NULL; +} + +template +void CImageMouseOverButton::ApplySettings( KeyValues *inResourceData ) +{ + m_bScaleImage = inResourceData->GetInt( "scaleImage", 0 ); + + // Active Image + delete [] m_pszActiveImageName; + m_pszActiveImageName = NULL; + + const char *activeImageName = inResourceData->GetString( "activeimage", "" ); + if ( *activeImageName ) + { + SetActiveImage( activeImageName ); + } + + // Inactive Image + delete [] m_pszInactiveImageName; + m_pszInactiveImageName = NULL; + + const char *inactiveImageName = inResourceData->GetString( "inactiveimage", "" ); + if ( *inactiveImageName ) + { + SetInactiveImage( inactiveImageName ); + } + + MouseOverButton::ApplySettings( inResourceData ); + + InvalidateLayout( false, true ); // force applyschemesettings to run +} + +template +void CImageMouseOverButton::ApplySchemeSettings( vgui::IScheme *pScheme ) +{ + MouseOverButton::ApplySchemeSettings( pScheme ); + + if ( m_pszActiveImageName && strlen( m_pszActiveImageName ) > 0 ) + { + SetActiveImage(scheme()->GetImage( m_pszActiveImageName, m_bScaleImage ) ); + } + + if ( m_pszInactiveImageName && strlen( m_pszInactiveImageName ) > 0 ) + { + SetInactiveImage(scheme()->GetImage( m_pszInactiveImageName, m_bScaleImage ) ); + } + + IBorder *pBorder = pScheme->GetBorder( "NoBorder" ); + SetDefaultBorder( pBorder); + SetDepressedBorder( pBorder ); + SetKeyFocusBorder( pBorder ); + + Color defaultFgColor = GetSchemeColor( "Button.TextColor", Color(255, 255, 255, 255), pScheme ); + Color armedFgColor = GetSchemeColor( "Button.ArmedTextColor", Color(255, 255, 255, 255), pScheme ); + Color depressedFgColor = GetSchemeColor( "Button.DepressedTextColor", Color(255, 255, 255, 255), pScheme ); + + Color blank(0,0,0,0); + SetDefaultColor( defaultFgColor, blank ); + SetArmedColor( armedFgColor, blank ); + SetDepressedColor( depressedFgColor, blank ); +} + +template +void CImageMouseOverButton::RecalculateImageSizes( void ) +{ + // Reset our images, which will force them to recalculate their size. + // Necessary for images shared with other scaling buttons. + SetActiveImage( m_pActiveImage ); + SetInactiveImage( m_pInactiveImage ); +} + +template +void CImageMouseOverButton::SetActiveImage( const char *imagename ) +{ + int len = Q_strlen( imagename ) + 1; + m_pszActiveImageName = new char[ len ]; + Q_strncpy( m_pszActiveImageName, imagename, len ); +} + +template +void CImageMouseOverButton::SetInactiveImage( const char *imagename ) +{ + int len = Q_strlen( imagename ) + 1; + m_pszInactiveImageName = new char[ len ]; + Q_strncpy( m_pszInactiveImageName, imagename, len ); +} + +template +void CImageMouseOverButton::SetActiveImage( vgui::IImage *image ) +{ + m_pActiveImage = image; + + if ( m_pActiveImage ) + { + int wide, tall; + if ( m_bScaleImage ) + { + // scaling, force the image size to be our size + GetSize( wide, tall ); + m_pActiveImage->SetSize( wide, tall ); + } + else + { + // not scaling, so set our size to the image size + m_pActiveImage->GetSize( wide, tall ); + SetSize( wide, tall ); + } + } + + Repaint(); +} + +template +void CImageMouseOverButton::SetInactiveImage( vgui::IImage *image ) +{ + m_pInactiveImage = image; + + if ( m_pInactiveImage ) + { + int wide, tall; + if ( m_bScaleImage) + { + // scaling, force the image size to be our size + GetSize( wide, tall ); + m_pInactiveImage->SetSize( wide, tall ); + } + else + { + // not scaling, so set our size to the image size + m_pInactiveImage->GetSize( wide, tall ); + SetSize( wide, tall ); + } + } + + Repaint(); +} + +template +void CImageMouseOverButton::OnSizeChanged( int newWide, int newTall ) +{ + if ( m_bScaleImage ) + { + // scaling, force the image size to be our size + + if ( m_pActiveImage ) + m_pActiveImage->SetSize( newWide, newTall ); + + if ( m_pInactiveImage ) + m_pInactiveImage->SetSize( newWide, newTall ); + } + MouseOverButton::OnSizeChanged( newWide, newTall ); +} + +template +void CImageMouseOverButton::Paint() +{ + SetActiveImage( m_pActiveImage ); + SetInactiveImage( m_pInactiveImage ); + + if ( IsArmed() ) + { + // draw the active image + if ( m_pActiveImage ) + { + vgui::surface()->DrawSetColor( 255, 255, 255, 255 ); + m_pActiveImage->SetPos( 0, 0 ); + m_pActiveImage->Paint(); + } + } + else + { + // draw the inactive image + if ( m_pInactiveImage ) + { + vgui::surface()->DrawSetColor( 255, 255, 255, 255 ); + m_pInactiveImage->SetPos( 0, 0 ); + m_pInactiveImage->Paint(); + } + } + + MouseOverButton::Paint(); +} + +template +void CImageMouseOverButton::ShowPage( void ) +{ + MouseOverButton::ShowPage(); + + // send message to parent that we triggered something + PostActionSignal( new KeyValues( "ShowPage", "page", GetName() ) ); +} + +template +void CImageMouseOverButton::HidePage( void ) +{ + MouseOverButton::HidePage(); + + // send message to parent that we triggered something + PostActionSignal( new KeyValues( "ShowPage", "page", GetName() ) ); +} + +#endif //IMAGE_MOUSE_OVER_BUTTON_H \ No newline at end of file diff --git a/src/src/game/client/game_controls/intromenu.cpp b/src/src/game/client/game_controls/intromenu.cpp new file mode 100644 index 0000000..6c045d6 --- /dev/null +++ b/src/src/game/client/game_controls/intromenu.cpp @@ -0,0 +1,122 @@ +//====== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======= +// +// Purpose: +// +//============================================================================= + +#include "cbase.h" +#include "intromenu.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "spectatorgui.h" +#include "gamerules.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +using namespace vgui; + +//----------------------------------------------------------------------------- +// Purpose: Constructor +//----------------------------------------------------------------------------- +CIntroMenu::CIntroMenu( IViewPort *pViewPort ) : Frame( NULL, PANEL_INTRO ) +{ + // initialize dialog + m_pViewPort = pViewPort; + + m_pTitleLabel = NULL; + + // load the new scheme early!! + SetScheme( "ClientScheme" ); + SetMoveable( false ); + SetSizeable( false ); + SetProportional( true ); + + // hide the system buttons + SetTitleBarVisible( false ); + + Reset(); +} + +//----------------------------------------------------------------------------- +// Purpose: Destructor +//----------------------------------------------------------------------------- +CIntroMenu::~CIntroMenu() +{ +} + +//----------------------------------------------------------------------------- +// Purpose: Sets the color of the top and bottom bars +//----------------------------------------------------------------------------- +void CIntroMenu::ApplySchemeSettings( IScheme *pScheme ) +{ + BaseClass::ApplySchemeSettings( pScheme ); + + LoadControlSettings("Resource/UI/IntroMenu.res"); + + m_pTitleLabel = dynamic_cast