diff options
Diffstat (limited to 'game/server/hl1/hl1_weapon_tripmine.cpp')
| -rw-r--r-- | game/server/hl1/hl1_weapon_tripmine.cpp | 573 |
1 files changed, 573 insertions, 0 deletions
diff --git a/game/server/hl1/hl1_weapon_tripmine.cpp b/game/server/hl1/hl1_weapon_tripmine.cpp new file mode 100644 index 0000000..8818cf7 --- /dev/null +++ b/game/server/hl1/hl1_weapon_tripmine.cpp @@ -0,0 +1,573 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Tripmine +// +// $NoKeywords: $ +//=============================================================================// + +#include "cbase.h" +#include "npcevent.h" +#include "hl1_basecombatweapon_shared.h" +#include "basecombatcharacter.h" +#include "ai_basenpc.h" +#include "player.h" +#include "gamerules.h" +#include "in_buttons.h" +#include "soundent.h" +#include "game.h" +#include "vstdlib/random.h" +#include "engine/IEngineSound.h" +#include "hl1_player.h" +#include "hl1_basegrenade.h" +#include "beam_shared.h" + +extern ConVar sk_plr_dmg_tripmine; + + +//----------------------------------------------------------------------------- +// CWeaponTripMine +//----------------------------------------------------------------------------- + + +#define TRIPMINE_MODEL "models/w_tripmine.mdl" + + +class CWeaponTripMine : public CBaseHL1CombatWeapon +{ + DECLARE_CLASS( CWeaponTripMine, CBaseHL1CombatWeapon ); +public: + + CWeaponTripMine( void ); + + void Spawn( void ); + void Precache( void ); + void Equip( CBaseCombatCharacter *pOwner ); + void PrimaryAttack( void ); + void WeaponIdle( void ); + bool Holster( CBaseCombatWeapon *pSwitchingTo = NULL ); + + DECLARE_SERVERCLASS(); + DECLARE_DATADESC(); + +private: + int m_iGroundIndex; + int m_iPickedUpIndex; +}; + +LINK_ENTITY_TO_CLASS( weapon_tripmine, CWeaponTripMine ); + +PRECACHE_WEAPON_REGISTER( weapon_tripmine ); + +IMPLEMENT_SERVERCLASS_ST( CWeaponTripMine, DT_WeaponTripMine ) +END_SEND_TABLE() + +BEGIN_DATADESC( CWeaponTripMine ) +END_DATADESC() + +//----------------------------------------------------------------------------- +// Purpose: Constructor +//----------------------------------------------------------------------------- +CWeaponTripMine::CWeaponTripMine( void ) +{ + m_bReloadsSingly = false; + m_bFiresUnderwater = true; +} + +void CWeaponTripMine::Spawn( void ) +{ + BaseClass::Spawn(); + + m_iWorldModelIndex = m_iGroundIndex; + SetModel( TRIPMINE_MODEL ); + + SetActivity( ACT_TRIPMINE_GROUND ); + ResetSequenceInfo( ); + m_flPlaybackRate = 0; + + if ( !g_pGameRules->IsDeathmatch() ) + { + UTIL_SetSize( this, Vector(-16, -16, 0), Vector(16, 16, 28) ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CWeaponTripMine::Precache( void ) +{ + BaseClass::Precache(); + + m_iGroundIndex = PrecacheModel( TRIPMINE_MODEL ); + m_iPickedUpIndex = PrecacheModel( GetWorldModel() ); + + UTIL_PrecacheOther( "monster_tripmine" ); +} + +void CWeaponTripMine::Equip( CBaseCombatCharacter *pOwner ) +{ + m_iWorldModelIndex = m_iPickedUpIndex; + + BaseClass::Equip( pOwner ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CWeaponTripMine::PrimaryAttack( void ) +{ + CHL1_Player *pPlayer = ToHL1Player( GetOwner() ); + if ( !pPlayer ) + { + return; + } + + if ( pPlayer->GetAmmoCount( m_iPrimaryAmmoType ) <= 0 ) + return; + + Vector vecAiming = pPlayer->GetAutoaimVector( 0 ); + Vector vecSrc = pPlayer->Weapon_ShootPosition( ); + + trace_t tr; + + UTIL_TraceLine( vecSrc, vecSrc + vecAiming * 64, MASK_SHOT, pPlayer, COLLISION_GROUP_NONE, &tr ); + + if ( tr.fraction < 1.0 ) + { + CBaseEntity *pEntity = tr.m_pEnt; + if ( pEntity && !( pEntity->GetFlags() & FL_CONVEYOR ) ) + { + QAngle angles; + VectorAngles( tr.plane.normal, angles ); + + CBaseEntity::Create( "monster_tripmine", tr.endpos + tr.plane.normal * 2, angles, pPlayer ); + + pPlayer->RemoveAmmo( 1, m_iPrimaryAmmoType ); + + pPlayer->SetAnimation( PLAYER_ATTACK1 ); + + if ( pPlayer->GetAmmoCount( m_iPrimaryAmmoType ) <= 0 ) + { + if ( !pPlayer->SwitchToNextBestWeapon( pPlayer->GetActiveWeapon() ) ) + Holster(); + } + else + { + SendWeaponAnim( ACT_VM_DRAW ); + SetWeaponIdleTime( gpGlobals->curtime + random->RandomFloat( 10, 15 ) ); + } + + m_flNextPrimaryAttack = gpGlobals->curtime + 0.5; + + SetWeaponIdleTime( gpGlobals->curtime ); // MO curtime correct ? + } + } + else + { + SetWeaponIdleTime( m_flTimeWeaponIdle = gpGlobals->curtime + random->RandomFloat( 10, 15 ) ); + } +} + +void CWeaponTripMine::WeaponIdle( void ) +{ + CBasePlayer *pPlayer = ToBasePlayer( GetOwner() ); + + if ( !pPlayer ) + { + return; + } + + if ( !HasWeaponIdleTimeElapsed() ) + return; + + int iAnim; + + if ( random->RandomFloat( 0, 1 ) <= 0.75 ) + { + iAnim = ACT_VM_IDLE; + } + else + { + iAnim = ACT_VM_FIDGET; + } + + SendWeaponAnim( iAnim ); +} + +bool CWeaponTripMine::Holster( CBaseCombatWeapon *pSwitchingTo ) +{ + CBasePlayer *pPlayer = ToBasePlayer( GetOwner() ); + if ( !pPlayer ) + { + return false; + } + + if ( !BaseClass::Holster( pSwitchingTo ) ) + { + return false; + } + + if ( pPlayer->GetAmmoCount( m_iPrimaryAmmoType ) <= 0 ) + { + SetThink( &CWeaponTripMine::DestroyItem ); + SetNextThink( gpGlobals->curtime + 0.1 ); + } + + pPlayer->SetNextAttack( gpGlobals->curtime + 0.5 ); + + return true; +} + + +//----------------------------------------------------------------------------- +// CTripmineGrenade +//----------------------------------------------------------------------------- + +#define TRIPMINE_BEAM_SPRITE "sprites/laserbeam.vmt" + +class CTripmineGrenade : public CHL1BaseGrenade +{ + DECLARE_CLASS( CTripmineGrenade, CHL1BaseGrenade ); +public: + CTripmineGrenade(); + void Spawn( void ); + void Precache( void ); + + int OnTakeDamage_Alive( const CTakeDamageInfo &info ); + + void WarningThink( void ); + void PowerupThink( void ); + void BeamBreakThink( void ); + void DelayDeathThink( void ); + void Event_Killed( const CTakeDamageInfo &info ); + + DECLARE_DATADESC(); + +private: + void MakeBeam( void ); + void KillBeam( void ); + +private: + float m_flPowerUp; + Vector m_vecDir; + Vector m_vecEnd; + float m_flBeamLength; + + CHandle<CBaseEntity> m_hRealOwner; + CHandle<CBeam> m_hBeam; + + CHandle<CBaseEntity> m_hStuckOn; + Vector m_posStuckOn; + QAngle m_angStuckOn; + + int m_iLaserModel; +}; + +LINK_ENTITY_TO_CLASS( monster_tripmine, CTripmineGrenade ); + +BEGIN_DATADESC( CTripmineGrenade ) + DEFINE_FIELD( m_flPowerUp, FIELD_TIME ), + DEFINE_FIELD( m_vecDir, FIELD_VECTOR ), + DEFINE_FIELD( m_vecEnd, FIELD_POSITION_VECTOR ), + DEFINE_FIELD( m_flBeamLength, FIELD_FLOAT ), +// DEFINE_FIELD( m_hBeam, FIELD_EHANDLE ), + DEFINE_FIELD( m_hRealOwner, FIELD_EHANDLE ), + DEFINE_FIELD( m_hStuckOn, FIELD_EHANDLE ), + DEFINE_FIELD( m_posStuckOn, FIELD_POSITION_VECTOR ), + DEFINE_FIELD( m_angStuckOn, FIELD_VECTOR ), + //DEFINE_FIELD( m_iLaserModel, FIELD_INTEGER ), + + // Function Pointers + DEFINE_THINKFUNC( WarningThink ), + DEFINE_THINKFUNC( PowerupThink ), + DEFINE_THINKFUNC( BeamBreakThink ), + DEFINE_THINKFUNC( DelayDeathThink ), +END_DATADESC() + + +CTripmineGrenade::CTripmineGrenade() +{ + m_vecDir.Init(); + m_vecEnd.Init(); +} + +void CTripmineGrenade::Spawn( void ) +{ + Precache( ); + // motor + SetMoveType( MOVETYPE_FLY ); + SetSolid( SOLID_BBOX ); + AddSolidFlags( FSOLID_NOT_SOLID ); + SetModel( TRIPMINE_MODEL ); + + // Don't collide with the player (the beam will still be tripped by one, however) + SetCollisionGroup( COLLISION_GROUP_WEAPON ); + + SetCycle( 0 ); + SetSequence( SelectWeightedSequence( ACT_TRIPMINE_WORLD ) ); + ResetSequenceInfo(); + m_flPlaybackRate = 0; + + UTIL_SetSize( this, Vector( -8, -8, -8), Vector(8, 8, 8) ); + + m_flDamage = sk_plr_dmg_tripmine.GetFloat(); + m_DmgRadius = m_flDamage * 2.5; + + if ( m_spawnflags & 1 ) + { + // power up quickly + m_flPowerUp = gpGlobals->curtime + 1.0; + } + else + { + // power up in 2.5 seconds + m_flPowerUp = gpGlobals->curtime + 2.5; + } + + SetThink( &CTripmineGrenade::PowerupThink ); + SetNextThink( gpGlobals->curtime + 0.2 ); + + m_takedamage = DAMAGE_YES; + + m_iHealth = 1; + + if ( GetOwnerEntity() != NULL ) + { + // play deploy sound + EmitSound( "TripmineGrenade.Deploy" ); + EmitSound( "TripmineGrenade.Charge" ); + + m_hRealOwner = GetOwnerEntity(); + } + AngleVectors( GetAbsAngles(), &m_vecDir ); + m_vecEnd = GetAbsOrigin() + m_vecDir * MAX_TRACE_LENGTH; +} + + +void CTripmineGrenade::Precache( void ) +{ + PrecacheModel( TRIPMINE_MODEL ); + m_iLaserModel = PrecacheModel( TRIPMINE_BEAM_SPRITE ); + + PrecacheScriptSound( "TripmineGrenade.Deploy" ); + PrecacheScriptSound( "TripmineGrenade.Charge" ); + PrecacheScriptSound( "TripmineGrenade.Activate" ); + +} + + +void CTripmineGrenade::WarningThink( void ) +{ + // set to power up + SetThink( &CTripmineGrenade::PowerupThink ); + SetNextThink( gpGlobals->curtime + 1.0f ); +} + + +void CTripmineGrenade::PowerupThink( void ) +{ + if ( m_hStuckOn == NULL ) + { + trace_t tr; + CBaseEntity *pOldOwner = GetOwnerEntity(); + + // don't explode if the player is standing in front of the laser + UTIL_TraceLine( GetAbsOrigin(), GetAbsOrigin() + m_vecDir * 32, MASK_SHOT, NULL, COLLISION_GROUP_NONE, &tr ); + + if( tr.m_pEnt && pOldOwner && + ( tr.m_pEnt == pOldOwner ) && pOldOwner->IsPlayer() ) + { + m_flPowerUp += 0.1; //delay the arming + SetNextThink( gpGlobals->curtime + 0.1f ); + return; + } + + // find out what we've been stuck on + SetOwnerEntity( NULL ); + + UTIL_TraceLine( GetAbsOrigin() + m_vecDir * 8, GetAbsOrigin() - m_vecDir * 32, MASK_SHOT, pOldOwner, COLLISION_GROUP_NONE, &tr ); + + if ( tr.startsolid ) + { + SetOwnerEntity( pOldOwner ); + m_flPowerUp += 0.1; + SetNextThink( gpGlobals->curtime + 0.1f ); + return; + } + if ( tr.fraction < 1.0 ) + { + SetOwnerEntity( tr.m_pEnt ); + m_hStuckOn = tr.m_pEnt; + m_posStuckOn = m_hStuckOn->GetAbsOrigin(); + m_angStuckOn = m_hStuckOn->GetAbsAngles(); + } + else + { + // somehow we've been deployed on nothing, or something that was there, but now isn't. + // remove ourselves + + StopSound( "TripmineGrenade.Deploy" ); + StopSound( "TripmineGrenade.Charge" ); + SetThink( &CBaseEntity::SUB_Remove ); + SetNextThink( gpGlobals->curtime + 0.1f ); +// ALERT( at_console, "WARNING:Tripmine at %.0f, %.0f, %.0f removed\n", pev->origin.x, pev->origin.y, pev->origin.z ); + KillBeam(); + return; + } + } + else if ( (m_posStuckOn != m_hStuckOn->GetAbsOrigin()) || (m_angStuckOn != m_hStuckOn->GetAbsAngles()) ) + { + // what we were stuck on has moved, or rotated. Create a tripmine weapon and drop to ground + + StopSound( "TripmineGrenade.Deploy" ); + StopSound( "TripmineGrenade.Charge" ); + CBaseEntity *pMine = Create( "weapon_tripmine", GetAbsOrigin() + m_vecDir * 24, GetAbsAngles() ); + pMine->AddSpawnFlags( SF_NORESPAWN ); + + SetThink( &CBaseEntity::SUB_Remove ); + SetNextThink( gpGlobals->curtime + 0.1f ); + KillBeam(); + return; + } + + if ( gpGlobals->curtime > m_flPowerUp ) + { + MakeBeam( ); + RemoveSolidFlags( FSOLID_NOT_SOLID ); + + m_bIsLive = true; + + // play enabled sound + EmitSound( "TripmineGrenade.Activate" ); + } + + SetNextThink( gpGlobals->curtime + 0.1f ); +} + + +void CTripmineGrenade::KillBeam( void ) +{ + if ( m_hBeam ) + { + UTIL_Remove( m_hBeam ); + m_hBeam = NULL; + } +} + + +void CTripmineGrenade::MakeBeam( void ) +{ + trace_t tr; + + UTIL_TraceLine( GetAbsOrigin(), m_vecEnd, MASK_SHOT, this, COLLISION_GROUP_NONE, &tr ); + + m_flBeamLength = tr.fraction; + + // set to follow laser spot + SetThink( &CTripmineGrenade::BeamBreakThink ); + + SetNextThink( gpGlobals->curtime + 1.0f ); + + Vector vecTmpEnd = GetAbsOrigin() + m_vecDir * MAX_TRACE_LENGTH * m_flBeamLength; + + m_hBeam = CBeam::BeamCreate( TRIPMINE_BEAM_SPRITE, 1.0 ); + m_hBeam->PointEntInit( vecTmpEnd, this ); + m_hBeam->SetColor( 0, 214, 198 ); + m_hBeam->SetScrollRate( 25.5 ); + m_hBeam->SetBrightness( 64 ); + m_hBeam->AddSpawnFlags( SF_BEAM_TEMPORARY ); // so it won't save and come back to haunt us later.. +} + + +void CTripmineGrenade::BeamBreakThink( void ) +{ + bool bBlowup = false; + trace_t tr; + + // NOT MASK_SHOT because we want only simple hit boxes + UTIL_TraceLine( GetAbsOrigin(), m_vecEnd, MASK_SOLID, this, COLLISION_GROUP_NONE, &tr ); + + // ALERT( at_console, "%f : %f\n", tr.flFraction, m_flBeamLength ); + + // respawn detect. + if ( !m_hBeam ) + { + MakeBeam(); + + trace_t stuckOnTrace; + Vector forward; + GetVectors( &forward, NULL, NULL ); + + UTIL_TraceLine( GetAbsOrigin(), GetAbsOrigin() - forward * 12.0f, MASK_SOLID, this, COLLISION_GROUP_NONE, &stuckOnTrace ); + + if ( stuckOnTrace.m_pEnt ) + { + m_hStuckOn = stuckOnTrace.m_pEnt; // reset stuck on ent too + } + } + + CBaseEntity *pEntity = tr.m_pEnt; + CBaseCombatCharacter *pBCC = ToBaseCombatCharacter( pEntity ); + + if ( pBCC || fabs( m_flBeamLength - tr.fraction ) > 0.001 ) + { + bBlowup = true; + } + else + { + if ( m_hStuckOn == NULL ) + bBlowup = true; + else if ( m_posStuckOn != m_hStuckOn->GetAbsOrigin() ) + bBlowup = true; + else if ( m_angStuckOn != m_hStuckOn->GetAbsAngles() ) + bBlowup = true; + } + + if ( bBlowup ) + { + SetOwnerEntity( m_hRealOwner ); + m_iHealth = 0; + Event_Killed( CTakeDamageInfo( this, m_hRealOwner, 100, GIB_NORMAL ) ); + return; + } + + SetNextThink( gpGlobals->curtime + 0.1 ); +} +/* +int CTripmineGrenade::OnTakeDamage_Alive( const CTakeDamageInfo &info ) +{ + if (gpGlobals->curtime < m_flPowerUp && info.GetDamage() < m_iHealth) + { + // disable + // Create( "weapon_tripmine", GetLocalOrigin() + m_vecDir * 24, GetAngles() ); + SetThink( &CBaseEntity::SUB_Remove ); + SetNextThink( gpGlobals->curtime + 0.1f ); + KillBeam(); + return 0; + } + return BaseClass::OnTakeDamage_Alive( info ); +}*/ + +void CTripmineGrenade::Event_Killed( const CTakeDamageInfo &info ) +{ + m_takedamage = DAMAGE_NO; + + if ( info.GetAttacker() && ( info.GetAttacker()->GetFlags() & FL_CLIENT ) ) + { + // some client has destroyed this mine, he'll get credit for any kills + SetOwnerEntity( info.GetAttacker() ); + } + + SetThink( &CTripmineGrenade::DelayDeathThink ); + SetNextThink( gpGlobals->curtime + random->RandomFloat( 0.1, 0.3 ) ); + + StopSound( "TripmineGrenade.Charge" ); +} + +void CTripmineGrenade::DelayDeathThink( void ) +{ + KillBeam(); + trace_t tr; + UTIL_TraceLine ( GetAbsOrigin() + m_vecDir * 8, GetAbsOrigin() - m_vecDir * 64, MASK_SOLID, this, COLLISION_GROUP_NONE, & tr); + + Explode( &tr, DMG_BLAST ); +} |