diff options
Diffstat (limited to 'game/server/tf/player_vs_environment/boss_alpha/behavior')
22 files changed, 1782 insertions, 0 deletions
diff --git a/game/server/tf/player_vs_environment/boss_alpha/behavior/boss_alpha_behavior.cpp b/game/server/tf/player_vs_environment/boss_alpha/behavior/boss_alpha_behavior.cpp new file mode 100644 index 0000000..6cfe287 --- /dev/null +++ b/game/server/tf/player_vs_environment/boss_alpha/behavior/boss_alpha_behavior.cpp @@ -0,0 +1,109 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// boss_alpha_behavior.cpp +// Michael Booth, November 2010 + +#include "cbase.h" + +#ifdef TF_RAID_MODE + +#include "CRagdollMagnet.h" +#include "tf_gamerules.h" +#include "tf_shareddefs.h" +#include "player_vs_environment/monster_resource.h" +#include "player_vs_environment/boss_alpha/boss_alpha.h" +#include "player_vs_environment/boss_alpha/behavior/boss_alpha_behavior.h" +#include "player_vs_environment/boss_alpha/behavior/boss_alpha_tactical_monitor.h" + + +//--------------------------------------------------------------------------------------------- +Action< CBossAlpha > *CBossAlphaBehavior::InitialContainedAction( CBossAlpha *me ) +{ + return new CBossAlphaTacticalMonitor; +} + + +//--------------------------------------------------------------------------------------------- +ActionResult< CBossAlpha > CBossAlphaBehavior::Update( CBossAlpha *me, float interval ) +{ + if ( m_vocalTimer.IsElapsed() ) + { + m_vocalTimer.Start( RandomFloat( 3.0f, 5.0f ) ); + + if ( !me->IsBusy() ) + { + me->EmitSound( "RobotBoss.Vocalize" ); + } + } + + return Continue(); +} + + +//--------------------------------------------------------------------------------------------- +EventDesiredResult< CBossAlpha > CBossAlphaBehavior::OnKilled( CBossAlpha *me, const CTakeDamageInfo &info ) +{ + // relay the event to the map logic + me->m_outputOnKilled.FireOutput( me, me ); + + // Calculate death force + Vector forceVector = me->CalcDamageForceVector( info ); + + // See if there's a ragdoll magnet that should influence our force. + CRagdollMagnet *magnet = CRagdollMagnet::FindBestMagnet( me ); + if ( magnet ) + { + forceVector += magnet->GetForceVector( me ); + } + + if ( me->IsMiniBoss() ) + { + me->EmitSound( "Cart.Explode" ); + me->BecomeRagdoll( info, forceVector ); + + if ( g_pMonsterResource ) + { + g_pMonsterResource->HideBossHealthMeter(); + } + } + else + { + // full end-of-game boss + UTIL_Remove( me ); + + if ( TFGameRules()->IsBossBattleMode() ) + { + // check that ALL bosses are dead + bool isBossBattleWon = true; + + CBossAlpha *boss = NULL; + while( ( boss = (CBossAlpha *)gEntList.FindEntityByClassname( boss, "boss_alpha" ) ) != NULL ) + { + if ( !me->IsSelf( boss ) && boss->IsAlive() && !boss->IsMiniBoss() ) + { + isBossBattleWon = false; + } + } + + if ( isBossBattleWon ) + { + TFGameRules()->SetWinningTeam( TF_TEAM_BLUE, WINREASON_OPPONENTS_DEAD ); + + if ( g_pMonsterResource ) + { + g_pMonsterResource->HideBossHealthMeter(); + } + } + } + } + + return TryDone(); +} + + +//--------------------------------------------------------------------------------------------- +EventDesiredResult< CBossAlpha > CBossAlphaBehavior::OnContact( CBossAlpha *me, CBaseEntity *other, CGameTrace *result ) +{ + return TryContinue(); +} + +#endif // TF_RAID_MODE diff --git a/game/server/tf/player_vs_environment/boss_alpha/behavior/boss_alpha_behavior.h b/game/server/tf/player_vs_environment/boss_alpha/behavior/boss_alpha_behavior.h new file mode 100644 index 0000000..c637bf5 --- /dev/null +++ b/game/server/tf/player_vs_environment/boss_alpha/behavior/boss_alpha_behavior.h @@ -0,0 +1,30 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// boss_alpha_behavior.h +// Michael Booth, November 2010 + +#ifndef BOSS_ALPHA_BEHAVIOR_H +#define BOSS_ALPHA_BEHAVIOR_H + +#ifdef TF_RAID_MODE + +//--------------------------------------------------------------------------------------------- +class CBossAlphaBehavior : public Action< CBossAlpha > +{ +public: + virtual Action< CBossAlpha > *InitialContainedAction( CBossAlpha *me ); + + virtual ActionResult< CBossAlpha > Update( CBossAlpha *me, float interval ); + + virtual EventDesiredResult< CBossAlpha > OnKilled( CBossAlpha *me, const CTakeDamageInfo &info ); + virtual EventDesiredResult< CBossAlpha > OnContact( CBossAlpha *me, CBaseEntity *other, CGameTrace *result = NULL ); + + virtual const char *GetName( void ) const { return "Behavior"; } // return name of this action + +private: + CountdownTimer m_vocalTimer; +}; + + +#endif // TF_RAID_MODE + +#endif // BOSS_ALPHA_BEHAVIOR_H diff --git a/game/server/tf/player_vs_environment/boss_alpha/behavior/boss_alpha_chase_victim.cpp b/game/server/tf/player_vs_environment/boss_alpha/behavior/boss_alpha_chase_victim.cpp new file mode 100644 index 0000000..77204b7 --- /dev/null +++ b/game/server/tf/player_vs_environment/boss_alpha/behavior/boss_alpha_chase_victim.cpp @@ -0,0 +1,170 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// boss_alpha_chase_victim.cpp +// Michael Booth, November 2010 + +#include "cbase.h" + +#ifdef TF_RAID_MODE + +#include "player_vs_environment/boss_alpha/boss_alpha.h" +#include "player_vs_environment/boss_alpha/behavior/boss_alpha_chase_victim.h" +#include "player_vs_environment/boss_alpha/behavior/boss_alpha_lost_victim.h" +#include "player_vs_environment/boss_alpha/behavior/boss_alpha_nuke_attack.h" +#include "player_vs_environment/boss_alpha/behavior/boss_alpha_launch_grenades.h" +#include "player_vs_environment/boss_alpha/behavior/boss_alpha_launch_rockets.h" + +extern ConVar tf_boss_alpha_grenade_launch_range; +extern ConVar tf_boss_alpha_chase_range; + + +//--------------------------------------------------------------------------------------------- +CBossAlphaChaseVictim::CBossAlphaChaseVictim( CBaseCombatCharacter *chaseTarget ) +{ + m_chaseTarget = chaseTarget; + m_lastKnownTargetSpot = chaseTarget->GetAbsOrigin(); +} + + +//--------------------------------------------------------------------------------------------- +ActionResult< CBossAlpha > CBossAlphaChaseVictim::OnStart( CBossAlpha *me, Action< CBossAlpha > *priorAction ) +{ + if ( m_chaseTarget == NULL ) + { + return Done( "Target is NULL" ); + } + + m_lastKnownTargetSpot = m_chaseTarget->GetAbsOrigin(); + + return Continue(); +} + + +//--------------------------------------------------------------------------------------------- +ActionResult< CBossAlpha > CBossAlphaChaseVictim::Update( CBossAlpha *me, float interval ) +{ + if ( m_chaseTarget == NULL || !m_chaseTarget->IsAlive() ) + { + return ChangeTo( new CBossAlphaLostVictim, "No victim" ); + } + + if ( m_chaseTarget != me->GetAttackTarget() ) + { + return Done( "Changing targets" ); + } + + Vector moveGoal = m_chaseTarget->GetAbsOrigin(); + + if ( me->IsLineOfSightClear( m_chaseTarget ) ) + { + if ( !m_visibleTimer.HasStarted() ) + { + m_visibleTimer.Start(); + } + + if ( me->HasAbility( CBossAlpha::CAN_NUKE ) && me->GetNukeTimer()->IsElapsed() ) + { + return SuspendFor( new CBossAlphaNukeAttack, "Nuking!" ); + } + + m_lastKnownTargetSpot = m_chaseTarget->GetAbsOrigin(); + + if ( me->HasAbility( CBossAlpha::CAN_LAUNCH_STICKIES ) ) + { + if ( ( me->GetGrenadeTimer()->IsElapsed() && me->IsRangeLessThan( m_chaseTarget, tf_boss_alpha_grenade_launch_range.GetFloat() ) ) || + me->IsInCondition( CBossAlpha::ENRAGED ) ) + { + return SuspendFor( new CBossAlphaLaunchGrenades, "Target is close (or I am enraged) - grenades!" ); + } + } + + // chase into line of sight a bit so they can't immediately get behind cover again + if ( me->HasAbility( CBossAlpha::CAN_FIRE_ROCKETS ) ) + { + if ( m_visibleTimer.IsGreaterThen( 1.0f ) || + me->IsRangeLessThan( m_chaseTarget, tf_boss_alpha_chase_range.GetFloat() ) ) + { + return SuspendFor( new CBossAlphaLaunchRockets, "Fire!" ); + } + } + + if ( me->IsRangeLessThan( m_chaseTarget, 150.0f ) ) + { + // too close - stand still + if ( !me->GetBodyInterface()->IsActivity( ACT_MP_STAND_MELEE ) ) + { + me->GetBodyInterface()->StartActivity( ACT_MP_STAND_MELEE ); + } + + return Continue(); + } + } + else + { + m_visibleTimer.Invalidate(); + + // move to where we last saw our target + moveGoal = m_lastKnownTargetSpot; + + if ( me->IsRangeLessThan( m_lastKnownTargetSpot, 20.0f ) ) + { + // reached spot where we last saw our victim - give up + me->SetAttackTarget( NULL ); + + return ChangeTo( new CBossAlphaLostVictim, "I lost my chase victim" ); + } + } + + + // move into sight of target + if ( m_path.GetAge() > 1.0f ) + { + CBossAlphaPathCost cost( me ); + m_path.Compute( me, moveGoal, cost ); + } + + me->GetLocomotionInterface()->Run(); + m_path.Update( me ); + + // play running animation + if ( !me->GetBodyInterface()->IsActivity( ACT_MP_RUN_MELEE ) ) + { + me->GetBodyInterface()->StartActivity( ACT_MP_RUN_MELEE ); + } + + return Continue(); +} + + +//--------------------------------------------------------------------------------------------- +EventDesiredResult< CBossAlpha > CBossAlphaChaseVictim::OnMoveToSuccess( CBossAlpha *me, const Path *path ) +{ + return TryDone( RESULT_CRITICAL, "Reached move goal" ); +} + + +//--------------------------------------------------------------------------------------------- +EventDesiredResult< CBossAlpha > CBossAlphaChaseVictim::OnMoveToFailure( CBossAlpha *me, const Path *path, MoveToFailureType reason ) +{ + return TryDone( RESULT_CRITICAL, "Path follow failed" ); +} + + +//--------------------------------------------------------------------------------------------- +void CBossAlphaChaseVictim::OnEnd( CBossAlpha *me, Action< CBossAlpha > *nextAction ) +{ +} + + +//--------------------------------------------------------------------------------------------- +EventDesiredResult< CBossAlpha > CBossAlphaChaseVictim::OnStuck( CBossAlpha *me ) +{ + // we're stuck - just warp to the our next path goal + if ( m_path.GetCurrentGoal() ) + { + me->SetAbsOrigin( m_path.GetCurrentGoal()->pos + Vector( 0, 0, 10.0f ) ); + } + + return TryContinue(); +} + +#endif // TF_RAID_MODE diff --git a/game/server/tf/player_vs_environment/boss_alpha/behavior/boss_alpha_chase_victim.h b/game/server/tf/player_vs_environment/boss_alpha/behavior/boss_alpha_chase_victim.h new file mode 100644 index 0000000..4cdf5ff --- /dev/null +++ b/game/server/tf/player_vs_environment/boss_alpha/behavior/boss_alpha_chase_victim.h @@ -0,0 +1,41 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// boss_alpha_chase_victim.h +// Michael Booth, November 2010 + +#ifndef BOSS_ALPHA_CHASE_VICTIM_H +#define BOSS_ALPHA_CHASE_VICTIM_H + +#ifdef TF_RAID_MODE + +#include "nav_mesh/tf_path_follower.h" + +//--------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------- +class CBossAlphaChaseVictim : public Action< CBossAlpha > +{ +public: + CBossAlphaChaseVictim( CBaseCombatCharacter *chaseTarget ); + + virtual ActionResult< CBossAlpha > OnStart( CBossAlpha *me, Action< CBossAlpha > *priorAction ); + virtual ActionResult< CBossAlpha > Update( CBossAlpha *me, float interval ); + virtual void OnEnd( CBossAlpha *me, Action< CBossAlpha > *nextAction ); + + virtual EventDesiredResult< CBossAlpha > OnStuck( CBossAlpha *me ); + virtual EventDesiredResult< CBossAlpha > OnMoveToSuccess( CBossAlpha *me, const Path *path ); + virtual EventDesiredResult< CBossAlpha > OnMoveToFailure( CBossAlpha *me, const Path *path, MoveToFailureType reason ); + + virtual const char *GetName( void ) const { return "ChaseVictim"; } // return name of this action + +private: + CTFPathFollower m_path; + IntervalTimer m_visibleTimer; + CHandle< CBaseCombatCharacter > m_lastTarget; + + CHandle< CBaseCombatCharacter > m_chaseTarget; + Vector m_lastKnownTargetSpot; +}; + + +#endif // TF_RAID_MODE + +#endif // BOSS_ALPHA_CHASE_VICTIM_H diff --git a/game/server/tf/player_vs_environment/boss_alpha/behavior/boss_alpha_get_off_me.cpp b/game/server/tf/player_vs_environment/boss_alpha/behavior/boss_alpha_get_off_me.cpp new file mode 100644 index 0000000..b68ca8e --- /dev/null +++ b/game/server/tf/player_vs_environment/boss_alpha/behavior/boss_alpha_get_off_me.cpp @@ -0,0 +1,93 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// boss_alpha_get_off_me.cpp +// Michael Booth, November 2010 + +#include "cbase.h" + +#ifdef TF_RAID_MODE + +#include "tf_player.h" +#include "player_vs_environment/boss_alpha/boss_alpha.h" +#include "player_vs_environment/boss_alpha/behavior/boss_alpha_get_off_me.h" + +ConVar tf_boss_alpha_charge_pushaway_force( "tf_boss_alpha_charge_pushaway_force", "500"/*, FCVAR_CHEAT*/ ); + + +//--------------------------------------------------------------------------------------------- +void PushawayPlayer( CTFPlayer *victim, const Vector &pushOrigin, float pushForce ) +{ + if ( !victim ) + return; + + if ( victim->GetFlags() & FL_ONGROUND ) + { + // launching into the air + victim->SetAbsVelocity( vec3_origin ); + + const float stunTime = 0.5f; + victim->m_Shared.StunPlayer( stunTime, 1.0, TF_STUN_MOVEMENT ); + + victim->ApplyPunchImpulseX( RandomInt( 10, 15 ) ); + victim->SpeakConceptIfAllowed( MP_CONCEPT_DEFLECTED, "projectile:0,victim:1" ); + } + + victim->RemoveFlag( FL_ONGROUND ); + + Vector toVictim = victim->WorldSpaceCenter() - pushOrigin; + toVictim.z = 0.0f; + toVictim.NormalizeInPlace(); + toVictim.z = 1.0f; + + victim->ApplyAbsVelocityImpulse( pushForce * toVictim ); +} + + +//--------------------------------------------------------------------------------------------- +ActionResult< CBossAlpha > CBossAlphaGetOffMe::OnStart( CBossAlpha *me, Action< CBossAlpha > *priorAction ) +{ + me->AddGestureSequence( me->LookupSequence( "gesture_melee_help" ) ); + m_timer.Start( 0.5f ); + + me->AddCondition( CBossAlpha::BUSY ); + + return Continue(); +} + + +//--------------------------------------------------------------------------------------------- +ActionResult< CBossAlpha > CBossAlphaGetOffMe::Update( CBossAlpha *me, float interval ) +{ + if ( m_timer.IsElapsed() ) + { + // blast players off of my head + CUtlVector< CTFPlayer * > onMeVector; + me->CollectPlayersStandingOnMe( &onMeVector ); + + Vector headPos; + QAngle headAngles; + if ( me->GetAttachment( "head", headPos, headAngles ) ) + { + for( int i=0; i<onMeVector.Count(); ++i ) + { + // push 'em off + PushawayPlayer( onMeVector[i], headPos, tf_boss_alpha_charge_pushaway_force.GetFloat() ); + } + } + + me->EmitSound( "Weapon_FlameThrower.AirBurstAttack" ); + + return Done(); + } + + return Continue(); +} + + +//--------------------------------------------------------------------------------------------- +void CBossAlphaGetOffMe::OnEnd( CBossAlpha *me, Action< CBossAlpha > *nextAction ) +{ + me->RemoveCondition( CBossAlpha::BUSY ); +} + + +#endif // TF_RAID_MODE diff --git a/game/server/tf/player_vs_environment/boss_alpha/behavior/boss_alpha_get_off_me.h b/game/server/tf/player_vs_environment/boss_alpha/behavior/boss_alpha_get_off_me.h new file mode 100644 index 0000000..5322103 --- /dev/null +++ b/game/server/tf/player_vs_environment/boss_alpha/behavior/boss_alpha_get_off_me.h @@ -0,0 +1,27 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// boss_alpha_get_off_me.h +// Michael Booth, November 2010 + +#ifndef BOSS_ALPHA_GET_OFF_ME_H +#define BOSS_ALPHA_GET_OFF_ME_H + +#ifdef TF_RAID_MODE + + +//---------------------------------------------------------------------------- +class CBossAlphaGetOffMe : public Action< CBossAlpha > +{ +public: + virtual ActionResult< CBossAlpha > OnStart( CBossAlpha *me, Action< CBossAlpha > *priorAction ); + virtual ActionResult< CBossAlpha > Update( CBossAlpha *me, float interval ); + virtual void OnEnd( CBossAlpha *me, Action< CBossAlpha > *nextAction ); + + virtual const char *GetName( void ) const { return "GetOffMe"; } // return name of this action + +private: + CountdownTimer m_timer; +}; + +#endif // TF_RAID_MODE + +#endif // BOSS_ALPHA_GET_OFF_ME_H diff --git a/game/server/tf/player_vs_environment/boss_alpha/behavior/boss_alpha_guard_spot.cpp b/game/server/tf/player_vs_environment/boss_alpha/behavior/boss_alpha_guard_spot.cpp new file mode 100644 index 0000000..7f80e68 --- /dev/null +++ b/game/server/tf/player_vs_environment/boss_alpha/behavior/boss_alpha_guard_spot.cpp @@ -0,0 +1,129 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// boss_alpha_guard_spot.cpp +// Michael Booth, November 2010 + +#include "cbase.h" + +#ifdef TF_RAID_MODE + +#include "tf_player.h" +#include "nav_mesh/tf_nav_area.h" +#include "tf_projectile_rocket.h" +#include "player_vs_environment/boss_alpha/boss_alpha.h" +#include "player_vs_environment/boss_alpha/behavior/boss_alpha_guard_spot.h" +#include "player_vs_environment/boss_alpha/behavior/boss_alpha_chase_victim.h" + + +//----------------------------------------------------------------------------------------------------- +ActionResult< CBossAlpha > CBossAlphaGuardSpot::OnStart( CBossAlpha *me, Action< CBossAlpha > *priorAction ) +{ + m_path.SetMinLookAheadDistance( 300.0f ); + + me->GetBodyInterface()->StartActivity( ACT_MP_STAND_ITEM1 ); + me->SetHomePosition( me->GetAbsOrigin() ); + + m_lookAtSpot = vec3_origin; + + return Continue(); +} + + +//----------------------------------------------------------------------------------------------------- +ActionResult< CBossAlpha > CBossAlphaGuardSpot::Update( CBossAlpha *me, float interval ) +{ + CBaseCombatCharacter *target = me->GetAttackTarget(); + if ( target ) + { + if ( me->IsLineOfSightClear( target ) || me->IsPrisonerOfMinion( target ) ) + { + return SuspendFor( new CBossAlphaChaseVictim( me->GetAttackTarget() ), "Get 'em!" ); + } + } + + CBaseCombatCharacter *visible = me->GetNearestVisibleEnemy(); + if ( visible ) + { + // look at visible victim out of range + me->GetLocomotionInterface()->FaceTowards( visible->WorldSpaceCenter() ); + } + + const float atHomeRange = 50.0f; + if ( me->IsRangeGreaterThan( me->GetHomePosition(), atHomeRange ) ) + { + if ( m_path.GetAge() > 3.0f ) + { + CBossAlphaPathCost cost( me ); + if ( m_path.Compute( me, me->GetHomePosition(), cost ) == false ) + { + // can't reach guard post - just jump there for now + me->Teleport( &me->GetHomePosition(), NULL, NULL ); + } + } + + m_path.Update( me ); + } + else + { + // on guard spot - look around + if ( m_lookTimer.IsElapsed() ) + { + m_lookTimer.Start( RandomFloat( 1.0f, 2.0f ) ); + + CTFNavArea *myArea = (CTFNavArea *)me->GetLastKnownArea(); + if ( myArea ) + { + const CUtlVector< CTFNavArea * > &invasionAreaVector = myArea->GetEnemyInvasionAreaVector( TF_TEAM_RED ); + + if ( invasionAreaVector.Count() > 0 ) + { + // try to not look directly at walls + const float minGazeRange = 300.0f; + const int retryCount = 20.0f; + for( int r=0; r<retryCount; ++r ) + { + int which = RandomInt( 0, invasionAreaVector.Count()-1 ); + Vector gazeSpot = invasionAreaVector[ which ]->GetRandomPoint() + Vector( 0, 0, 0.75f * HumanHeight ); + + if ( me->IsRangeGreaterThan( gazeSpot, minGazeRange ) && me->GetVisionInterface()->IsLineOfSightClear( gazeSpot ) ) + { + // use maxLookInterval so these looks override body aiming from path following + m_lookAtSpot = gazeSpot; + break; + } + } + } + } + } + + me->GetLocomotionInterface()->FaceTowards( m_lookAtSpot ); + } + + if ( me->GetLocomotionInterface()->IsAttemptingToMove() ) + { + // play running animation + if ( !me->GetBodyInterface()->IsActivity( ACT_MP_RUN_MELEE ) ) + { + me->GetBodyInterface()->StartActivity( ACT_MP_RUN_MELEE ); + } + } + else + { + // standing still + if ( !me->GetBodyInterface()->IsActivity( ACT_MP_STAND_ITEM1 ) ) + { + me->GetBodyInterface()->StartActivity( ACT_MP_STAND_ITEM1 ); + } + } + + return Continue(); +} + + +//----------------------------------------------------------------------------------------------------- +EventDesiredResult< CBossAlpha > CBossAlphaGuardSpot::OnInjured( CBossAlpha *me, const CTakeDamageInfo &info ) +{ + return TryContinue(); +} + + +#endif // TF_RAID_MODE diff --git a/game/server/tf/player_vs_environment/boss_alpha/behavior/boss_alpha_guard_spot.h b/game/server/tf/player_vs_environment/boss_alpha/behavior/boss_alpha_guard_spot.h new file mode 100644 index 0000000..8fc8685 --- /dev/null +++ b/game/server/tf/player_vs_environment/boss_alpha/behavior/boss_alpha_guard_spot.h @@ -0,0 +1,28 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// boss_alpha_guard_spot.h +// Michael Booth, November 2010 + +#include "cbase.h" + +#ifdef TF_RAID_MODE + +#include "nav_mesh/tf_path_follower.h" + +//--------------------------------------------------------------------------------------------- +class CBossAlphaGuardSpot : public Action< CBossAlpha > +{ +public: + virtual ActionResult< CBossAlpha > OnStart( CBossAlpha *me, Action< CBossAlpha > *priorAction ); + virtual ActionResult< CBossAlpha > Update( CBossAlpha *me, float interval ); + virtual EventDesiredResult< CBossAlpha > OnInjured( CBossAlpha *me, const CTakeDamageInfo &info ); + + virtual const char *GetName( void ) const { return "GuardSpot"; } // return name of this action + +private: + CTFPathFollower m_path; + CountdownTimer m_lookTimer; + Vector m_lookAtSpot; +}; + + +#endif // TF_RAID_MODE diff --git a/game/server/tf/player_vs_environment/boss_alpha/behavior/boss_alpha_launch_grenades.cpp b/game/server/tf/player_vs_environment/boss_alpha/behavior/boss_alpha_launch_grenades.cpp new file mode 100644 index 0000000..34008d3 --- /dev/null +++ b/game/server/tf/player_vs_environment/boss_alpha/behavior/boss_alpha_launch_grenades.cpp @@ -0,0 +1,204 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// boss_alpha_launch_grenades.cpp +// Michael Booth, November 2010 + +#include "cbase.h" + +#ifdef TF_RAID_MODE + +#include "player_vs_environment/boss_alpha/boss_alpha.h" +#include "player_vs_environment/boss_alpha/behavior/boss_alpha_launch_grenades.h" + +ConVar tf_boss_alpha_grenade_ring_min_horiz_vel( "tf_boss_alpha_grenade_ring_min_horiz_vel", "100"/*, FCVAR_CHEAT*/ ); +ConVar tf_boss_alpha_grenade_ring_max_horiz_vel( "tf_boss_alpha_grenade_ring_max_horiz_vel", "350"/*, FCVAR_CHEAT*/ ); +ConVar tf_boss_alpha_grenade_vert_vel( "tf_boss_alpha_grenade_vert_vel", "750"/*, FCVAR_CHEAT*/ ); +ConVar tf_boss_alpha_grenade_det_time( "tf_boss_alpha_grenade_det_time", "3"/*, FCVAR_CHEAT*/ ); +ConVar tf_boss_alpha_grenade_damage( "tf_boss_alpha_grenade_damage", "25"/*, FCVAR_CHEAT*/ ); + + +//--------------------------------------------------------------------------------------------- +ActionResult< CBossAlpha > CBossAlphaLaunchGrenades::OnStart( CBossAlpha *me, Action< CBossAlpha > *priorAction ) +{ + me->GetBodyInterface()->StartActivity( ACT_MP_STAND_SECONDARY ); + m_animLayer = me->AddLayeredSequence( me->LookupSequence( "gesture_melee_cheer" ), 0 ); + + m_timer.Start( 1.0f ); + m_detonateTimer.Invalidate(); + me->AddCondition( CBossAlpha::BUSY ); + me->GetGrenadeTimer()->Start( me->GetGrenadeInterval() ); + + me->EmitSound( "RobotBoss.LaunchGrenades" ); + + return Continue(); +} + + +//--------------------------------------------------------------------------------------------- +void CBossAlphaLaunchGrenades::LaunchGrenade( CBossAlpha *me, const Vector &launchVel, CTFWeaponInfo *weaponInfo ) +{ + CTFGrenadePipebombProjectile *pProjectile = CTFGrenadePipebombProjectile::Create( me->WorldSpaceCenter() + Vector( 0, 0, 100 ), vec3_angle, launchVel, + AngularImpulse( 600, random->RandomInt( -1200, 1200 ), 0 ), + me, *weaponInfo, TF_PROJECTILE_PIPEBOMB_REMOTE, 1 ); + if ( pProjectile ) + { + pProjectile->SetLauncher( me ); + pProjectile->SetDamage( tf_boss_alpha_grenade_damage.GetFloat() ); + + if ( me->IsInCondition( CBossAlpha::ENRAGED ) ) + { + pProjectile->SetCritical( true ); + } + + m_grenadeVector.AddToTail( pProjectile ); + } +} + + +//--------------------------------------------------------------------------------------------- +void CBossAlphaLaunchGrenades::LaunchGrenadeRings( CBossAlpha *me ) +{ + const char *weaponAlias = WeaponIdToAlias( TF_WEAPON_GRENADELAUNCHER ); + if ( !weaponAlias ) + return; + + WEAPON_FILE_INFO_HANDLE weaponInfoHandle = LookupWeaponInfoSlot( weaponAlias ); + if ( weaponInfoHandle == GetInvalidWeaponInfoHandle() ) + return; + + CTFWeaponInfo *weaponInfo = static_cast< CTFWeaponInfo * >( GetFileWeaponInfoFromHandle( weaponInfoHandle ) ); + + QAngle myAngles = me->EyeAngles(); + + // create rings of stickies + float deltaVel = tf_boss_alpha_grenade_ring_max_horiz_vel.GetFloat() - tf_boss_alpha_grenade_ring_min_horiz_vel.GetFloat(); + const int ringCount = 2; + for( int r=0; r<ringCount; ++r ) + { + float u = (float)r/(float)(ringCount-1); + + float horizVel = tf_boss_alpha_grenade_ring_min_horiz_vel.GetFloat() + u * deltaVel; + + float angleDelta = 10.0f + 20.0f * ( 1.0f - u ); + + for( float angle=0.0f; angle<360.0f; angle += angleDelta ) + { + Vector forward; + AngleVectors( myAngles, &forward ); + + Vector vecVelocity( horizVel * forward.x, horizVel * forward.y, tf_boss_alpha_grenade_vert_vel.GetFloat() ); + + LaunchGrenade( me, vecVelocity, weaponInfo ); + + myAngles.y += angleDelta; + } + } +} + + +ConVar tf_boss_alpha_grenade_spoke_angle( "tf_boss_alpha_grenade_spoke_angle", "45"/*, FCVAR_CHEAT*/ ); +ConVar tf_boss_alpha_grenade_spoke_count( "tf_boss_alpha_grenade_spoke_count", "15"/*, FCVAR_CHEAT*/ ); +ConVar tf_boss_alpha_grenade_spoke_min_horiz_vel( "tf_boss_alpha_grenade_spoke_min_horiz_vel", "100"/*, FCVAR_CHEAT*/ ); +ConVar tf_boss_alpha_grenade_spoke_max_horiz_vel( "tf_boss_alpha_grenade_spoke_max_horiz_vel", "750"/*, FCVAR_CHEAT*/ ); + + +//--------------------------------------------------------------------------------------------- +void CBossAlphaLaunchGrenades::LaunchGrenadeSpokes( CBossAlpha *me ) +{ + const char *weaponAlias = WeaponIdToAlias( TF_WEAPON_GRENADELAUNCHER ); + if ( !weaponAlias ) + return; + + WEAPON_FILE_INFO_HANDLE weaponInfoHandle = LookupWeaponInfoSlot( weaponAlias ); + if ( weaponInfoHandle == GetInvalidWeaponInfoHandle() ) + return; + + CTFWeaponInfo *weaponInfo = static_cast< CTFWeaponInfo * >( GetFileWeaponInfoFromHandle( weaponInfoHandle ) ); + + // create spokes of stickies + float deltaVel = tf_boss_alpha_grenade_spoke_max_horiz_vel.GetFloat() - tf_boss_alpha_grenade_spoke_min_horiz_vel.GetFloat(); + float angleDelta = tf_boss_alpha_grenade_spoke_angle.GetFloat(); + QAngle myAngles = me->EyeAngles(); + + for( float angle=0.0f; angle<360.0f; angle += angleDelta ) + { + Vector forward; + AngleVectors( myAngles, &forward ); + + int spokeCount = tf_boss_alpha_grenade_spoke_count.GetInt(); + + for( int i=0; i<spokeCount; ++i ) + { + float u = (float)i/(float)(spokeCount-1); + + float horizVel = tf_boss_alpha_grenade_spoke_min_horiz_vel.GetFloat() + u * deltaVel; + + Vector vecVelocity( horizVel * forward.x, horizVel * forward.y, tf_boss_alpha_grenade_vert_vel.GetFloat() ); + + LaunchGrenade( me, vecVelocity, weaponInfo ); + } + + myAngles.y += angleDelta; + } +} + + +//--------------------------------------------------------------------------------------------- +ActionResult< CBossAlpha > CBossAlphaLaunchGrenades::Update( CBossAlpha *me, float interval ) +{ + QAngle myAngles = me->EyeAngles(); + + if ( m_timer.HasStarted() && m_timer.IsElapsed() ) + { + m_timer.Invalidate(); + + if ( RandomInt( 0, 100 ) < 50 ) + { + LaunchGrenadeRings( me ); + } + else + { + LaunchGrenadeSpokes( me ); + } + + me->EmitSound( "Weapon_Grenade_Normal.Single" ); + + m_detonateTimer.Start( tf_boss_alpha_grenade_det_time.GetFloat() ); + } + + if ( m_detonateTimer.HasStarted() && m_detonateTimer.IsElapsed() ) + { + // detonate the stickies + for( int i=0; i<m_grenadeVector.Count(); ++i ) + { + if ( m_grenadeVector[i] ) + { + m_grenadeVector[i]->Detonate(); + } + } + + return Done(); + } + + return Continue(); +} + + +//--------------------------------------------------------------------------------------------- +void CBossAlphaLaunchGrenades::OnEnd( CBossAlpha *me, Action< CBossAlpha > *nextAction ) +{ + // fizzle any outstanding stickies + for( int i=0; i<m_grenadeVector.Count(); ++i ) + { + if ( m_grenadeVector[i] ) + { + m_grenadeVector[i]->Fizzle(); + m_grenadeVector[i]->Detonate(); + } + } + + me->RemoveCondition( CBossAlpha::ENRAGED ); + me->RemoveCondition( CBossAlpha::BUSY ); + me->FastRemoveLayer( m_animLayer ); +} + +#endif // TF_RAID_MODE diff --git a/game/server/tf/player_vs_environment/boss_alpha/behavior/boss_alpha_launch_grenades.h b/game/server/tf/player_vs_environment/boss_alpha/behavior/boss_alpha_launch_grenades.h new file mode 100644 index 0000000..592bfd5 --- /dev/null +++ b/game/server/tf/player_vs_environment/boss_alpha/behavior/boss_alpha_launch_grenades.h @@ -0,0 +1,36 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// boss_alpha_launch_grenades.h +// Michael Booth, November 2010 + +#ifndef BOSS_ALPHA_LAUNCH_GRENADES_H +#define BOSS_ALPHA_LAUNCH_GRENADES_H + +#ifdef TF_RAID_MODE + +#include "tf_weapon_grenade_pipebomb.h" + +class CBossAlphaLaunchGrenades : public Action< CBossAlpha > +{ +public: + virtual ActionResult< CBossAlpha > OnStart( CBossAlpha *me, Action< CBossAlpha > *priorAction ); + virtual ActionResult< CBossAlpha > Update( CBossAlpha *me, float interval ); + virtual void OnEnd( CBossAlpha *me, Action< CBossAlpha > *nextAction ); + + // if anything interrupts this action, abort it + virtual ActionResult< CBossAlpha > OnSuspend( CBossAlpha *me, Action< CBossAlpha > *interruptingAction ) { return Done(); } + + virtual const char *GetName( void ) const { return "LaunchGrenades"; } // return name of this action + +private: + CountdownTimer m_timer; + CountdownTimer m_detonateTimer; + CUtlVector< CHandle< CTFGrenadePipebombProjectile > > m_grenadeVector; + void LaunchGrenade( CBossAlpha *me, const Vector &launchVel, CTFWeaponInfo *weaponInfo ); + void LaunchGrenadeRings( CBossAlpha *me ); + void LaunchGrenadeSpokes( CBossAlpha *me ); + int m_animLayer; +}; + +#endif // TF_RAID_MODE + +#endif // BOSS_ALPHA_LAUNCH_GRENADES_H
\ No newline at end of file diff --git a/game/server/tf/player_vs_environment/boss_alpha/behavior/boss_alpha_launch_rockets.cpp b/game/server/tf/player_vs_environment/boss_alpha/behavior/boss_alpha_launch_rockets.cpp new file mode 100644 index 0000000..a1558d8 --- /dev/null +++ b/game/server/tf/player_vs_environment/boss_alpha/behavior/boss_alpha_launch_rockets.cpp @@ -0,0 +1,119 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// boss_alpha_launch_rockets.cpp +// Michael Booth, November 2010 + +#include "cbase.h" + +#ifdef TF_RAID_MODE + +#include "tf_projectile_rocket.h" +#include "player_vs_environment/boss_alpha/boss_alpha.h" +#include "player_vs_environment/boss_alpha/behavior/boss_alpha_launch_rockets.h" + +ConVar tf_boss_alpha_dont_shoot( "tf_boss_alpha_dont_shoot", "0"/*, FCVAR_CHEAT*/ ); + + +//--------------------------------------------------------------------------------------------- +ActionResult< CBossAlpha > CBossAlphaLaunchRockets::OnStart( CBossAlpha *me, Action< CBossAlpha > *priorAction ) +{ + // start animation + me->GetBodyInterface()->StartActivity( ACT_MP_STAND_SECONDARY ); + + m_animLayer = me->AddLayeredSequence( me->LookupSequence( "taunt02" ), 0 ); + + m_timer.Start( 1.0f ); + + m_rocketsLeft = me->GetRocketLaunchCount(); + + me->AddCondition( CBossAlpha::BUSY ); + me->LockAttackTarget(); + + me->EmitSound( "RobotBoss.LaunchRockets" ); + + if ( me->GetAttackTarget() == NULL ) + { + return Done( "No target" ); + } + + m_target = me->GetAttackTarget(); + m_lastTargetPosition = m_target->WorldSpaceCenter(); + + return Continue(); +} + + +//--------------------------------------------------------------------------------------------- +ActionResult< CBossAlpha > CBossAlphaLaunchRockets::Update( CBossAlpha *me, float interval ) +{ + if ( m_target != NULL ) + { + m_lastTargetPosition = m_target->WorldSpaceCenter(); + } + + me->GetLocomotionInterface()->FaceTowards( m_lastTargetPosition ); + + if ( m_timer.IsElapsed() && m_launchTimer.IsElapsed() ) + { + if ( !m_rocketsLeft ) + { + return Done(); + } + + --m_rocketsLeft; + m_launchTimer.Start( me->GetRocketInterval() ); + + QAngle launchAngles = me->GetAbsAngles(); + + if ( m_target == NULL ) + { + Vector to = m_lastTargetPosition - me->WorldSpaceCenter(); + VectorAngles( to, launchAngles ); + } + else + { + float range = me->GetRangeTo( m_target->EyePosition() ); + + const float rocketSpeed = me->GetRocketAimError() * 1100.0f; // 2000.0f; // 1100.0f; nerfing accuracy + float flightTime = range / rocketSpeed; + + Vector aimSpot = m_target->EyePosition() + m_target->GetAbsVelocity() * flightTime; + + Vector to = aimSpot - me->WorldSpaceCenter(); + VectorAngles( to, launchAngles ); + } + + if ( !tf_boss_alpha_dont_shoot.GetBool() ) + { + CTFProjectile_Rocket *pRocket = CTFProjectile_Rocket::Create( me, me->WorldSpaceCenter(), launchAngles, me, me ); + if ( pRocket ) + { + if ( me->IsInCondition( CBossAlpha::ENRAGED ) ) + { + pRocket->SetCritical( true ); + pRocket->EmitSound( "Weapon_RPG.SingleCrit" ); + } + else + { + me->EmitSound( me->GetRocketSoundEffect() ); + } + + pRocket->SetDamage( me->GetRocketDamage() ); + } + } + } + + return Continue(); +} + + +//--------------------------------------------------------------------------------------------- +void CBossAlphaLaunchRockets::OnEnd( CBossAlpha *me, Action< CBossAlpha > *nextAction ) +{ + me->RemoveCondition( CBossAlpha::ENRAGED ); + me->RemoveCondition( CBossAlpha::BUSY ); + me->FastRemoveLayer( m_animLayer ); + me->UnlockAttackTarget(); +} + + +#endif // TF_RAID_MODE diff --git a/game/server/tf/player_vs_environment/boss_alpha/behavior/boss_alpha_launch_rockets.h b/game/server/tf/player_vs_environment/boss_alpha/behavior/boss_alpha_launch_rockets.h new file mode 100644 index 0000000..2f216b9 --- /dev/null +++ b/game/server/tf/player_vs_environment/boss_alpha/behavior/boss_alpha_launch_rockets.h @@ -0,0 +1,38 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// boss_alpha_launch_rockets.h +// Michael Booth, November 2010 + +#ifndef BOSS_ALPHA_LAUNCH_ROCKETS_H +#define BOSS_ALPHA_LAUNCH_ROCKETS_H + +#ifdef TF_RAID_MODE + +//--------------------------------------------------------------------------------------------- +class CBossAlphaLaunchRockets : public Action< CBossAlpha > +{ +public: + virtual ActionResult< CBossAlpha > OnStart( CBossAlpha *me, Action< CBossAlpha > *priorAction ); + virtual ActionResult< CBossAlpha > Update( CBossAlpha *me, float interval ); + virtual void OnEnd( CBossAlpha *me, Action< CBossAlpha > *nextAction ); + + // if anything interrupts this action, abort it + virtual ActionResult< CBossAlpha > OnSuspend( CBossAlpha *me, Action< CBossAlpha > *interruptingAction ) { return Done(); } + + virtual const char *GetName( void ) const { return "LaunchRockets"; } // return name of this action + +private: + CountdownTimer m_timer; + + CountdownTimer m_launchTimer; + int m_rocketsLeft; + + int m_animLayer; + + CHandle< CBaseCombatCharacter > m_target; + Vector m_lastTargetPosition; +}; + + +#endif // TF_RAID_MODE + +#endif // BOSS_ALPHA_LAUNCH_ROCKETS_H diff --git a/game/server/tf/player_vs_environment/boss_alpha/behavior/boss_alpha_lost_victim.cpp b/game/server/tf/player_vs_environment/boss_alpha/behavior/boss_alpha_lost_victim.cpp new file mode 100644 index 0000000..f935cfa --- /dev/null +++ b/game/server/tf/player_vs_environment/boss_alpha/behavior/boss_alpha_lost_victim.cpp @@ -0,0 +1,64 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// boss_alpha_lost_victim.cpp +// Michael Booth, November 2010 + +#include "cbase.h" + +#ifdef TF_RAID_MODE + +#include "player_vs_environment/boss_alpha/boss_alpha.h" +#include "player_vs_environment/boss_alpha/behavior/boss_alpha_lost_victim.h" + +//--------------------------------------------------------------------------------------------- +ActionResult< CBossAlpha > CBossAlphaLostVictim::OnStart( CBossAlpha *me, Action< CBossAlpha > *priorAction ) +{ + m_headTurn = 0.0f; + m_headYawPoseParameter = me->LookupPoseParameter( "body_yaw" ); + + m_timer.Start( RandomFloat( 3.0f, 5.0f ) ); + + me->EmitSound( "RobotBoss.Scanning" ); + + return Continue(); +} + + +//--------------------------------------------------------------------------------------------- +ActionResult< CBossAlpha > CBossAlphaLostVictim::Update( CBossAlpha *me, float interval ) +{ + if ( m_timer.IsElapsed() ) + { + return Done( "Giving up" ); + } + + CBaseCombatCharacter *target = me->GetAttackTarget(); + if ( target ) + { + if ( me->IsLineOfSightClear( target ) || me->IsPrisonerOfMinion( target ) ) + { + me->EmitSound( "RobotBoss.Acquire" ); + me->AddGesture( ACT_MP_GESTURE_FLINCH_CHEST ); + return Done( "Ah hah!" ); + } + } + + const float rate = M_PI / 3.0f; + m_headTurn += rate * interval; + + float s, c; + SinCos( m_headTurn, &s, &c ); + + me->SetPoseParameter( m_headYawPoseParameter, 40.0f * s ); + + return Continue(); +} + + +//--------------------------------------------------------------------------------------------- +void CBossAlphaLostVictim::OnEnd( CBossAlpha *me, Action< CBossAlpha > *nextAction ) +{ + me->SetPoseParameter( m_headYawPoseParameter, 0 ); +} + + +#endif // TF_RAID_MODE diff --git a/game/server/tf/player_vs_environment/boss_alpha/behavior/boss_alpha_lost_victim.h b/game/server/tf/player_vs_environment/boss_alpha/behavior/boss_alpha_lost_victim.h new file mode 100644 index 0000000..b5be9c1 --- /dev/null +++ b/game/server/tf/player_vs_environment/boss_alpha/behavior/boss_alpha_lost_victim.h @@ -0,0 +1,28 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// boss_alpha_lost_victim.h +// Michael Booth, November 2010 + +#ifndef BOSS_ALPHA_LOST_VICTIM_H +#define BOSS_ALPHA_LOST_VICTIM_H + +#ifdef TF_RAID_MODE + +//--------------------------------------------------------------------------------------------- +class CBossAlphaLostVictim : public Action< CBossAlpha > +{ +public: + virtual ActionResult< CBossAlpha > OnStart( CBossAlpha *me, Action< CBossAlpha > *priorAction ); + virtual ActionResult< CBossAlpha > Update( CBossAlpha *me, float interval ); + virtual void OnEnd( CBossAlpha *me, Action< CBossAlpha > *nextAction ); + + virtual const char *GetName( void ) const { return "LostVictim"; } // return name of this action + +private: + CountdownTimer m_timer; + float m_headTurn; + int m_headYawPoseParameter; +}; + +#endif // TF_RAID_MODE + +#endif // BOSS_ALPHA_LOST_VICTIM_H diff --git a/game/server/tf/player_vs_environment/boss_alpha/behavior/boss_alpha_nuke_attack.cpp b/game/server/tf/player_vs_environment/boss_alpha/behavior/boss_alpha_nuke_attack.cpp new file mode 100644 index 0000000..f1a3289 --- /dev/null +++ b/game/server/tf/player_vs_environment/boss_alpha/behavior/boss_alpha_nuke_attack.cpp @@ -0,0 +1,208 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// boss_alpha_nuke_attack.cpp +// Michael Booth, November 2010 + +#include "cbase.h" + +#ifdef TF_RAID_MODE + +#include "tf_player.h" +#include "tf_team.h" +#include "player_vs_environment/monster_resource.h" +#include "player_vs_environment/boss_alpha/boss_alpha.h" +#include "player_vs_environment/boss_alpha/behavior/boss_alpha_nuke_attack.h" +#include "player_vs_environment/boss_alpha/behavior/boss_alpha_stunned.h" + + +ConVar tf_boss_alpha_nuke_charge_time( "tf_boss_alpha_nuke_charge_time", "5" ); +ConVar tf_boss_alpha_nuke_interval( "tf_boss_alpha_nuke_interval", "20" ); +ConVar tf_boss_alpha_nuke_lethal_time( "tf_boss_alpha_nuke_lethal_time", "999999999" ); // 300 +ConVar tf_boss_alpha_nuke_damage( "tf_boss_alpha_nuke_damage", "75"/*, FCVAR_CHEAT*/ ); +ConVar tf_boss_alpha_nuke_max_remaining_health( "tf_boss_alpha_nuke_max_remaining_health", "60"/*, FCVAR_CHEAT*/ ); +ConVar tf_boss_alpha_nuke_afterburn_time( "tf_boss_alpha_nuke_afterburn_time", "5"/*, FCVAR_CHEAT*/ ); + +extern ConVar tf_boss_alpha_stunned_duration; + + +//--------------------------------------------------------------------------------------------- +ActionResult< CBossAlpha > CBossAlphaNukeAttack::OnStart( CBossAlpha *me, Action< CBossAlpha > *priorAction ) +{ + me->GetBodyInterface()->StartActivity( ACT_MP_JUMP_FLOAT_LOSERSTATE ); + me->StartNukeEffect(); + + me->EmitSound( "RobotBoss.ChargeUpNukeAttack" ); + // me->AddCondition( CBossAlpha::VULNERABLE_TO_STUN ); + + m_chargeUpTimer.Start( tf_boss_alpha_nuke_charge_time.GetFloat() ); + m_shakeTimer.Start( 0.25f ); + + + return Continue(); +} + + +//--------------------------------------------------------------------------------------------- +ActionResult< CBossAlpha > CBossAlphaNukeAttack::Update( CBossAlpha *me, float interval ) +{ + float stunRatio = me->GetStunDamage() / me->GetBecomeStunnedDamage(); + + if ( me->HasAbility( CBossAlpha::CAN_BE_STUNNED ) && stunRatio >= 1.0f ) + { + return ChangeTo( new CBossAlphaStunned( tf_boss_alpha_stunned_duration.GetFloat() ), "They got me" ); + } + + // update the client's HUD + if ( g_pMonsterResource ) + { + g_pMonsterResource->SetBossStunPercentage( 1.0f - stunRatio ); + } + + if ( m_shakeTimer.IsElapsed() ) + { + m_shakeTimer.Reset(); + UTIL_ScreenShake( me->GetAbsOrigin(), 15.0f, 5.0f, 1.0f, 3000.0f, SHAKE_START ); + } + + if ( m_chargeUpTimer.IsElapsed() ) + { + // BLAST! + CUtlVector< CTFPlayer * > playerVector; + CollectPlayers( &playerVector, TF_TEAM_RED, COLLECT_ONLY_LIVING_PLAYERS ); + CollectPlayers( &playerVector, TF_TEAM_BLUE, COLLECT_ONLY_LIVING_PLAYERS, APPEND_PLAYERS ); + + me->EmitSound( "RobotBoss.NukeAttack" ); + + CUtlVector< CBaseCombatCharacter * > victimVector; + + int i; + + // players + for ( i=0; i<playerVector.Count(); ++i ) + { + CBasePlayer *player = playerVector[i]; + + if ( player && player->IsAlive() && player->GetTeamNumber() == TF_TEAM_BLUE ) + { + victimVector.AddToTail( player ); + } + } + + // objects + CTFTeam *team = GetGlobalTFTeam( TF_TEAM_BLUE ); + if ( team ) + { + for ( i=0; i<team->GetNumObjects(); ++i ) + { + CBaseObject *object = team->GetObject( i ); + if ( object ) + { + victimVector.AddToTail( object ); + } + } + } + +#ifdef SKIPME + team = GetGlobalTFTeam( TF_TEAM_RED ); + if ( team ) + { + for ( i=0; i<team->GetNumObjects(); ++i ) + { + CBaseObject *object = team->GetObject( i ); + if ( object ) + { + victimVector.AddToTail( object ); + } + } + } + + // non-player bots + CUtlVector< INextBot * > botVector; + TheNextBots().CollectAllBots( &botVector ); + for( i=0; i<botVector.Count(); ++i ) + { + CBaseCombatCharacter *bot = botVector[i]->GetEntity(); + + if ( !bot->IsPlayer() && bot->IsAlive() ) + { + victimVector.AddToTail( bot ); + } + } +#endif // SKIPME + + for( int i=0; i<victimVector.Count(); ++i ) + { + CBaseCombatCharacter *victim = victimVector[i]; + + if ( me->IsSelf( victim ) ) + continue; + + if ( me->IsLineOfSightClear( victim ) ) + { + Vector toVictim = victim->WorldSpaceCenter() - me->WorldSpaceCenter(); + toVictim.NormalizeInPlace(); + + float damage = tf_boss_alpha_nuke_damage.GetFloat(); + + if ( me->GetAge() > tf_boss_alpha_nuke_lethal_time.GetFloat() ) + { + // nuke is now lethal + damage = 999.9f; + } + else if ( tf_boss_alpha_nuke_max_remaining_health.GetFloat() >= 0.0f ) + { + // nuke slams everyone's health to this + if ( victim->GetHealth() > tf_boss_alpha_nuke_max_remaining_health.GetFloat() ) + { + damage = victim->GetHealth() - tf_boss_alpha_nuke_max_remaining_health.GetFloat(); + } + } + + CTakeDamageInfo info( me, me, damage, DMG_ENERGYBEAM, TF_DMG_CUSTOM_NONE ); + CalculateMeleeDamageForce( &info, toVictim, me->WorldSpaceCenter(), 1.0f ); + victim->TakeDamage( info ); + + if ( victim->IsPlayer() ) + { + CTFPlayer *playerVictim = ToTFPlayer( victim ); + + // catch them on fire (unless they are a Pyro) + if ( !playerVictim->IsPlayerClass( TF_CLASS_PYRO ) ) + { + playerVictim->m_Shared.Burn( me, tf_boss_alpha_nuke_afterburn_time.GetFloat() ); + } + + color32 colorHit = { 255, 255, 255, 255 }; + UTIL_ScreenFade( victim, colorHit, 1.0f, 0.1f, FFADE_IN ); + } + } + } + + return Done(); + } + + return Continue(); +} + + +//--------------------------------------------------------------------------------------------- +void CBossAlphaNukeAttack::OnEnd( CBossAlpha *me, Action< CBossAlpha > *nextAction ) +{ + me->RemoveCondition( CBossAlpha::VULNERABLE_TO_STUN ); + me->StopNukeEffect(); + me->ClearStunDamage(); + me->GetNukeTimer()->Start( tf_boss_alpha_nuke_interval.GetFloat() ); + + if ( g_pMonsterResource ) + { + g_pMonsterResource->HideBossStunMeter(); + } +} + + +//--------------------------------------------------------------------------------------------- +EventDesiredResult< CBossAlpha > CBossAlphaNukeAttack::OnInjured( CBossAlpha *me, const CTakeDamageInfo &info ) +{ + return TryToSustain( RESULT_CRITICAL ); +} + +#endif // TF_RAID_MODE diff --git a/game/server/tf/player_vs_environment/boss_alpha/behavior/boss_alpha_nuke_attack.h b/game/server/tf/player_vs_environment/boss_alpha/behavior/boss_alpha_nuke_attack.h new file mode 100644 index 0000000..3566a59 --- /dev/null +++ b/game/server/tf/player_vs_environment/boss_alpha/behavior/boss_alpha_nuke_attack.h @@ -0,0 +1,31 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// boss_alpha_nuke_attack.h +// Michael Booth, November 2010 + +#ifndef BOSS_ALPHA_NUKE_ATTACK_H +#define BOSS_ALPHA_NUKE_ATTACK_H + +#ifdef TF_RAID_MODE + +class CBossAlphaNukeAttack : public Action< CBossAlpha > +{ +public: + virtual ActionResult< CBossAlpha > OnStart( CBossAlpha *me, Action< CBossAlpha > *priorAction ); + virtual ActionResult< CBossAlpha > Update( CBossAlpha *me, float interval ); + virtual void OnEnd( CBossAlpha *me, Action< CBossAlpha > *nextAction ); + + // if anything interrupts this action, abort it + virtual ActionResult< CBossAlpha > OnSuspend( CBossAlpha *me, Action< CBossAlpha > *interruptingAction ) { return Done(); } + + virtual EventDesiredResult< CBossAlpha > OnInjured( CBossAlpha *me, const CTakeDamageInfo &info ); + + virtual const char *GetName( void ) const { return "NukeAttack"; } // return name of this action + +private: + CountdownTimer m_shakeTimer; + CountdownTimer m_chargeUpTimer; +}; + +#endif // TF_RAID_MODE + +#endif // BOSS_ALPHA_NUKE_ATTACK_H diff --git a/game/server/tf/player_vs_environment/boss_alpha/behavior/boss_alpha_stunned.cpp b/game/server/tf/player_vs_environment/boss_alpha/behavior/boss_alpha_stunned.cpp new file mode 100644 index 0000000..19f340f --- /dev/null +++ b/game/server/tf/player_vs_environment/boss_alpha/behavior/boss_alpha_stunned.cpp @@ -0,0 +1,171 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// boss_alpha_stunned.cpp +// Michael Booth, November 2010 + +#include "cbase.h" + +#ifdef TF_RAID_MODE + +#include "tf_shareddefs.h" +#include "tf_ammo_pack.h" +#include "player_vs_environment/boss_alpha/boss_alpha.h" +#include "player_vs_environment/boss_alpha/behavior/boss_alpha_stunned.h" + + +extern ConVar tf_boss_alpha_min_nuke_after_stun_time; + + +//--------------------------------------------------------------------------------------------- +CBossAlphaStunned::CBossAlphaStunned( float duration, Action< CBossAlpha > *nextAction ) +{ + m_timer.Start( duration ); + m_nextAction = nextAction; +} + + +//--------------------------------------------------------------------------------------------- +ConVar tf_boss_alpha_stun_ammo_count( "tf_boss_alpha_stun_ammo_count", "3"/*, FCVAR_CHEAT*/ ); +ConVar tf_boss_alpha_stun_ammo_amount( "tf_boss_alpha_stun_ammo_amount", "100"/*, FCVAR_CHEAT*/ ); +ConVar tf_boss_alpha_stun_ammo_velocity( "tf_boss_alpha_stun_ammo_velocity", "100"/*, FCVAR_CHEAT*/ ); + +void TossAmmoPack( CBossAlpha *me ) +{ + int iPrimary = tf_boss_alpha_stun_ammo_amount.GetInt(); + int iSecondary = tf_boss_alpha_stun_ammo_amount.GetInt(); + int iMetal = tf_boss_alpha_stun_ammo_amount.GetInt(); + + // Create the ammo pack. + CTFAmmoPack *pAmmoPack = CTFAmmoPack::Create( me->GetAbsOrigin(), me->GetAbsAngles(), NULL, "models/items/ammopack_medium.mdl" ); + if ( pAmmoPack ) + { +/* + Vector vel; + + vel.x = RandomFloat( -1.0f, 1.0f ) * tf_boss_alpha_stun_ammo_velocity.GetFloat(); + vel.y = RandomFloat( -1.0f, 1.0f ) * tf_boss_alpha_stun_ammo_velocity.GetFloat(); + vel.z = tf_boss_alpha_stun_ammo_velocity.GetFloat(); + + pAmmoPack->SetInitialVelocity( vel ); +*/ + pAmmoPack->m_nSkin = 0; + + // Give the ammo pack some health, so that trains can destroy it. + pAmmoPack->SetCollisionGroup( COLLISION_GROUP_DEBRIS ); + pAmmoPack->m_takedamage = DAMAGE_YES; + pAmmoPack->SetHealth( 900 ); + + pAmmoPack->SetBodygroup( 1, 1 ); + + pAmmoPack->ApplyLocalAngularVelocityImpulse( AngularImpulse( 600, random->RandomInt( -1200, 1200 ), 0 ) ); + + DispatchSpawn( pAmmoPack ); + + // Fill up the ammo pack. + pAmmoPack->GiveAmmo( iPrimary, TF_AMMO_PRIMARY ); + pAmmoPack->GiveAmmo( iSecondary, TF_AMMO_SECONDARY ); + pAmmoPack->GiveAmmo( iMetal, TF_AMMO_METAL ); + } +} + + +//--------------------------------------------------------------------------------------------- +ActionResult< CBossAlpha > CBossAlphaStunned::OnStart( CBossAlpha *me, Action< CBossAlpha > *priorAction ) +{ + // start animation + me->GetBodyInterface()->StartActivity( ACT_MP_STAND_MELEE ); + m_layerUsed = me->AddLayeredSequence( me->LookupSequence( "PRIMARY_Stun_begin" ), 0 ); + m_state = BECOMING_STUNNED; + + m_timer.Reset(); + + me->AddCondition( CBossAlpha::STUNNED ); + me->EmitSound( "RobotBoss.StunStart" ); + + // throw out some ammo + for( int i=0; i<tf_boss_alpha_stun_ammo_count.GetInt(); ++i ) + { + TossAmmoPack( me ); + } + + // relay the event to the map logic + me->m_outputOnStunned.FireOutput( me, me ); + + return Continue(); +} + + +//--------------------------------------------------------------------------------------------- +ActionResult< CBossAlpha > CBossAlphaStunned::Update( CBossAlpha *me, float interval ) +{ + switch( m_state ) + { + case BECOMING_STUNNED: + if ( me->IsSequenceFinished() ) + { + me->FastRemoveLayer( m_layerUsed ); + + m_state = STUNNED; + m_layerUsed = me->AddLayeredSequence( me->LookupSequence( "PRIMARY_stun_middle" ), 0 ); + me->SetLayerLooping( m_layerUsed, true ); + me->EmitSound( "RobotBoss.Stunned" ); + } + break; + + case STUNNED: + if ( m_timer.IsElapsed() ) + { + me->FastRemoveLayer( m_layerUsed ); + + m_state = RECOVERING; + m_layerUsed = me->AddLayeredSequence( me->LookupSequence( "PRIMARY_stun_end" ), 0 ); + me->StopSound( "RobotBoss.Stunned" ); + me->EmitSound( "RobotBoss.StunRecover" ); + } + break; + + case RECOVERING: + if ( me->IsSequenceFinished() ) + { + me->FastRemoveLayer( m_layerUsed ); + + if ( m_nextAction ) + { + return ChangeTo( m_nextAction, "Stun finished" ); + } + + return Done( "Stun finished" ); + } + break; + } + + return Continue(); +} + + +//--------------------------------------------------------------------------------------------- +EventDesiredResult< CBossAlpha > CBossAlphaStunned::OnInjured( CBossAlpha *me, const CTakeDamageInfo &info ) +{ + return TryToSustain( RESULT_CRITICAL ); +} + + +//--------------------------------------------------------------------------------------------- +void CBossAlphaStunned::OnEnd( CBossAlpha *me, Action< CBossAlpha > *nextAction ) +{ + me->RemoveCondition( CBossAlpha::STUNNED ); + + if ( me->HasAbility( CBossAlpha::CAN_ENRAGE ) ) + { + // being stunned makes the boss ANGRY! + me->AddCondition( CBossAlpha::ENRAGED ); + } + + // make sure the boss attacks at least once before he starts a nuke + if ( me->GetNukeTimer()->GetRemainingTime() < tf_boss_alpha_min_nuke_after_stun_time.GetFloat() ) + { + me->GetNukeTimer()->Start( tf_boss_alpha_min_nuke_after_stun_time.GetFloat() ); + } +} + + +#endif // TF_RAID_MODE diff --git a/game/server/tf/player_vs_environment/boss_alpha/behavior/boss_alpha_stunned.h b/game/server/tf/player_vs_environment/boss_alpha/behavior/boss_alpha_stunned.h new file mode 100644 index 0000000..d73ba17 --- /dev/null +++ b/game/server/tf/player_vs_environment/boss_alpha/behavior/boss_alpha_stunned.h @@ -0,0 +1,39 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// boss_alpha_stunned.h +// Michael Booth, November 2010 + +#ifndef BOSS_ALPHA_STUNNED_H +#define BOSS_ALPHA_STUNNED_H + +#ifdef TF_RAID_MODE + +class CBossAlphaStunned : public Action< CBossAlpha > +{ +public: + CBossAlphaStunned( float duration, Action< CBossAlpha > *nextAction = NULL ); + + virtual ActionResult< CBossAlpha > OnStart( CBossAlpha *me, Action< CBossAlpha > *priorAction ); + virtual ActionResult< CBossAlpha > Update( CBossAlpha *me, float interval ); + virtual void OnEnd( CBossAlpha *me, Action< CBossAlpha > *nextAction ); + + virtual EventDesiredResult< CBossAlpha > OnInjured( CBossAlpha *me, const CTakeDamageInfo &info ); + + virtual const char *GetName( void ) const { return "Stunned"; } // return name of this action + +private: + CountdownTimer m_timer; + enum StunStateType + { + BECOMING_STUNNED, + STUNNED, + RECOVERING + } + m_state; + int m_layerUsed; + + Action< CBossAlpha > *m_nextAction; +}; + +#endif // TF_RAID_MODE + +#endif // BOSS_ALPHA_STUNNED_H diff --git a/game/server/tf/player_vs_environment/boss_alpha/behavior/boss_alpha_tactical_monitor.cpp b/game/server/tf/player_vs_environment/boss_alpha/behavior/boss_alpha_tactical_monitor.cpp new file mode 100644 index 0000000..eca4107 --- /dev/null +++ b/game/server/tf/player_vs_environment/boss_alpha/behavior/boss_alpha_tactical_monitor.cpp @@ -0,0 +1,81 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// boss_alpha_tactical_monitor.cpp +// Michael Booth, November 2010 + +#include "cbase.h" + +#ifdef TF_RAID_MODE + +#include "tf_gamerules.h" +#include "player_vs_environment/boss_alpha/boss_alpha.h" +#include "player_vs_environment/boss_alpha/behavior/boss_alpha_tactical_monitor.h" +#include "player_vs_environment/boss_alpha/behavior/boss_alpha_get_off_me.h" +#include "player_vs_environment/boss_alpha/behavior/boss_alpha_wait_for_players.h" +#include "player_vs_environment/boss_alpha/behavior/boss_alpha_stunned.h" + + +ConVar tf_boss_alpha_get_off_me_duration( "tf_boss_alpha_get_off_me_duration", "3"/*, FCVAR_CHEAT */ ); +ConVar tf_boss_alpha_stunned_duration( "tf_boss_alpha_stunned_duration", "10" ); + + +//--------------------------------------------------------------------------------------------- +Action< CBossAlpha > *CBossAlphaTacticalMonitor::InitialContainedAction( CBossAlpha *me ) +{ + if ( TFGameRules()->IsBossBattleMode() ) + { + return new CBossAlphaWaitForPlayers; + } + + return NULL; +} + + +//--------------------------------------------------------------------------------------------- +ActionResult< CBossAlpha > CBossAlphaTacticalMonitor::OnStart( CBossAlpha *me, Action< CBossAlpha > *priorAction ) +{ + m_getOffMeTimer.Invalidate(); + + return Continue(); +} + + +//--------------------------------------------------------------------------------------------- +ActionResult< CBossAlpha > CBossAlphaTacticalMonitor::Update( CBossAlpha *me, float interval ) +{ + if ( me->IsInCondition( CBossAlpha::STUNNED ) ) + { + return SuspendFor( new CBossAlphaStunned( tf_boss_alpha_stunned_duration.GetFloat() ), "Ouch!" ); + } + + if ( !m_getOffMeTimer.HasStarted() ) + { + CUtlVector< CTFPlayer * > onMeVector; + me->CollectPlayersStandingOnMe( &onMeVector ); + + if ( onMeVector.Count() ) + { + // someone is standing on me - push them off soon + m_getOffMeTimer.Start( tf_boss_alpha_get_off_me_duration.GetFloat() ); + } + } + else if ( m_getOffMeTimer.IsElapsed() ) + { + if ( !me->IsBusy() ) + { + m_getOffMeTimer.Invalidate(); + + // if someone is still on me, push them off + CUtlVector< CTFPlayer * > onMeVector; + me->CollectPlayersStandingOnMe( &onMeVector ); + if ( onMeVector.Count() ) + { + return SuspendFor( new CBossAlphaGetOffMe, "Get offa me!" ); + } + } + } + + return Continue(); +} + + +#endif // TF_RAID_MODE diff --git a/game/server/tf/player_vs_environment/boss_alpha/behavior/boss_alpha_tactical_monitor.h b/game/server/tf/player_vs_environment/boss_alpha/behavior/boss_alpha_tactical_monitor.h new file mode 100644 index 0000000..e612b7c --- /dev/null +++ b/game/server/tf/player_vs_environment/boss_alpha/behavior/boss_alpha_tactical_monitor.h @@ -0,0 +1,32 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// boss_alpha_tactical_monitor.h +// Michael Booth, November 2010 + +#ifndef BOSS_ALPHA_TACTICAL_MONITOR_H +#define BOSS_ALPHA_TACTICAL_MONITOR_H + +#ifdef TF_RAID_MODE + +class CBossAlpha; + + +//--------------------------------------------------------------------------------------------- +class CBossAlphaTacticalMonitor : public Action< CBossAlpha > +{ +public: + virtual Action< CBossAlpha > *InitialContainedAction( CBossAlpha *me ); + + virtual ActionResult< CBossAlpha > OnStart( CBossAlpha *me, Action< CBossAlpha > *priorAction ); + virtual ActionResult< CBossAlpha > Update( CBossAlpha *me, float interval ); + + virtual const char *GetName( void ) const { return "TacticalMonitor"; } // return name of this action + +private: + CountdownTimer m_backOffCooldownTimer; + CountdownTimer m_getOffMeTimer; +}; + + +#endif // TF_RAID_MODE + +#endif // BOSS_ALPHA_TACTICAL_MONITOR_H diff --git a/game/server/tf/player_vs_environment/boss_alpha/behavior/boss_alpha_wait_for_players.cpp b/game/server/tf/player_vs_environment/boss_alpha/behavior/boss_alpha_wait_for_players.cpp new file mode 100644 index 0000000..cec965f --- /dev/null +++ b/game/server/tf/player_vs_environment/boss_alpha/behavior/boss_alpha_wait_for_players.cpp @@ -0,0 +1,79 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// boss_alpha_wait_for_players.cpp +// Michael Booth, November 2010 + +#include "cbase.h" + +#ifdef TF_RAID_MODE + +#include "player_vs_environment/boss_alpha/boss_alpha.h" +#include "player_vs_environment/boss_alpha/behavior/boss_alpha_wait_for_players.h" +#include "player_vs_environment/boss_alpha/behavior/boss_alpha_guard_spot.h" + + +extern ConVar tf_boss_alpha_nuke_interval; + +ConVar tf_boss_alpha_sleep( "tf_boss_alpha_sleep", "0"/*, FCVAR_CHEAT */ ); + + +//--------------------------------------------------------------------------------------------- +ActionResult< CBossAlpha > CBossAlphaWaitForPlayers::OnStart( CBossAlpha *me, Action< CBossAlpha > *priorAction ) +{ + me->AddCondition( CBossAlpha::BUSY ); + + return Continue(); +} + + +//--------------------------------------------------------------------------------------------- +ActionResult< CBossAlpha > CBossAlphaWaitForPlayers::Update( CBossAlpha *me, float interval ) +{ + if ( tf_boss_alpha_sleep.GetBool() ) + { + return Continue(); + } + + CBaseCombatCharacter *target = me->GetAttackTarget(); + if ( target ) + { + return ChangeTo( new CBossAlphaGuardSpot, "I see you..." ); + } + + return Continue(); +} + + +//--------------------------------------------------------------------------------------------- +void CBossAlphaWaitForPlayers::OnEnd( CBossAlpha *me, Action< CBossAlpha > *nextAction ) +{ + me->RemoveCondition( CBossAlpha::BUSY ); + + me->GetNukeTimer()->Start( tf_boss_alpha_nuke_interval.GetFloat() ); + me->GetGrenadeTimer()->Reset(); +} + + +//--------------------------------------------------------------------------------------------- +EventDesiredResult< CBossAlpha > CBossAlphaWaitForPlayers::OnInjured( CBossAlpha *me, const CTakeDamageInfo &info ) +{ + if ( tf_boss_alpha_sleep.GetBool() ) + { + return TryContinue(); + } + + return TryChangeTo( new CBossAlphaGuardSpot, RESULT_CRITICAL, "Ouch!" ); +} + + +//--------------------------------------------------------------------------------------------- +EventDesiredResult< CBossAlpha > CBossAlphaWaitForPlayers::OnContact( CBossAlpha *me, CBaseEntity *other, CGameTrace *result ) +{ + if ( other && other->IsPlayer() && !tf_boss_alpha_sleep.GetBool() ) + { + return TryChangeTo( new CBossAlphaGuardSpot, RESULT_CRITICAL, "Don't touch me" ); + } + + return TryContinue(); +} + +#endif // TF_RAID_MODE diff --git a/game/server/tf/player_vs_environment/boss_alpha/behavior/boss_alpha_wait_for_players.h b/game/server/tf/player_vs_environment/boss_alpha/behavior/boss_alpha_wait_for_players.h new file mode 100644 index 0000000..a24011d --- /dev/null +++ b/game/server/tf/player_vs_environment/boss_alpha/behavior/boss_alpha_wait_for_players.h @@ -0,0 +1,25 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// boss_alpha_wait_for_players.h +// Michael Booth, November 2010 + +#ifndef BOSS_ALPHA_WAIT_FOR_PLAYER_H +#define BOSS_ALPHA_WAIT_FOR_PLAYER_H + +#ifdef TF_RAID_MODE + +class CBossAlphaWaitForPlayers : public Action< CBossAlpha > +{ +public: + virtual ActionResult< CBossAlpha > OnStart( CBossAlpha *me, Action< CBossAlpha > *priorAction ); + virtual ActionResult< CBossAlpha > Update( CBossAlpha *me, float interval ); + virtual void OnEnd( CBossAlpha *me, Action< CBossAlpha > *nextAction ); + + virtual EventDesiredResult< CBossAlpha > OnInjured( CBossAlpha *me, const CTakeDamageInfo &info ); + virtual EventDesiredResult< CBossAlpha > OnContact( CBossAlpha *me, CBaseEntity *other, CGameTrace *result = NULL ); + + virtual const char *GetName( void ) const { return "WaitForPlayers"; } // return name of this action +}; + +#endif // TF_RAID_MODE + +#endif // BOSS_ALPHA_WAIT_FOR_PLAYER_H |