Team Fortress 2 Source Code as on 22/4/2020
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.
 
 
 
 
 
 

541 lines
13 KiB

//========= Copyright Valve Corporation, All rights reserved. ============//
// bot_npc.h
// A NextBot non-player derived actor
// Michael Booth, November 2010
#ifndef BOT_NPC_H
#define BOT_NPC_H
#ifdef OBSOLETE_USE_BOSS_ALPHA
#include "NextBot.h"
#include "NextBotBehavior.h"
#include "NextBotGroundLocomotion.h"
#include "Path/NextBotPathFollow.h"
#include "bot_npc_body.h"
#include "bot/map_entities/tf_spawner_boss.h"
class CTFPlayer;
class CBotNPC;
//----------------------------------------------------------------------------
class CBotNPCLocomotion : public NextBotGroundLocomotion
{
public:
CBotNPCLocomotion( INextBot *bot );
virtual ~CBotNPCLocomotion() { }
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;
}
private:
float m_runSpeed;
};
//----------------------------------------------------------------------------
class CBotNPCIntention : public IIntention
{
public:
CBotNPCIntention( CBotNPC *me );
virtual ~CBotNPCIntention();
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< CBotNPC > *m_behavior;
};
//----------------------------------------------------------------------------
class CBotNPCVision : public IVision
{
public:
CBotNPCVision( INextBot *bot ) : IVision( bot )
{
}
virtual ~CBotNPCVision() { }
virtual bool IsIgnored( CBaseEntity *subject ) const; // return true to completely ignore this entity (may not be in sight when this is called)
};
//----------------------------------------------------------------------------
class CBotNPCWeapon : public CBaseAnimating
{
public:
CBotNPCWeapon( CBotNPC *owner )
{
m_owner = owner;
}
virtual ~CBotNPCWeapon() { }
virtual void StartAttack( void ) { }
virtual void Update( void ) { }
private:
CHandle< CBotNPC > m_owner;
};
//----------------------------------------------------------------------------
class CBotNPCWeapon_Axe : public CBotNPCWeapon
{
public:
DECLARE_CLASS( CBotNPCWeapon_Axe, CBotNPCWeapon );
CBotNPCWeapon_Axe( CBotNPC *owner );
virtual ~CBotNPCWeapon_Axe() { }
virtual void StartAttack( void );
virtual void Update( void );
};
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
class CBotNPCGetOffMe : public Action< CBotNPC >
{
public:
virtual ActionResult< CBotNPC > OnStart( CBotNPC *me, Action< CBotNPC > *priorAction );
virtual ActionResult< CBotNPC > Update( CBotNPC *me, float interval );
virtual void OnEnd( CBotNPC *me, Action< CBotNPC > *nextAction );
virtual const char *GetName( void ) const { return "GetOffMe"; } // return name of this action
private:
CountdownTimer m_timer;
};
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
class CBotNPC : public NextBotCombatCharacter
{
public:
DECLARE_CLASS( CBotNPC, NextBotCombatCharacter );
DECLARE_SERVERCLASS();
CBotNPC();
virtual ~CBotNPC();
virtual void Precache();
virtual void Spawn( void );
virtual int OnTakeDamage_Alive( const CTakeDamageInfo &info );
// INextBot
virtual CBotNPCIntention *GetIntentionInterface( void ) const { return m_intention; }
virtual CBotNPCLocomotion *GetLocomotionInterface( void ) const { return m_locomotor; }
virtual CBotNPCBody *GetBodyInterface( void ) const { return m_body; }
virtual CBotNPCVision *GetVisionInterface( void ) const { return m_vision; }
virtual void Update( void );
virtual bool IsPotentiallyChaseable( CTFPlayer *victim );
void SetSpawner( CTFSpawnerBoss *spawner ); // remember the spawner that created us
CTFSpawnerBoss *GetSpawner( void ) const; // return the spawner that created us
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 SetLaserTarget( CBaseEntity *target );
CBaseEntity *GetLaserTarget( 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
void InputSpawn( inputdata_t &inputdata );
COutputEvent m_outputOnStunned; // fired the boss becomes stunned
private:
CBotNPCIntention *m_intention;
CBotNPCLocomotion *m_locomotor;
CBotNPCBody *m_body;
CBotNPCVision *m_vision;
CHandle< CTFSpawnerBoss > m_spawner;
CBaseAnimating *m_axe;
CBaseAnimating *m_shield;
void PrecacheArmorParts( void );
void InstallArmorParts( void );
CUtlVector< CBaseAnimating * > m_armorPartVector;
CountdownTimer m_axeSwingTimer;
CountdownTimer m_attackTimer;
CountdownTimer m_nukeTimer;
CountdownTimer m_grenadeTimer;
CountdownTimer m_ouchTimer;
CountdownTimer m_hateTauntTimer;
CNetworkHandle( CBaseEntity, m_laserTarget );
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;
IntervalTimer m_ageTimer;
};
inline bool CBotNPC::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 void CBotNPC::SetSpawner( CTFSpawnerBoss *spawner )
{
m_spawner = spawner;
}
inline CTFSpawnerBoss *CBotNPC::GetSpawner( void ) const
{
return m_spawner;
}
inline bool CBotNPC::IsAttackTarget( CBaseCombatCharacter *target ) const
{
if ( HasAttackTarget() )
{
return ( m_attackTarget == target ) ? true : false;
}
return false;
}
inline bool CBotNPC::HasAttackTarget( void ) const
{
return ( m_attackTarget == NULL || !m_attackTarget->IsAlive() ) ? false : true;
}
inline void CBotNPC::LockAttackTarget( void )
{
m_isAttackTargetLocked = HasAttackTarget();
}
inline void CBotNPC::UnlockAttackTarget( void )
{
m_isAttackTargetLocked = false;
}
inline float CBotNPC::GetAge( void ) const
{
return m_ageTimer.GetElapsedTime();
}
inline void CBotNPC::StartNukeEffect( void )
{
m_isNuking = true;
}
inline void CBotNPC::StopNukeEffect( void )
{
m_isNuking = false;
}
inline void CBotNPC::ClearStunDamage( void )
{
m_stunDamage = 0.0f;
}
inline void CBotNPC::AccumulateStunDamage( float damage )
{
m_stunDamage += damage;
}
inline float CBotNPC::GetStunDamage( void ) const
{
return m_stunDamage;
}
inline void CBotNPC::SetLaserTarget( CBaseEntity *target )
{
m_laserTarget = target;
}
inline CBaseEntity *CBotNPC::GetLaserTarget( void ) const
{
return m_laserTarget;
}
inline float CBotNPC::GetReceivedDamagePerSecond( void ) const
{
return m_currentDamagePerSecond;
}
inline float CBotNPC::GetReceivedDamagePerSecondDelta( void ) const
{
return m_currentDamagePerSecond - m_lastDamagePerSecond;
}
inline CountdownTimer *CBotNPC::GetNukeTimer( void )
{
return &m_nukeTimer;
}
inline CountdownTimer *CBotNPC::GetGrenadeTimer( void )
{
return &m_grenadeTimer;
}
inline CBaseAnimating *CBotNPC::GetWeapon( void ) const
{
return m_axe;
}
inline CBaseAnimating *CBotNPC::GetShield( void ) const
{
return m_shield;
}
inline void CBotNPC::SetHomePosition( const Vector &pos )
{
m_homePos = pos;
}
inline const Vector &CBotNPC::GetHomePosition( void ) const
{
return m_homePos;
}
inline CBaseCombatCharacter *CBotNPC::GetNearestVisibleEnemy( void ) const
{
return m_nearestVisibleEnemy;
}
inline void CBotNPC::AddCondition( Condition c )
{
m_conditionFlags |= c;
}
inline bool CBotNPC::IsInCondition( Condition c ) const
{
return ( m_conditionFlags & c ) ? true : false;
}
inline const CUtlVector< CBotNPC::AttackerInfo > &CBotNPC::GetAttackerVector( void ) const
{
return m_attackerVector;
}
//--------------------------------------------------------------------------------------------------------------
class CBotNPCPathCost : public IPathCost
{
public:
CBotNPCPathCost( CBotNPC *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;
}
}
CBotNPC *m_me;
};
#endif // #ifdef OBSOLETE_USE_BOSS_ALPHA
#endif // BOT_NPC_H