1
0
mirror of https://github.com/alliedmodders/hl2sdk.git synced 2025-01-05 17:13:36 +08:00
hl2sdk/dlls/hl2_dll/player_missile.cpp

544 lines
15 KiB
C++

//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "player_control.h"
#include "hl2_player.h"
#include "decals.h"
#include "shake.h"
#include "soundent.h"
#include "ndebugoverlay.h"
#include "smoke_trail.h"
#include "grenade_homer.h"
#include "vstdlib/random.h"
#include "engine/IEngineSound.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
#define PMISSILE_MISSILE_MODEL "models/weapons/w_missile.mdl"
#define PMISSILE_HULL_MINS Vector(-22,-22,-22)
#define PMISSILE_HULL_MAXS Vector(22,22,22)
#define PMISSILE_SPEED 800
#define PMISSILE_TURN_RATE 100
#define PMISSILE_DIE_TIME 2
#define PMISSILE_TRAIL_LIFE 6
#define PMISSILE_LOSE_CONTROL_DIST 30
#define PMISSILE_DANGER_SOUND_DURATION 0.1
extern short g_sModelIndexFireball;
class CPlayer_Missile : public CPlayer_Control
{
public:
DECLARE_CLASS( CPlayer_Missile, CPlayer_Control );
void Precache(void);
void Spawn(void);
Class_T Classify( void);
void ControlActivate( void );
void ControlDeactivate( void );
// Inputs
void InputActivate( inputdata_t &inputdata );
void InputDeactivate( inputdata_t &inputdata );
void Launch(void);
void FlyThink(void);
void ExplodeThink(void);
void RemoveThink(void);
void FlyTouch( CBaseEntity *pOther );
void BlowUp(void);
void LoseMissileControl(void);
void Event_Killed( const CTakeDamageInfo &info );
int OnTakeDamage_Alive( const CTakeDamageInfo &info );
CPlayer_Missile();
float m_flLaunchDelay;
float m_flDamage;
float m_flDamageRadius;
CHandle<SmokeTrail> m_hSmokeTrail;
Vector m_vSpawnPos;
QAngle m_vSpawnAng;
Vector m_vBounceVel;
bool m_bShake;
float m_flStatic;
float m_flNextDangerTime;
DECLARE_DATADESC();
};
BEGIN_DATADESC( CPlayer_Missile )
DEFINE_KEYFIELD( m_flLaunchDelay, FIELD_FLOAT, "LaunchDelay"),
DEFINE_KEYFIELD( m_flDamage, FIELD_FLOAT, "Damage"),
DEFINE_KEYFIELD( m_flDamageRadius, FIELD_FLOAT, "DamageRadius"),
// Fields
DEFINE_FIELD( m_hSmokeTrail, FIELD_EHANDLE),
DEFINE_FIELD( m_vSpawnPos, FIELD_POSITION_VECTOR ),
DEFINE_FIELD( m_vSpawnAng, FIELD_VECTOR ),
DEFINE_FIELD( m_vBounceVel, FIELD_VECTOR ),
DEFINE_FIELD( m_bShake, FIELD_BOOLEAN ),
DEFINE_FIELD( m_flStatic, FIELD_FLOAT ),
DEFINE_FIELD( m_flNextDangerTime, FIELD_TIME ),
// Function Pointers
DEFINE_FUNCTION( Launch ),
DEFINE_FUNCTION( FlyThink ),
DEFINE_FUNCTION( ExplodeThink ),
DEFINE_FUNCTION( RemoveThink ),
DEFINE_FUNCTION( FlyTouch ),
END_DATADESC()
LINK_ENTITY_TO_CLASS( player_missile, CPlayer_Missile );
//------------------------------------------------------------------------------
// Purpose :
//------------------------------------------------------------------------------
void CPlayer_Missile::Precache( void )
{
PrecacheModel("models/manhack_sphere.mdl");
PrecacheModel( PMISSILE_MISSILE_MODEL );
PrecacheScriptSound( "Player_Manhack.Fly" );
PrecacheScriptSound( "Player_Manhack.Fire" );
PrecacheScriptSound( "Player_Manhack.Damage" );
}
//------------------------------------------------------------------------------
// Purpose :
//------------------------------------------------------------------------------
void CPlayer_Missile::Spawn( void )
{
Precache();
SetMoveType( MOVETYPE_FLY );
SetFriction( 0.55 ); // deading the bounce a bit
SetGravity(0.0);
m_iMaxHealth = m_iHealth;
m_iHealth = 0;
SetSolid( SOLID_BBOX );
AddEffects( EF_NODRAW );
AddFlag( FL_OBJECT ); // So shows up in NPC Look()
SetModel( "models/manhack_sphere.mdl" );
UTIL_SetSize(this, PMISSILE_HULL_MINS, PMISSILE_HULL_MAXS);
m_bActive = false;
m_vSpawnPos = GetLocalOrigin();
m_vSpawnAng = GetLocalAngles();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CPlayer_Missile::InputActivate( inputdata_t &inputdata )
{
// Make sure not already active
if (m_bActive)
{
return;
}
BaseClass::InputActivate( inputdata );
Vector origin = GetLocalOrigin();
origin.z += 50;
SetLocalOrigin( origin );
RemoveSolidFlags( FSOLID_NOT_SOLID );
// Using player angles to determine turning. Initailze to 0,0,0
CHL2_Player* pPlayer = (CHL2_Player*)UTIL_GetLocalPlayer();
Assert( pPlayer );
pPlayer->SetLocalAngles( vec3_angle ); // Note: Set GetLocalAngles(), not pl.v_angle
pPlayer->SnapEyeAngles( vec3_angle ); // Force reset
pPlayer->SetFOV( this, 100 );
pPlayer->SetViewEntity( this );
m_flStatic = 0;
SetThink(Launch);
SetNextThink( gpGlobals->curtime + m_flLaunchDelay );
}
//------------------------------------------------------------------------------
// Purpose :
//------------------------------------------------------------------------------
void CPlayer_Missile::Launch(void)
{
m_lifeState = LIFE_ALIVE;
m_takedamage = DAMAGE_YES;
m_iHealth = m_iMaxHealth;
// Shoot forward
Vector vVelocity;
AngleVectors( GetLocalAngles(), &vVelocity);
SetAbsVelocity( vVelocity*PMISSILE_SPEED );
EmitSound( "Player_Manhack.Fly" );
EmitSound( "Player_Manhack.Fire" );
SetThink(FlyThink);
SetTouch(FlyTouch);
SetNextThink( gpGlobals->curtime );
// Start smoke trail
SmokeTrail *pSmokeTrail = SmokeTrail::CreateSmokeTrail();
if(pSmokeTrail)
{
pSmokeTrail->m_SpawnRate = 90;
pSmokeTrail->m_ParticleLifetime = PMISSILE_TRAIL_LIFE;
pSmokeTrail->m_StartColor.Init(0.1, 0.1, 0.1);
pSmokeTrail->m_EndColor.Init(0.5,0.5,0.5);
pSmokeTrail->m_StartSize = 10;
pSmokeTrail->m_EndSize = 50;
pSmokeTrail->m_SpawnRadius = 1;
pSmokeTrail->m_MinSpeed = 15;
pSmokeTrail->m_MaxSpeed = 25;
pSmokeTrail->SetLifetime(120);
pSmokeTrail->FollowEntity(this);
m_hSmokeTrail = pSmokeTrail;
}
}
//-----------------------------------------------------------------------------
// Purpose: Input handler for turning off the steam jet.
//-----------------------------------------------------------------------------
void CPlayer_Missile::InputDeactivate( inputdata_t &inputdata )
{
ControlDeactivate();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CPlayer_Missile::ControlDeactivate( void )
{
BaseClass::ControlDeactivate();
CHL2_Player* pPlayer = (CHL2_Player*)UTIL_GetLocalPlayer();
Assert( pPlayer );
pPlayer->SetViewEntity( pPlayer );
if ( pPlayer->GetActiveWeapon() )
{
pPlayer->GetActiveWeapon()->Deploy();
}
pPlayer->m_Local.m_iHideHUD &= ~HIDEHUD_WEAPONSELECTION;
SetAbsVelocity( vec3_origin );
SetLocalAngles( m_vSpawnAng );
SetLocalOrigin( m_vSpawnPos );
AddEffects( EF_NODRAW );
}
//------------------------------------------------------------------------------
// Purpose :
//------------------------------------------------------------------------------
int CPlayer_Missile::OnTakeDamage_Alive( const CTakeDamageInfo &info )
{
if ( (info.GetDamageType() & DMG_MISSILEDEFENSE))
{
if (random->RandomInt(0,1)==0)
{
EmitSound( "Player_Manhack.Damage" );
}
m_bShake = true;
}
else
{
// UNDONE: Blow up to anything else for now
BlowUp();
}
return BaseClass::OnTakeDamage_Alive( info );
}
//-----------------------------------------------------------------------------
// Purpose: Blow it up
//-----------------------------------------------------------------------------
void CPlayer_Missile::Event_Killed( const CTakeDamageInfo &info )
{
BlowUp();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CPlayer_Missile::FlyTouch(CBaseEntity *pOther)
{
BlowUp();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CPlayer_Missile::BlowUp(void)
{
// Don't take damage any more
m_takedamage = DAMAGE_NO;
// Mark as dead so won't be attacked
m_lifeState = LIFE_DEAD;
// Stop fly and launch sounds
StopSound( "Player_Manhack.Fly" );
StopSound( "Player_Manhack.Fire" );
CPASFilter filter( GetAbsOrigin() );
te->Explosion( filter, 0.0,
&GetAbsOrigin(),
g_sModelIndexFireball,
2.0,
15,
TE_EXPLFLAG_NONE,
m_flDamageRadius,
m_flDamage );
Vector vecForward = GetAbsVelocity();
VectorNormalize(vecForward);
trace_t tr;
UTIL_TraceLine ( GetAbsOrigin(), GetAbsOrigin() + 60*vecForward, MASK_SOLID_BRUSHONLY,
this, COLLISION_GROUP_NONE, &tr);
UTIL_DecalTrace( &tr, "Scorch" );
UTIL_ScreenShake( GetAbsOrigin(), 25.0, 150.0, 1.0, 750, SHAKE_START );
CSoundEnt::InsertSound ( SOUND_DANGER, GetAbsOrigin(), 1024, 3.0 );
RadiusDamage ( CTakeDamageInfo( this, this, m_flDamage, DMG_BLAST ), GetAbsOrigin(), m_flDamageRadius, CLASS_NONE, NULL );
SetThink(ExplodeThink);
SetTouch(NULL);
m_vBounceVel = -0.2 * GetAbsVelocity();
AddSolidFlags( FSOLID_NOT_SOLID );
// Stop emitting smoke
if(m_hSmokeTrail)
{
m_hSmokeTrail->SetEmit(false);
}
}
//-----------------------------------------------------------------------------
// Purpose: Manhack is still dangerous when dead
// Input :
// Output :
//-----------------------------------------------------------------------------
void CPlayer_Missile::FlyThink()
{
SetNextThink( gpGlobals->curtime );
// -------------------
// Get the player
// -------------------
CBasePlayer* pPlayer = UTIL_GetLocalPlayer();
if (!pPlayer) return;
// ---------------------------------------------------
// Calulate amount of xturn from player mouse movement
// ---------------------------------------------------
QAngle vecViewAngles = pPlayer->EyeAngles();
float xLev;
if (vecViewAngles.x < 180)
{
xLev = vecViewAngles.x/180;
}
else
{
xLev = (vecViewAngles.x-360)/180;
}
// ---------------------------------------------------
// Calulate amount of xturn from player mouse movement
// ---------------------------------------------------
float yLev;
// Keep yaw in bounds (don't let loop)
if (vecViewAngles.y > 90)
{
if (vecViewAngles.y < 180)
{
pPlayer->SetLocalAngles( QAngle( vecViewAngles.x - 360, 90, 0 ) );
QAngle newViewAngles = vecViewAngles;
newViewAngles.y = 90;
pPlayer->SnapEyeAngles( newViewAngles );
}
else if (vecViewAngles.y < 270)
{
pPlayer->SetLocalAngles( QAngle( vecViewAngles.x, 270, 0 ) );
QAngle newViewAngles = vecViewAngles;
newViewAngles.y = 270;
pPlayer->SnapEyeAngles( newViewAngles );
}
}
if (vecViewAngles.y < 180)
{
yLev = vecViewAngles.y/180;
}
else
{
yLev = (vecViewAngles.y-360)/180;
}
//<<TEMP.>> this is a temp HUD until we create a real one on the client
NDebugOverlay::ScreenText( 0.5, 0.5+0.2*xLev, "|", 255, 0, 0, 255, 0.0);
NDebugOverlay::ScreenText( 0.5-(0.1*yLev), 0.5, "=", 255, 0, 0, 255, 0.0);
NDebugOverlay::ScreenText( 0.5-(0.1*yLev), 0.5+0.2*xLev, "*", 255, 0, 0, 255, 0.0);
NDebugOverlay::ScreenText( 0.45, 0.5, "-----------------------", 0, 255, 0, 255, 0.0);
NDebugOverlay::ScreenText( 0.5, 0.425, "|", 0, 255, 0, 255, 0.0);
NDebugOverlay::ScreenText( 0.5, 0.45, "|", 0, 255, 0, 255, 0.0);
NDebugOverlay::ScreenText( 0.5, 0.475, "|", 0, 255, 0, 255, 0.0);
NDebugOverlay::ScreenText( 0.5, 0.5, "|", 0, 255, 0, 255, 0.0);
NDebugOverlay::ScreenText( 0.5, 0.525, "|", 0, 255, 0, 255, 0.0);
NDebugOverlay::ScreenText( 0.5, 0.55, "|", 0, 255, 0, 255, 0.0);
NDebugOverlay::ScreenText( 0.5, 0.575, "|", 0, 255, 0, 255, 0.0);
// Add in turn
Vector vRight,vUp;
AngleVectors( GetLocalAngles(), 0, &vRight,&vUp);
QAngle angles = GetLocalAngles();
angles.x += PMISSILE_TURN_RATE*xLev*gpGlobals->frametime;
angles.y += PMISSILE_TURN_RATE*yLev*gpGlobals->frametime;
if (m_bShake)
{
angles.x += random->RandomFloat(-3.0,3.0);
angles.y += random->RandomFloat(-3.0,3.0);
m_bShake = false;
}
SetLocalAngles( angles );
// Reset velocity
Vector vVelocity;
AngleVectors( GetLocalAngles(), &vVelocity);
SetAbsVelocity( vVelocity*PMISSILE_SPEED );
// Add some screen noise
float flClipDist = PlayerControlClipDistance();
if (flClipDist < PMISSILE_LOSE_CONTROL_DIST)
{
LoseMissileControl();
}
// Average static over time
float flStatic = 255*(1-flClipDist/PCONTROL_CLIP_DIST);
m_flStatic = 0.9*m_flStatic + 0.1*flStatic;
color32 white = {255,255,255,m_flStatic};
UTIL_ScreenFade( pPlayer, white, 0.01, 0.1, FFADE_MODULATE );
// Insert danger sound so NPCs run away from me
if (gpGlobals->curtime > m_flNextDangerTime)
{
CSoundEnt::InsertSound ( SOUND_DANGER, GetAbsOrigin(), 2000, PMISSILE_DANGER_SOUND_DURATION );
m_flNextDangerTime = gpGlobals->curtime + PMISSILE_DANGER_SOUND_DURATION;
}
}
//-----------------------------------------------------------------------------
// Purpose: Explode
// Input :
// Output :
//-----------------------------------------------------------------------------
void CPlayer_Missile::LoseMissileControl(void)
{
// Create a missile to take the place of this one
CGrenadeHomer *pGrenade = (CGrenadeHomer*)CreateEntityByName( "grenade_homer" );
if ( pGrenade )
{
pGrenade->Spawn();
pGrenade->SetLocalOrigin( GetLocalOrigin() );
pGrenade->SetLocalAngles( GetLocalAngles() );
pGrenade->SetModel( PMISSILE_MISSILE_MODEL );
pGrenade->SetDamage(m_flDamage);
pGrenade->SetDamageRadius(m_flDamageRadius);
pGrenade->Launch(this,NULL,GetAbsVelocity(),0,0,HOMER_SMOKE_TRAIL_OFF);
pGrenade->m_hRocketTrail[0] = m_hSmokeTrail;
m_hSmokeTrail->FollowEntity(pGrenade);
}
m_takedamage = DAMAGE_NO;
m_lifeState = LIFE_DEAD;
StopSound( "Player_Manhack.Fly" );
ControlDeactivate();
}
//-----------------------------------------------------------------------------
// Purpose: Explode
// Input :
// Output :
//-----------------------------------------------------------------------------
void CPlayer_Missile::ExplodeThink()
{
SetAbsVelocity( m_vBounceVel );
color32 black = {0,0,0,255};
CHL2_Player* pPlayer = (CHL2_Player*)UTIL_GetLocalPlayer();
Assert( pPlayer );
UTIL_ScreenFade( pPlayer, black, 2.0, 0.1, FFADE_OUT );
SetThink(RemoveThink);
SetNextThink( gpGlobals->curtime + PMISSILE_DIE_TIME );
}
//-----------------------------------------------------------------------------
// Purpose: Remove me
//-----------------------------------------------------------------------------
void CPlayer_Missile::RemoveThink()
{
ControlDeactivate();
}
//------------------------------------------------------------------------------
// Purpose :
//------------------------------------------------------------------------------
Class_T CPlayer_Missile::Classify( void)
{
return CLASS_MISSILE;
};
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CPlayer_Missile::CPlayer_Missile()
{
m_vSpawnPos.Init(0,0,0);
m_vSpawnAng.Init(0,0,0);
m_vBounceVel.Init(0,0,0);
}