//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: // // $NoKeywords: $ // //=============================================================================// #include "cbase.h" #include "weapon_dodbasebomb.h" #ifdef CLIENT_DLL #include "c_dod_player.h" #else #include "dod_player.h" #include "dod_bombtarget.h" #include "collisionutils.h" #include "in_buttons.h" #endif IMPLEMENT_NETWORKCLASS_ALIASED( DODBaseBombWeapon, DT_BaseBombWeapon ) BEGIN_NETWORK_TABLE( CDODBaseBombWeapon, DT_BaseBombWeapon ) #ifdef CLIENT_DLL //RecvPropBool( RECVINFO(m_bDeployed) ) #else //SendPropBool( SENDINFO(m_bDeployed) ) #endif END_NETWORK_TABLE() BEGIN_PREDICTION_DATA( CDODBaseBombWeapon ) END_PREDICTION_DATA() #ifndef CLIENT_DLL BEGIN_DATADESC( CDODBaseBombWeapon ) END_DATADESC() #endif LINK_ENTITY_TO_CLASS( weapon_basebomb, CDODBaseBombWeapon ); PRECACHE_WEAPON_REGISTER( weapon_basebomb ); acttable_t CDODBaseBombWeapon::m_acttable[] = { { ACT_PRONE_IDLE, ACT_DOD_PRONEWALK_IDLE_PISTOL, false }, //? { ACT_PRONE_FORWARD, ACT_DOD_PRONEWALK_IDLE_PISTOL, false }, //? { ACT_DOD_STAND_IDLE, ACT_DOD_STAND_IDLE_TNT, false }, { ACT_DOD_CROUCH_IDLE, ACT_DOD_CROUCH_IDLE_TNT, false }, //? { ACT_DOD_CROUCHWALK_IDLE, ACT_DOD_CROUCHWALK_IDLE_TNT, false }, { ACT_DOD_WALK_IDLE, ACT_DOD_WALK_IDLE_TNT, false }, { ACT_DOD_RUN_IDLE, ACT_DOD_RUN_IDLE_TNT, false }, { ACT_SPRINT, ACT_DOD_SPRINT_IDLE_TNT, false }, // Hand Signals { ACT_DOD_HS_IDLE, ACT_DOD_HS_IDLE_PISTOL, false }, { ACT_DOD_HS_CROUCH, ACT_DOD_HS_CROUCH_PISTOL, false }, }; IMPLEMENT_ACTTABLE( CDODBaseBombWeapon ); CDODBaseBombWeapon::CDODBaseBombWeapon() { } void CDODBaseBombWeapon::Spawn( ) { WEAPON_FILE_INFO_HANDLE hWpnInfo = LookupWeaponInfoSlot( GetClassname() ); Assert( hWpnInfo != GetInvalidWeaponInfoHandle() ); CDODWeaponInfo *pWeaponInfo = dynamic_cast< CDODWeaponInfo* >( GetFileWeaponInfoFromHandle( hWpnInfo ) ); Assert( pWeaponInfo && "Failed to get CDODWeaponInfo in weapon spawn" ); m_pWeaponInfo = pWeaponInfo; SetPlanting( false ); BaseClass::Spawn(); } void CDODBaseBombWeapon::Precache() { BaseClass::Precache(); } bool CDODBaseBombWeapon::Deploy( ) { #ifdef CLIENT_DLL CDODPlayer *pPlayer = GetDODPlayerOwner(); if ( pPlayer ) { pPlayer->HintMessage( HINT_BOMB_FIRST_SELECT ); } #endif return DefaultDeploy( (char*)GetViewModel(), (char*)GetWorldModel(), GetDrawActivity(), (char*)GetAnimPrefix() ); } void CDODBaseBombWeapon::PrimaryAttack() { #ifndef CLIENT_DLL if ( IsPlanting() ) { CDODBombTarget *pTarget = (CDODBombTarget *)m_hBombTarget.Get(); CBasePlayer *pPlayer = GetPlayerOwner(); if ( !pTarget || !pPlayer ) { CancelPlanting(); return; } if ( pTarget->CanPlantHere( GetDODPlayerOwner() ) == false ) { // if the target is not active anymore, cancel ( someone planted there already? ) CancelPlanting(); } else if ( ( pTarget->GetAbsOrigin() - pPlayer->WorldSpaceCenter() ).Length() > DOD_BOMB_PLANT_RADIUS ) { // if we're too far away, cancel CancelPlanting(); } else if ( IsLookingAtBombTarget( pPlayer, pTarget ) == false || ( pPlayer->GetFlags() & FL_ONGROUND ) == 0 ) { // not looking at the target anymore CancelPlanting(); } else if ( gpGlobals->curtime > m_flPlantCompleteTime ) { // we finished the plant CompletePlant(); } else { m_flNextPlantCheck = gpGlobals->curtime + 0.2; } return; } // find nearby, visible bomb targets CBaseEntity *pEnt = NULL; CDODBombTarget *pBestTarget = NULL; float flBestDist = FLT_MAX; CDODPlayer *pPlayer = GetDODPlayerOwner(); if ( !pPlayer ) return; while( ( pEnt = gEntList.FindEntityByClassname( pEnt, "dod_bomb_target" ) ) != NULL ) { CDODBombTarget *pTarget = static_cast( pEnt ); if ( !pTarget->CanPlantHere( pPlayer ) ) continue; Vector pos = pPlayer->WorldSpaceCenter(); float flDist = ( pos - pTarget->GetAbsOrigin() ).Length(); // if we are looking directly at a bomb target and it is within our radius, that automatically wins if ( flDist < flBestDist && flDist < DOD_BOMB_PLANT_RADIUS && IsLookingAtBombTarget( pPlayer, pTarget ) && ( pPlayer->GetFlags() & FL_ONGROUND ) ) { flBestDist = flDist; pBestTarget = pTarget; } } if ( pBestTarget ) { StartPlanting( pBestTarget ); } m_flNextPlantCheck = gpGlobals->curtime + 0.2; // true if the player is not holding primary attack m_bUsePlant = !( pPlayer->m_nButtons & (IN_ATTACK|IN_ATTACK2) ); #endif } void CDODBaseBombWeapon::SecondaryAttack() { PrimaryAttack(); } #ifndef CLIENT_DLL void CDODBaseBombWeapon::StartPlanting( CDODBombTarget *pTarget ) { // we have already checked that we can plant here // store a pointer to the target we're bombing m_hBombTarget = pTarget; // must do this after setting the bomb target as we tell the planter // what target they are at SetPlanting( true ); // set the timer for when we'll be done m_flPlantCompleteTime = gpGlobals->curtime + DOD_BOMB_PLANT_TIME; // play the planting animation SendWeaponAnim( ACT_VM_PRIMARYATTACK ); CDODPlayer *pPlayer = GetDODPlayerOwner(); if ( pPlayer ) { pPlayer->DoAnimationEvent( PLAYERANIMEVENT_PLANT_TNT ); pPlayer->SetMaxSpeed( 1 ); pPlayer->SetProgressBarTime( DOD_BOMB_PLANT_TIME ); } } bool CDODBaseBombWeapon::CancelPlanting( void ) { bool bHolster = false; SetPlanting( false ); // play a stop animation SendWeaponAnim( ACT_VM_IDLE ); CDODPlayer *pPlayer = GetDODPlayerOwner(); if ( pPlayer ) { pPlayer->DoAnimationEvent( PLAYERANIMEVENT_CANCEL_GESTURES ); // restore player speed pPlayer->SetMaxSpeed( 600 ); pPlayer->ResetProgressBar(); if ( m_bUsePlant ) { pPlayer->SelectLastItem(); bHolster = true; } } return bHolster; } void CDODBaseBombWeapon::CompletePlant( void ) { CDODPlayer *pPlayer = ToDODPlayer( GetPlayerOwner() ); if ( pPlayer ) { SetPlanting( false ); // restore player speed GetDODPlayerOwner()->SetMaxSpeed( 600 ); // Tell the target that we finished planting the bomb ((CDODBombTarget *)m_hBombTarget.Get())->CompletePlanting( pPlayer ); // destroy the bomb weapon pPlayer->Weapon_Drop( this, NULL, NULL ); UTIL_Remove(this); pPlayer->ResetProgressBar(); pPlayer->SelectLastItem(); } } bool CDODBaseBombWeapon::IsLookingAtBombTarget( CBasePlayer *pPlayer, CDODBombTarget *pTarget ) { Vector forward; AngleVectors( pPlayer->EyeAngles(), &forward ); Vector toBomb = pTarget->GetAbsOrigin() - pPlayer->EyePosition(); toBomb.NormalizeInPlace(); return ( DotProduct( forward, toBomb ) >= 0.8 ); } #endif void CDODBaseBombWeapon::ItemPostFrame() { #ifndef CLIENT_DLL CBasePlayer *pPlayer = GetPlayerOwner(); if ( !pPlayer ) return; if ( pPlayer->m_nButtons & (IN_ATTACK|IN_ATTACK2) ) { PrimaryAttack(); } // Only use the time check if we are planting with the +use key // adds a slight lag to breaking the player lock otherwise else if ( !m_bUsePlant || m_flNextPlantCheck < gpGlobals->curtime ) { if ( IsPlanting() ) { // reset all planting bool bHolster = CancelPlanting(); // sometimes after canceling we put the weapon away and switch // to our last weapon. In that case, we don't want to send any more // anim calls b/c it confuses the client. if ( bHolster ) { // we've put this weapon away, stop everything return; } // anim now m_flTimeWeaponIdle = 0; } // idle if (m_flTimeWeaponIdle > gpGlobals->curtime) return; SendWeaponAnim( GetIdleActivity() ); m_flTimeWeaponIdle = gpGlobals->curtime + SequenceDuration(); // if we're not planting, why do we have the bomb out? // switch to our next best weapon pPlayer->SelectLastItem(); } #endif // CLIENT_DLL } bool CDODBaseBombWeapon::Holster( CBaseCombatWeapon *pSwitchingTo ) { #ifndef CLIENT_DLL if ( IsPlanting() ) CancelPlanting(); #endif return BaseClass::Holster( pSwitchingTo ); } void CDODBaseBombWeapon::SetPlanting( bool bPlanting ) { m_bPlanting = bPlanting; #ifndef CLIENT_DLL CDODPlayer *pPlayer = GetDODPlayerOwner(); if ( pPlayer ) { pPlayer->SetPlanting( m_bPlanting ? (CDODBombTarget *)m_hBombTarget.Get() : NULL ); } #endif } bool CDODBaseBombWeapon::IsPlanting( void ) { return m_bPlanting; }