You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
509 lines
13 KiB
509 lines
13 KiB
4 years ago
|
//========= 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
|