This commit is contained in:
FluorescentCIAAfricanAmerican
2020-04-22 12:56:21 -04:00
commit 3bf9df6b27
15370 changed files with 5489726 additions and 0 deletions
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,508 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
// boss_alpha.h
// Our first "real" TF Boss
// Michael Booth, November 2010
#ifndef BOSS_ALPHA_H
#define BOSS_ALPHA_H
#ifdef TF_RAID_MODE
#include "NextBot.h"
#include "NextBotBehavior.h"
#include "NextBotGroundLocomotion.h"
#include "Path/NextBotPathFollow.h"
#include "bot_npc/bot_npc_body.h"
#include "bot/map_entities/tf_spawner_boss.h"
class CTFPlayer;
class CBossAlpha;
//----------------------------------------------------------------------------
class CBossAlphaLocomotion : public NextBotGroundLocomotion
{
public:
CBossAlphaLocomotion( INextBot *bot );
virtual ~CBossAlphaLocomotion() { }
virtual float GetRunSpeed( void ) const; // get maximum running speed
virtual float GetStepHeight( void ) const; // if delta Z is greater than this, we have to jump to get up
virtual float GetMaxJumpHeight( void ) const; // return maximum height of a jump
virtual float GetMaxAcceleration( void ) const
{
return 2500.0f;
}
virtual float GetMaxYawRate( void ) const // return max rate of yaw rotation
{
return 50.0f;
}
private:
float m_runSpeed;
};
//----------------------------------------------------------------------------
class CBossAlphaIntention : public IIntention
{
public:
CBossAlphaIntention( CBossAlpha *me );
virtual ~CBossAlphaIntention();
virtual void Reset( void );
virtual void Update( void );
virtual QueryResultType IsPositionAllowed( const INextBot *me, const Vector &pos ) const; // is the a place we can be?
virtual INextBotEventResponder *FirstContainedResponder( void ) const { return m_behavior; }
virtual INextBotEventResponder *NextContainedResponder( INextBotEventResponder *current ) const { return NULL; }
private:
Behavior< CBossAlpha > *m_behavior;
};
//----------------------------------------------------------------------------
class CBossAlphaVision : public IVision
{
public:
CBossAlphaVision( INextBot *bot ) : IVision( bot )
{
}
virtual ~CBossAlphaVision() { }
virtual bool IsIgnored( CBaseEntity *subject ) const; // return true to completely ignore this entity (may not be in sight when this is called)
};
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
class CBossAlpha : public NextBotCombatCharacter
{
public:
DECLARE_CLASS( CBossAlpha, NextBotCombatCharacter );
DECLARE_SERVERCLASS();
DECLARE_DATADESC();
CBossAlpha();
virtual ~CBossAlpha();
virtual void Precache();
virtual void Spawn( void );
virtual int OnTakeDamage_Alive( const CTakeDamageInfo &info );
// INextBot
virtual CBossAlphaIntention *GetIntentionInterface( void ) const { return m_intention; }
virtual CBossAlphaLocomotion *GetLocomotionInterface( void ) const { return m_locomotor; }
virtual CBotNPCBody *GetBodyInterface( void ) const { return m_body; }
virtual CBossAlphaVision *GetVisionInterface( void ) const { return m_vision; }
virtual bool IsRemovedOnReset( void ) const { return false; } // remove this bot when the NextBot manager calls Reset
virtual void Update( void );
// virtual bool IsPotentiallyChaseable( CTFPlayer *victim );
void Break( void ); // bust into gibs
struct AttackerInfo
{
CHandle< CBaseCombatCharacter > m_attacker;
float m_timestamp;
float m_damage;
bool m_wasCritical;
};
const CUtlVector< AttackerInfo > &GetAttackerVector( void ) const;
void RememberAttacker( CBaseCombatCharacter *attacker, float damage, bool wasCritical );
struct ThreatInfo
{
CHandle< CBaseCombatCharacter > m_who;
float m_threat;
};
const ThreatInfo *GetMaxThreat( void ) const;
const ThreatInfo *GetThreat( CBaseCombatCharacter *who ) const;
void SwingAxe( void );
void UpdateAxeSwing( void );
bool IsSwingingAxe( void ) const;
//----------------------------------
enum Ability
{
CAN_BE_STUNNED = 0x01,
CAN_NUKE = 0x02,
CAN_ENRAGE = 0x04,
CAN_FIRE_ROCKETS = 0x08,
CAN_LAUNCH_STICKIES = 0x10,
CAN_LAUNCH_MINIONS = 0x20,
};
virtual bool HasAbility( Ability ability ) const;
virtual bool IsMiniBoss( void ) const { return false; }
virtual float GetMoveSpeed( void ) const { return 300.0f; }
virtual int GetRocketLaunchCount( void ) const { return 5; }
virtual float GetRocketDamage( void ) const { return 25.0f; }
virtual float GetRocketAimError( void ) const { return 1.81f; }
virtual float GetRocketInterval( void ) const { return 0.3f; }
virtual const char *GetRocketSoundEffect( void ) const { return "Weapon_RPG.Single"; }
virtual float GetGrenadeInterval( void ) const { return 10.0f; }
virtual float GetBecomeStunnedDamage( void ) const { return 500.0f; }
//----------------------------------
enum Condition
{
SHIELDED = 0x01,
CHARGING = 0x02,
STUNNED = 0x04,
INVULNERABLE = 0x08,
VULNERABLE_TO_STUN = 0x10,
BUSY = 0x20,
ENRAGED = 0x40,
};
bool IsBusy( void ) const; // returns true if we're in a condition that means we can't start another action
void AddCondition( Condition c );
void RemoveCondition( Condition c );
bool IsInCondition( Condition c ) const;
bool IsAttackTarget( CBaseCombatCharacter *target ) const;
bool HasAttackTarget( void ) const;
void SetAttackTarget( CBaseCombatCharacter *target, float duration = 0.0f );
CBaseCombatCharacter *GetAttackTarget( void ) const;
void LockAttackTarget( void ); // don't allow target to change until it is unlocked or the target is destroyed
void UnlockAttackTarget( void );
CBaseCombatCharacter *GetNearestVisibleEnemy( void ) const;
void SetHomePosition( const Vector &pos );
const Vector &GetHomePosition( void ) const;
CBaseAnimating *GetWeapon( void ) const;
CBaseAnimating *GetShield( void ) const;
CountdownTimer *GetNukeTimer( void );
CountdownTimer *GetGrenadeTimer( void );
float GetReceivedDamagePerSecond( void ) const;
float GetReceivedDamagePerSecondDelta( void ) const;
void ClearStunDamage( void );
void AccumulateStunDamage( float damage );
float GetStunDamage( void ) const;
CTFPlayer *GetClosestMinionPrisoner( void );
bool IsPrisonerOfMinion( CBaseCombatCharacter *victim );
void StartNukeEffect( void );
void StopNukeEffect( void );
float GetAge( void ) const; // how long have we been alive
void CollectPlayersStandingOnMe( CUtlVector< CTFPlayer * > *playerVector );
// Entity I/O
COutputEvent m_outputOnStunned;
COutputEvent m_outputOnHealthBelow90Percent;
COutputEvent m_outputOnHealthBelow80Percent;
COutputEvent m_outputOnHealthBelow70Percent;
COutputEvent m_outputOnHealthBelow60Percent;
COutputEvent m_outputOnHealthBelow50Percent;
COutputEvent m_outputOnHealthBelow40Percent;
COutputEvent m_outputOnHealthBelow30Percent;
COutputEvent m_outputOnHealthBelow20Percent;
COutputEvent m_outputOnHealthBelow10Percent;
COutputEvent m_outputOnKilled;
protected:
virtual void TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr, CDmgAccumulator *pAccumulator );
private:
CBossAlphaIntention *m_intention;
CBossAlphaLocomotion *m_locomotor;
CBotNPCBody *m_body;
CBossAlphaVision *m_vision;
CBaseAnimating *m_axe;
CBaseAnimating *m_shield;
CountdownTimer m_axeSwingTimer;
CountdownTimer m_attackTimer;
CountdownTimer m_nukeTimer;
CountdownTimer m_grenadeTimer;
CountdownTimer m_ouchTimer;
CountdownTimer m_hateTauntTimer;
CNetworkVar( bool, m_isNuking );
CHandle< CBaseCombatCharacter > m_nearestVisibleEnemy;
void UpdateNearestVisibleEnemy( void );
CountdownTimer m_nearestVisibleEnemyTimer;
CUtlVector< AttackerInfo > m_attackerVector; // list of everyone who injured me, and when
CUtlVector< ThreatInfo > m_threatVector; // list of attackers and their current damage/second on me
float m_currentDamagePerSecond;
float m_lastDamagePerSecond;
void UpdateDamagePerSecond( void );
CHandle< CBaseCombatCharacter > m_attackTarget;
CountdownTimer m_attackTargetTimer;
bool m_isAttackTargetLocked;
void UpdateAttackTarget( void );
int m_damagePoseParameter;
bool m_isShielded;
Vector m_homePos;
bool IsIgnored( CTFPlayer *player ) const;
unsigned int m_conditionFlags;
float m_stunDamage;
float m_lastHealthPercentage;
IntervalTimer m_ageTimer;
void UpdateSkillShots( void );
bool CheckSkillShots( const CTakeDamageInfo &info );
CountdownTimer m_headStunTimer;
CountdownTimer m_consecutiveRocketTimer;
int m_consecutiveRockets;
CountdownTimer m_ricochetSoundTimer;
void ResetSkillShots( void );
void OnSkillShotComboStarted( void );
void OnSkillShot( void );
CountdownTimer m_skillShotComboTimer;
int m_skillShotCount;
bool m_isPrecisionShotDone;
CountdownTimer m_precisionSkillShotTimer;
bool m_isPrecisionShotHit[3];
bool m_isDamageSpongeSkillShotDone;
float m_damageSpongeSkillShotAmount;
bool m_isHardHitSkillShotDone;
trace_t m_lastTraceAttackTrace;
Vector m_lastTraceAttackDir;
};
inline bool CBossAlpha::HasAbility( Ability ability ) const
{
const int myAbilities = CAN_BE_STUNNED | CAN_NUKE | CAN_ENRAGE | CAN_FIRE_ROCKETS | CAN_LAUNCH_STICKIES | CAN_LAUNCH_MINIONS;
return myAbilities & ability ? true : false;
}
inline bool CBossAlpha::IsAttackTarget( CBaseCombatCharacter *target ) const
{
if ( HasAttackTarget() )
{
return ( m_attackTarget == target ) ? true : false;
}
return false;
}
inline bool CBossAlpha::HasAttackTarget( void ) const
{
return ( m_attackTarget == NULL || !m_attackTarget->IsAlive() ) ? false : true;
}
inline void CBossAlpha::LockAttackTarget( void )
{
m_isAttackTargetLocked = HasAttackTarget();
}
inline void CBossAlpha::UnlockAttackTarget( void )
{
m_isAttackTargetLocked = false;
}
inline float CBossAlpha::GetAge( void ) const
{
return m_ageTimer.GetElapsedTime();
}
inline void CBossAlpha::StartNukeEffect( void )
{
m_isNuking = true;
}
inline void CBossAlpha::StopNukeEffect( void )
{
m_isNuking = false;
}
inline void CBossAlpha::ClearStunDamage( void )
{
m_stunDamage = 0.0f;
}
inline void CBossAlpha::AccumulateStunDamage( float damage )
{
m_stunDamage += damage;
}
inline float CBossAlpha::GetStunDamage( void ) const
{
return m_stunDamage;
}
inline float CBossAlpha::GetReceivedDamagePerSecond( void ) const
{
return m_currentDamagePerSecond;
}
inline float CBossAlpha::GetReceivedDamagePerSecondDelta( void ) const
{
return m_currentDamagePerSecond - m_lastDamagePerSecond;
}
inline CountdownTimer *CBossAlpha::GetNukeTimer( void )
{
return &m_nukeTimer;
}
inline CountdownTimer *CBossAlpha::GetGrenadeTimer( void )
{
return &m_grenadeTimer;
}
inline CBaseAnimating *CBossAlpha::GetWeapon( void ) const
{
return m_axe;
}
inline CBaseAnimating *CBossAlpha::GetShield( void ) const
{
return m_shield;
}
inline void CBossAlpha::SetHomePosition( const Vector &pos )
{
m_homePos = pos;
}
inline const Vector &CBossAlpha::GetHomePosition( void ) const
{
return m_homePos;
}
inline CBaseCombatCharacter *CBossAlpha::GetNearestVisibleEnemy( void ) const
{
return m_nearestVisibleEnemy;
}
inline void CBossAlpha::AddCondition( Condition c )
{
m_conditionFlags |= c;
}
inline bool CBossAlpha::IsInCondition( Condition c ) const
{
return ( m_conditionFlags & c ) ? true : false;
}
inline const CUtlVector< CBossAlpha::AttackerInfo > &CBossAlpha::GetAttackerVector( void ) const
{
return m_attackerVector;
}
//--------------------------------------------------------------------------------------------------------------
class CBossAlphaPathCost : public IPathCost
{
public:
CBossAlphaPathCost( CBossAlpha *me )
{
m_me = me;
}
// return the cost (weighted distance between) of moving from "fromArea" to "area", or -1 if the move is not allowed
virtual float operator()( CNavArea *area, CNavArea *fromArea, const CNavLadder *ladder, const CFuncElevator *elevator, float length ) const
{
if ( fromArea == NULL )
{
// first area in path, no cost
return 0.0f;
}
else
{
if ( !m_me->GetLocomotionInterface()->IsAreaTraversable( area ) )
{
// our locomotor says we can't move here
return -1.0f;
}
// compute distance traveled along path so far
float dist;
if ( ladder )
{
dist = ladder->m_length;
}
else if ( length > 0.0 )
{
// optimization to avoid recomputing length
dist = length;
}
else
{
dist = ( area->GetCenter() - fromArea->GetCenter() ).Length();
}
float cost = dist + fromArea->GetCostSoFar();
// check height change
float deltaZ = fromArea->ComputeAdjacentConnectionHeightChange( area );
if ( deltaZ >= m_me->GetLocomotionInterface()->GetStepHeight() )
{
if ( deltaZ >= m_me->GetLocomotionInterface()->GetMaxJumpHeight() )
{
// too high to reach
return -1.0f;
}
// jumping is slower than flat ground
const float jumpPenalty = 5.0f;
cost += jumpPenalty * dist;
}
else if ( deltaZ < -m_me->GetLocomotionInterface()->GetDeathDropHeight() )
{
// too far to drop
return -1.0f;
}
return cost;
}
}
CBossAlpha *m_me;
};
#endif // TF_RAID_MODE
#endif // BOSS_ALPHA_H