mirror of
https://github.com/alliedmodders/hl2sdk.git
synced 2025-01-09 18:48:51 +08:00
3776 lines
120 KiB
C++
3776 lines
120 KiB
C++
#include "cbase.h"
|
|
#include "precache_register.h"
|
|
#include "FX_Sparks.h"
|
|
#include "iefx.h"
|
|
#include "c_te_effect_dispatch.h"
|
|
#include "particles_ez.h"
|
|
#include "decals.h"
|
|
#include "engine/IEngineSound.h"
|
|
#include "fx_quad.h"
|
|
#include "engine/IVDebugOverlay.h"
|
|
#include "shareddefs.h"
|
|
#include "fx_blood.h"
|
|
#include "effect_color_tables.h"
|
|
#include "fx.h"
|
|
#include "c_asw_fx.h"
|
|
#include "c_asw_generic_emitter_entity.h"
|
|
#include "c_asw_mesh_emitter_entity.h"
|
|
#include "asw_shareddefs.h"
|
|
#include "beamdraw.h"
|
|
#include "iviewrender_beams.h"
|
|
#include "IEffects.h"
|
|
#include "view.h"
|
|
#include "soundemittersystem/isoundemittersystembase.h"
|
|
#include "studio.h"
|
|
#include "bone_setup.h"
|
|
#include "engine/ivmodelinfo.h"
|
|
#include "tier0/vprof.h"
|
|
#include "c_user_message_register.h"
|
|
#include "c_asw_marine.h"
|
|
#include "c_asw_weapon.h"
|
|
#include "c_asw_alien.h"
|
|
#include "datacache/imdlcache.h"
|
|
#include "c_asw_level_exploder.h"
|
|
#include "fx_explosion.h"
|
|
#include "particles_localspace.h"
|
|
#include "toolframework_client.h"
|
|
#include "tier1/keyvalues.h"
|
|
#include "asw_fx_shared.h"
|
|
#include "c_asw_alien.h"
|
|
#include "shake.h"
|
|
#include "ivieweffects.h"
|
|
#include "asw_marine_shared.h"
|
|
#include "c_asw_egg.h"
|
|
|
|
// memdbgon must be the last include file in a .cpp file!!!
|
|
#include "tier0/memdbgon.h"
|
|
|
|
ConVar asw_gib_bleed_time("asw_gib_bleed_time", "1.5", 0, "How long drone gibs bleed for");
|
|
ConVar asw_pierce_spark_scale("asw_pierce_spark_scale", "0.9", 0, "Scale applied to piercing spark effect");
|
|
ConVar asw_tracer_style("asw_tracer_style", "1", FCVAR_ARCHIVE, "Specify tracer style. 0=none 1=normal 2=grey line");
|
|
ConVar asw_use_particle_tracers( "asw_use_particle_tracers", "1", FCVAR_REPLICATED | FCVAR_CHEAT, "Use particle tracers instead of the old school HL2 ones" );
|
|
|
|
extern ConVar asw_muzzle_flash_new_type;
|
|
|
|
PRECACHE_REGISTER_BEGIN( GLOBAL, PrecacheASW )
|
|
PRECACHE( MATERIAL, "swarm/effects/aswtracer" )
|
|
PRECACHE( MATERIAL, "swarm/effects/aswtracernormal" )
|
|
PRECACHE( MATERIAL, "swarm/effects/aswtracerred" )
|
|
PRECACHE( MATERIAL, "swarm/effects/aswtracernormalred" )
|
|
PRECACHE( MATERIAL, "swarm/effects/muzzleflashred1" )
|
|
PRECACHE( MATERIAL, "swarm/effects/muzzleflashred2" )
|
|
PRECACHE( MATERIAL, "swarm/effects/muzzleflashred3" )
|
|
PRECACHE( MATERIAL, "swarm/effects/muzzleflashred4" )
|
|
|
|
// precache textures used by vgui panels (is there a better place for this?)
|
|
PRECACHE( MATERIAL, "vgui/swarm/computer/computerscan" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/computer/computerbackdrop" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/computer/computerbackdropred" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/computer/iconcamera" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/computer/iconcamerastriped" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/computer/iconcog" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/computer/iconcogstriped" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/computer/iconfiles" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/computer/iconfilesstriped" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/computer/iconfolder" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/computer/iconfolderstriped" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/computer/iconmail" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/computer/iconmailstriped" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/computer/iconnewslcd" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/computer/iconnewslcdstriped" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/computer/iconstocks" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/computer/iconstocksstriped" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/computer/iconweather" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/computer/iconweatherstriped" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/computer/iconsinglefile" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/computer/iconturret" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/computer/iconturretstriped" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/computer/windowclose" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/computer/synteklogo2" )
|
|
|
|
PRECACHE( MATERIAL, "vgui/swarm/computer/tumblerswitchdirection" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/computer/tumblerswitchdirection_over" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/computer/TumblerSwitchUP" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/computer/TumblerSwitchUPMOUSE" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/computer/TumblerSwitchDOWN" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/computer/TumblerSwitchDOWNMOUSE" )
|
|
|
|
PRECACHE( MATERIAL, "vgui/swarm/computer/windowminimise" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/hacking/tilehoriz" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/hacking/tileleft" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/hacking/tileright" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/hacking/leftconnect" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/hacking/rightconnect" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/hacking/swarmdoorhackopen" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/hacking/fastmarker" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/hud/tickboxticked" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/hud/horizdoorhealthbar" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/hud/horizdoorhealthbarr" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/hud/horizdoorhealthbari" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/hud/doorhealth" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/hud/doorweld" )
|
|
|
|
//PRECACHE( MATERIAL, "vgui/swarm/briefing/statshots" )
|
|
//PRECACHE( MATERIAL, "vgui/swarm/briefing/statdamage" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/briefing/skillparticle" )
|
|
PRECACHE( MATERIAL, "vgui/icon_button_arrow_right" )
|
|
|
|
//PRECACHE( MATERIAL, "vgui/swarm/briefing/statkilled" )
|
|
//PRECACHE( MATERIAL, "vgui/swarm/briefing/stattime" )
|
|
//PRECACHE( MATERIAL, "vgui/swarm/briefing/stataccuracy" )
|
|
//PRECACHE( MATERIAL, "vgui/swarm/briefing/statfriendly" )
|
|
//PRECACHE( MATERIAL, "vgui/swarm/briefing/statshots2" )
|
|
//PRECACHE( MATERIAL, "vgui/swarm/briefing/statskillpoints" )
|
|
//PRECACHE( MATERIAL, "vgui/swarm/briefing/statburned" )
|
|
//PRECACHE( MATERIAL, "vgui/swarm/briefing/statheal" )
|
|
//PRECACHE( MATERIAL, "vgui/swarm/briefing/stathack" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/briefing/topleftbracket" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/briefing/toprightbracket" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/briefing/bottomleftbracket" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/briefing/bottomrightbracket" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/briefing/shadedbutton" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/briefing/shadedbutton_over" )
|
|
//PRECACHE( MATERIAL, "vgui/swarm/ObjectiveIcons/OIconBloodhound" )
|
|
//PRECACHE( MATERIAL, "vgui/swarm/ObjectiveIcons/OIconCargoForklift" )
|
|
//PRECACHE( MATERIAL, "vgui/swarm/ObjectiveIcons/OIconDroneSide" )
|
|
//PRECACHE( MATERIAL, "vgui/swarm/ObjectiveIcons/OIconDroneTop" )
|
|
//PRECACHE( MATERIAL, "vgui/swarm/ObjectiveIcons/OIconEgg" )
|
|
//PRECACHE( MATERIAL, "vgui/swarm/ObjectiveIcons/OIconParasiteSide" )
|
|
//PRECACHE( MATERIAL, "vgui/swarm/ObjectiveIcons/OIconParasiteTop" )
|
|
//PRECACHE( MATERIAL, "vgui/swarm/ObjectiveIcons/OIconPlanet" )
|
|
//PRECACHE( MATERIAL, "vgui/swarm/ObjectiveIcons/OIconSolarSystem" )
|
|
//PRECACHE( MATERIAL, "vgui/swarm/ObjectiveIcons/OIconStarchart" )
|
|
//PRECACHE( MATERIAL, "vgui/swarm/ObjectiveIcons/OIconTerminal" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/SkillButtons/Accuracy" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/SkillButtons/Agility" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/SkillButtons/Autogun" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/SkillButtons/Drugs" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/SkillButtons/Engineering" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/SkillButtons/Grenade" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/SkillButtons/Hacking" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/SkillButtons/Healing" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/SkillButtons/Health" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/SkillButtons/Leadership" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/SkillButtons/Melee" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/SkillButtons/Piercing" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/SkillButtons/Scanner" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/SkillButtons/Secondary" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/SkillButtons/SkillIncendiary" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/SkillButtons/SkillPlus" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/SkillButtons/SkillReload" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/SkillButtons/Vindicator" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/SkillButtons/Xenowound" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/SkillButtons/Accuracy_over" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/SkillButtons/Agility_over" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/SkillButtons/Autogun_over" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/SkillButtons/Drugs_over" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/SkillButtons/Engineering_over" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/SkillButtons/Grenade_over" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/SkillButtons/Hacking_over" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/SkillButtons/Healing_over" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/SkillButtons/Health_over" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/SkillButtons/Leadership_over" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/SkillButtons/Melee_over" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/SkillButtons/Piercing_over" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/SkillButtons/Scanner_over" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/SkillButtons/Secondary_over" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/SkillButtons/SkillIncendiary_over" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/SkillButtons/SkillPlus_over" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/SkillButtons/SkillReload_over" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/SkillButtons/Vindicator_over" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/SkillButtons/Xenowound_over" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/playerlist/booticon" )
|
|
PRECACHE( MATERIAL, "vgui/swarm/playerlist/leadericon" )
|
|
PRECACHE( PARTICLE_SYSTEM, "weapon_shell_casing_rifle" )
|
|
PRECACHE( PARTICLE_SYSTEM, "weapon_shell_casing_shotgun" )
|
|
PRECACHE( PARTICLE_SYSTEM, "snow_explosion" )
|
|
PRECACHE( PARTICLE_SYSTEM, "impact_steam" )
|
|
PRECACHE( PARTICLE_SYSTEM, "impact_steam_small" )
|
|
PRECACHE( PARTICLE_SYSTEM, "impact_steam_short" )
|
|
PRECACHE_REGISTER_END()
|
|
|
|
#define ASW_BLOOD_BRIGHTNESS 0.25f
|
|
//#define ASW_DO_BLOOD_LIGHT_CALCS // define to make blood particle systems scale color/alpha by light at that point
|
|
|
|
extern void GetBloodColor( int bloodtype, colorentry_t &color );
|
|
extern PMaterialHandle g_Material_Spark;
|
|
PMaterialHandle g_Material_Blue_nocull;
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Used for bullets hitting bleeding surfaces
|
|
//-----------------------------------------------------------------------------
|
|
void ASW_FX_BloodBulletImpact( const Vector &origin, const Vector &normal, float scale, unsigned char r, unsigned char g, unsigned char b )
|
|
{
|
|
if ( UTIL_IsLowViolence() )
|
|
return;
|
|
|
|
Vector offset;
|
|
#ifdef ASW_DO_BLOOD_LIGHT_CALCS
|
|
Vector color = engine->GetLightForPointFast(origin, true);
|
|
color.x = LinearToTexture( color.x ) / 255.0f;
|
|
color.y = LinearToTexture( color.y ) / 255.0f;
|
|
color.z = LinearToTexture( color.z ) / 255.0f;
|
|
|
|
// only use half of lighting
|
|
color.x += (1.0f - color.x) * ASW_BLOOD_BRIGHTNESS;
|
|
color.y += (1.0f - color.y) * ASW_BLOOD_BRIGHTNESS;
|
|
color.z += (1.0f - color.z) * ASW_BLOOD_BRIGHTNESS;
|
|
|
|
color.x *= (r/255.0f);
|
|
color.y *= (g/255.0f);
|
|
color.z *= (b/255.0f);
|
|
#else
|
|
Vector color = Vector(r/255.0f,g/255.0f,b/255.0f);
|
|
#endif
|
|
float colorRamp;
|
|
|
|
Vector offDir;
|
|
|
|
CSmartPtr<CBloodSprayEmitter> pSimple = CBloodSprayEmitter::Create( "bloodgore" );
|
|
if ( !pSimple )
|
|
return;
|
|
|
|
pSimple->SetSortOrigin( origin );
|
|
pSimple->SetGravity( 0 );
|
|
|
|
// Blood impact
|
|
PMaterialHandle hMaterial = ParticleMgr()->GetPMaterial( "effects/blood_core" );
|
|
|
|
SimpleParticle *pParticle;
|
|
|
|
Vector dir = normal * RandomVector( -0.5f, 0.5f );
|
|
|
|
offset = origin + ( 2.0f * normal );
|
|
|
|
pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), hMaterial, offset );
|
|
|
|
if ( pParticle != NULL )
|
|
{
|
|
pParticle->m_flLifetime = 0.0f;
|
|
pParticle->m_flDieTime = random->RandomFloat( 0.25f, 0.5f) * 1.5f;
|
|
|
|
pParticle->m_vecVelocity = dir * random->RandomFloat( 16.0f, 32.0f );
|
|
pParticle->m_vecVelocity[2] -= random->RandomFloat( 8.0f, 16.0f );
|
|
|
|
colorRamp = random->RandomFloat( 0.75f, 2.0f );
|
|
|
|
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( 3, 3 ) * scale; // was 2 -> 4
|
|
pParticle->m_uchEndSize = pParticle->m_uchStartSize * 8 * scale;
|
|
|
|
pParticle->m_uchStartAlpha = 255.0f * ASW_BLOOD_BRIGHTNESS;
|
|
pParticle->m_uchEndAlpha = 0;
|
|
|
|
pParticle->m_flRoll = random->RandomInt( 0, 360 );
|
|
pParticle->m_flRollDelta = random->RandomFloat( -2.0f, 2.0f );
|
|
}
|
|
|
|
hMaterial = ParticleMgr()->GetPMaterial( "effects/blood_gore" );
|
|
|
|
for ( int i = 0; i < 4; i++ )
|
|
{
|
|
offset = origin + ( 2.0f * normal );
|
|
|
|
pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), hMaterial, offset );
|
|
|
|
if ( pParticle != NULL )
|
|
{
|
|
pParticle->m_flLifetime = 0.0f;
|
|
pParticle->m_flDieTime = random->RandomFloat( 0.5f, 0.75f) * 1.5f;
|
|
|
|
pParticle->m_vecVelocity = dir * random->RandomFloat( 16.0f, 32.0f )*(i+1);
|
|
pParticle->m_vecVelocity[2] -= random->RandomFloat( 32.0f, 64.0f )*(i+1);
|
|
|
|
colorRamp = random->RandomFloat( 0.75f, 2.0f );
|
|
|
|
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( 2, 2 ) * scale * 0.4; // was 1 to 2
|
|
pParticle->m_uchEndSize = pParticle->m_uchStartSize * 2 * scale * 0.4;
|
|
|
|
pParticle->m_uchStartAlpha = 255;
|
|
pParticle->m_uchEndAlpha = 0;
|
|
|
|
pParticle->m_flRoll = random->RandomInt( 0, 360 );
|
|
pParticle->m_flRollDelta = random->RandomFloat( -1.0f, 1.0f );
|
|
}
|
|
}
|
|
|
|
//
|
|
// Dump out drops
|
|
//
|
|
TrailParticle *tParticle;
|
|
|
|
CSmartPtr<CTrailParticles> pTrailEmitter = CTrailParticles::Create( "blooddrops" );
|
|
if ( !pTrailEmitter )
|
|
return;
|
|
|
|
pTrailEmitter->SetSortOrigin( origin );
|
|
|
|
// Partial gravity on blood drops
|
|
pTrailEmitter->SetGravity( 400.0 );
|
|
|
|
// Enable simple collisions with nearby surfaces
|
|
pTrailEmitter->Setup(origin, &normal, 1, 10, 100, 400, 0.2, 0 );
|
|
|
|
hMaterial = ParticleMgr()->GetPMaterial( "effects/blood_drop" );
|
|
|
|
//
|
|
// Shorter droplets
|
|
//
|
|
for ( int i = 0; i < 8; i++ )
|
|
{
|
|
// Originate from within a circle 'scale' inches in diameter
|
|
offset = origin + RandomVector(-scale, scale);
|
|
|
|
tParticle = (TrailParticle *) pTrailEmitter->AddParticle( sizeof(TrailParticle), hMaterial, offset );
|
|
|
|
if ( tParticle == NULL )
|
|
break;
|
|
|
|
tParticle->m_flLifetime = 0.0f;
|
|
|
|
offDir = RandomVector( -1.0f, 1.0f );
|
|
|
|
tParticle->m_vecVelocity = offDir * random->RandomFloat( 64.0f, 128.0f );
|
|
|
|
tParticle->m_flWidth = random->RandomFloat( 0.5f, 2.0f ) * scale;
|
|
tParticle->m_flLength = random->RandomFloat( 0.05f, 0.15f ) * scale;
|
|
tParticle->m_flDieTime = random->RandomFloat( 0.25f, 0.5f ) * 1.5f;
|
|
|
|
FloatToColor32( tParticle->m_color, color[0], color[1], color[2], 1.0f );
|
|
}
|
|
|
|
// TODO: Play a sound?
|
|
//CLocalPlayerFilter filter;
|
|
//C_BaseEntity::EmitSound( filter, SOUND_FROM_WORLD, CHAN_VOICE, "Physics.WaterSplash", 1.0, ATTN_NORM, 0, 100, &origin );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//-----------------------------------------------------------------------------
|
|
void ASW_BloodImpactCallback( const CEffectData & data )
|
|
{
|
|
Vector vecPosition;
|
|
vecPosition = data.m_vOrigin;
|
|
|
|
// Fetch the blood color.
|
|
colorentry_t color;
|
|
GetBloodColor( data.m_nColor, color );
|
|
|
|
ASW_FX_BloodBulletImpact( vecPosition, data.m_vNormal, data.m_flScale, color.r, color.g, color.b );
|
|
}
|
|
|
|
DECLARE_CLIENT_EFFECT( ASWBloodImpact, ASW_BloodImpactCallback );
|
|
|
|
|
|
void WeldSparkCallback( const CEffectData & data )
|
|
{
|
|
Vector vecNormal;
|
|
Vector vecPosition;
|
|
|
|
vecPosition = data.m_vOrigin;
|
|
vecNormal = data.m_vNormal;
|
|
|
|
FX_Sparks( vecPosition, 1, 2, vecNormal, 5, 32, 160 );
|
|
}
|
|
|
|
DECLARE_CLIENT_EFFECT( ASWWelderSparks, WeldSparkCallback );
|
|
|
|
|
|
// ==========
|
|
// Drone Gibs
|
|
// ==========
|
|
|
|
#define NUM_DRONE_GIBS_UNIQUE 16
|
|
const char *pszDroneGibs_Unique[NUM_DRONE_GIBS_UNIQUE] = {
|
|
"models/swarm/DroneGibs/dronepart01.mdl",
|
|
//"models/swarm\DroneGibs\DronePart02.mdl", // mouth
|
|
"models/swarm/DroneGibs/dronepart20.mdl",
|
|
//"models/swarm\DroneGibs\DronePart21.mdl", // eyeball
|
|
"models/swarm/DroneGibs/dronepart29.mdl",
|
|
"models/swarm/DroneGibs/dronepart31.mdl",
|
|
"models/swarm/DroneGibs/dronepart32.mdl",
|
|
//"models/swarm\DroneGibs\DronePart36.mdl", // wing
|
|
//"models/swarm\DroneGibs\DronePart37.mdl", // wing
|
|
//"models/swarm\DroneGibs\DronePart38.mdl", // wings
|
|
//"models/swarm\DroneGibs\DronePart39.mdl", // wings
|
|
"models/swarm/DroneGibs/dronepart44.mdl",
|
|
"models/swarm/DroneGibs/dronepart45.mdl",
|
|
"models/swarm/DroneGibs/dronepart47.mdl",
|
|
"models/swarm/DroneGibs/dronepart49.mdl",
|
|
"models/swarm/DroneGibs/dronepart50.mdl",
|
|
"models/swarm/DroneGibs/dronepart53.mdl",
|
|
"models/swarm/DroneGibs/dronepart54.mdl",
|
|
"models/swarm/DroneGibs/dronepart56.mdl",
|
|
"models/swarm/DroneGibs/dronepart57.mdl",
|
|
"models/swarm/DroneGibs/dronepart58.mdl",
|
|
"models/swarm/DroneGibs/dronepart59.mdl"
|
|
};
|
|
|
|
ConVar g_drone_maxgibs( "g_drone_maxgibs", "16", FCVAR_ARCHIVE );
|
|
|
|
void CDroneGibManager::LevelInitPreEntity( void )
|
|
{
|
|
m_LRU.Purge();
|
|
}
|
|
|
|
CDroneGibManager s_DroneGibManager;
|
|
|
|
void CDroneGibManager::AddGib( C_BaseEntity *pEntity )
|
|
{
|
|
m_LRU.AddToTail( pEntity );
|
|
}
|
|
|
|
void CDroneGibManager::RemoveGib( C_BaseEntity *pEntity )
|
|
{
|
|
m_LRU.FindAndRemove( pEntity );
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Methods of IGameSystem
|
|
//-----------------------------------------------------------------------------
|
|
void CDroneGibManager::Update( float frametime )
|
|
{
|
|
if ( m_LRU.Count() < g_drone_maxgibs.GetInt() )
|
|
return;
|
|
|
|
int i = 0;
|
|
i = m_LRU.Head();
|
|
|
|
if ( m_LRU[ i ].Get() )
|
|
{
|
|
m_LRU[ i ].Get()->SetNextClientThink( gpGlobals->curtime );
|
|
}
|
|
|
|
m_LRU.Remove(i);
|
|
}
|
|
|
|
// Drone gib - marks surfaces when it bounces
|
|
|
|
class C_DroneGib : public C_Gib
|
|
{
|
|
typedef C_Gib BaseClass;
|
|
public:
|
|
|
|
static C_DroneGib *C_DroneGib::CreateClientsideGib( const char *pszModelName,
|
|
Vector vecOrigin, Vector vecForceDir, AngularImpulse vecAngularImp,
|
|
float m_flLifetime = DEFAULT_GIB_LIFETIME, int skin=0 )
|
|
{
|
|
C_DroneGib *pGib = new C_DroneGib;
|
|
|
|
if ( pGib == NULL )
|
|
return NULL;
|
|
|
|
if ( pGib->InitializeGib( pszModelName, vecOrigin, vecForceDir, vecAngularImp, m_flLifetime ) == false )
|
|
return NULL;
|
|
|
|
pGib->SetSkin( skin );
|
|
|
|
s_DroneGibManager.AddGib( pGib );
|
|
|
|
// attach an emitter ot it
|
|
|
|
C_ASW_Emitter *pEmitter = new C_ASW_Emitter;
|
|
if (pEmitter)
|
|
{
|
|
if (pEmitter->InitializeAsClientEntity( NULL, false ))
|
|
{
|
|
// randomly pick a jet, a drip or a burst
|
|
float f = random->RandomFloat();
|
|
if (f < 0.33f)
|
|
Q_snprintf(pEmitter->m_szTemplateName, sizeof(pEmitter->m_szTemplateName), "dronebloodjet");
|
|
else if (f < 0.66f)
|
|
Q_snprintf(pEmitter->m_szTemplateName, sizeof(pEmitter->m_szTemplateName), "dronebloodburst");
|
|
else
|
|
Q_snprintf(pEmitter->m_szTemplateName, sizeof(pEmitter->m_szTemplateName), "droneblooddroplets");
|
|
pEmitter->m_fScale = 1.0f;
|
|
pEmitter->m_bEmit = true;
|
|
pEmitter->SetAbsOrigin(vecOrigin);
|
|
pEmitter->CreateEmitter();
|
|
pEmitter->SetAbsOrigin(vecOrigin + Vector(0,0,30));
|
|
pEmitter->SetAbsAngles(pGib->GetAbsAngles());
|
|
|
|
// randomly pick an attach point
|
|
pEmitter->ClientAttach(pGib, "bleed");
|
|
pEmitter->SetDieTime(gpGlobals->curtime + asw_gib_bleed_time.GetFloat()); // stop emitting once the ragdoll gibs
|
|
}
|
|
else
|
|
{
|
|
UTIL_Remove( pEmitter );
|
|
}
|
|
}
|
|
|
|
return pGib;
|
|
}
|
|
|
|
// Decal the surface
|
|
virtual void HitSurface( C_BaseEntity *pOther )
|
|
{
|
|
|
|
}
|
|
};
|
|
|
|
|
|
void FX_DroneBleed( const Vector &origin, const Vector &direction, float scale )
|
|
{
|
|
Vector offset;
|
|
|
|
#ifdef ASW_DO_BLOOD_LIGHT_CALCS
|
|
Vector color = engine->GetLightForPointFast(origin, true);
|
|
color.x = 0;
|
|
color.y = LinearToTexture( color.y ) / 255.0f;
|
|
color.z = 0;
|
|
|
|
// only use half of lighting
|
|
color.y += (1.0f - color.y) * ASW_BLOOD_BRIGHTNESS;
|
|
color.y *= 255.0f;
|
|
#else
|
|
Vector color(0, 255, 0);
|
|
#endif
|
|
|
|
// Throw some blood
|
|
CSmartPtr<CSimpleEmitter> pSimple = CSimpleEmitter::Create( "FX_DroneGib" );
|
|
pSimple->SetSortOrigin( origin );
|
|
|
|
PMaterialHandle hMaterial = pSimple->GetPMaterial( "effects/blood" );
|
|
|
|
Vector vDir;
|
|
|
|
vDir.Random( -1.0f, 1.0f );
|
|
|
|
for ( int i = 0; i < 4; i++ )
|
|
{
|
|
SimpleParticle *sParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), hMaterial, origin );
|
|
|
|
if ( sParticle == NULL )
|
|
return;
|
|
|
|
sParticle->m_flLifetime = 0.0f;
|
|
sParticle->m_flDieTime = random->RandomFloat( 0.5f, 0.75f );
|
|
|
|
float speed = random->RandomFloat( 16.0f, 64.0f );
|
|
|
|
sParticle->m_vecVelocity = vDir * -speed;
|
|
sParticle->m_vecVelocity[2] += 16.0f;
|
|
|
|
sParticle->m_uchColor[0] = 0;
|
|
sParticle->m_uchColor[1] = color.y;
|
|
sParticle->m_uchColor[2] = 0;
|
|
sParticle->m_uchStartAlpha = 255.0f * ASW_BLOOD_BRIGHTNESS;
|
|
sParticle->m_uchEndAlpha = 0;
|
|
sParticle->m_uchStartSize = random->RandomInt( 8, 16 );
|
|
sParticle->m_uchEndSize = sParticle->m_uchStartSize * 2;
|
|
sParticle->m_flRoll = random->RandomInt( 0, 360 );
|
|
sParticle->m_flRollDelta = random->RandomFloat( -1.0f, 1.0f );
|
|
}
|
|
|
|
hMaterial = pSimple->GetPMaterial( "effects/blood2" );
|
|
|
|
for ( int i = 0; i < 4; i++ )
|
|
{
|
|
SimpleParticle *sParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), hMaterial, origin );
|
|
|
|
if ( sParticle == NULL )
|
|
{
|
|
return;
|
|
}
|
|
|
|
sParticle->m_flLifetime = 0.0f;
|
|
sParticle->m_flDieTime = random->RandomFloat( 0.5f, 0.75f );
|
|
|
|
float speed = random->RandomFloat( 16.0f, 64.0f );
|
|
|
|
sParticle->m_vecVelocity = vDir * -speed;
|
|
sParticle->m_vecVelocity[2] += 16.0f;
|
|
|
|
sParticle->m_uchColor[0] = 0;
|
|
sParticle->m_uchColor[1] = color.y;
|
|
sParticle->m_uchColor[2] = 0;
|
|
sParticle->m_uchStartAlpha = random->RandomInt( 64, 128 );
|
|
sParticle->m_uchEndAlpha = 0;
|
|
sParticle->m_uchStartSize = random->RandomInt( 8, 16 );
|
|
sParticle->m_uchEndSize = sParticle->m_uchStartSize * 2;
|
|
sParticle->m_flRoll = random->RandomInt( 0, 360 );
|
|
sParticle->m_flRollDelta = random->RandomFloat( -1.0f, 1.0f );
|
|
}
|
|
}
|
|
|
|
void DroneBleedCallback( const CEffectData &data )
|
|
{
|
|
FX_DroneBleed( data.m_vOrigin, data.m_vNormal, data.m_flScale );
|
|
}
|
|
|
|
DECLARE_CLIENT_EFFECT( DroneBleed, DroneBleedCallback );
|
|
|
|
void FX_GibMeshEmitter( const char *szModel, const char *szTemplate, const Vector &origin, const Vector &direction, int skin, float fScale, bool bFrozen )
|
|
{
|
|
C_ASW_Mesh_Emitter *pEmitter = new C_ASW_Mesh_Emitter;
|
|
if (pEmitter)
|
|
{
|
|
if (pEmitter->InitializeAsClientEntity( szModel, false ))
|
|
{
|
|
Q_snprintf(pEmitter->m_szTemplateName, sizeof(pEmitter->m_szTemplateName), szTemplate);
|
|
pEmitter->SetSkin( skin );
|
|
pEmitter->m_fScale = fScale;
|
|
pEmitter->m_bEmit = true;
|
|
pEmitter->SetAbsOrigin(origin);
|
|
pEmitter->CreateEmitter(direction);
|
|
pEmitter->SetAbsOrigin(origin);
|
|
pEmitter->SetDieTime(gpGlobals->curtime + 15.0f);
|
|
pEmitter->SetFrozen( bFrozen );
|
|
}
|
|
else
|
|
{
|
|
UTIL_Remove( pEmitter );
|
|
}
|
|
}
|
|
}
|
|
|
|
void FX_DroneGib( const Vector &origin, const Vector &direction, float scale, int skin, bool bOnFire )
|
|
{
|
|
Vector offset;
|
|
// Throw some blood
|
|
#ifdef ASW_DO_BLOOD_LIGHT_CALCS
|
|
Vector color = engine->GetLightForPointFast(origin, true);
|
|
color.x = 0;
|
|
color.y = LinearToTexture( color.y ) / 255.0f;
|
|
color.z = 0;
|
|
|
|
// only use half of lighting
|
|
color.y += (1.0f - color.y) * ASW_BLOOD_BRIGHTNESS;
|
|
color.y *= 255.0f;
|
|
#else
|
|
Vector color(0, 255, 0);
|
|
#endif
|
|
|
|
QAngle vecAngles;
|
|
VectorAngles( -direction, vecAngles );
|
|
DispatchParticleEffect( "drone_death", origin, vecAngles );
|
|
|
|
// make our gib emitters
|
|
Vector vecForce = direction * 100.0f;
|
|
if (bOnFire)
|
|
{
|
|
FX_GibMeshEmitter("models/swarm/DroneGibs/dronepart01.mdl", "dronegibfire1", origin, vecForce, skin);
|
|
FX_GibMeshEmitter("models/swarm/DroneGibs/dronepart58.mdl", "dronegibfire1", origin, vecForce, skin);
|
|
FX_GibMeshEmitter("models/swarm/DroneGibs/dronepart29.mdl", "dronegibfire1", origin, vecForce, skin);
|
|
}
|
|
else
|
|
{
|
|
FX_GibMeshEmitter("models/swarm/DroneGibs/dronepart01.mdl", "dronegib1", origin, vecForce, skin);
|
|
FX_GibMeshEmitter("models/swarm/DroneGibs/dronepart58.mdl", "dronegib2", origin, vecForce, skin);
|
|
FX_GibMeshEmitter("models/swarm/DroneGibs/dronepart29.mdl", "dronegib3", origin, vecForce, skin);
|
|
}
|
|
}
|
|
|
|
void DroneGibCallback( const CEffectData &data )
|
|
{
|
|
FX_DroneGib( data.m_vOrigin, data.m_vNormal, data.m_flScale, data.m_nColor, (data.m_fFlags & ASW_GIBFLAG_ON_FIRE) );
|
|
}
|
|
|
|
DECLARE_CLIENT_EFFECT( DroneGib, DroneGibCallback );
|
|
|
|
|
|
|
|
void FX_HarvesterGib( const Vector &origin, const Vector &direction, float scale, int skin, bool bOnFire )
|
|
{
|
|
Vector offset;
|
|
#ifdef ASW_DO_BLOOD_LIGHT_CALCS
|
|
Vector color = engine->GetLightForPointFast(origin, true);
|
|
color.x = 0;
|
|
color.y = LinearToTexture( color.y ) / 255.0f;
|
|
color.z = 0;
|
|
|
|
// only use half of lighting
|
|
color.y += (1.0f - color.y) * ASW_BLOOD_BRIGHTNESS;
|
|
color.y *= 255.0f;
|
|
#else
|
|
Vector color(0, 255, 0);
|
|
#endif
|
|
|
|
// Throw some blood
|
|
CSmartPtr<CSimpleEmitter> pSimple = CSimpleEmitter::Create( "FX_HarvesterGib" );
|
|
pSimple->SetSortOrigin( origin );
|
|
|
|
PMaterialHandle hMaterial = pSimple->GetPMaterial( "effects/blood" );
|
|
Vector vDir;
|
|
vDir.Random( -1.0f, 1.0f );
|
|
for ( int i = 0; i < 4; i++ )
|
|
{
|
|
SimpleParticle *sParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), hMaterial, origin );
|
|
|
|
if ( sParticle == NULL )
|
|
return;
|
|
|
|
sParticle->m_flLifetime = 0.0f;
|
|
sParticle->m_flDieTime = random->RandomFloat( 0.5f, 0.75f );
|
|
|
|
float speed = random->RandomFloat( 16.0f, 64.0f );
|
|
|
|
sParticle->m_vecVelocity = vDir * -speed;
|
|
sParticle->m_vecVelocity[2] += 16.0f;
|
|
|
|
sParticle->m_uchColor[0] = 0;
|
|
sParticle->m_uchColor[1] = color.y;
|
|
sParticle->m_uchColor[2] = 0;
|
|
sParticle->m_uchStartAlpha = 255.0f * ASW_BLOOD_BRIGHTNESS;
|
|
sParticle->m_uchEndAlpha = 0;
|
|
sParticle->m_uchStartSize = random->RandomInt( 16, 32 );
|
|
sParticle->m_uchEndSize = sParticle->m_uchStartSize * 2;
|
|
sParticle->m_flRoll = random->RandomInt( 0, 360 );
|
|
sParticle->m_flRollDelta = random->RandomFloat( -1.0f, 1.0f );
|
|
}
|
|
|
|
hMaterial = pSimple->GetPMaterial( "effects/blood2" );
|
|
|
|
for ( int i = 0; i < 4; i++ )
|
|
{
|
|
SimpleParticle *sParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), hMaterial, origin );
|
|
|
|
if ( sParticle == NULL )
|
|
{
|
|
return;
|
|
}
|
|
|
|
sParticle->m_flLifetime = 0.0f;
|
|
sParticle->m_flDieTime = random->RandomFloat( 0.5f, 0.75f );
|
|
|
|
float speed = random->RandomFloat( 16.0f, 64.0f );
|
|
|
|
sParticle->m_vecVelocity = vDir * -speed;
|
|
sParticle->m_vecVelocity[2] += 16.0f;
|
|
|
|
sParticle->m_uchColor[0] = 0;
|
|
sParticle->m_uchColor[1] = color.y;
|
|
sParticle->m_uchColor[2] = 0;
|
|
sParticle->m_uchStartAlpha = random->RandomInt( 64, 128 );
|
|
sParticle->m_uchEndAlpha = 0;
|
|
sParticle->m_uchStartSize = random->RandomInt( 16, 32 );
|
|
sParticle->m_uchEndSize = sParticle->m_uchStartSize * 2;
|
|
sParticle->m_flRoll = random->RandomInt( 0, 360 );
|
|
sParticle->m_flRollDelta = random->RandomFloat( -1.0f, 1.0f );
|
|
}
|
|
|
|
// make our gib emitters
|
|
Vector vecForce = direction * 100.0f;
|
|
if (bOnFire)
|
|
{
|
|
FX_GibMeshEmitter("models/swarm/DroneGibs/dronepart58.mdl", "dronegibfire1", origin, vecForce, skin);
|
|
FX_GibMeshEmitter("models/swarm/DroneGibs/dronepart58.mdl", "dronegibfire1", origin, vecForce, skin);
|
|
FX_GibMeshEmitter("models/swarm/DroneGibs/dronepart59.mdl", "dronegibfire1", origin, vecForce, skin);
|
|
}
|
|
else
|
|
{
|
|
FX_GibMeshEmitter("models/swarm/DroneGibs/dronepart58.mdl", "dronegib1", origin, vecForce, skin);
|
|
FX_GibMeshEmitter("models/swarm/DroneGibs/dronepart58.mdl", "dronegib2", origin, vecForce, skin);
|
|
FX_GibMeshEmitter("models/swarm/DroneGibs/dronepart59.mdl", "dronegib3", origin, vecForce, skin);
|
|
}
|
|
|
|
CLocalPlayerFilter filter;
|
|
CSoundParameters params;
|
|
|
|
// make a gib sound
|
|
if ( C_BaseEntity::GetParametersForSound( "ASW_Drone.GibSplat", params, NULL ) )
|
|
{
|
|
EmitSound_t ep( params );
|
|
|
|
ep.m_flVolume = 1.0f;
|
|
ep.m_nChannel = CHAN_AUTO;
|
|
ep.m_pOrigin = &origin;
|
|
|
|
C_BaseEntity::EmitSound( filter, 0, ep );
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
// Input : &data -
|
|
//-----------------------------------------------------------------------------
|
|
void HarvesterGibCallback( const CEffectData &data )
|
|
{
|
|
FX_HarvesterGib( data.m_vOrigin, data.m_vNormal, data.m_flScale, data.m_nColor, (data.m_fFlags & ASW_GIBFLAG_ON_FIRE) );
|
|
}
|
|
|
|
DECLARE_CLIENT_EFFECT( HarvesterGib, HarvesterGibCallback );
|
|
|
|
// Grub Gibs
|
|
|
|
#define NUM_GRUB_GIBS_UNIQUE 6
|
|
const char *pszGrubGibs_Unique[NUM_GRUB_GIBS_UNIQUE] = {
|
|
"models/Swarm/Grubs/GrubGib1.mdl",
|
|
"models/Swarm/Grubs/GrubGib2.mdl",
|
|
"models/Swarm/Grubs/GrubGib3.mdl",
|
|
"models/Swarm/Grubs/GrubGib4.mdl",
|
|
"models/Swarm/Grubs/GrubGib5.mdl",
|
|
"models/Swarm/Grubs/GrubGib6.mdl"
|
|
};
|
|
|
|
void FX_GrubGib( const Vector &origin, const Vector &direction, float scale, bool bOnFire )
|
|
{
|
|
Vector offset = origin + Vector(0,0,8);
|
|
if (bOnFire)
|
|
DispatchParticleEffect( "grub_death_fire", offset, QAngle( 0, 0, 0 ) );
|
|
else
|
|
DispatchParticleEffect( "grub_death", offset, QAngle( 0, 0, 0 ) );
|
|
|
|
CLocalPlayerFilter filter;
|
|
CSoundParameters params;
|
|
|
|
// make a gib sound
|
|
if ( C_BaseEntity::GetParametersForSound( "ASW_Drone.GibSplatQuiet", params, NULL ) )
|
|
{
|
|
EmitSound_t ep( params );
|
|
ep.m_pOrigin = &origin;
|
|
|
|
C_BaseEntity::EmitSound( filter, 0, ep );
|
|
}
|
|
}
|
|
|
|
void GrubGibCallback( const CEffectData &data )
|
|
{
|
|
FX_GrubGib( data.m_vOrigin, data.m_vNormal, data.m_flScale, (data.m_fFlags & ASW_GIBFLAG_ON_FIRE) );
|
|
}
|
|
|
|
DECLARE_CLIENT_EFFECT( GrubGib, GrubGibCallback );
|
|
|
|
// ==========
|
|
// Parasite Gibs
|
|
// ==========
|
|
|
|
#define NUM_PARASITE_GIBS_UNIQUE 8
|
|
const char *pszParasiteGibs_Unique[NUM_PARASITE_GIBS_UNIQUE] = {
|
|
"models/swarm/Parasite/ParasiteGibAbdomen.mdl",
|
|
"models/swarm/Parasite/ParasiteGibHead.mdl",
|
|
"models/swarm/Parasite/ParasiteGibFrontLeg.mdl",
|
|
"models/swarm/Parasite/ParasiteGibMidLeg.mdl",
|
|
"models/swarm/Parasite/ParasiteGibBackLeg.mdl",
|
|
"models/swarm/Parasite/ParasiteGibFrontLeg.mdl",
|
|
"models/swarm/Parasite/ParasiteGibMidLeg.mdl",
|
|
"models/swarm/Parasite/ParasiteGibBackLeg.mdl"
|
|
};
|
|
|
|
void FX_ParasiteGib( const Vector &origin, const Vector &direction, float scale, int skin, bool bUseGibImpactSounds, bool bOnFire )
|
|
{
|
|
Vector offset;
|
|
// make our gib emitters.
|
|
Vector vecForce = direction;
|
|
vecForce.z = 1.0f;
|
|
vecForce *= 100.0f;
|
|
Vector gibspot = origin + Vector(0,0,5);
|
|
if (bUseGibImpactSounds)
|
|
{
|
|
if (bOnFire)
|
|
{
|
|
FX_GibMeshEmitter("Models/Swarm/Parasite/ParasiteGibMidLeg.mdl", "parasitegibfire1", gibspot, vecForce, 0);
|
|
FX_GibMeshEmitter("Models/Swarm/Parasite/ParasiteGibHead.mdl", "parasitegibfire1", gibspot, vecForce, 0);
|
|
FX_GibMeshEmitter("Models/Swarm/Parasite/ParasiteGibAbdomen.mdl", "parasitegibfire1", gibspot, vecForce, 0);
|
|
}
|
|
else
|
|
{
|
|
FX_GibMeshEmitter("Models/Swarm/Parasite/ParasiteGibMidLeg.mdl", "parasitegib2", gibspot, vecForce, 0);
|
|
FX_GibMeshEmitter("Models/Swarm/Parasite/ParasiteGibHead.mdl", "parasitegib1", gibspot, vecForce, 0);
|
|
FX_GibMeshEmitter("Models/Swarm/Parasite/ParasiteGibAbdomen.mdl", "parasitegib1", gibspot, vecForce, 0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (bOnFire)
|
|
{
|
|
FX_GibMeshEmitter("Models/Swarm/Parasite/ParasiteGibMidLeg.mdl", "parasitegibfire1quiet", gibspot, vecForce, 0);
|
|
FX_GibMeshEmitter("Models/Swarm/Parasite/ParasiteGibHead.mdl", "parasitegibfire1quiet", gibspot, vecForce, 0);
|
|
FX_GibMeshEmitter("Models/Swarm/Parasite/ParasiteGibAbdomen.mdl", "parasitegibfire1quiet", gibspot, vecForce, 0);
|
|
}
|
|
else
|
|
{
|
|
FX_GibMeshEmitter("Models/Swarm/Parasite/ParasiteGibMidLeg.mdl", "parasitegib2quiet", gibspot, vecForce, 0);
|
|
FX_GibMeshEmitter("Models/Swarm/Parasite/ParasiteGibHead.mdl", "parasitegib1quiet", gibspot, vecForce, 0);
|
|
FX_GibMeshEmitter("Models/Swarm/Parasite/ParasiteGibAbdomen.mdl", "parasitegib1quiet", gibspot, vecForce, 0);
|
|
}
|
|
}
|
|
|
|
CLocalPlayerFilter filter;
|
|
CSoundParameters params;
|
|
|
|
// make a gib sound
|
|
if ( C_BaseEntity::GetParametersForSound( "ASW_Drone.GibSplatQuiet", params, NULL ) )
|
|
{
|
|
EmitSound_t ep( params );
|
|
ep.m_pOrigin = &origin;
|
|
|
|
C_BaseEntity::EmitSound( filter, 0, ep );
|
|
}
|
|
|
|
// Throw some blood
|
|
|
|
QAngle vecAngles;
|
|
VectorAngles( direction, vecAngles );
|
|
DispatchParticleEffect( "drone_shot", origin, vecAngles );
|
|
|
|
/*
|
|
CSmartPtr<CSimpleEmitter> pSimple = CSimpleEmitter::Create( "FX_DroneGib" );
|
|
pSimple->SetSortOrigin( origin );
|
|
|
|
PMaterialHandle hMaterial = pSimple->GetPMaterial( "effects/blood" );
|
|
|
|
Vector vDir;
|
|
|
|
#ifdef ASW_DO_BLOOD_LIGHT_CALCS
|
|
Vector color = engine->GetLightForPointFast(origin, true);
|
|
color.x = 0;
|
|
color.y = LinearToTexture( color.y ) / 255.0f;
|
|
color.z = 0;
|
|
|
|
// only use half of lighting
|
|
color.y += (1.0f - color.y) * ASW_BLOOD_BRIGHTNESS;
|
|
color.y *= 255.0f;
|
|
#else
|
|
Vector color(0, 255, 0);
|
|
#endif
|
|
|
|
vDir.Random( -1.0f, 1.0f );
|
|
|
|
for ( int i = 0; i < 4; i++ )
|
|
{
|
|
SimpleParticle *sParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), hMaterial, origin );
|
|
|
|
if ( sParticle == NULL )
|
|
return;
|
|
|
|
sParticle->m_flLifetime = 0.0f;
|
|
sParticle->m_flDieTime = random->RandomFloat( 0.5f, 0.75f );
|
|
|
|
float speed = random->RandomFloat( 16.0f, 64.0f );
|
|
|
|
sParticle->m_vecVelocity = vDir * -speed;
|
|
sParticle->m_vecVelocity[2] += 16.0f;
|
|
|
|
sParticle->m_uchColor[0] = 0;
|
|
sParticle->m_uchColor[1] = color.y;
|
|
sParticle->m_uchColor[2] = 0;
|
|
sParticle->m_uchStartAlpha = 255.0f * ASW_BLOOD_BRIGHTNESS;
|
|
sParticle->m_uchEndAlpha = 0;
|
|
sParticle->m_uchStartSize = random->RandomInt( 16, 32 );
|
|
sParticle->m_uchEndSize = sParticle->m_uchStartSize * 2;
|
|
sParticle->m_flRoll = random->RandomInt( 0, 360 );
|
|
sParticle->m_flRollDelta = random->RandomFloat( -1.0f, 1.0f );
|
|
}
|
|
|
|
hMaterial = pSimple->GetPMaterial( "effects/blood2" );
|
|
|
|
for ( int i = 0; i < 4; i++ )
|
|
{
|
|
SimpleParticle *sParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), hMaterial, origin );
|
|
|
|
if ( sParticle == NULL )
|
|
{
|
|
return;
|
|
}
|
|
|
|
sParticle->m_flLifetime = 0.0f;
|
|
sParticle->m_flDieTime = random->RandomFloat( 0.5f, 0.75f );
|
|
|
|
float speed = random->RandomFloat( 16.0f, 64.0f );
|
|
|
|
sParticle->m_vecVelocity = vDir * -speed;
|
|
sParticle->m_vecVelocity[2] += 16.0f;
|
|
|
|
sParticle->m_uchColor[0] = 0;
|
|
sParticle->m_uchColor[1] = color.y;
|
|
sParticle->m_uchColor[2] = 0;
|
|
sParticle->m_uchStartAlpha = random->RandomInt( 64, 128 );
|
|
sParticle->m_uchEndAlpha = 0;
|
|
sParticle->m_uchStartSize = random->RandomInt( 16, 32 );
|
|
sParticle->m_uchEndSize = sParticle->m_uchStartSize * 2;
|
|
sParticle->m_flRoll = random->RandomInt( 0, 360 );
|
|
sParticle->m_flRollDelta = random->RandomFloat( -1.0f, 1.0f );
|
|
}
|
|
*/
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
// Input : &data -
|
|
//-----------------------------------------------------------------------------
|
|
void ParasiteGibCallback( const CEffectData &data )
|
|
{
|
|
FX_ParasiteGib( data.m_vOrigin, data.m_vNormal, data.m_flScale, data.m_nColor, true, (data.m_fFlags & ASW_GIBFLAG_ON_FIRE) );
|
|
}
|
|
|
|
DECLARE_CLIENT_EFFECT( ParasiteGib, ParasiteGibCallback );
|
|
|
|
void HarvesiteGibCallback( const CEffectData &data )
|
|
{
|
|
FX_ParasiteGib( data.m_vOrigin, data.m_vNormal, data.m_flScale, data.m_nColor, false, (data.m_fFlags & ASW_GIBFLAG_ON_FIRE) );
|
|
}
|
|
|
|
DECLARE_CLIENT_EFFECT( HarvesiteGib, HarvesiteGibCallback );
|
|
|
|
|
|
void FX_QueenSpitBurst( const Vector &origin, const Vector &direction, float scale, int skin )
|
|
{
|
|
C_ASW_Emitter *pEmitter = new C_ASW_Emitter;
|
|
if (pEmitter)
|
|
{
|
|
if (pEmitter->InitializeAsClientEntity( NULL, false ))
|
|
{
|
|
Q_snprintf(pEmitter->m_szTemplateName, sizeof(pEmitter->m_szTemplateName), "queenburst");
|
|
pEmitter->m_fScale = scale;
|
|
pEmitter->m_bEmit = true;
|
|
pEmitter->SetAbsOrigin(origin);
|
|
pEmitter->CreateEmitter();
|
|
pEmitter->SetAbsOrigin(origin);
|
|
pEmitter->SetDieTime(gpGlobals->curtime + 3.0f);
|
|
}
|
|
else
|
|
{
|
|
UTIL_Remove( pEmitter );
|
|
}
|
|
}
|
|
}
|
|
|
|
void QueenSpitBurstCallback( const CEffectData &data )
|
|
{
|
|
FX_QueenSpitBurst( data.m_vOrigin, data.m_vNormal, data.m_flScale, 0 );
|
|
}
|
|
|
|
DECLARE_CLIENT_EFFECT( QueenSpitBurst, QueenSpitBurstCallback );
|
|
|
|
// egg gibs
|
|
void FX_EggGibs( const Vector &origin, int flags, int iEntIndex )
|
|
{
|
|
C_ASW_Egg *pEgg = dynamic_cast<C_ASW_Egg*>(ClientEntityList().GetEnt(iEntIndex));
|
|
MDLCACHE_CRITICAL_SECTION();
|
|
C_BaseAnimating::PushAllowBoneAccess( true, false, "FX_EggGibs" );
|
|
|
|
if (flags & EGG_FLAG_OPEN && pEgg)
|
|
{
|
|
DispatchParticleEffect( "egg_open", PATTACH_POINT_FOLLOW, pEgg, "attach_death" );
|
|
}
|
|
|
|
if (flags & EGG_FLAG_HATCH && pEgg)
|
|
{
|
|
DispatchParticleEffect( "egg_hatch", PATTACH_POINT_FOLLOW, pEgg, "attach_death" );
|
|
}
|
|
|
|
if (flags & EGG_FLAG_DIE)
|
|
{
|
|
DispatchParticleEffect( "egg_death", origin, QAngle( 0, 0, 0 ) );
|
|
}
|
|
|
|
if (flags & EGG_FLAG_GRUBSACK_DIE)
|
|
{
|
|
DispatchParticleEffect( "grubsack_death", origin, QAngle( 0, 0, 0 ) );
|
|
}
|
|
|
|
CLocalPlayerFilter filter;
|
|
CSoundParameters params;
|
|
|
|
// make a gib sound
|
|
if ( C_BaseEntity::GetParametersForSound( "ASW_Drone.GibSplatQuiet", params, NULL ) )
|
|
{
|
|
EmitSound_t ep( params );
|
|
ep.m_pOrigin = &origin;
|
|
|
|
C_BaseEntity::EmitSound( filter, 0, ep );
|
|
}
|
|
|
|
C_BaseAnimating::PopBoneAccess( "FX_EggGibs" );
|
|
}
|
|
|
|
|
|
void __MsgFunc_ASWEggEffects( bf_read &msg )
|
|
{
|
|
Vector vecOrigin;
|
|
vecOrigin.x = msg.ReadFloat();
|
|
vecOrigin.y = msg.ReadFloat();
|
|
vecOrigin.z = msg.ReadFloat();
|
|
|
|
int iFlags = msg.ReadShort();
|
|
|
|
int iEggIndex = msg.ReadShort();
|
|
|
|
FX_EggGibs( vecOrigin, iFlags, iEggIndex );
|
|
}
|
|
USER_MESSAGE_REGISTER( ASWEggEffects );
|
|
|
|
/*
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
// Input : &data -
|
|
//-----------------------------------------------------------------------------
|
|
void EggGibsCallback( const CEffectData &data )
|
|
{
|
|
|
|
FX_EggGibs( data.m_vOrigin, data.m_fFlags, data.m_nOtherEntIndex );
|
|
}
|
|
|
|
DECLARE_CLIENT_EFFECT( EggGibs, EggGibsCallback );
|
|
*/
|
|
|
|
void FX_BuildStunElectroBeam( C_BaseEntity *pEntity, Vector &vecOrigin, Vector &vecEnd )
|
|
{
|
|
BeamInfo_t beamInfo;
|
|
beamInfo.m_pStartEnt = pEntity;
|
|
beamInfo.m_nStartAttachment = 0;
|
|
beamInfo.m_pEndEnt = NULL;
|
|
beamInfo.m_nEndAttachment = 0;
|
|
beamInfo.m_nType = TE_BEAMTESLA;
|
|
beamInfo.m_vecStart = vecOrigin;
|
|
beamInfo.m_vecEnd = vecEnd;
|
|
beamInfo.m_pszModelName = "swarm/effects/electrostunbeam.vmt";
|
|
beamInfo.m_flHaloScale = 0.0;
|
|
beamInfo.m_flLife = random->RandomFloat( 0.45f, 0.5f );
|
|
beamInfo.m_flWidth = random->RandomFloat( 4.0f, 7.0f );
|
|
beamInfo.m_flEndWidth = 1.0f;
|
|
beamInfo.m_flFadeLength = 0.5f;
|
|
beamInfo.m_flAmplitude = 24;
|
|
beamInfo.m_flBrightness = 255.0;
|
|
beamInfo.m_flSpeed = 150.0f;
|
|
beamInfo.m_nStartFrame = 0.0;
|
|
beamInfo.m_flFrameRate = 30.0;
|
|
beamInfo.m_flRed = 255.0;
|
|
beamInfo.m_flGreen = 255.0;
|
|
beamInfo.m_flBlue = 255.0;
|
|
beamInfo.m_nSegments = 18;
|
|
beamInfo.m_bRenderable = true;
|
|
beamInfo.m_nFlags = 0; //FBEAM_ONLYNOISEONCE;
|
|
|
|
beams->CreateBeamEntPoint( beamInfo );
|
|
}
|
|
|
|
|
|
void FX_ProbeStunElectroBeam( CBaseEntity *pEntity, mstudiobbox_t *pHitBox, const matrix3x4_t &hitboxToWorld, bool bRandom, float flYawOffset )
|
|
{
|
|
Vector vecOrigin;
|
|
QAngle vecAngles;
|
|
MatrixGetColumn( hitboxToWorld, 3, vecOrigin );
|
|
MatrixAngles( hitboxToWorld, vecAngles.Base() );
|
|
|
|
// Make a couple of tries at it
|
|
int iTries = -1;
|
|
Vector vecForward;
|
|
trace_t tr;
|
|
do
|
|
{
|
|
iTries++;
|
|
|
|
// Some beams are deliberatly aimed around the point, the rest are random.
|
|
if ( !bRandom )
|
|
{
|
|
QAngle vecTemp = vecAngles;
|
|
vecTemp[YAW] += flYawOffset;
|
|
AngleVectors( vecTemp, &vecForward );
|
|
|
|
// Randomly angle it up or down
|
|
vecForward.z = RandomFloat( -1, 1 );
|
|
}
|
|
else
|
|
{
|
|
vecForward = RandomVector( -1, 1 );
|
|
}
|
|
|
|
UTIL_TraceLine( vecOrigin, vecOrigin + (vecForward * 48), MASK_SHOT, pEntity, COLLISION_GROUP_NONE, &tr );
|
|
} while ( tr.fraction >= 1.0 && iTries < 3 );
|
|
|
|
Vector vecEnd = tr.endpos - (vecForward * 8);
|
|
|
|
// Only spark & glow if we hit something
|
|
if ( tr.fraction < 1.0 )
|
|
{
|
|
if ( !EffectOccluded( tr.endpos ) )
|
|
{
|
|
//ASSERT_LOCAL_PLAYER_RESOLVABLE();
|
|
//int nSlot = GET_ACTIVE_SPLITSCREEN_SLOT();
|
|
|
|
DispatchParticleEffect( "electrical_arc_01_system", vecOrigin, vecEnd, vecAngles );
|
|
|
|
/*
|
|
CUtlReference<CNewParticleEffect> pEffect;
|
|
pEffect = pEntity->ParticleProp()->Create( "ElectroStun_arc_1", PATTACH_ABSORIGIN_FOLLOW );
|
|
pEntity->ParticleProp()->AddControlPoint( pEffect, 1, pEntity, PATTACH_CUSTOMORIGIN );
|
|
pEffect->SetControlPoint( 0, vecOrigin );
|
|
pEffect->SetControlPoint( 1, vecEnd );
|
|
*/
|
|
|
|
/*
|
|
// Move it towards the camera
|
|
Vector vecFlash = tr.endpos;
|
|
Vector vecForward;
|
|
AngleVectors( MainViewAngles(nSlot), &vecForward );
|
|
vecFlash -= (vecForward * 8);
|
|
|
|
FX_ElectroStunSplash( vecFlash, -vecForward, false );
|
|
|
|
// End glow
|
|
CSmartPtr<CSimpleEmitter> pSimple = CSimpleEmitter::Create( "dust" );
|
|
pSimple->SetSortOrigin( vecFlash );
|
|
SimpleParticle *pParticle;
|
|
pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), pSimple->GetPMaterial( "effects/tesla_glow_noz" ), vecFlash );
|
|
if ( pParticle != NULL )
|
|
{
|
|
pParticle->m_flLifetime = 0.0f;
|
|
pParticle->m_flDieTime = RandomFloat( 0.5, 1 );
|
|
pParticle->m_vecVelocity = vec3_origin;
|
|
pParticle->m_uchColor[0] = 49;
|
|
pParticle->m_uchColor[1] = 218;
|
|
pParticle->m_uchColor[2] = 255;
|
|
pParticle->m_uchStartSize = RandomFloat( 4,6 );
|
|
pParticle->m_uchEndSize = pParticle->m_uchStartSize - 2;
|
|
pParticle->m_uchStartAlpha = 255;
|
|
pParticle->m_uchEndAlpha = 10;
|
|
pParticle->m_flRoll = RandomFloat( 0,360 );
|
|
pParticle->m_flRollDelta = 0;
|
|
}
|
|
*/
|
|
}
|
|
}
|
|
|
|
//FX_BuildStunElectroBeam( pEntity, vecOrigin, tr.endpos );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Sorts the components of a vector
|
|
//-----------------------------------------------------------------------------
|
|
static inline void ASWSortAbsVectorComponents( const Vector& src, int* pVecIdx )
|
|
{
|
|
Vector absVec( fabs(src[0]), fabs(src[1]), fabs(src[2]) );
|
|
|
|
int maxIdx = (absVec[0] > absVec[1]) ? 0 : 1;
|
|
if (absVec[2] > absVec[maxIdx])
|
|
{
|
|
maxIdx = 2;
|
|
}
|
|
|
|
// always choose something right-handed....
|
|
switch( maxIdx )
|
|
{
|
|
case 0:
|
|
pVecIdx[0] = 1;
|
|
pVecIdx[1] = 2;
|
|
pVecIdx[2] = 0;
|
|
break;
|
|
case 1:
|
|
pVecIdx[0] = 2;
|
|
pVecIdx[1] = 0;
|
|
pVecIdx[2] = 1;
|
|
break;
|
|
case 2:
|
|
pVecIdx[0] = 0;
|
|
pVecIdx[1] = 1;
|
|
pVecIdx[2] = 2;
|
|
break;
|
|
}
|
|
}
|
|
|
|
void ASWComputeRenderInfo( mstudiobbox_t *pHitBox, const matrix3x4_t &hitboxToWorld,
|
|
Vector *pVecAbsOrigin, Vector *pXVec, Vector *pYVec )
|
|
{
|
|
// Compute the center of the hitbox in worldspace
|
|
Vector vecHitboxCenter;
|
|
VectorAdd( pHitBox->bbmin, pHitBox->bbmax, vecHitboxCenter );
|
|
vecHitboxCenter *= 0.5f;
|
|
VectorTransform( vecHitboxCenter, hitboxToWorld, *pVecAbsOrigin );
|
|
|
|
// Get the object's basis
|
|
Vector vec[3];
|
|
MatrixGetColumn( hitboxToWorld, 0, vec[0] );
|
|
MatrixGetColumn( hitboxToWorld, 1, vec[1] );
|
|
MatrixGetColumn( hitboxToWorld, 2, vec[2] );
|
|
// vec[1] *= -1.0f;
|
|
|
|
Vector vecViewDir;
|
|
VectorSubtract( CurrentViewOrigin(), *pVecAbsOrigin, vecViewDir );
|
|
VectorNormalize( vecViewDir );
|
|
|
|
// Project the shadow casting direction into the space of the hitbox
|
|
Vector localViewDir;
|
|
localViewDir[0] = DotProduct( vec[0], vecViewDir );
|
|
localViewDir[1] = DotProduct( vec[1], vecViewDir );
|
|
localViewDir[2] = DotProduct( vec[2], vecViewDir );
|
|
|
|
// Figure out which vector has the largest component perpendicular
|
|
// to the view direction...
|
|
// Sort by how perpendicular it is
|
|
int vecIdx[3];
|
|
ASWSortAbsVectorComponents( localViewDir, vecIdx );
|
|
|
|
// Here's our hitbox basis vectors; namely the ones that are
|
|
// most perpendicular to the view direction
|
|
*pXVec = vec[vecIdx[0]];
|
|
*pYVec = vec[vecIdx[1]];
|
|
|
|
// Project them into a plane perpendicular to the view direction
|
|
*pXVec -= vecViewDir * DotProduct( vecViewDir, *pXVec );
|
|
*pYVec -= vecViewDir * DotProduct( vecViewDir, *pYVec );
|
|
VectorNormalize( *pXVec );
|
|
VectorNormalize( *pYVec );
|
|
|
|
// Compute the hitbox size
|
|
Vector boxSize;
|
|
VectorSubtract( pHitBox->bbmax, pHitBox->bbmin, boxSize );
|
|
|
|
// We project the two longest sides into the vectors perpendicular
|
|
// to the projection direction, then add in the projection of the perp direction
|
|
Vector2D size( boxSize[vecIdx[0]], boxSize[vecIdx[1]] );
|
|
size.x *= fabs( DotProduct( vec[vecIdx[0]], *pXVec ) );
|
|
size.y *= fabs( DotProduct( vec[vecIdx[1]], *pYVec ) );
|
|
|
|
// Add the third component into x and y
|
|
size.x += boxSize[vecIdx[2]] * fabs( DotProduct( vec[vecIdx[2]], *pXVec ) );
|
|
size.y += boxSize[vecIdx[2]] * fabs( DotProduct( vec[vecIdx[2]], *pYVec ) );
|
|
|
|
// Bloat a bit, since the shadow wants to extend outside the model a bit
|
|
size *= 2.0f;
|
|
|
|
// Clamp the minimum size
|
|
Vector2DMax( size, Vector2D(10.0f, 10.0f), size );
|
|
|
|
// Factor the size into the xvec + yvec
|
|
(*pXVec) *= size.x * 0.5f;
|
|
(*pYVec) *= size.y * 0.5f;
|
|
}
|
|
|
|
void FX_ElectroStun(C_BaseAnimating *pAnimating)
|
|
{
|
|
matrix3x4_t *hitboxbones[MAXSTUDIOBONES];
|
|
if ( pAnimating->HitboxToWorldTransforms( hitboxbones ) == false )
|
|
return;
|
|
|
|
studiohdr_t *pStudioHdr = modelinfo->GetStudiomodel( pAnimating->GetModel() );
|
|
if ( pStudioHdr == NULL )
|
|
return;
|
|
|
|
mstudiohitboxset_t *set = pStudioHdr->pHitboxSet( pAnimating->GetHitboxSet() );
|
|
if ( set == NULL )
|
|
return;
|
|
|
|
int nHitbox = random->RandomInt( 0, set->numhitboxes - 1 );
|
|
Vector vecAbsOrigin, xvec, yvec;
|
|
mstudiobbox_t *pBox = set->pHitbox(nHitbox);
|
|
if ( !pBox )
|
|
return;
|
|
|
|
Vector vecPosition;
|
|
QAngle vecAngles;
|
|
pAnimating->GetBonePosition( pBox->bone, vecPosition, vecAngles );
|
|
|
|
CUtlReference<CNewParticleEffect> pEffect;
|
|
pEffect = pAnimating->ParticleProp()->Create( "ElectroStun_arc_01_system", PATTACH_ABSORIGIN_FOLLOW, -1, vecPosition - pAnimating->GetAbsOrigin() );
|
|
}
|
|
|
|
void FX_ElectoStun(C_BaseAnimating *pAnimating);
|
|
|
|
void ElectroStunCallback( const CEffectData &data )
|
|
{
|
|
C_BaseAnimating *pAnimating = dynamic_cast<C_BaseAnimating*>(data.GetEntity());
|
|
if (pAnimating)
|
|
FX_ElectroStun( pAnimating );
|
|
}
|
|
|
|
DECLARE_CLIENT_EFFECT( ElectroStun, ElectroStunCallback );
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Energy splash for plasma/beam weapon impacts
|
|
// Input : &pos - origin point of effect
|
|
//-----------------------------------------------------------------------------
|
|
#define ENERGY_SPLASH_SPREAD 0.7f
|
|
#define ENERGY_SPLASH_MINSPEED 128.0f
|
|
#define ENERGY_SPLASH_MAXSPEED 160.0f
|
|
#define ENERGY_SPLASH_GRAVITY 800.0f
|
|
#define ENERGY_SPLASH_DAMPEN 0.3f
|
|
|
|
void FX_ElectroStunSplash( const Vector &pos, const Vector &normal, int nFlags )
|
|
{
|
|
//VPROF_BUDGET( "FX_ElectroStunSplash", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
|
|
Vector offset = pos + ( normal * 2.0f );
|
|
|
|
// Quick flash
|
|
FX_AddQuad( pos, // origin
|
|
normal, // normal
|
|
32.0f, // start size
|
|
0, // end size
|
|
0.75f, // sizeBias
|
|
1.0f, /// startAlpha
|
|
0.0f, // endAlpha
|
|
0.4f, // alphaBias
|
|
random->RandomInt( 0, 360 ), // yaw
|
|
0, // deltayaw
|
|
Vector( 1.0f, 1.0f, 1.0f ), // color
|
|
0.25f, // lifetime
|
|
"swarm/effects/bluemuzzle_nocull", // shader
|
|
(FXQUAD_BIAS_SCALE|FXQUAD_BIAS_ALPHA) ); // flags
|
|
|
|
// Lingering burn
|
|
FX_AddQuad( pos,
|
|
normal,
|
|
8,
|
|
16,
|
|
0.75f,
|
|
1.0f,
|
|
0.0f,
|
|
0.4f,
|
|
random->RandomInt( 0, 360 ),
|
|
0,
|
|
Vector( 1.0f, 1.0f, 1.0f ),
|
|
0.5f,
|
|
"swarm/effects/bluemuzzle_nocull",
|
|
(FXQUAD_BIAS_SCALE|FXQUAD_BIAS_ALPHA) );
|
|
|
|
SimpleParticle *sParticle;
|
|
|
|
CSmartPtr<CSimpleEmitter> pEmitter;
|
|
|
|
pEmitter = CSimpleEmitter::Create( "C_EntityDissolve" );
|
|
pEmitter->SetSortOrigin( pos );
|
|
|
|
if ( g_Material_Spark == NULL )
|
|
{
|
|
g_Material_Spark = pEmitter->GetPMaterial( "effects/spark" );
|
|
}
|
|
|
|
// Anime ground effects
|
|
for ( int j = 0; j < 8; j++ )
|
|
{
|
|
offset.x = random->RandomFloat( -8.0f, 8.0f );
|
|
offset.y = random->RandomFloat( -8.0f, 8.0f );
|
|
offset.z = random->RandomFloat( 0.0f, 4.0f );
|
|
|
|
offset += pos;
|
|
|
|
sParticle = (SimpleParticle *) pEmitter->AddParticle( sizeof(SimpleParticle), g_Material_Spark, offset );
|
|
|
|
if ( sParticle == NULL )
|
|
return;
|
|
|
|
sParticle->m_vecVelocity = Vector( Helper_RandomFloat( -4.0f, 4.0f ), Helper_RandomFloat( -4.0f, 4.0f ), Helper_RandomFloat( 16.0f, 64.0f ) );
|
|
|
|
sParticle->m_uchStartSize = random->RandomFloat( 2, 4 );
|
|
|
|
sParticle->m_flDieTime = random->RandomFloat( 0.4f, 0.6f );
|
|
|
|
sParticle->m_flLifetime = 0.0f;
|
|
|
|
sParticle->m_flRoll = Helper_RandomInt( 0, 360 );
|
|
|
|
float alpha = 255;
|
|
|
|
sParticle->m_flRollDelta = Helper_RandomFloat( -4.0f, 4.0f );
|
|
sParticle->m_uchColor[0] = alpha;
|
|
sParticle->m_uchColor[1] = alpha;
|
|
sParticle->m_uchColor[2] = alpha;
|
|
sParticle->m_uchStartAlpha = alpha;
|
|
sParticle->m_uchEndAlpha = 0;
|
|
sParticle->m_uchEndSize = 0;
|
|
}
|
|
}
|
|
|
|
void FX_PierceSpark( const Vector &pos, const Vector &normal)
|
|
{
|
|
|
|
CUtlReference<CNewParticleEffect> pEffect = CNewParticleEffect::CreateOrAggregate( NULL, "piercing_spark", pos, NULL, -1 );
|
|
if ( pEffect.IsValid() && pEffect->IsValid() )
|
|
{
|
|
pEffect->SetSortOrigin( pos );
|
|
pEffect->SetControlPoint( 0, pos );
|
|
|
|
pEffect->SetControlPointForwardVector ( 0, -normal );
|
|
//Vector vecForward, vecRight, vecUp;
|
|
//AngleVectors( normal, &vecForward, &vecRight, &vecUp );
|
|
//pEffect->SetControlPointOrientation( 0, vecForward, vecRight, vecUp );
|
|
}
|
|
|
|
/*
|
|
C_ASW_Emitter *pEmitter = new C_ASW_Emitter;
|
|
if (pEmitter)
|
|
{
|
|
if (pEmitter->InitializeAsClientEntity( NULL, false ))
|
|
{
|
|
Q_snprintf(pEmitter->m_szTemplateName, sizeof(pEmitter->m_szTemplateName), "piercespark");
|
|
pEmitter->m_fScale = asw_pierce_spark_scale.GetFloat();
|
|
pEmitter->m_bEmit = true;
|
|
pEmitter->SetAbsOrigin(pos);
|
|
pEmitter->CreateEmitter();
|
|
pEmitter->SetAbsOrigin(pos);
|
|
float yaw = UTIL_VecToYaw(normal) + 90;
|
|
QAngle ang(0,yaw,0);
|
|
pEmitter->SetAbsAngles(ang);
|
|
|
|
pEmitter->SetDieTime(gpGlobals->curtime + 1.0f);
|
|
}
|
|
else
|
|
{
|
|
UTIL_Remove( pEmitter );
|
|
}
|
|
}
|
|
*/
|
|
}
|
|
|
|
void PierceSparkCallback( const CEffectData & data )
|
|
{
|
|
FX_PierceSpark( data.m_vOrigin, data.m_vNormal );
|
|
}
|
|
|
|
DECLARE_CLIENT_EFFECT( PierceSpark, PierceSparkCallback );
|
|
|
|
void FX_ExtinguisherCloud( C_BaseAnimating *pEnt, const Vector &pos)
|
|
{
|
|
C_ASW_Emitter *pEmitter = new C_ASW_Emitter;
|
|
if (pEmitter)
|
|
{
|
|
if (pEmitter->InitializeAsClientEntity( NULL, false ))
|
|
{
|
|
Q_snprintf(pEmitter->m_szTemplateName, sizeof(pEmitter->m_szTemplateName), "fireextinguisherself");
|
|
pEmitter->m_bEmit = true;
|
|
pEmitter->SetAbsOrigin(pos);
|
|
pEmitter->CreateEmitter();
|
|
pEmitter->SetAbsOrigin(pos);
|
|
QAngle ang(0,0,0);
|
|
pEmitter->SetAbsAngles(ang);
|
|
if (pEnt)
|
|
pEmitter->ClientAttach(pEnt, "Center");
|
|
|
|
pEmitter->SetDieTime(gpGlobals->curtime + 1.0f);
|
|
}
|
|
else
|
|
{
|
|
UTIL_Remove( pEmitter );
|
|
}
|
|
}
|
|
}
|
|
|
|
void ExtinguisherCloudCallback( const CEffectData & data )
|
|
{
|
|
C_BaseAnimating *pAnimating = dynamic_cast<C_BaseAnimating*>(data.GetEntity());
|
|
if (pAnimating)
|
|
FX_ExtinguisherCloud( pAnimating, data.m_vOrigin );
|
|
else
|
|
FX_ExtinguisherCloud( NULL, data.m_vOrigin );
|
|
}
|
|
|
|
DECLARE_CLIENT_EFFECT( ExtinguisherCloud, ExtinguisherCloudCallback );
|
|
|
|
// Used for sorting hitboxes by volume.
|
|
//
|
|
struct ASWHitboxVolume_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 ASWSortHitboxVolumes(ASWHitboxVolume_t *elem1, ASWHitboxVolume_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;
|
|
}
|
|
|
|
inline float ASWCalcBoxVolume(const Vector &mins, const Vector &maxs)
|
|
{
|
|
return (maxs.x - mins.x) * (maxs.y - mins.y) * (maxs.z - mins.z);
|
|
}
|
|
|
|
void ASW_AttachFireToHitboxes(C_BaseAnimating *pAnimating, int iNumFires, float fMaxScale)
|
|
{
|
|
#ifdef INFESTED_FIRE
|
|
if (!pAnimating || !pAnimating->GetModel())
|
|
return;
|
|
|
|
if (iNumFires > ASW_NUM_FIRE_EMITTERS)
|
|
iNumFires = ASW_NUM_FIRE_EMITTERS;
|
|
|
|
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.
|
|
ASWHitboxVolume_t hitboxvolume[MAXSTUDIOBONES];
|
|
for ( int i = 0; i < set->numhitboxes; i++ )
|
|
{
|
|
mstudiobbox_t *pBox = set->pHitbox(i);
|
|
hitboxvolume[i].nIndex = i;
|
|
hitboxvolume[i].flVolume = ASWCalcBoxVolume(pBox->bbmin, pBox->bbmax);
|
|
}
|
|
qsort(hitboxvolume, set->numhitboxes, sizeof(hitboxvolume[0]), (int (__cdecl *)(const void *, const void *))ASWSortHitboxVolumes);
|
|
|
|
for ( int i = 0; i < iNumFires; i++ )
|
|
{
|
|
int hitboxindex;
|
|
|
|
if (!pAnimating->m_hFireEmitters[i].Get())
|
|
return;
|
|
|
|
// Pick the 2 biggest hitboxes, or random ones if there are less than 5 hitboxes,
|
|
// then pick random ones after that.
|
|
if (( i < 2 ) && ( 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] );
|
|
// Calculate a position within the hitbox to place the fire.
|
|
Vector vecFire = 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( vecFire, *hitboxbones[pBox->bone], vecAbsOrigin);
|
|
pAnimating->m_hFireEmitters[i]->SetAbsOrigin( vecAbsOrigin );
|
|
|
|
float flVolume = hitboxvolume[hitboxindex].flVolume;
|
|
|
|
Assert( IsFinite(flVolume) );
|
|
|
|
#define FLAME_HITBOX_MIN_VOLUME 1000.0f
|
|
#define FLAME_HITBOX_MAX_VOLUME 2000.0f // asw
|
|
|
|
if( flVolume < FLAME_HITBOX_MIN_VOLUME )
|
|
{
|
|
flVolume = FLAME_HITBOX_MIN_VOLUME;
|
|
}
|
|
else if( flVolume > FLAME_HITBOX_MAX_VOLUME )
|
|
{
|
|
flVolume = FLAME_HITBOX_MAX_VOLUME;
|
|
}
|
|
|
|
pAnimating->m_hFireEmitters[i]->m_fScale = MIN(flVolume * 0.00048f, fMaxScale);
|
|
}
|
|
// note: this is missing any code to scale the emitters to match the hitbox sizes
|
|
#endif
|
|
}
|
|
|
|
ConVar asw_rg_explosion("asw_rg_explosion", "0", 0, "Should the rg tracer have an explosion at the end?");
|
|
|
|
void FX_ASW_RGEffect(const Vector &vecStart, const Vector &vecEnd)
|
|
{
|
|
CSmartPtr<CSimpleEmitter> pSimple = CSimpleEmitter::Create( "RGEffect" );
|
|
if ( !pSimple )
|
|
return;
|
|
|
|
pSimple->SetSortOrigin( vecStart );
|
|
|
|
// Blood impact
|
|
PMaterialHandle hMaterial = ParticleMgr()->GetPMaterial( "effects/yellowflare" );
|
|
|
|
SimpleParticle *pParticle;
|
|
Color aura(66, 142, 192, 255);
|
|
Color core(192, 192, 192, 255);
|
|
float scale = 1;
|
|
|
|
if (asw_rg_explosion.GetBool())
|
|
{
|
|
BaseExplosionEffect().Create( vecEnd, 2, 0.3, TE_EXPLFLAG_NONE );
|
|
// scaled explosion removed
|
|
//BaseExplosionEffect().CreateScaled( vecEnd, 2, 0.3, TE_EXPLFLAG_NONE );
|
|
}
|
|
|
|
Vector diff = vecEnd - vecStart;
|
|
float dist = diff.Length();
|
|
|
|
Vector dir = diff;
|
|
dir.NormalizeInPlace();
|
|
Vector up;
|
|
QAngle ang, backwards_ang;
|
|
VectorAngles( dir, ang );
|
|
VectorAngles( -dir, backwards_ang );
|
|
AngleVectors( ang, NULL, NULL, &up);
|
|
|
|
// rg smoke
|
|
C_ASW_Emitter *pEmitter = new C_ASW_Emitter;
|
|
if (pEmitter)
|
|
{
|
|
if (pEmitter->InitializeAsClientEntity( NULL, false ))
|
|
{
|
|
// randomly pick a jet, a drip or a burst
|
|
Q_snprintf(pEmitter->m_szTemplateName, sizeof(pEmitter->m_szTemplateName), "railgunsmoke");
|
|
pEmitter->m_fScale = 1.0f;
|
|
pEmitter->m_bEmit = true;
|
|
pEmitter->SetAbsOrigin(vecEnd);
|
|
pEmitter->CreateEmitter();
|
|
pEmitter->SetAbsOrigin(vecEnd);
|
|
pEmitter->SetAbsAngles(backwards_ang);
|
|
pEmitter->SetDieTime(gpGlobals->curtime + 2.0f);
|
|
}
|
|
else
|
|
{
|
|
UTIL_Remove( pEmitter );
|
|
}
|
|
}
|
|
|
|
// rg spray
|
|
pEmitter = new C_ASW_Emitter;
|
|
if (pEmitter)
|
|
{
|
|
if (pEmitter->InitializeAsClientEntity( NULL, false ))
|
|
{
|
|
// randomly pick a jet, a drip or a burst
|
|
Q_snprintf(pEmitter->m_szTemplateName, sizeof(pEmitter->m_szTemplateName), "railgunspray");
|
|
pEmitter->m_fScale = 1.0f;
|
|
pEmitter->m_bEmit = true;
|
|
pEmitter->SetAbsOrigin(vecEnd);
|
|
pEmitter->CreateEmitter();
|
|
pEmitter->SetAbsOrigin(vecEnd);
|
|
pEmitter->SetAbsAngles(backwards_ang);
|
|
pEmitter->SetDieTime(gpGlobals->curtime + 1.0f);
|
|
}
|
|
else
|
|
{
|
|
UTIL_Remove( pEmitter );
|
|
}
|
|
}
|
|
|
|
// rg circle
|
|
pEmitter = new C_ASW_Emitter;
|
|
if (pEmitter)
|
|
{
|
|
if (pEmitter->InitializeAsClientEntity( NULL, false ))
|
|
{
|
|
// randomly pick a jet, a drip or a burst
|
|
Q_snprintf(pEmitter->m_szTemplateName, sizeof(pEmitter->m_szTemplateName), "railguncircle");
|
|
pEmitter->m_fScale = 1.0f;
|
|
pEmitter->m_bEmit = true;
|
|
pEmitter->SetAbsOrigin(vecEnd);
|
|
pEmitter->CreateEmitter();
|
|
pEmitter->SetAbsOrigin(vecEnd);
|
|
pEmitter->SetAbsAngles(backwards_ang);
|
|
pEmitter->SetDieTime(gpGlobals->curtime + 1.0f);
|
|
}
|
|
else
|
|
{
|
|
UTIL_Remove( pEmitter );
|
|
}
|
|
}
|
|
|
|
int num_particles = dist / 1.5f; // spawn 1 particle every 3 units (upped to 1.5)
|
|
|
|
VMatrix rot;
|
|
float angle = 0;
|
|
Vector offset;
|
|
for (int i=0;i<num_particles;i++)
|
|
{
|
|
float f = float(i) / float(num_particles);
|
|
Vector vecPos = vecStart + diff * f;
|
|
MatrixBuildRotationAboutAxis( rot, dir, angle );
|
|
Vector3DMultiply( rot, up, offset );
|
|
vecPos += offset * 7;
|
|
angle += 10;
|
|
// aura
|
|
pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), hMaterial, vecPos );
|
|
|
|
if ( pParticle != NULL )
|
|
{
|
|
pParticle->m_flLifetime = 0.0f;
|
|
pParticle->m_flDieTime = 0.6f; //0.9f;
|
|
|
|
//pParticle->m_vecVelocity = dir * random->RandomFloat( 16.0f, 32.0f ) + offset * 32.0f;
|
|
//pParticle->m_vecVelocity[2] -= random->RandomFloat( 8.0f, 16.0f );
|
|
//pParticle->m_vecVelocity = offset * 32.0f;
|
|
pParticle->m_vecVelocity.Init();
|
|
pParticle->m_iFlags = 0;
|
|
|
|
float colorRamp = 1.5f * f; //random->RandomFloat( 0.75f, 2.0f );
|
|
|
|
pParticle->m_uchColor[0] = MIN( 255.0f, aura[0] * colorRamp );
|
|
pParticle->m_uchColor[1] = MIN( 255.0f, aura[1] * colorRamp );
|
|
pParticle->m_uchColor[2] = MIN( 255.0f, aura[2] * colorRamp );
|
|
|
|
pParticle->m_uchStartSize = 4 * scale;
|
|
pParticle->m_uchEndSize = pParticle->m_uchStartSize * 5 * scale;
|
|
|
|
pParticle->m_uchStartAlpha = 64;
|
|
pParticle->m_uchEndAlpha = 0;
|
|
|
|
pParticle->m_flRoll = 0; // random->RandomInt( 0, 360 );
|
|
pParticle->m_flRollDelta = 0;
|
|
}
|
|
|
|
// core
|
|
pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), hMaterial, vecPos );
|
|
|
|
if ( pParticle != NULL )
|
|
{
|
|
pParticle->m_flLifetime = 0.0f;
|
|
pParticle->m_flDieTime = 0.6f;
|
|
|
|
//pParticle->m_vecVelocity = dir * random->RandomFloat( 16.0f, 32.0f ) + offset * 32.0f;
|
|
//pParticle->m_vecVelocity[2] -= random->RandomFloat( 8.0f, 16.0f );
|
|
//pParticle->m_vecVelocity = offset * 32.0f;
|
|
pParticle->m_vecVelocity.Init();
|
|
pParticle->m_iFlags = 0;
|
|
|
|
float colorRamp = 1.5f * f; //random->RandomFloat( 0.75f, 2.0f );
|
|
|
|
pParticle->m_uchColor[0] = MIN( 255.0f, core[0] * colorRamp );
|
|
pParticle->m_uchColor[1] = MIN( 255.0f, core[1] * colorRamp );
|
|
pParticle->m_uchColor[2] = MIN( 255.0f, core[2] * colorRamp );
|
|
|
|
pParticle->m_uchStartSize = 2 * scale;
|
|
pParticle->m_uchEndSize = pParticle->m_uchStartSize * 3 * scale;
|
|
|
|
pParticle->m_uchStartAlpha = 64;
|
|
pParticle->m_uchEndAlpha = 0;
|
|
|
|
pParticle->m_flRoll = 0; // random->RandomInt( 0, 360 );
|
|
pParticle->m_flRollDelta = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
extern Vector GetTracerOrigin( const CEffectData &data );
|
|
void FX_ASWTracer( const Vector& start, const Vector& end, int velocity, bool makeWhiz, bool bRedTracer, int iForceStyle )
|
|
{
|
|
VPROF_BUDGET( "FX_ASWTracer", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
|
|
|
|
if (iForceStyle == -1)
|
|
iForceStyle = asw_tracer_style.GetInt();
|
|
|
|
if (iForceStyle == 0)
|
|
return;
|
|
|
|
if (iForceStyle == 2) // line tracer
|
|
{
|
|
//Don't make small tracers
|
|
float dist;
|
|
Vector dir;
|
|
|
|
VectorSubtract( end, start, dir );
|
|
dist = VectorNormalize( dir );
|
|
|
|
// Don't make short tracers.
|
|
if ( dist < 64 )
|
|
return;
|
|
|
|
float length = dist;
|
|
if (length > 512.0f)
|
|
length = 512;
|
|
|
|
float life = ( dist + length ) / velocity; //NOTENOTE: We want the tail to finish its run as well
|
|
|
|
//Add it
|
|
FX_AddDiscreetLine( start, dir, velocity, length, dist, random->RandomFloat( 0.5f, 1.5f ),
|
|
life, bRedTracer ? "swarm/effects/aswtracerred" : "swarm/effects/aswtracer" );
|
|
}
|
|
else //standard short per bullet tracer
|
|
{
|
|
//Don't make small tracers
|
|
float dist;
|
|
Vector dir;
|
|
|
|
VectorSubtract( end, start, dir );
|
|
dist = VectorNormalize( dir );
|
|
|
|
// Don't make short tracers.
|
|
if ( dist < 64 )
|
|
return;
|
|
|
|
//float length = dist;
|
|
//if (length > 512.0f)
|
|
//length = 512;
|
|
|
|
// asw test short tracers
|
|
//float length = random->RandomFloat( 128.0f, 256.0f );
|
|
float length = random->RandomFloat( 64.0f, 128.0f );
|
|
|
|
float life = ( dist + length ) / velocity; //NOTENOTE: We want the tail to finish its run as well
|
|
|
|
NDebugOverlay::Line( start, start + dir * length, 128, 64, 64, true, 0.33f );
|
|
|
|
//Add it
|
|
FX_AddDiscreetLine( start, dir, velocity, length, dist, random->RandomFloat( 0.5f, 1.5f ),
|
|
life, bRedTracer ? "swarm/effects/aswtracernormalred" : "swarm/effects/aswtracernormal" );
|
|
}
|
|
|
|
// note: not bothering with whiz sounds as the camera is too high up to hear them anyway
|
|
}
|
|
|
|
|
|
void ASWDoParticleTracer( const char *pTracerEffectName, const Vector &vecStart, const Vector &vecEnd, bool bRedTracer, int iAttributeEffects = 0 )
|
|
{
|
|
VPROF_BUDGET( "ASWDoParticleTracer", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
|
|
|
|
if ( asw_tracer_style.GetInt() == 0 )
|
|
return;
|
|
|
|
// we want to aggregate particles because we are spawning a lot in rapid succession for tracers - this spawns MUCH less systems to spawn them
|
|
// NOTE: you cannot use beams/ropes in any particle system that is aggregated - they don't work properly :(
|
|
CUtlReference<CNewParticleEffect> pTracer = CNewParticleEffect::CreateOrAggregate( NULL, pTracerEffectName, vecStart, NULL );
|
|
if ( pTracer.IsValid() && pTracer->IsValid() )
|
|
{
|
|
pTracer->SetControlPoint( 0, vecStart );
|
|
pTracer->SetControlPoint( 1, vecEnd );
|
|
// the color
|
|
Vector vecColor = Vector( 1, 1, 1 );
|
|
if ( bRedTracer )
|
|
vecColor = Vector( 1, 0.65, 0.65 );
|
|
|
|
pTracer->SetControlPoint( 10, vecColor );
|
|
}
|
|
|
|
if ( iAttributeEffects > 0 )
|
|
{
|
|
CUtlReference<CNewParticleEffect> pAttribTracer = CNewParticleEffect::CreateOrAggregate( NULL, "attrib_tracer_fx", vecStart, NULL );
|
|
if ( pAttribTracer.IsValid() && pAttribTracer->IsValid() )
|
|
{
|
|
pAttribTracer->SetControlPoint( 0, vecStart );
|
|
pAttribTracer->SetControlPoint( 1, vecEnd );
|
|
|
|
/*
|
|
20.0 freeze
|
|
20.1 fire
|
|
20.2 electric
|
|
21.0 chem
|
|
21.1 explode
|
|
*/
|
|
|
|
pAttribTracer->SetControlPoint( 20, Vector( (iAttributeEffects&BULLET_ATT_FREEZE) ? 1.1f : 0, (iAttributeEffects&BULLET_ATT_FIRE) ? 1.1f : 0, (iAttributeEffects&BULLET_ATT_ELECTRIC) ? 1.1f : 0 ) );
|
|
pAttribTracer->SetControlPoint( 21, Vector( (iAttributeEffects&BULLET_ATT_CHEMICAL) ? 1.1f : 0, (iAttributeEffects&BULLET_ATT_EXPLODE) ? 1.1f : 0, 0 ) );
|
|
}
|
|
}
|
|
}
|
|
|
|
void ASWDoParticleTracer( C_ASW_Weapon *pWeapon, const Vector &vecStart, const Vector &vecEnd, bool bRedTracer, int iAttributeEffects )
|
|
{
|
|
ASWDoParticleTracer( pWeapon->GetTracerEffectName(), vecStart, vecEnd, bRedTracer, iAttributeEffects );
|
|
}
|
|
|
|
void ASWTracerCallback( const CEffectData &data )
|
|
{
|
|
C_BasePlayer *player = C_BasePlayer::GetLocalPlayer();
|
|
|
|
if ( player == NULL )
|
|
return;
|
|
|
|
// Grab the data
|
|
Vector vecStart = GetTracerOrigin( data );
|
|
float flVelocity = data.m_flScale;
|
|
bool bWhiz = (data.m_fFlags & TRACER_FLAG_WHIZ);
|
|
|
|
C_ASW_Weapon *pWpn = dynamic_cast<C_ASW_Weapon*>( data.m_hEntity.Get() );
|
|
bool bRedTracer = ( pWpn && pWpn->GetMuzzleFlashRed() );
|
|
|
|
// Use default velocity if none specified
|
|
if ( !flVelocity )
|
|
{
|
|
flVelocity = 3000;
|
|
}
|
|
|
|
// Do tracer effect
|
|
Msg("spawning dispatch effect tracer\n");
|
|
FX_ASWTracer( (Vector&)vecStart, (Vector&)data.m_vOrigin, flVelocity, bWhiz, bRedTracer );
|
|
}
|
|
|
|
DECLARE_CLIENT_EFFECT( ASWTracer, ASWTracerCallback );
|
|
|
|
static int asw_num_u_tracers = 0;
|
|
void ASWUTracer(C_ASW_Marine *pMarine, const Vector &vecEnd, int iAttributeEffects )
|
|
{
|
|
MDLCACHE_CRITICAL_SECTION();
|
|
Vector vecStart;
|
|
QAngle vecAngles;
|
|
|
|
if ( !pMarine || pMarine->IsDormant() )
|
|
return;
|
|
|
|
C_ASW_Weapon *pWpn = pMarine->GetActiveASWWeapon();//dynamic_cast<C_BaseCombatWeapon *>( pEnt );
|
|
if ( !pWpn || pWpn->IsDormant() )
|
|
return;
|
|
|
|
C_BaseAnimating::PushAllowBoneAccess( true, false, "ASWUTracer" );
|
|
|
|
pWpn->ProcessMuzzleFlashEvent();
|
|
|
|
int nAttachmentIndex = pWpn->LookupAttachment( "muzzle" );
|
|
if ( nAttachmentIndex <= 0 )
|
|
nAttachmentIndex = 1; // default to the first attachment if it doesn't have a muzzle
|
|
|
|
// Get the muzzle origin
|
|
if ( !pWpn->GetAttachment( nAttachmentIndex, vecStart, vecAngles ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
asw_num_u_tracers++;
|
|
if ( asw_use_particle_tracers.GetBool() )
|
|
ASWDoParticleTracer( pWpn, vecStart, vecEnd, pWpn->GetMuzzleFlashRed(), iAttributeEffects );
|
|
else
|
|
FX_ASWTracer( vecStart, vecEnd, 3000, false, pWpn->GetMuzzleFlashRed() );
|
|
|
|
// do a trace to the hit surface for impacts
|
|
trace_t tr;
|
|
Vector diff = vecStart - vecEnd;
|
|
diff.NormalizeInPlace();
|
|
diff *= 6; // go 6 inches away from surfaces
|
|
CTraceFilterSimple traceFilter(pMarine ,COLLISION_GROUP_NONE);
|
|
UTIL_TraceLine(vecEnd + diff, vecEnd - diff, MASK_SHOT, &traceFilter, &tr);
|
|
// do impact effect
|
|
UTIL_ImpactTrace( &tr, DMG_BULLET );
|
|
|
|
// make the marine do a firing anim
|
|
|
|
pMarine->DoAnimationEvent( PLAYERANIMEVENT_FIRE_GUN_PRIMARY );
|
|
|
|
C_BaseAnimating::PopBoneAccess( "ASWUTracer" );
|
|
}
|
|
|
|
// no tracer, just do the muzzle flash and impact
|
|
void ASWUTracerless(C_ASW_Marine *pMarine, const Vector &vecEnd, int iAttributeEffects )
|
|
{
|
|
MDLCACHE_CRITICAL_SECTION();
|
|
Vector vecStart;
|
|
QAngle vecAngles;
|
|
|
|
if ( !pMarine || pMarine->IsDormant() )
|
|
return;
|
|
|
|
C_ASW_Weapon *pWpn = pMarine->GetActiveASWWeapon();//dynamic_cast<C_BaseCombatWeapon *>( pEnt );
|
|
if ( !pWpn || pWpn->IsDormant() )
|
|
return;
|
|
|
|
C_BaseAnimating::PushAllowBoneAccess( true, false, "ASWUTracerless" );
|
|
|
|
pWpn->ProcessMuzzleFlashEvent();
|
|
|
|
int nAttachmentIndex = pWpn->LookupAttachment( "muzzle" );
|
|
if ( nAttachmentIndex <= 0 )
|
|
nAttachmentIndex = 1; // default to the first attachment if it doesn't have a muzzle
|
|
|
|
// Get the muzzle origin
|
|
if ( !pWpn->GetAttachment( nAttachmentIndex, vecStart, vecAngles ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
// do a trace to the hit surface for impacts
|
|
trace_t tr;
|
|
Vector diff = vecStart - vecEnd;
|
|
diff.NormalizeInPlace();
|
|
diff *= 6; // go 6 inches away from surfaces
|
|
CTraceFilterSimple traceFilter(pMarine ,COLLISION_GROUP_NONE);
|
|
UTIL_TraceLine(vecEnd + diff, vecEnd - diff, MASK_SHOT, &traceFilter, &tr);
|
|
// do impact effect
|
|
UTIL_ImpactTrace( &tr, DMG_BULLET );
|
|
|
|
// make the marine do a firing anim
|
|
|
|
pMarine->DoAnimationEvent( PLAYERANIMEVENT_FIRE_GUN_PRIMARY );
|
|
|
|
C_BaseAnimating::PopBoneAccess( "ASWUTracerless" );
|
|
}
|
|
|
|
void ASWUTracerDual( C_ASW_Marine *pMarine, const Vector &vecEnd, int nDualType /* = (ASW_TRACER_DUAL_LEFT | ASW_TRACER_DUAL_RIGHT) */, int iAttributeEffects )
|
|
{
|
|
MDLCACHE_CRITICAL_SECTION();
|
|
Vector vecStart;
|
|
QAngle vecAngles;
|
|
|
|
if ( !pMarine || pMarine->IsDormant() )
|
|
return;
|
|
|
|
C_ASW_Weapon *pWpn = pMarine->GetActiveASWWeapon();//dynamic_cast<C_BaseCombatWeapon *>( pEnt );
|
|
if ( !pWpn || pWpn->IsDormant() )
|
|
return;
|
|
|
|
C_BaseAnimating::PushAllowBoneAccess( true, false, "ASWUTracerDual" );
|
|
|
|
Vector diff;
|
|
trace_t tr;
|
|
|
|
const char *szAttachmentName = "muzzle";
|
|
if ( nDualType & ASW_FX_TRACER_DUAL_LEFT )
|
|
{
|
|
int nLeftMuzzleAttachment = pWpn->LookupAttachment( szAttachmentName );
|
|
|
|
// Get the muzzle origin
|
|
if ( !pWpn->GetAttachment( nLeftMuzzleAttachment, vecStart, vecAngles ) )
|
|
{
|
|
C_BaseAnimating::PopBoneAccess( "ASWUTracerDual" );
|
|
return;
|
|
}
|
|
|
|
// TODO: this is sort of hacky-right now, if we want more robust support for tracers coming from left or right hand
|
|
// TODO: we can look at passing attachments into ProcessMuzzleFlashEvent() or syncing more weapon state to C_ASWWeapon
|
|
int nAttachmentPop = pWpn->GetMuzzleAttachment();
|
|
pWpn->SetMuzzleAttachment( nLeftMuzzleAttachment );
|
|
pWpn->ProcessMuzzleFlashEvent();
|
|
pWpn->SetMuzzleAttachment( nAttachmentPop );
|
|
|
|
asw_num_u_tracers++;
|
|
if ( asw_use_particle_tracers.GetBool() )
|
|
ASWDoParticleTracer( pWpn, vecStart, vecEnd, pWpn->GetMuzzleFlashRed(), iAttributeEffects );
|
|
else
|
|
FX_ASWTracer( vecStart, vecEnd, 3000, false, pWpn->GetMuzzleFlashRed() );
|
|
|
|
// do a trace to the hit surface for impacts
|
|
diff = vecStart - vecEnd;
|
|
diff.NormalizeInPlace();
|
|
diff *= 6; // go 6 inches away from surfaces
|
|
CTraceFilterSimple traceFilter(pMarine ,COLLISION_GROUP_NONE);
|
|
UTIL_TraceLine(vecEnd + diff, vecEnd - diff, MASK_SHOT, &traceFilter, &tr);
|
|
// do impact effect
|
|
UTIL_ImpactTrace( &tr, DMG_BULLET );
|
|
}
|
|
|
|
if ( nDualType & ASW_FX_TRACER_DUAL_RIGHT )
|
|
{
|
|
// do tracer from other gun
|
|
szAttachmentName = "muzzle_flash_l";
|
|
|
|
int nRightMuzzleAttachment = pWpn->LookupAttachment( szAttachmentName );
|
|
|
|
if( !pWpn->GetAttachment( nRightMuzzleAttachment, vecStart, vecAngles ) )
|
|
{
|
|
C_BaseAnimating::PopBoneAccess( "ASWUTracerDual" );
|
|
return;
|
|
}
|
|
|
|
// TODO: this is sort of hacky-right now, if we want more robust support for tracers coming from left or right hand
|
|
// TODO: we can look at passing attachments into ProcessMuzzleFlashEvent() or syncing more weapon state to C_ASWWeapon
|
|
int nAttachmentPop = pWpn->GetMuzzleAttachment();
|
|
pWpn->SetMuzzleAttachment( nRightMuzzleAttachment );
|
|
pWpn->ProcessMuzzleFlashEvent();
|
|
pWpn->SetMuzzleAttachment( nAttachmentPop );
|
|
|
|
asw_num_u_tracers++;
|
|
if ( asw_use_particle_tracers.GetBool() )
|
|
ASWDoParticleTracer( pWpn, vecStart, vecEnd, pWpn->GetMuzzleFlashRed(), iAttributeEffects );
|
|
else
|
|
FX_ASWTracer( vecStart, vecEnd, 3000, false, pWpn->GetMuzzleFlashRed() );
|
|
|
|
// do a trace to the hit surface for impacts
|
|
diff = vecStart - vecEnd;
|
|
diff.NormalizeInPlace();
|
|
diff *= 6; // go 6 inches away from surfaces
|
|
CTraceFilterSimple traceFilter2( pMarine,COLLISION_GROUP_NONE );
|
|
UTIL_TraceLine(vecEnd + diff, vecEnd - diff, MASK_SHOT, &traceFilter2, &tr);
|
|
// do impact effect
|
|
UTIL_ImpactTrace( &tr, DMG_BULLET );
|
|
}
|
|
|
|
// make the marine do a firing anim
|
|
pMarine->DoAnimationEvent( PLAYERANIMEVENT_FIRE_GUN_PRIMARY );
|
|
|
|
C_BaseAnimating::PopBoneAccess( "ASWUTracerDual" );
|
|
}
|
|
|
|
void ASWUTracerUnattached(C_ASW_Marine *pMarine, const Vector &vecStart, const Vector &vecEnd, int iAttributeEffects)
|
|
{
|
|
asw_num_u_tracers++;
|
|
|
|
if ( !pMarine || pMarine->IsDormant() )
|
|
return;
|
|
|
|
C_ASW_Weapon *pWpn = pMarine->GetActiveASWWeapon();
|
|
if ( !pWpn || pWpn->IsDormant() )
|
|
return;
|
|
|
|
if ( asw_use_particle_tracers.GetBool() )
|
|
ASWDoParticleTracer( pWpn, vecStart, vecEnd, pWpn->GetMuzzleFlashRed(), iAttributeEffects );
|
|
else
|
|
FX_ASWTracer( vecStart, vecEnd, 3000, false, pWpn->GetMuzzleFlashRed() );
|
|
|
|
// do a trace to the hit surface for impacts
|
|
trace_t tr;
|
|
Vector diff = vecStart - vecEnd;
|
|
diff.NormalizeInPlace();
|
|
diff *= 6; // go 6 inches away from surfaces
|
|
CTraceFilterSimple traceFilter(NULL ,COLLISION_GROUP_NONE);
|
|
UTIL_TraceLine(vecEnd + diff, vecEnd - diff, MASK_SHOT, &traceFilter, &tr);
|
|
// do impact effect
|
|
UTIL_ImpactTrace( &tr, DMG_BULLET );
|
|
}
|
|
|
|
void ASWUTracerRG(C_ASW_Marine *pMarine, const Vector &vecEnd, int iAttributeEffects)
|
|
{
|
|
MDLCACHE_CRITICAL_SECTION();
|
|
Vector vecStart;
|
|
QAngle vecAngles;
|
|
|
|
if ( !pMarine || pMarine->IsDormant() )
|
|
return;
|
|
|
|
C_ASW_Weapon *pWpn = pMarine->GetActiveASWWeapon();//dynamic_cast<C_BaseCombatWeapon *>( pEnt );
|
|
if ( !pWpn || pWpn->IsDormant() )
|
|
return;
|
|
|
|
C_BaseAnimating::PushAllowBoneAccess( true, false, "ASWUTracerRG" );
|
|
|
|
pWpn->ProcessMuzzleFlashEvent();
|
|
|
|
int nAttachmentIndex = pWpn->LookupAttachment( "muzzle" );
|
|
if ( nAttachmentIndex <= 0 )
|
|
nAttachmentIndex = 1; // default to the first attachment if it doesn't have a muzzle
|
|
|
|
// Get the muzzle origin
|
|
if ( !pWpn->GetAttachment( nAttachmentIndex, vecStart, vecAngles ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
asw_num_u_tracers++;
|
|
if ( asw_use_particle_tracers.GetBool() )
|
|
{
|
|
ASWDoParticleTracer( pWpn, vecStart, vecEnd, pWpn->GetMuzzleFlashRed(), iAttributeEffects );
|
|
}
|
|
else
|
|
{
|
|
FX_ASWTracer( vecStart, vecEnd, 3000, false, pWpn->GetMuzzleFlashRed(), 2 );
|
|
FX_ASW_RGEffect( vecStart, vecEnd );
|
|
}
|
|
|
|
//FX_ASW_RGEffect( vecStart, vecEnd );
|
|
|
|
// do a trace to the hit surface for impacts
|
|
trace_t tr;
|
|
Vector diff = vecStart - vecEnd;
|
|
diff.NormalizeInPlace();
|
|
diff *= 2; // go 2 inches away from surfaces
|
|
CTraceFilterSimple traceFilter(pMarine ,COLLISION_GROUP_NONE);
|
|
UTIL_TraceLine(vecEnd + diff, vecEnd - diff, MASK_SHOT, &traceFilter, &tr);
|
|
// do impact effect
|
|
UTIL_ImpactTrace( &tr, DMG_ENERGYBEAM );
|
|
|
|
// make the marine do a firing anim
|
|
|
|
pMarine->DoAnimationEvent( PLAYERANIMEVENT_FIRE_GUN_PRIMARY );
|
|
|
|
C_BaseAnimating::PopBoneAccess( "ASWUTracerRG" );
|
|
}
|
|
|
|
void DoAttributeTracer( const Vector &vecStart, const Vector &vecEnd, int iAttributeEffects )
|
|
{
|
|
if ( iAttributeEffects <= 0 )
|
|
return;
|
|
|
|
/*
|
|
// do attribute tracer between vecStart and vecEnd
|
|
QAngle vecAngles;
|
|
Vector vecToEnd = vecEnd - vecStart;
|
|
VectorNormalize(vecToEnd);
|
|
VectorAngles( vecToEnd, vecAngles );
|
|
|
|
bool bDefaultCrit = true;
|
|
|
|
if ( iAttributeEffects & BULLET_ATT_EXPLODE )
|
|
{
|
|
DispatchParticleEffect( "tracer_explosive", vecStart, vecEnd, vecAngles );
|
|
}
|
|
|
|
if ( iAttributeEffects & BULLET_ATT_FIRE_CRIT )
|
|
{
|
|
DispatchParticleEffect( "tracer_ignite", vecStart, vecEnd, vecAngles );
|
|
bDefaultCrit = false;
|
|
}
|
|
if ( iAttributeEffects & BULLET_ATT_CHEMICAL_CRIT )
|
|
{
|
|
DispatchParticleEffect( "tracer_radiation", vecStart, vecEnd, vecAngles );
|
|
bDefaultCrit = false;
|
|
}
|
|
if ( iAttributeEffects & BULLET_ATT_ELECTRIC_CRIT )
|
|
{
|
|
DispatchParticleEffect( "tracer_electricity", vecStart, vecEnd, vecAngles );
|
|
bDefaultCrit = false;
|
|
}
|
|
if ( iAttributeEffects & BULLET_ATT_FREEZE_CRIT )
|
|
{
|
|
DispatchParticleEffect( "tracer_freeze", vecStart, vecEnd, vecAngles );
|
|
bDefaultCrit = false;
|
|
}
|
|
if ( bDefaultCrit && iAttributeEffects & BULLET_ATT_CRITICAL_HIT )
|
|
{
|
|
DispatchParticleEffect( "tracer_critical_hit", vecStart, vecEnd, vecAngles );
|
|
}
|
|
*/
|
|
}
|
|
|
|
void DoAttributeTracer( C_ASW_Marine *pMarine, const Vector &vecEnd, int iAttributeEffects, bool bUnattached = false )
|
|
{
|
|
MDLCACHE_CRITICAL_SECTION();
|
|
Vector vecStart;
|
|
QAngle vecAngles;
|
|
|
|
if ( iAttributeEffects <= 0 || !pMarine || pMarine->IsDormant() )
|
|
return;
|
|
|
|
C_ASW_Weapon *pWpn = pMarine->GetActiveASWWeapon();
|
|
if ( !pWpn || pWpn->IsDormant() )
|
|
return;
|
|
|
|
C_BaseAnimating::PushAllowBoneAccess( true, false, "DoAttributeTracer" );
|
|
|
|
pWpn->ProcessMuzzleFlashEvent();
|
|
|
|
// Get the muzzle origin
|
|
if ( !bUnattached )
|
|
{
|
|
int nAttachmentIndex = pWpn->LookupAttachment( "muzzle" );
|
|
if ( nAttachmentIndex <= 0 )
|
|
nAttachmentIndex = 1; // default to the first attachment if it doesn't have a muzzle
|
|
|
|
// Get the muzzle origin
|
|
if ( !pWpn->GetAttachment( nAttachmentIndex, vecStart, vecAngles ) )
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
DoAttributeTracer( vecStart, vecEnd, iAttributeEffects );
|
|
|
|
C_BaseAnimating::PopBoneAccess( "DoAttributeTracer" );
|
|
}
|
|
|
|
// user message version
|
|
static int asw_num_tracers = 0;
|
|
void __MsgFunc_ASWUTracer( bf_read &msg )
|
|
{
|
|
int iMarine = msg.ReadShort();
|
|
C_ASW_Marine *pMarine = dynamic_cast<C_ASW_Marine*>(ClientEntityList().GetEnt(iMarine)); // turn iMarine ent index into the marine
|
|
|
|
Vector vecEnd;
|
|
vecEnd.x = msg.ReadFloat();
|
|
vecEnd.y = msg.ReadFloat();
|
|
vecEnd.z = msg.ReadFloat();
|
|
|
|
asw_num_tracers++;
|
|
|
|
int iAttributeEffects = msg.ReadShort();
|
|
ASWUTracer( pMarine, vecEnd, iAttributeEffects );
|
|
|
|
if ( iAttributeEffects > 0 )
|
|
{
|
|
DoAttributeTracer( pMarine, vecEnd, iAttributeEffects );
|
|
}
|
|
}
|
|
USER_MESSAGE_REGISTER( ASWUTracer );
|
|
|
|
void __MsgFunc_ASWUTracerless( bf_read &msg )
|
|
{
|
|
int iMarine = msg.ReadShort();
|
|
C_ASW_Marine *pMarine = dynamic_cast<C_ASW_Marine*>(ClientEntityList().GetEnt(iMarine)); // turn iMarine ent index into the marine
|
|
|
|
Vector vecEnd;
|
|
vecEnd.x = msg.ReadFloat();
|
|
vecEnd.y = msg.ReadFloat();
|
|
vecEnd.z = msg.ReadFloat();
|
|
|
|
asw_num_tracers++;
|
|
|
|
int iAttributeEffects = msg.ReadShort();
|
|
ASWUTracerless( pMarine, vecEnd, iAttributeEffects );
|
|
|
|
if ( iAttributeEffects > 0 )
|
|
{
|
|
DoAttributeTracer( pMarine, vecEnd, iAttributeEffects );
|
|
}
|
|
}
|
|
USER_MESSAGE_REGISTER( ASWUTracerless );
|
|
|
|
void __MsgFunc_ASWUTracerDual( bf_read &msg )
|
|
{
|
|
int iMarine = msg.ReadShort();
|
|
C_ASW_Marine *pMarine = dynamic_cast<C_ASW_Marine*>(ClientEntityList().GetEnt(iMarine)); // turn iMarine ent index into the marine
|
|
|
|
Vector vecEnd;
|
|
vecEnd.x = msg.ReadFloat();
|
|
vecEnd.y = msg.ReadFloat();
|
|
vecEnd.z = msg.ReadFloat();
|
|
|
|
asw_num_tracers++;
|
|
|
|
int iAttributeEffects = msg.ReadShort();
|
|
ASWUTracerDual( pMarine, vecEnd, (ASW_FX_TRACER_DUAL_LEFT | ASW_FX_TRACER_DUAL_RIGHT), iAttributeEffects );
|
|
|
|
if ( iAttributeEffects > 0 )
|
|
{
|
|
DoAttributeTracer( pMarine, vecEnd, iAttributeEffects );
|
|
}
|
|
}
|
|
USER_MESSAGE_REGISTER( ASWUTracerDual );
|
|
|
|
void __MsgFunc_ASWUTracerDualLeft( bf_read &msg )
|
|
{
|
|
int iMarine = msg.ReadShort();
|
|
C_ASW_Marine *pMarine = dynamic_cast<C_ASW_Marine*>(ClientEntityList().GetEnt(iMarine)); // turn iMarine ent index into the marine
|
|
|
|
Vector vecEnd;
|
|
vecEnd.x = msg.ReadFloat();
|
|
vecEnd.y = msg.ReadFloat();
|
|
vecEnd.z = msg.ReadFloat();
|
|
|
|
asw_num_tracers++;
|
|
|
|
int iAttributeEffects = msg.ReadShort();
|
|
ASWUTracerDual( pMarine, vecEnd, ASW_FX_TRACER_DUAL_LEFT, iAttributeEffects );
|
|
|
|
if ( iAttributeEffects > 0 )
|
|
{
|
|
DoAttributeTracer( pMarine, vecEnd, iAttributeEffects );
|
|
}
|
|
}
|
|
USER_MESSAGE_REGISTER( ASWUTracerDualLeft );
|
|
|
|
void __MsgFunc_ASWUTracerDualRight( bf_read &msg )
|
|
{
|
|
int iMarine = msg.ReadShort();
|
|
C_ASW_Marine *pMarine = dynamic_cast<C_ASW_Marine*>(ClientEntityList().GetEnt(iMarine)); // turn iMarine ent index into the marine
|
|
|
|
Vector vecEnd;
|
|
vecEnd.x = msg.ReadFloat();
|
|
vecEnd.y = msg.ReadFloat();
|
|
vecEnd.z = msg.ReadFloat();
|
|
|
|
asw_num_tracers++;
|
|
|
|
int iAttributeEffects = msg.ReadShort();
|
|
ASWUTracerDual( pMarine, vecEnd, ASW_FX_TRACER_DUAL_RIGHT, iAttributeEffects );
|
|
|
|
if ( iAttributeEffects > 0 )
|
|
{
|
|
DoAttributeTracer( pMarine, vecEnd, iAttributeEffects );
|
|
}
|
|
}
|
|
USER_MESSAGE_REGISTER( ASWUTracerDualRight );
|
|
|
|
void __MsgFunc_ASWUTracerRG( bf_read &msg )
|
|
{
|
|
int iMarine = msg.ReadShort();
|
|
C_ASW_Marine *pMarine = dynamic_cast<C_ASW_Marine*>(ClientEntityList().GetEnt(iMarine)); // turn iMarine ent index into the marine
|
|
|
|
Vector vecEnd;
|
|
vecEnd.x = msg.ReadFloat();
|
|
vecEnd.y = msg.ReadFloat();
|
|
vecEnd.z = msg.ReadFloat();
|
|
|
|
asw_num_tracers++;
|
|
|
|
int iAttributeEffects = msg.ReadShort();
|
|
ASWUTracerRG( pMarine, vecEnd, iAttributeEffects );
|
|
|
|
if ( iAttributeEffects > 0 )
|
|
{
|
|
DoAttributeTracer( pMarine, vecEnd, iAttributeEffects );
|
|
}
|
|
}
|
|
USER_MESSAGE_REGISTER( ASWUTracerRG );
|
|
|
|
void __MsgFunc_ASWUTracerUnattached( bf_read &msg )
|
|
{
|
|
int iMarine = msg.ReadShort();
|
|
C_ASW_Marine *pMarine = dynamic_cast<C_ASW_Marine*>(ClientEntityList().GetEnt(iMarine)); // turn iMarine ent index into the marine
|
|
|
|
Vector vecEnd;
|
|
vecEnd.x = msg.ReadFloat();
|
|
vecEnd.y = msg.ReadFloat();
|
|
vecEnd.z = msg.ReadFloat();
|
|
Vector vecStart;
|
|
vecStart.x = msg.ReadFloat();
|
|
vecStart.y = msg.ReadFloat();
|
|
vecStart.z = msg.ReadFloat();
|
|
|
|
asw_num_tracers++;
|
|
|
|
int iAttributeEffects = msg.ReadShort();
|
|
ASWUTracerUnattached( pMarine, vecStart, vecEnd, iAttributeEffects );
|
|
|
|
if ( iAttributeEffects > 0 )
|
|
{
|
|
DoAttributeTracer( vecStart, vecEnd, iAttributeEffects );
|
|
}
|
|
}
|
|
USER_MESSAGE_REGISTER( ASWUTracerUnattached );
|
|
|
|
|
|
void ASWUTracerCallback( const CEffectData &data )
|
|
{
|
|
C_BasePlayer *player = C_BasePlayer::GetLocalPlayer();
|
|
|
|
if ( player == NULL )
|
|
return;
|
|
|
|
// Do tracer effect
|
|
C_ASW_Marine *pMarine = dynamic_cast<C_ASW_Marine*>(data.GetEntity());
|
|
ASWUTracer( pMarine, (Vector&)data.m_vOrigin, data.m_nMaterial );
|
|
DoAttributeTracer( pMarine, (Vector&)data.m_vOrigin, data.m_nMaterial );
|
|
}
|
|
DECLARE_CLIENT_EFFECT( ASWUTracer, ASWUTracerCallback );
|
|
|
|
void ASWUTracerRGCallback( const CEffectData &data )
|
|
{
|
|
C_BasePlayer *player = C_BasePlayer::GetLocalPlayer();
|
|
|
|
if ( player == NULL )
|
|
return;
|
|
|
|
// Do tracer effect
|
|
C_ASW_Marine *pMarine = dynamic_cast<C_ASW_Marine*>(data.GetEntity());
|
|
ASWUTracerRG( pMarine, (Vector&)data.m_vOrigin, data.m_nMaterial );
|
|
DoAttributeTracer( pMarine, (Vector&)data.m_vOrigin, data.m_nMaterial );
|
|
}
|
|
DECLARE_CLIENT_EFFECT( ASWUTracerRG, ASWUTracerRGCallback );
|
|
|
|
void ASWUTracerlessCallback( const CEffectData &data )
|
|
{
|
|
C_BasePlayer *player = C_BasePlayer::GetLocalPlayer();
|
|
|
|
if ( player == NULL )
|
|
return;
|
|
|
|
// Do tracer effect
|
|
C_ASW_Marine *pMarine = dynamic_cast<C_ASW_Marine*>(data.GetEntity());
|
|
ASWUTracerless( pMarine, (Vector&)data.m_vOrigin, data.m_nMaterial );
|
|
DoAttributeTracer( pMarine, (Vector&)data.m_vOrigin, data.m_nMaterial );
|
|
}
|
|
DECLARE_CLIENT_EFFECT( ASWUTracerless, ASWUTracerlessCallback );
|
|
|
|
void ASWUTracerDualCallback( const CEffectData &data )
|
|
{
|
|
C_BasePlayer *player = C_BasePlayer::GetLocalPlayer();
|
|
|
|
if ( player == NULL )
|
|
return;
|
|
|
|
// Do tracer effect
|
|
C_ASW_Marine *pMarine = dynamic_cast<C_ASW_Marine*>(data.GetEntity());
|
|
ASWUTracerDual( pMarine, (Vector&)data.m_vOrigin, (ASW_FX_TRACER_DUAL_LEFT | ASW_FX_TRACER_DUAL_RIGHT), data.m_nMaterial );
|
|
DoAttributeTracer( pMarine, (Vector&)data.m_vOrigin, data.m_nMaterial );
|
|
}
|
|
DECLARE_CLIENT_EFFECT( ASWUTracerDual, ASWUTracerDualCallback );
|
|
|
|
void ASWUTracerDualCallbackRight( const CEffectData &data )
|
|
{
|
|
C_BasePlayer *player = C_BasePlayer::GetLocalPlayer();
|
|
|
|
if ( player == NULL )
|
|
return;
|
|
|
|
// Do tracer effect
|
|
C_ASW_Marine *pMarine = dynamic_cast<C_ASW_Marine*>(data.GetEntity());
|
|
ASWUTracerDual( pMarine, (Vector&)data.m_vOrigin, ASW_FX_TRACER_DUAL_RIGHT, data.m_nMaterial );
|
|
DoAttributeTracer( pMarine, (Vector&)data.m_vOrigin, data.m_nMaterial );
|
|
}
|
|
DECLARE_CLIENT_EFFECT( ASWUTracerDualRight, ASWUTracerDualCallbackRight );
|
|
|
|
void ASWUTracerDualCallbackLeft( const CEffectData &data )
|
|
{
|
|
C_BasePlayer *player = C_BasePlayer::GetLocalPlayer();
|
|
|
|
if ( player == NULL )
|
|
return;
|
|
|
|
// Do tracer effect
|
|
C_ASW_Marine *pMarine = dynamic_cast<C_ASW_Marine*>(data.GetEntity());
|
|
ASWUTracerDual( pMarine, (Vector&)data.m_vOrigin, ASW_FX_TRACER_DUAL_LEFT, data.m_nMaterial );
|
|
DoAttributeTracer( pMarine, (Vector&)data.m_vOrigin, data.m_nMaterial );
|
|
}
|
|
DECLARE_CLIENT_EFFECT( ASWUTracerDualLeft, ASWUTracerDualCallbackLeft );
|
|
|
|
void ASWUTracerUnattachedCallback( const CEffectData &data )
|
|
{
|
|
C_BasePlayer *player = C_BasePlayer::GetLocalPlayer();
|
|
|
|
if ( player == NULL )
|
|
return;
|
|
|
|
// Do tracer effect
|
|
C_ASW_Marine *pMarine = dynamic_cast<C_ASW_Marine*>(data.GetEntity());
|
|
ASWUTracerUnattached( pMarine, (Vector&)data.m_vStart, (Vector&)data.m_vOrigin, data.m_nMaterial );
|
|
DoAttributeTracer( (Vector&)data.m_vStart, (Vector&)data.m_vOrigin, data.m_nMaterial );
|
|
}
|
|
DECLARE_CLIENT_EFFECT( ASWUTracerUnattached, ASWUTracerUnattachedCallback );
|
|
|
|
|
|
void asw_tracer_count_f()
|
|
{
|
|
Msg("spawned %d tracers from user messages. %d tracers total \n", asw_num_tracers, asw_num_u_tracers);
|
|
}
|
|
static ConCommand asw_tracer_count("asw_tracer_count", asw_tracer_count_f, "Shows number of tracers spawned", FCVAR_CHEAT);
|
|
|
|
void FX_ASWWaterRipple( const Vector &origin, float scale, Vector *pColor, float flLifetime, float flAlpha )
|
|
{
|
|
VPROF_BUDGET( "FX_ASWWaterRipple", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
|
|
trace_t tr;
|
|
|
|
Vector color = pColor ? *pColor : Vector( 0.8f, 0.8f, 0.75f );
|
|
|
|
Vector vecNormal = Vector(0,0,1);
|
|
|
|
{
|
|
//Add a ripple quad to the surface
|
|
FX_AddQuad( origin + ( vecNormal * 0.5f ),
|
|
vecNormal,
|
|
64.0f*scale,
|
|
128.0f*scale,
|
|
0.7f,
|
|
flAlpha, // start alpha
|
|
0.0f, // end alpha
|
|
0.25f,
|
|
random->RandomFloat( 0, 360 ),
|
|
random->RandomFloat( -16.0f, 16.0f ),
|
|
color,
|
|
flLifetime,
|
|
"effects/splashwake1",
|
|
(FXQUAD_BIAS_SCALE|FXQUAD_BIAS_ALPHA) );
|
|
}
|
|
}
|
|
|
|
extern ConVar cl_show_splashes;
|
|
extern inline void FX_GetSplashLighting( Vector position, Vector *color, float *luminosity );
|
|
#define SPLASH_MIN_SPEED 50.0f
|
|
#define SPLASH_MAX_SPEED 100.0f
|
|
void FX_ASWSplash( const Vector &origin, const Vector &normal, float scale )
|
|
{
|
|
VPROF_BUDGET( "FX_ASWSplash", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
|
|
|
|
if ( cl_show_splashes.GetBool() == false )
|
|
return;
|
|
|
|
Vector color;
|
|
float luminosity;
|
|
|
|
// Get our lighting information
|
|
FX_GetSplashLighting( origin + ( normal * scale ), &color, &luminosity );
|
|
|
|
float flScale = scale / 8.0f;
|
|
|
|
if ( flScale > 4.0f )
|
|
{
|
|
flScale = 4.0f;
|
|
}
|
|
|
|
// Setup our trail emitter
|
|
CSmartPtr<CTrailParticles> sparkEmitter = CTrailParticles::Create( "splash" );
|
|
|
|
if ( !sparkEmitter )
|
|
return;
|
|
|
|
sparkEmitter->SetSortOrigin( origin );
|
|
sparkEmitter->m_ParticleCollision.SetGravity( 800.0f );
|
|
sparkEmitter->SetFlag( bitsPARTICLE_TRAIL_VELOCITY_DAMPEN );
|
|
sparkEmitter->SetVelocityDampen( 2.0f );
|
|
sparkEmitter->GetBinding().SetBBox( origin - Vector( 32, 32, 32 ), origin + Vector( 32, 32, 32 ) );
|
|
|
|
PMaterialHandle hMaterial = ParticleMgr()->GetPMaterial( "effects/splash2" );
|
|
|
|
TrailParticle *tParticle;
|
|
|
|
Vector offDir;
|
|
Vector offset;
|
|
float colorRamp;
|
|
|
|
//Dump out drops
|
|
for ( int i = 0; i < 16; i++ )
|
|
{
|
|
offset = origin;
|
|
offset[0] += random->RandomFloat( -8.0f, 8.0f ) * flScale;
|
|
offset[1] += random->RandomFloat( -8.0f, 8.0f ) * flScale;
|
|
|
|
tParticle = (TrailParticle *) sparkEmitter->AddParticle( sizeof(TrailParticle), hMaterial, offset );
|
|
|
|
if ( tParticle == NULL )
|
|
break;
|
|
|
|
tParticle->m_flLifetime = 0.0f;
|
|
tParticle->m_flDieTime = random->RandomFloat( 0.25f, 0.5f );
|
|
|
|
offDir = normal + RandomVector( -0.8f, 0.8f );
|
|
|
|
tParticle->m_vecVelocity = offDir * random->RandomFloat( SPLASH_MIN_SPEED * flScale * 3.0f, SPLASH_MAX_SPEED * flScale * 3.0f );
|
|
//tParticle->m_vecVelocity[2] += random->RandomFloat( 32.0f, 64.0f ) * flScale;
|
|
tParticle->m_vecVelocity[2] += random->RandomFloat( 8.0f, 16.0f ) * flScale;
|
|
|
|
tParticle->m_flWidth = random->RandomFloat( 1.0f, 3.0f );
|
|
tParticle->m_flLength = random->RandomFloat( 0.025f, 0.05f );
|
|
|
|
colorRamp = random->RandomFloat( 0.75f, 1.25f );
|
|
|
|
tParticle->m_color.r = MIN( 1.0f, color[0] * colorRamp ) * 255;
|
|
tParticle->m_color.g = MIN( 1.0f, color[1] * colorRamp ) * 255;
|
|
tParticle->m_color.b = MIN( 1.0f, color[2] * colorRamp ) * 255;
|
|
tParticle->m_color.a = luminosity * 255;
|
|
}
|
|
|
|
// Setup the particle emitter
|
|
CSmartPtr<CSplashParticle> pSimple = CSplashParticle::Create( "splish" );
|
|
pSimple->SetSortOrigin( origin );
|
|
pSimple->SetClipHeight( origin.z );
|
|
pSimple->SetParticleCullRadius( scale * 2.0f );
|
|
pSimple->GetBinding().SetBBox( origin - Vector( 32, 32, 32 ), origin + Vector( 32, 32, 32 ) );
|
|
|
|
SimpleParticle *pParticle;
|
|
|
|
//Main gout
|
|
for ( int i = 0; i < 8; i++ )
|
|
{
|
|
pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), hMaterial, origin );
|
|
|
|
if ( pParticle == NULL )
|
|
break;
|
|
|
|
pParticle->m_flLifetime = 0.0f;
|
|
pParticle->m_flDieTime = 2.0f; //NOTENOTE: We use a clip plane to realistically control our lifespan
|
|
|
|
pParticle->m_vecVelocity.Random( -0.2f, 0.2f );
|
|
//pParticle->m_vecVelocity += ( normal * random->RandomFloat( 4.0f, 6.0f ) );
|
|
pParticle->m_vecVelocity += ( normal * random->RandomFloat( 1.0f, 2.0f ) );
|
|
|
|
VectorNormalize( pParticle->m_vecVelocity );
|
|
|
|
pParticle->m_vecVelocity *= 50 * flScale * (8-i);
|
|
|
|
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 = 24 * flScale * RemapValClamped( i, 7, 0, 1, 0.5f );
|
|
pParticle->m_uchEndSize = MIN( 255, pParticle->m_uchStartSize * 2 );
|
|
|
|
pParticle->m_uchStartAlpha = RemapValClamped( i, 7, 0, 255, 32 ) * luminosity;
|
|
pParticle->m_uchEndAlpha = 0;
|
|
|
|
pParticle->m_flRoll = random->RandomInt( 0, 360 );
|
|
pParticle->m_flRollDelta = random->RandomFloat( -4.0f, 4.0f );
|
|
}
|
|
}
|
|
|
|
void ASWSplashCallback( const CEffectData &data )
|
|
{
|
|
Vector normal;
|
|
AngleVectors( data.m_vAngles, &normal );
|
|
FX_ASWSplash( data.m_vOrigin, Vector(0,0,1), data.m_flScale );
|
|
}
|
|
|
|
DECLARE_CLIENT_EFFECT( aswwatersplash, ASWSplashCallback );
|
|
|
|
void FX_ASW_StunExplosion(const Vector &origin)
|
|
{
|
|
DispatchParticleEffect( "stungrenade_core", origin, QAngle( 0, 0, 0 ) );
|
|
}
|
|
|
|
void ASWStunExplosionCallback( const CEffectData &data )
|
|
{
|
|
FX_ASW_StunExplosion( data.m_vOrigin );
|
|
}
|
|
|
|
DECLARE_CLIENT_EFFECT( aswstunexplo, ASWStunExplosionCallback );
|
|
|
|
void ASWExplodeMapCallback( const CEffectData &data )
|
|
{
|
|
C_ASW_Level_Exploder::CreateClientsideLevelExploder();
|
|
}
|
|
|
|
DECLARE_CLIENT_EFFECT( ASWExplodeMap, ASWExplodeMapCallback );
|
|
|
|
void ASW_AcidBurnCallback( const CEffectData & data )
|
|
{
|
|
int iMarine = data.m_nOtherEntIndex;
|
|
C_ASW_Marine *pMarine = dynamic_cast<C_ASW_Marine*>(ClientEntityList().GetEnt(iMarine)); // turn iMarine ent index into the marine
|
|
if ( !pMarine )
|
|
return;
|
|
|
|
Vector vecSourcePos;
|
|
vecSourcePos = data.m_vOrigin;
|
|
|
|
//Vector vecMarineOffset = pMarine->GetAbsOrigin() + Vector( 0, 0, 60 );
|
|
Vector vecKillDir = pMarine->GetAbsOrigin() - vecSourcePos;
|
|
VectorNormalize( vecKillDir );
|
|
|
|
CUtlReference<CNewParticleEffect> pEffect;
|
|
pEffect = pMarine->ParticleProp()->Create( "acid_touch", PATTACH_ABSORIGIN_FOLLOW, -1, (-vecKillDir * 16) + Vector( 0, 0, 60 ) );
|
|
pMarine->ParticleProp()->AddControlPoint( pEffect, 1, pMarine, PATTACH_CUSTOMORIGIN );
|
|
pEffect->SetControlPoint( 1, vecSourcePos );
|
|
|
|
/*
|
|
unsigned char color[3];
|
|
color[0] = 128;
|
|
color[1] = 30;
|
|
color[2] = 30;
|
|
|
|
FX_Smoke( vecPosition, QAngle(-90,0,0), 2.0f, 5, &color[0], 128 );
|
|
*/
|
|
}
|
|
|
|
DECLARE_CLIENT_EFFECT( ASWAcidBurn, ASW_AcidBurnCallback );
|
|
|
|
void ASW_FireBurstCallback( const CEffectData & data )
|
|
{
|
|
DispatchParticleEffect( "vindicator_grenade", data.m_vOrigin, QAngle(0,0,0) );
|
|
}
|
|
|
|
DECLARE_CLIENT_EFFECT( ASWFireBurst, ASW_FireBurstCallback );
|
|
|
|
|
|
void FX_ASW_ShotgunSmoke(const Vector& vecOrigin, const QAngle& angFacing)
|
|
{
|
|
C_ASW_Emitter *pEmitter = new C_ASW_Emitter;
|
|
if (pEmitter)
|
|
{
|
|
if (pEmitter->InitializeAsClientEntity( NULL, false ))
|
|
{
|
|
Q_snprintf(pEmitter->m_szTemplateName, sizeof(pEmitter->m_szTemplateName), "shotgunsmoke");
|
|
pEmitter->m_fScale = 1.0f;
|
|
pEmitter->m_bEmit = true;
|
|
pEmitter->SetAbsOrigin(vecOrigin);
|
|
pEmitter->SetAbsAngles(angFacing);
|
|
pEmitter->CreateEmitter();
|
|
pEmitter->SetDieTime(gpGlobals->curtime + 2.0f);
|
|
}
|
|
else
|
|
{
|
|
UTIL_Remove( pEmitter );
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
void FX_ASW_CivvyCorpse(const Vector &origin, const QAngle& direction, const Vector& force)
|
|
{
|
|
CBaseEntity *pGib = CreateRagGib( "models/swarm/civilianz/civilianz.mdl", origin, direction, force );
|
|
}
|
|
|
|
void ASWCivvyCorpseCallback( const CEffectData &data )
|
|
{
|
|
FX_ASW_CivvyCorpse( data.m_vOrigin, data.m_vAngles, data.m_vNormal );
|
|
}
|
|
|
|
DECLARE_CLIENT_EFFECT( "aswcorpse", ASWCivvyCorpseCallback );
|
|
*/
|
|
/*
|
|
C_BaseAnimating* FX_ASW_Clientside_Ragdoll(const Vector &origin, const QAngle &facing)
|
|
{
|
|
C_BaseAnimating *pRagdoll = this;
|
|
|
|
C_ClientRagdoll *pRagdollCopy = new C_ClientRagdoll( false );
|
|
if ( pRagdollCopy == NULL )
|
|
return NULL;
|
|
|
|
C_BaseAnimating *pRagdoll = pRagdollCopy;
|
|
|
|
const char *pModelName = "models/swarm/civilianz/civilianz.mdl";
|
|
|
|
if ( pRagdoll->InitializeAsClientEntity( pModelName, false ) == false )
|
|
{
|
|
pRagdoll->Release();
|
|
return NULL;
|
|
}
|
|
|
|
// We need to take these from the entity
|
|
pRagdoll->SetAbsOrigin( origin );
|
|
pRagdoll->SetAbsAngles( facing );
|
|
|
|
pRagdoll->m_nRenderFX = kRenderFxRagdoll;
|
|
//pRagdoll->SetRenderMode( GetRenderMode() );
|
|
//pRagdoll->SetRenderColor( GetRenderColor().r, GetRenderColor().g, GetRenderColor().b, GetRenderColor().a );
|
|
|
|
//pRagdoll->m_nBody = 0;
|
|
//pRagdoll->m_nSkin = 0;
|
|
//pRagdoll->m_vecForce = Vector(0, 0, 0);
|
|
//pRagdoll->m_nForceBone = 0;
|
|
pRagdoll->SetNextClientThink( CLIENT_THINK_ALWAYS );
|
|
|
|
pRagdoll->SetModelName( AllocPooledString(pModelName) );
|
|
|
|
pRagdoll->m_builtRagdoll = true;
|
|
|
|
// Store off our old mins & maxs
|
|
//pRagdoll->m_vecPreRagdollMins = WorldAlignMins();
|
|
//pRagdoll->m_vecPreRagdollMaxs = WorldAlignMaxs();
|
|
|
|
matrix3x4_t preBones[MAXSTUDIOBONES];
|
|
matrix3x4_t curBones[MAXSTUDIOBONES];
|
|
|
|
// Force MOVETYPE_STEP interpolation
|
|
//MoveType_t savedMovetype = GetMoveType();
|
|
//SetMoveType( MOVETYPE_STEP );
|
|
|
|
// 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 );
|
|
|
|
// 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();
|
|
|
|
// Cache off ragdoll bone positions/quaternions
|
|
//if ( pRagdoll->m_bStoreRagdollInfo && pRagdoll->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 );
|
|
//}
|
|
|
|
|
|
//pRagdoll->m_nRestoreSequence = GetSequence();
|
|
//pRagdoll->SetSequence( SelectWeightedSequence( ACT_DIERAGDOLL ) );
|
|
//pRagdoll->m_nPrevSequence = GetSequence();
|
|
pRagdoll->m_flPlaybackRate = 0;
|
|
pRagdoll->UpdatePartitionListEntry();
|
|
|
|
//NoteRagdollCreationTick( pRagdoll );
|
|
|
|
//UpdateVisibility();
|
|
|
|
return pRagdoll;
|
|
}*/
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
// Input : scale -
|
|
// attachmentIndex -
|
|
// bOneFrame -
|
|
//-----------------------------------------------------------------------------
|
|
void FX_ASW_MuzzleEffectAttached(
|
|
float scale,
|
|
ClientEntityHandle_t hEntity,
|
|
int attachmentIndex,
|
|
unsigned char *pFlashColor,
|
|
bool bOneFrame )
|
|
{
|
|
VPROF_BUDGET( "FX_ASW_MuzzleEffectAttached", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
|
|
|
|
CSmartPtr<CLocalSpaceEmitter> pSimple = CLocalSpaceEmitter::Create( "MuzzleFlash", hEntity, attachmentIndex );
|
|
|
|
SimpleParticle *pParticle;
|
|
Vector forward(1,0,0), offset;
|
|
Vector movement;
|
|
|
|
float flScale = random->RandomFloat( scale-0.25f, scale+0.25f );
|
|
|
|
if ( flScale < 0.5f )
|
|
{
|
|
flScale = 0.5f;
|
|
}
|
|
else if ( flScale > 8.0f )
|
|
{
|
|
flScale = 8.0f;
|
|
}
|
|
|
|
//
|
|
// Flash
|
|
//
|
|
|
|
int i;
|
|
for ( i = 1; i < 9; i++ )
|
|
{
|
|
offset = (forward * (i*2.0f*scale));
|
|
|
|
pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), pSimple->GetPMaterial( VarArgs( "effects/muzzleflash%d", random->RandomInt(1,4) ) ), offset );
|
|
|
|
if ( pParticle == NULL )
|
|
return;
|
|
|
|
pParticle->m_flLifetime = 0.0f;
|
|
pParticle->m_flDieTime = bOneFrame ? 0.0001f : 0.1f;
|
|
|
|
pParticle->m_vecVelocity.Init();
|
|
pParticle->m_vecVelocity = movement;
|
|
|
|
if ( !pFlashColor )
|
|
{
|
|
pParticle->m_uchColor[0] = 255;
|
|
pParticle->m_uchColor[1] = 255;
|
|
pParticle->m_uchColor[2] = 255;
|
|
}
|
|
else
|
|
{
|
|
pParticle->m_uchColor[0] = pFlashColor[0];
|
|
pParticle->m_uchColor[1] = pFlashColor[1];
|
|
pParticle->m_uchColor[2] = pFlashColor[2];
|
|
}
|
|
|
|
pParticle->m_uchStartAlpha = 255;
|
|
pParticle->m_uchEndAlpha = 128;
|
|
|
|
pParticle->m_uchStartSize = (random->RandomFloat( 6.0f, 9.0f ) * (12-(i))/9) * flScale;
|
|
pParticle->m_uchEndSize = pParticle->m_uchStartSize;
|
|
// asw test
|
|
pParticle->m_uchStartSize = 0;
|
|
pParticle->m_flRoll = random->RandomInt( 0, 360 );
|
|
pParticle->m_flRollDelta = 0.0f;
|
|
}
|
|
|
|
|
|
if ( !ToolsEnabled() )
|
|
return;
|
|
|
|
if ( !clienttools->IsInRecordingMode() )
|
|
return;
|
|
|
|
C_BaseEntity *pEnt = ClientEntityList().GetBaseEntityFromHandle( hEntity );
|
|
if ( pEnt )
|
|
{
|
|
pEnt->RecordToolMessage();
|
|
}
|
|
|
|
// NOTE: Particle system destruction message will be sent by the particle effect itself.
|
|
int nId = pSimple->AllocateToolParticleEffectId();
|
|
|
|
KeyValues *msg = new KeyValues( "ParticleSystem_Create" );
|
|
msg->SetString( "name", "FX_MuzzleEffectAttached" );
|
|
msg->SetInt( "id", nId );
|
|
msg->SetFloat( "time", gpGlobals->curtime );
|
|
|
|
KeyValues *pEmitter = msg->FindKey( "DmeSpriteEmitter", true );
|
|
pEmitter->SetInt( "count", 9 );
|
|
pEmitter->SetFloat( "duration", 0 );
|
|
pEmitter->SetString( "material", "effects/muzzleflash2" ); // FIXME - create DmeMultiMaterialSpriteEmitter to support the 4 materials of muzzleflash
|
|
pEmitter->SetInt( "active", true );
|
|
|
|
KeyValues *pInitializers = pEmitter->FindKey( "initializers", true );
|
|
|
|
KeyValues *pPosition = pInitializers->FindKey( "DmeLinearAttachedPositionInitializer", true );
|
|
pPosition->SetPtr( "entindex", (void*)pEnt->entindex() );
|
|
pPosition->SetInt( "attachmentIndex", attachmentIndex );
|
|
pPosition->SetFloat( "linearOffsetX", 2.0f * scale );
|
|
|
|
// TODO - create a DmeConstantLifetimeInitializer
|
|
KeyValues *pLifetime = pInitializers->FindKey( "DmeRandomLifetimeInitializer", true );
|
|
pLifetime->SetFloat( "minLifetime", bOneFrame ? 1.0f / 24.0f : 0.1f );
|
|
pLifetime->SetFloat( "maxLifetime", bOneFrame ? 1.0f / 24.0f : 0.1f );
|
|
|
|
KeyValues *pVelocity = pInitializers->FindKey( "DmeConstantVelocityInitializer", true );
|
|
pVelocity->SetFloat( "velocityX", 0.0f );
|
|
pVelocity->SetFloat( "velocityY", 0.0f );
|
|
pVelocity->SetFloat( "velocityZ", 0.0f );
|
|
|
|
KeyValues *pRoll = pInitializers->FindKey( "DmeRandomRollInitializer", true );
|
|
pRoll->SetFloat( "minRoll", 0.0f );
|
|
pRoll->SetFloat( "maxRoll", 360.0f );
|
|
|
|
// TODO - create a DmeConstantRollSpeedInitializer
|
|
KeyValues *pRollSpeed = pInitializers->FindKey( "DmeRandomRollSpeedInitializer", true );
|
|
pRollSpeed->SetFloat( "minRollSpeed", 0.0f );
|
|
pRollSpeed->SetFloat( "maxRollSpeed", 0.0f );
|
|
|
|
// TODO - create a DmeConstantColorInitializer
|
|
KeyValues *pColor = pInitializers->FindKey( "DmeRandomInterpolatedColorInitializer", true );
|
|
Color color( pFlashColor ? pFlashColor[ 0 ] : 255, pFlashColor ? pFlashColor[ 1 ] : 255, pFlashColor ? pFlashColor[ 2 ] : 255, 255 );
|
|
pColor->SetColor( "color1", color );
|
|
pColor->SetColor( "color2", color );
|
|
|
|
// TODO - create a DmeConstantAlphaInitializer
|
|
KeyValues *pAlpha = pInitializers->FindKey( "DmeRandomAlphaInitializer", true );
|
|
pAlpha->SetInt( "minStartAlpha", 255 );
|
|
pAlpha->SetInt( "maxStartAlpha", 255 );
|
|
pAlpha->SetInt( "minEndAlpha", 128 );
|
|
pAlpha->SetInt( "maxEndAlpha", 128 );
|
|
|
|
// size = rand(6..9) * indexed(12/9..4/9) * flScale = rand(6..9) * ( 4f + f * i )
|
|
KeyValues *pSize = pInitializers->FindKey( "DmeMuzzleFlashSizeInitializer", true );
|
|
float f = flScale / 9.0f;
|
|
pSize->SetFloat( "indexedBase", 4.0f * f );
|
|
pSize->SetFloat( "indexedDelta", f );
|
|
pSize->SetFloat( "minRandomFactor", 6.0f );
|
|
pSize->SetFloat( "maxRandomFactor", 9.0f );
|
|
|
|
/*
|
|
KeyValues *pUpdaters = pEmitter->FindKey( "updaters", true );
|
|
|
|
pUpdaters->FindKey( "DmePositionVelocityUpdater", true );
|
|
pUpdaters->FindKey( "DmeRollUpdater", true );
|
|
pUpdaters->FindKey( "DmeAlphaLinearUpdater", true );
|
|
pUpdaters->FindKey( "DmeSizeUpdater", true );
|
|
*/
|
|
ToolFramework_PostToolMessage( HTOOLHANDLE_INVALID, msg );
|
|
msg->deleteThis();
|
|
}
|
|
|
|
void FX_ASW_RedMuzzleEffectAttached(
|
|
float scale,
|
|
ClientEntityHandle_t hEntity,
|
|
int attachmentIndex,
|
|
unsigned char *pFlashColor,
|
|
bool bOneFrame )
|
|
{
|
|
VPROF_BUDGET( "FX_ASW_RedMuzzleEffectAttached", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
|
|
|
|
CSmartPtr<CLocalSpaceEmitter> pSimple = CLocalSpaceEmitter::Create( "MuzzleFlash", hEntity, attachmentIndex );
|
|
|
|
SimpleParticle *pParticle;
|
|
Vector forward(1,0,0), offset;
|
|
// asw
|
|
Vector movement;
|
|
|
|
float flScale = random->RandomFloat( scale-0.25f, scale+0.25f );
|
|
|
|
if ( flScale < 0.5f )
|
|
{
|
|
flScale = 0.5f;
|
|
}
|
|
else if ( flScale > 8.0f )
|
|
{
|
|
flScale = 8.0f;
|
|
}
|
|
|
|
//
|
|
// Flash
|
|
//
|
|
|
|
int i;
|
|
for ( i = 1; i < 9; i++ )
|
|
{
|
|
#ifndef INFESTED_DLL
|
|
offset = (forward * (i*2.0f*scale));
|
|
#else
|
|
offset = vec3_origin;
|
|
movement = (forward * (i*2.0f*scale)) / 0.1f;
|
|
#endif
|
|
|
|
pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), pSimple->GetPMaterial( VarArgs("swarm/effects/muzzleflashred%d", random->RandomInt(1,4)) ), offset );
|
|
|
|
if ( pParticle == NULL )
|
|
return;
|
|
|
|
pParticle->m_flLifetime = 0.0f;
|
|
pParticle->m_flDieTime = bOneFrame ? 0.0001f : 0.1f;
|
|
|
|
pParticle->m_vecVelocity.Init();
|
|
// asw test
|
|
pParticle->m_vecVelocity = movement;
|
|
|
|
if ( !pFlashColor )
|
|
{
|
|
pParticle->m_uchColor[0] = 255;
|
|
pParticle->m_uchColor[1] = 255;
|
|
pParticle->m_uchColor[2] = 255;
|
|
}
|
|
else
|
|
{
|
|
pParticle->m_uchColor[0] = pFlashColor[0];
|
|
pParticle->m_uchColor[1] = pFlashColor[1];
|
|
pParticle->m_uchColor[2] = pFlashColor[2];
|
|
}
|
|
|
|
pParticle->m_uchStartAlpha = 255;
|
|
pParticle->m_uchEndAlpha = 128;
|
|
|
|
pParticle->m_uchStartSize = (random->RandomFloat( 6.0f, 9.0f ) * (12-(i))/9) * flScale;
|
|
pParticle->m_uchEndSize = pParticle->m_uchStartSize;
|
|
// asw test
|
|
pParticle->m_uchStartSize = 0;
|
|
pParticle->m_flRoll = random->RandomInt( 0, 360 );
|
|
pParticle->m_flRollDelta = 0.0f;
|
|
}
|
|
|
|
|
|
if ( !ToolsEnabled() )
|
|
return;
|
|
|
|
if ( !clienttools->IsInRecordingMode() )
|
|
return;
|
|
|
|
C_BaseEntity *pEnt = ClientEntityList().GetBaseEntityFromHandle( hEntity );
|
|
if ( pEnt )
|
|
{
|
|
pEnt->RecordToolMessage();
|
|
}
|
|
|
|
// NOTE: Particle system destruction message will be sent by the particle effect itself.
|
|
int nId = pSimple->AllocateToolParticleEffectId();
|
|
|
|
KeyValues *msg = new KeyValues( "ParticleSystem_Create" );
|
|
msg->SetString( "name", "FX_MuzzleEffectAttached" );
|
|
msg->SetInt( "id", nId );
|
|
msg->SetFloat( "time", gpGlobals->curtime );
|
|
|
|
KeyValues *pEmitter = msg->FindKey( "DmeSpriteEmitter", true );
|
|
pEmitter->SetInt( "count", 9 );
|
|
pEmitter->SetFloat( "duration", 0 );
|
|
pEmitter->SetString( "material", "effects/muzzleflash2" ); // FIXME - create DmeMultiMaterialSpriteEmitter to support the 4 materials of muzzleflash
|
|
pEmitter->SetInt( "active", true );
|
|
|
|
KeyValues *pInitializers = pEmitter->FindKey( "initializers", true );
|
|
|
|
KeyValues *pPosition = pInitializers->FindKey( "DmeLinearAttachedPositionInitializer", true );
|
|
pPosition->SetPtr( "entindex", (void*)pEnt->entindex() );
|
|
pPosition->SetInt( "attachmentIndex", attachmentIndex );
|
|
pPosition->SetFloat( "linearOffsetX", 2.0f * scale );
|
|
|
|
// TODO - create a DmeConstantLifetimeInitializer
|
|
KeyValues *pLifetime = pInitializers->FindKey( "DmeRandomLifetimeInitializer", true );
|
|
pLifetime->SetFloat( "minLifetime", bOneFrame ? 1.0f / 24.0f : 0.1f );
|
|
pLifetime->SetFloat( "maxLifetime", bOneFrame ? 1.0f / 24.0f : 0.1f );
|
|
|
|
KeyValues *pVelocity = pInitializers->FindKey( "DmeConstantVelocityInitializer", true );
|
|
pVelocity->SetFloat( "velocityX", 0.0f );
|
|
pVelocity->SetFloat( "velocityY", 0.0f );
|
|
pVelocity->SetFloat( "velocityZ", 0.0f );
|
|
|
|
KeyValues *pRoll = pInitializers->FindKey( "DmeRandomRollInitializer", true );
|
|
pRoll->SetFloat( "minRoll", 0.0f );
|
|
pRoll->SetFloat( "maxRoll", 360.0f );
|
|
|
|
// TODO - create a DmeConstantRollSpeedInitializer
|
|
KeyValues *pRollSpeed = pInitializers->FindKey( "DmeRandomRollSpeedInitializer", true );
|
|
pRollSpeed->SetFloat( "minRollSpeed", 0.0f );
|
|
pRollSpeed->SetFloat( "maxRollSpeed", 0.0f );
|
|
|
|
// TODO - create a DmeConstantColorInitializer
|
|
KeyValues *pColor = pInitializers->FindKey( "DmeRandomInterpolatedColorInitializer", true );
|
|
Color color( pFlashColor ? pFlashColor[ 0 ] : 255, pFlashColor ? pFlashColor[ 1 ] : 255, pFlashColor ? pFlashColor[ 2 ] : 255, 255 );
|
|
pColor->SetColor( "color1", color );
|
|
pColor->SetColor( "color2", color );
|
|
|
|
// TODO - create a DmeConstantAlphaInitializer
|
|
KeyValues *pAlpha = pInitializers->FindKey( "DmeRandomAlphaInitializer", true );
|
|
pAlpha->SetInt( "minStartAlpha", 255 );
|
|
pAlpha->SetInt( "maxStartAlpha", 255 );
|
|
pAlpha->SetInt( "minEndAlpha", 128 );
|
|
pAlpha->SetInt( "maxEndAlpha", 128 );
|
|
|
|
// size = rand(6..9) * indexed(12/9..4/9) * flScale = rand(6..9) * ( 4f + f * i )
|
|
KeyValues *pSize = pInitializers->FindKey( "DmeMuzzleFlashSizeInitializer", true );
|
|
float f = flScale / 9.0f;
|
|
pSize->SetFloat( "indexedBase", 4.0f * f );
|
|
pSize->SetFloat( "indexedDelta", f );
|
|
pSize->SetFloat( "minRandomFactor", 6.0f );
|
|
pSize->SetFloat( "maxRandomFactor", 9.0f );
|
|
|
|
/*
|
|
KeyValues *pUpdaters = pEmitter->FindKey( "updaters", true );
|
|
|
|
pUpdaters->FindKey( "DmePositionVelocityUpdater", true );
|
|
pUpdaters->FindKey( "DmeRollUpdater", true );
|
|
pUpdaters->FindKey( "DmeAlphaLinearUpdater", true );
|
|
pUpdaters->FindKey( "DmeSizeUpdater", true );
|
|
*/
|
|
ToolFramework_PostToolMessage( HTOOLHANDLE_INVALID, msg );
|
|
msg->deleteThis();
|
|
}
|
|
|
|
void FX_QueenDie(C_BaseAnimating *pQueen)
|
|
{
|
|
if (!pQueen)
|
|
return;
|
|
|
|
C_ASW_Emitter *pEmitter = new C_ASW_Emitter;
|
|
if (pEmitter)
|
|
{
|
|
if (pEmitter->InitializeAsClientEntity( NULL, false ))
|
|
{
|
|
Q_snprintf(pEmitter->m_szTemplateName, sizeof(pEmitter->m_szTemplateName), "queendie");
|
|
pEmitter->m_fScale = 2.0f;
|
|
pEmitter->m_bEmit = true;
|
|
pEmitter->CreateEmitter();
|
|
pEmitter->SetAbsOrigin(pQueen->WorldSpaceCenter());
|
|
pEmitter->SetAbsAngles(QAngle(0,0,0));
|
|
pEmitter->SetDieTime(gpGlobals->curtime + 4.0f);
|
|
pEmitter->ClientAttach(pQueen, "SpitSource");
|
|
}
|
|
else
|
|
{
|
|
UTIL_Remove( pEmitter );
|
|
}
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: create a muzzle flassh using the new particle system
|
|
//-----------------------------------------------------------------------------
|
|
void FX_ASW_ParticleMuzzleFlashAttached( float scale, ClientEntityHandle_t hEntity, int attachmentIndex, bool bIsRed )
|
|
{
|
|
VPROF_BUDGET( "FX_ASW_ParticleMuzzleFlashAttached", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
|
|
|
|
C_ASW_Weapon *pWeapon = dynamic_cast<C_ASW_Weapon*>( hEntity.Get() );
|
|
if ( !pWeapon )
|
|
return;
|
|
|
|
if ( !asw_muzzle_flash_new_type.GetBool() )
|
|
{
|
|
CUtlReference<CNewParticleEffect> pMuzzle = pWeapon->ParticleProp()->Create( pWeapon->GetMuzzleEffectName(), PATTACH_POINT_FOLLOW, attachmentIndex );
|
|
if ( !pMuzzle || !pMuzzle->IsValid() )
|
|
return;
|
|
|
|
Vector vecStart;
|
|
QAngle vecAngles;
|
|
// Get the muzzle origin
|
|
if ( !pWeapon->GetAttachment( attachmentIndex, vecStart, vecAngles ) )
|
|
return;
|
|
|
|
// scale
|
|
pMuzzle->SetControlPoint( 10, Vector( scale, 0, 0 ) );
|
|
|
|
// color
|
|
Vector vecColor = Vector( 1, 1, 1 );
|
|
if ( bIsRed )
|
|
vecColor = Vector( 1, 0.55, 0.55 );
|
|
pMuzzle->SetControlPoint( 20, vecColor );
|
|
}
|
|
else
|
|
{
|
|
pWeapon->m_fMuzzleFlashTime = gpGlobals->curtime + 0.1f;
|
|
}
|
|
}
|
|
|
|
void QueenDieCallback( const CEffectData &data )
|
|
{
|
|
C_BaseAnimating *pAnimating = dynamic_cast<C_BaseAnimating*>(data.GetEntity());
|
|
if (pAnimating)
|
|
FX_QueenDie( pAnimating );
|
|
}
|
|
|
|
DECLARE_CLIENT_EFFECT( QueenDie, QueenDieCallback );
|
|
|
|
void __MsgFunc_ASWEnvExplosionFX( bf_read &msg )
|
|
{
|
|
Vector vecPos;
|
|
vecPos.x = msg.ReadFloat();
|
|
vecPos.y = msg.ReadFloat();
|
|
vecPos.z = msg.ReadFloat();
|
|
float flRadius = msg.ReadFloat();
|
|
int iOnGround = msg.ReadOneBit() ? 1 : 0;
|
|
|
|
if ( iOnGround )
|
|
{
|
|
trace_t tr;
|
|
CTraceFilterWorldOnly traceFilter;
|
|
UTIL_TraceLine( vecPos, vecPos + Vector( 0, 0, -64), MASK_SOLID, &traceFilter, &tr );
|
|
if ( tr.fraction != 1.0f )
|
|
{
|
|
surfacedata_t *pSurface = physprops->GetSurfaceData( tr.surface.surfaceProps );
|
|
if ( pSurface )
|
|
{
|
|
if ( pSurface->game.material == CHAR_TEX_SNOW )
|
|
DispatchParticleEffect( "snow_explosion", tr.endpos, Vector( flRadius, 0, 0 ), QAngle( 0, 0, 0 ) );
|
|
}
|
|
}
|
|
}
|
|
|
|
CUtlReference<CNewParticleEffect> pEffect = CNewParticleEffect::Create( NULL, "asw_env_explosion" );
|
|
if ( pEffect->IsValid() )
|
|
{
|
|
pEffect->SetSortOrigin( vecPos );
|
|
pEffect->SetControlPoint( 0, vecPos );
|
|
pEffect->SetControlPoint( 1, Vector( flRadius, iOnGround, 0 ) );
|
|
// this is the ring on the ground
|
|
pEffect->SetControlPoint( 2, Vector( flRadius, flRadius, flRadius ) );
|
|
|
|
//Vector vecForward, vecRight, vecUp;
|
|
//AngleVectors( data.m_vAngles, &vecForward, &vecRight, &vecUp );
|
|
//pEffect->SetControlPointOrientation( 0, vecForward, vecRight, vecUp );
|
|
}
|
|
}
|
|
USER_MESSAGE_REGISTER( ASWEnvExplosionFX );
|
|
|
|
void __MsgFunc_ASWBuzzerDeath( bf_read &msg )
|
|
{
|
|
Vector vecPos;
|
|
vecPos.x = msg.ReadFloat();
|
|
vecPos.y = msg.ReadFloat();
|
|
vecPos.z = msg.ReadFloat();
|
|
|
|
DispatchParticleEffect( "buzzer_death", vecPos, Vector( 0, 0, 0 ), QAngle( 0, 0, 0 ) );
|
|
}
|
|
USER_MESSAGE_REGISTER( ASWBuzzerDeath );
|
|
|
|
void __MsgFunc_ASWGrenadeExplosion( bf_read &msg )
|
|
{
|
|
Vector vecPos;
|
|
vecPos.x = msg.ReadFloat();
|
|
vecPos.y = msg.ReadFloat();
|
|
vecPos.z = msg.ReadFloat();
|
|
float flRadius = msg.ReadFloat();
|
|
|
|
trace_t tr;
|
|
CTraceFilterWorldOnly traceFilter;
|
|
UTIL_TraceLine( vecPos, vecPos + Vector( 0, 0, -64), MASK_SOLID, &traceFilter, &tr );
|
|
if ( tr.fraction != 1.0f )
|
|
{
|
|
surfacedata_t *pSurface = physprops->GetSurfaceData( tr.surface.surfaceProps );
|
|
if ( pSurface )
|
|
{
|
|
if ( pSurface->game.material == CHAR_TEX_SNOW )
|
|
DispatchParticleEffect( "snow_explosion", tr.endpos, Vector( flRadius, 0, 0 ), QAngle( 0, 0, 0 ) );
|
|
}
|
|
}
|
|
|
|
DispatchParticleEffect( "explosion_grenade", vecPos, Vector( flRadius, 0, 0 ), QAngle( 0, 0, 0 ) );
|
|
}
|
|
USER_MESSAGE_REGISTER( ASWGrenadeExplosion );
|
|
|
|
void __MsgFunc_ASWBarrelExplosion( bf_read &msg )
|
|
{
|
|
Vector vecPos;
|
|
vecPos.x = msg.ReadFloat();
|
|
vecPos.y = msg.ReadFloat();
|
|
vecPos.z = msg.ReadFloat();
|
|
float flRadius = msg.ReadFloat();
|
|
|
|
trace_t tr;
|
|
CTraceFilterWorldOnly traceFilter;
|
|
UTIL_TraceLine( vecPos, vecPos + Vector( 0, 0, -64), MASK_SOLID, &traceFilter, &tr );
|
|
if ( tr.fraction != 1.0f )
|
|
{
|
|
surfacedata_t *pSurface = physprops->GetSurfaceData( tr.surface.surfaceProps );
|
|
if ( pSurface )
|
|
{
|
|
if ( pSurface->game.material == CHAR_TEX_SNOW )
|
|
DispatchParticleEffect( "snow_explosion", tr.endpos, Vector( flRadius, 0, 0 ), QAngle( 0, 0, 0 ) );
|
|
}
|
|
}
|
|
|
|
DispatchParticleEffect( "explosion_barrel", vecPos, Vector( flRadius, 0, 0 ), QAngle( 0, 0, 0 ) );
|
|
}
|
|
USER_MESSAGE_REGISTER( ASWBarrelExplosion );
|
|
|
|
void __MsgFunc_ASWMarineHitByMelee( bf_read &msg )
|
|
{
|
|
int iMarine = msg.ReadShort();
|
|
C_ASW_Marine *pMarine = dynamic_cast<C_ASW_Marine*>(ClientEntityList().GetEnt(iMarine)); // turn iMarine ent index into the marine
|
|
if ( !pMarine )
|
|
return;
|
|
|
|
Vector attachOrigin;
|
|
attachOrigin.x = msg.ReadFloat();
|
|
attachOrigin.y = msg.ReadFloat();
|
|
attachOrigin.z = msg.ReadFloat();
|
|
|
|
Vector vecDir = attachOrigin - pMarine->GetAbsOrigin();
|
|
VectorNormalize(vecDir);
|
|
|
|
UTIL_ASW_MarineTakeDamage( (pMarine->WorldSpaceCenter() + Vector(0,0,24)) + vecDir*8, vecDir, pMarine->BloodColor(), 5, pMarine );
|
|
}
|
|
USER_MESSAGE_REGISTER( ASWMarineHitByMelee );
|
|
|
|
void __MsgFunc_ASWMarineHitByFF( bf_read &msg )
|
|
{
|
|
int iMarine = msg.ReadShort();
|
|
C_ASW_Marine *pMarine = dynamic_cast<C_ASW_Marine*>(ClientEntityList().GetEnt(iMarine)); // turn iMarine ent index into the marine
|
|
if ( !pMarine )
|
|
return;
|
|
|
|
Vector attachOrigin;
|
|
attachOrigin.x = msg.ReadFloat();
|
|
attachOrigin.y = msg.ReadFloat();
|
|
attachOrigin.z = msg.ReadFloat();
|
|
|
|
Vector vecDir = attachOrigin - pMarine->WorldSpaceCenter();
|
|
VectorNormalize(vecDir);
|
|
|
|
UTIL_ASW_MarineTakeDamage( attachOrigin, vecDir, pMarine->BloodColor(), 5, pMarine, true );
|
|
}
|
|
|
|
USER_MESSAGE_REGISTER( ASWMarineHitByFF );
|
|
|
|
void __MsgFunc_ASWEnemyZappedByThorns( bf_read &msg )
|
|
{
|
|
int iMarine = msg.ReadShort();
|
|
C_ASW_Marine *pMarine = dynamic_cast<C_ASW_Marine*>(ClientEntityList().GetEnt(iMarine)); // turn iMarine ent index into the marine
|
|
if ( !pMarine )
|
|
return;
|
|
|
|
int iAlien = msg.ReadShort();
|
|
C_ASW_Alien *pAlien = dynamic_cast<C_ASW_Alien*>(ClientEntityList().GetEnt(iAlien)); // turn iMarine ent index into the marine
|
|
if ( !pAlien )
|
|
return;
|
|
|
|
Vector vecDir = pMarine->GetAbsOrigin() - pAlien->GetAbsOrigin();
|
|
VectorNormalize(vecDir);
|
|
|
|
Vector vecCtrl0 = (pAlien->WorldSpaceCenter() + Vector(0,0,20)) + vecDir*8;
|
|
Vector vecCtrl1 = (pMarine->WorldSpaceCenter() + Vector(0,0,20)) - vecDir*8;
|
|
|
|
//QAngle vecAngles;
|
|
//VectorAngles( -vecDir, vecAngles );
|
|
//Vector vecForward, vecRight, vecUp;
|
|
//AngleVectors( vecAngles, &vecForward, &vecRight, &vecUp );
|
|
|
|
CUtlReference<CNewParticleEffect> pEffect;
|
|
|
|
pEffect = pAlien->ParticleProp()->Create( "thorns_zap", PATTACH_ABSORIGIN_FOLLOW );
|
|
pAlien->ParticleProp()->AddControlPoint( pEffect, 1, pMarine, PATTACH_CUSTOMORIGIN );
|
|
pEffect->SetControlPoint( 0, vecCtrl0 );
|
|
pEffect->SetControlPoint( 1, vecCtrl1 );
|
|
//pEffect->SetControlPointOrientation( 0, vecForward, vecRight, vecUp );
|
|
|
|
CLocalPlayerFilter filter;
|
|
CSoundParameters params;
|
|
|
|
// zap the alien!
|
|
if ( C_BaseEntity::GetParametersForSound( "ASW_ElectrifiedSuit.Zap", params, NULL ) )
|
|
{
|
|
EmitSound_t ep( params );
|
|
ep.m_pOrigin = &vecCtrl0;
|
|
|
|
C_BaseEntity::EmitSound( filter, 0, ep );
|
|
}
|
|
}
|
|
USER_MESSAGE_REGISTER( ASWEnemyZappedByThorns );
|
|
|
|
void __MsgFunc_ASWEnemyZappedByTesla( bf_read &msg )
|
|
{
|
|
Vector attachOrigin;
|
|
attachOrigin.x = msg.ReadFloat();
|
|
attachOrigin.y = msg.ReadFloat();
|
|
attachOrigin.z = msg.ReadFloat();
|
|
|
|
int iEnemy = msg.ReadShort();
|
|
C_BaseEntity *pEnemy = dynamic_cast<C_BaseEntity*>(ClientEntityList().GetEnt(iEnemy)); // turn iMarine ent index into the marine
|
|
if ( !pEnemy )
|
|
return;
|
|
|
|
Vector vecDir = attachOrigin - pEnemy->GetAbsOrigin();
|
|
VectorNormalize(vecDir);
|
|
|
|
Vector vecCtrl0 = (pEnemy->WorldSpaceCenter() + Vector(0,0,20)) - vecDir*8;
|
|
Vector vecCtrl1 = attachOrigin;
|
|
|
|
//QAngle vecAngles;
|
|
//VectorAngles( -vecDir, vecAngles );
|
|
//Vector vecForward, vecRight, vecUp;
|
|
//AngleVectors( vecAngles, &vecForward, &vecRight, &vecUp );
|
|
|
|
CUtlReference<CNewParticleEffect> pEffect;
|
|
|
|
pEffect = pEnemy->ParticleProp()->Create( "tesla_zap_fx", PATTACH_ABSORIGIN_FOLLOW, NULL, Vector( 0, 0, 32 ) );
|
|
//pEnemy->ParticleProp()->AddControlPoint( pEffect, 1, pSource, PATTACH_CUSTOMORIGIN );
|
|
pEffect->SetControlPoint( 0, vecCtrl0 );
|
|
pEffect->SetControlPoint( 1, vecCtrl1 );
|
|
//pEffect->SetControlPointOrientation( 0, vecForward, vecRight, vecUp );
|
|
|
|
CLocalPlayerFilter filter;
|
|
CSoundParameters params;
|
|
|
|
// zap the alien!
|
|
if ( C_BaseEntity::GetParametersForSound( "ASW_Tesla_Trap.Zap", params, NULL ) )
|
|
{
|
|
EmitSound_t ep( params );
|
|
ep.m_pOrigin = &vecCtrl0;
|
|
|
|
C_BaseEntity::EmitSound( filter, 0, ep );
|
|
}
|
|
|
|
C_ASW_Marine *pMarine = C_ASW_Marine::GetLocalMarine();
|
|
if ( !pMarine )
|
|
return;
|
|
|
|
float flDist = pMarine->GetAbsOrigin().DistTo( attachOrigin );
|
|
|
|
const float flRadius = 300.0f;
|
|
float flPerc = 1.0 - clamp<float>( flDist / flRadius, 0.0f, 1.0f );
|
|
|
|
ScreenShake_t shake;
|
|
shake.command = SHAKE_START;
|
|
shake.amplitude = 1.0f * flPerc;
|
|
shake.frequency = 80.f;
|
|
shake.duration = 0.5f;
|
|
|
|
GetViewEffects()->Shake( shake );
|
|
}
|
|
USER_MESSAGE_REGISTER( ASWEnemyZappedByTesla );
|
|
|
|
void __MsgFunc_ASWEnemyTeslaGunArcShock( bf_read &msg )
|
|
{
|
|
int iSrcEnt = msg.ReadShort();
|
|
C_BaseEntity *pSrcEnt = dynamic_cast<C_BaseEntity*>(ClientEntityList().GetEnt(iSrcEnt)); // turn iMarine ent index into the marine
|
|
if ( !pSrcEnt )
|
|
return;
|
|
|
|
int iEnemy = msg.ReadShort();
|
|
C_BaseEntity *pEnemy = dynamic_cast<C_BaseEntity*>(ClientEntityList().GetEnt(iEnemy)); // turn iMarine ent index into the marine
|
|
if ( !pEnemy )
|
|
return;
|
|
|
|
Vector vecDir = pSrcEnt->GetAbsOrigin() - pEnemy->GetAbsOrigin();
|
|
VectorNormalize(vecDir);
|
|
|
|
Vector vecCtrl0 = (pEnemy->WorldSpaceCenter() + Vector(0,0,20)) - vecDir*8;
|
|
Vector vecCtrl1 = pSrcEnt->WorldSpaceCenter() + vecDir*8;
|
|
|
|
|
|
CUtlReference<CNewParticleEffect> pEffect;
|
|
|
|
pEffect = pEnemy->ParticleProp()->Create( "tesla_zap_fx", PATTACH_ABSORIGIN_FOLLOW, NULL, Vector( 0, 0, 32 ) );
|
|
pEffect->SetControlPoint( 0, vecCtrl0 );
|
|
pEffect->SetControlPoint( 1, vecCtrl1 );
|
|
|
|
CLocalPlayerFilter filter;
|
|
CSoundParameters params;
|
|
|
|
/*
|
|
// zap the alien!
|
|
if ( C_BaseEntity::GetParametersForSound( "ASW_Tesla_Trap.Zap", params, NULL ) )
|
|
{
|
|
EmitSound_t ep( params );
|
|
ep.m_pOrigin = &vecCtrl0;
|
|
|
|
C_BaseEntity::EmitSound( filter, 0, ep );
|
|
}
|
|
*/
|
|
|
|
/*
|
|
C_ASW_Marine *pMarine = C_ASW_Marine::GetLocalMarine();
|
|
if ( !pMarine )
|
|
return;
|
|
|
|
float flDist = pMarine->GetAbsOrigin().DistTo( attachOrigin );
|
|
|
|
const float flRadius = 300.0f;
|
|
float flPerc = 1.0 - clamp<float>( flDist / flRadius, 0.0f, 1.0f );
|
|
|
|
ScreenShake_t shake;
|
|
shake.command = SHAKE_START;
|
|
shake.amplitude = 1.0f * flPerc;
|
|
shake.frequency = 80.f;
|
|
shake.duration = 0.5f;
|
|
|
|
GetViewEffects()->Shake( shake );
|
|
*/
|
|
}
|
|
USER_MESSAGE_REGISTER( ASWEnemyTeslaGunArcShock );
|
|
|
|
// TODO: We're doing this via a user-message since the mining laser attaches to control points -
|
|
// explore integrating this into the ParticleSystem client effect via CBaseEffect?
|
|
void __MsgFunc_ASWMiningLaserZap( bf_read &msg )
|
|
{
|
|
int iMiningLaser = msg.ReadShort();
|
|
int iTarget = msg.ReadShort();
|
|
int iAttachmentIndex = msg.ReadShort();
|
|
|
|
C_BaseEntity *pMiningLaser = dynamic_cast<C_BaseEntity*>(ClientEntityList().GetEnt(iMiningLaser));
|
|
|
|
if ( !pMiningLaser )
|
|
{
|
|
return;
|
|
}
|
|
|
|
C_BaseEntity *pTarget = ClientEntityList().GetEnt(iTarget);
|
|
Vector impactOrigin;
|
|
|
|
impactOrigin.x = msg.ReadFloat();
|
|
impactOrigin.y = msg.ReadFloat();
|
|
impactOrigin.z = msg.ReadFloat();
|
|
|
|
C_BaseAnimating::PushAllowBoneAccess( true, false, "ASWMiningLaserZap" );
|
|
|
|
CUtlReference<CNewParticleEffect> pEffect;
|
|
|
|
// attach to either a bone or just to the entity
|
|
if ( iAttachmentIndex == -1 )
|
|
{
|
|
pEffect = pMiningLaser->ParticleProp()->Create( "electric_weapon_shot", PATTACH_ABSORIGIN_FOLLOW );
|
|
pEffect->SetControlPointEntity( 0, pMiningLaser );
|
|
}
|
|
else
|
|
{
|
|
pEffect = pMiningLaser->ParticleProp()->Create( "electric_weapon_shot", PATTACH_POINT_FOLLOW, iAttachmentIndex );
|
|
}
|
|
|
|
|
|
// Use impactOrigin if we didn't hit anything interesting
|
|
if( !pTarget || pTarget->m_takedamage == DAMAGE_NO )
|
|
{
|
|
pEffect->SetControlPoint( 1, impactOrigin );
|
|
}
|
|
else
|
|
{
|
|
Vector vTargetMins, vTargetMaxs;
|
|
float flHeight = pTarget->BoundingRadius();
|
|
Vector vOffset( 0.0f, 0.0f, flHeight * 0.25 );
|
|
|
|
C_ASW_Alien* pAlien = dynamic_cast<C_ASW_Alien*>(pTarget);
|
|
// TODO: get some standardization in the attachment naming
|
|
if ( pAlien && pAlien->LookupAttachment( "eyes" ) )
|
|
{
|
|
pMiningLaser->ParticleProp()->AddControlPoint( pEffect, 1, pTarget, PATTACH_POINT_FOLLOW, "eyes" );
|
|
}
|
|
else
|
|
{
|
|
pMiningLaser->ParticleProp()->AddControlPoint( pEffect, 1, pTarget, PATTACH_ABSORIGIN_FOLLOW, NULL, vOffset );
|
|
}
|
|
|
|
// UNDONE: this gives hit feedback, but is too noisy for now
|
|
//CUtlReference<CNewParticleEffect> pTargetEffect;
|
|
//pTargetEffect = pTarget->ParticleProp()->Create( "electrical_arc_01_system", PATTACH_ABSORIGIN_FOLLOW,-1, vOffset );
|
|
//pTargetEffect->SetControlPointEntity( 0, pTarget );
|
|
//pTargetEffect->SetControlPoint( 1, impactOrigin );
|
|
}
|
|
|
|
//CLocalPlayerFilter filter;
|
|
//C_BaseEntity::EmitSound( filter, SOUND_FROM_WORLD, "ASW_Mining_Laser.BeamImpact", &impactOrigin );
|
|
|
|
C_BaseAnimating::PopBoneAccess( "ASWMiningLaserZap" );
|
|
}
|
|
USER_MESSAGE_REGISTER( ASWMiningLaserZap );
|
|
|
|
const char *s_pszBurstPipeEffects[]=
|
|
{
|
|
"impact_steam",
|
|
"impact_steam_small",
|
|
"impact_steam_short"
|
|
};
|
|
|
|
ConVar asw_burst_pipe_chance( "asw_burst_pipe_chance", "0.25f" );
|
|
|
|
void FX_ASW_Potential_Burst_Pipe( const Vector &vecImpactPoint, const Vector &vecReflect, const Vector &vecShotBackward, const Vector &vecNormal )
|
|
{
|
|
if ( RandomFloat() > asw_burst_pipe_chance.GetFloat() )
|
|
return;
|
|
|
|
const char *szEffectName = s_pszBurstPipeEffects[ RandomInt( 0, NELEMS( s_pszBurstPipeEffects) - 1 ) ];
|
|
CUtlReference<CNewParticleEffect> pSteamEffect = CNewParticleEffect::CreateOrAggregate( NULL, szEffectName, vecImpactPoint, NULL );
|
|
if ( pSteamEffect )
|
|
{
|
|
Vector vecImpactY, vecImpactZ;
|
|
VectorVectors( vecNormal, vecImpactY, vecImpactZ );
|
|
vecImpactY *= -1.0f;
|
|
|
|
pSteamEffect->SetControlPoint( 0, vecImpactPoint );
|
|
pSteamEffect->SetControlPointOrientation( 0, vecImpactZ, vecImpactY, vecNormal );
|
|
}
|
|
} |