diff options
Diffstat (limited to 'game/server/tf/halloween/halloween_base_boss.cpp')
| -rw-r--r-- | game/server/tf/halloween/halloween_base_boss.cpp | 313 |
1 files changed, 313 insertions, 0 deletions
diff --git a/game/server/tf/halloween/halloween_base_boss.cpp b/game/server/tf/halloween/halloween_base_boss.cpp new file mode 100644 index 0000000..014bde7 --- /dev/null +++ b/game/server/tf/halloween/halloween_base_boss.cpp @@ -0,0 +1,313 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// halloween_boss_base.cpp +// Shared code for the Halloween Bosses +// Michael Booth, October 2011 + +#include "cbase.h" +#include "tf_player.h" +#include "tf_gamerules.h" +#include "halloween_base_boss.h" +#include "tf_gamestats.h" + + +//----------------------------------------------------------------------------------------------------- +CHalloweenBaseBoss::CHalloweenBaseBoss() +{ + m_wasSpawnedByCheats = false; +} + + +//----------------------------------------------------------------------------------------------------- +CHalloweenBaseBoss::~CHalloweenBaseBoss() +{ +} + + +//----------------------------------------------------------------------------------------------------- +void CHalloweenBaseBoss::Spawn( void ) +{ + BaseClass::Spawn(); + + ConVarRef sv_cheats( "sv_cheats" ); + if ( sv_cheats.IsValid() && sv_cheats.GetBool() ) + { + // remember we spawned with a cheat command + m_wasSpawnedByCheats = true; + } + + m_damagePerSecond = 0.0f; + m_maxDamagePerSecond = 0.0f; + + if ( TFGameRules() ) + { + TFGameRules()->AddActiveBoss( this ); + } + + // track how many players were playing when boss spawned + CUtlVector< CTFPlayer * > playerVector; + CollectPlayers( &playerVector, TF_TEAM_RED ); + CollectPlayers( &playerVector, TF_TEAM_BLUE, false, APPEND_PLAYERS ); + + // status + CTF_GameStats.Event_HalloweenBossEvent( GetBossType(), GetLevel(), HALLOWEEN_EVENT_BOSS_SPAWN, playerVector.Count(), 0.0f ); +} + + +//----------------------------------------------------------------------------------------------------- +void CHalloweenBaseBoss::Update( void ) +{ + BaseClass::Update(); + + UpdateDamagePerSecond(); +} + +//----------------------------------------------------------------------------------------------------- +void CHalloweenBaseBoss::UpdateOnRemove() +{ + if ( TFGameRules() ) + { + TFGameRules()->RemoveActiveBoss( this ); + } + + BaseClass::UpdateOnRemove(); +} + +//----------------------------------------------------------------------------------------------------- +int CHalloweenBaseBoss::OnTakeDamage( const CTakeDamageInfo &info ) +{ + if ( info.GetDamage() && ( info.GetAttacker() != this ) ) + { + CTFPlayer *pAttacker = ToTFPlayer( info.GetAttacker() ); + + if ( pAttacker && info.GetWeapon() ) + { + CTFWeaponBase *pWeapon = dynamic_cast<CTFWeaponBase *>( info.GetWeapon() ); + if ( pWeapon ) + { + pWeapon->ApplyOnHitAttributes( this, pAttacker, info ); + } + } + } + + return BaseClass::OnTakeDamage( info ); +} + +//----------------------------------------------------------------------------------------------------- +int CHalloweenBaseBoss::OnTakeDamage_Alive( const CTakeDamageInfo &rawInfo ) +{ + CTakeDamageInfo info = rawInfo; + + if ( info.GetAttacker() && info.GetAttacker()->GetTeamNumber() == GetTeamNumber() ) + { + return 0; + } + + if ( TFGameRules()->RoundHasBeenWon() ) + { + info.SetDamage( 0.0f ); + } + + if ( info.GetDamageType() & DMG_CRITICAL ) + { + // do the critical damage increase + info.SetDamage( info.GetDamage() * GetCritInjuryMultiplier() ); + } + + // keep a list of everyone who hurt me, and when + CTFPlayer *playerAttacker = ToTFPlayer( info.GetAttacker() ); + if ( playerAttacker ) + { + CTFWeaponBase *attackerWeapon = assert_cast< CTFWeaponBase * >( info.GetWeapon() ); + bool isMeleeAttack = attackerWeapon && attackerWeapon->IsMeleeWeapon(); + + RememberAttacker( playerAttacker, isMeleeAttack, info.GetDamage() ); + + for( int i=0; i<playerAttacker->m_Shared.GetNumHealers(); ++i ) + { + CTFPlayer *medic = ToTFPlayer( playerAttacker->m_Shared.GetHealerByIndex( i ) ); + if ( medic ) + { + // medics healing my attacker are also considered attackers + // they do zero damage to keep DPS calculations sane + RememberAttacker( medic, isMeleeAttack, 0.0f ); + } + } + } + + // fire event for client combat text, beep, etc. + IGameEvent *event = gameeventmanager->CreateEvent( "npc_hurt" ); + if ( event ) + { + event->SetInt( "entindex", entindex() ); + event->SetInt( "health", MAX( 0, GetHealth() ) ); + event->SetInt( "damageamount", info.GetDamage() ); + event->SetBool( "crit", ( info.GetDamageType() & DMG_CRITICAL ) ? true : false ); + event->SetInt( "boss", GetBossType() ); + + CTFPlayer *attackerPlayer = ToTFPlayer( info.GetAttacker() ); + if ( attackerPlayer ) + { + event->SetInt( "attacker_player", attackerPlayer->GetUserID() ); + + if ( attackerPlayer->GetActiveTFWeapon() ) + { + event->SetInt( "weaponid", attackerPlayer->GetActiveTFWeapon()->GetWeaponID() ); + } + else + { + event->SetInt( "weaponid", 0 ); + } + } + else + { + // hurt by world + event->SetInt( "attacker_player", 0 ); + event->SetInt( "weaponid", 0 ); + } + + gameeventmanager->FireEvent( event ); + } + + return BaseClass::OnTakeDamage_Alive( info ); +} + +void CHalloweenBaseBoss::Event_Killed( const CTakeDamageInfo &info ) +{ + const CUtlVector< AttackerInfo > &attackerVector = GetAttackerVector(); + for( int i=0; i<attackerVector.Count(); ++i ) + { + if ( attackerVector[i].m_attacker != NULL ) + { + IGameEvent *pEvent = gameeventmanager->CreateEvent( "halloween_boss_killed" ); + if ( pEvent ) + { + pEvent->SetInt( "boss", GetBossType() ); + pEvent->SetInt( "killer", attackerVector[i].m_attacker->GetUserID() ); + gameeventmanager->FireEvent( pEvent, true ); + } + + // Shoot a huge soul at players that have damaged the boss + TFGameRules()->DropHalloweenSoulPack( 25, EyePosition(), attackerVector[i].m_attacker, TEAM_SPECTATOR ); + } + } + + BaseClass::Event_Killed( info ); +} + +//--------------------------------------------------------------------------------------------- +void CHalloweenBaseBoss::RememberAttacker( CTFPlayer *playerAttacker, bool wasMeleeHit, float damage ) +{ + // record the damage for dps calculations + DamageRateInfo info; + info.m_damage = damage; + info.m_timestamp = gpGlobals->curtime; + m_damageVector.AddToTail( info ); + + int i; + + // has this player hurt me before + for( i=0; i<m_attackerVector.Count(); ++i ) + { + if ( m_attackerVector[i].m_attacker && m_attackerVector[i].m_attacker->entindex() == playerAttacker->entindex() ) + { + // this player is hurting me again + m_attackerVector[i].m_timestamp = gpGlobals->curtime; + m_attackerVector[i].m_wasLastHitFromMeleeWeapon = wasMeleeHit; + return; + } + } + + // new attacker + AttackerInfo attackerInfo; + + attackerInfo.m_attacker = playerAttacker; + attackerInfo.m_timestamp = gpGlobals->curtime; + attackerInfo.m_wasLastHitFromMeleeWeapon = wasMeleeHit; + + m_attackerVector.AddToTail( attackerInfo ); +} + + +//--------------------------------------------------------------------------------------------- +void CHalloweenBaseBoss::UpdateDamagePerSecond( void ) +{ + const float windowDuration = 5.0f; + int i; + + m_damagePerSecond = 0.0f; + + for( i=0; i<m_damageVector.Count(); ++i ) + { + float age = gpGlobals->curtime - m_damageVector[i].m_timestamp; + + if ( age > windowDuration ) + { + // too old + continue; + } + + m_damagePerSecond += m_damageVector[i].m_damage; + } + + m_damagePerSecond /= windowDuration; + + if ( m_damagePerSecond > m_maxDamagePerSecond ) + { + m_maxDamagePerSecond = m_damagePerSecond; + } + +// if ( m_damagePerSecond > 0.0001f ) +// { +// DevMsg( "%3.2f: dps = %3.2f\n", gpGlobals->curtime, m_damagePerSecond ); +// } +} + + +//--------------------------------------------------------------------------------------------- +void CHalloweenBaseBoss::Break( void ) +{ + CPVSFilter filter( GetAbsOrigin() ); + UserMessageBegin( filter, "BreakModel" ); + WRITE_SHORT( GetModelIndex() ); + WRITE_VEC3COORD( GetAbsOrigin() ); + WRITE_ANGLES( GetAbsAngles() ); + WRITE_SHORT( m_nSkin ); + MessageEnd(); +} + + +//--------------------------------------------------------------------------------------------- +/*static*/ CHalloweenBaseBoss* CHalloweenBaseBoss::SpawnBossAtPos( HalloweenBossType bossType, const Vector& vSpawnPos, int nTeam /*= TF_TEAM_HALLOWEEN*/, CBaseEntity* pOwner /*= NULL*/ ) +{ + const char* pszBossType = NULL; + switch ( bossType ) + { + case HALLOWEEN_BOSS_HHH: + pszBossType = "headless_hatman"; + break; + case HALLOWEEN_BOSS_MONOCULUS: + pszBossType = "eyeball_boss"; + break; + case HALLOWEEN_BOSS_MERASMUS: + pszBossType = "merasmus"; + break; + default: + AssertMsg( 0, "Invalid Halloween Boss Type" ); + } + + CHalloweenBaseBoss *pBoss = NULL; + if ( pszBossType ) + { + pBoss = dynamic_cast< CHalloweenBaseBoss * >( CreateEntityByName( pszBossType ) ); + if ( pBoss ) + { + pBoss->SetAbsOrigin( vSpawnPos + Vector( 0, 0, 10.0f ) ); + pBoss->ChangeTeam( nTeam ); + pBoss->SetOwnerEntity( pOwner ); + + DispatchSpawn( pBoss ); + } + } + + return pBoss; +} |