mirror of
https://github.com/nillerusr/source-engine.git
synced 2026-08-13 20:21:06 +00:00
1
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,541 @@
|
||||
//========= 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
|
||||
@@ -0,0 +1,402 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
// bot_npc_archer.cpp
|
||||
// A NextBot non-player derived archer
|
||||
// Michael Booth, November 2010
|
||||
|
||||
#include "cbase.h"
|
||||
|
||||
#include "tf_player.h"
|
||||
#include "tf_gamerules.h"
|
||||
#include "tf_team.h"
|
||||
#include "tf_projectile_arrow.h"
|
||||
#include "tf_weapon_grenade_pipebomb.h"
|
||||
#include "nav_mesh/tf_nav_area.h"
|
||||
#include "bot_npc_archer.h"
|
||||
#include "NextBot/Path/NextBotChasePath.h"
|
||||
#include "econ_wearable.h"
|
||||
#include "team_control_point_master.h"
|
||||
#include "particle_parse.h"
|
||||
#include "CRagdollMagnet.h"
|
||||
#include "NextBot/Behavior/BehaviorMoveTo.h"
|
||||
|
||||
ConVar tf_bot_npc_archer_health( "tf_bot_npc_archer_health", "100", FCVAR_CHEAT );
|
||||
|
||||
ConVar tf_bot_npc_archer_speed( "tf_bot_npc_archer_speed", "100", FCVAR_CHEAT );
|
||||
|
||||
ConVar tf_bot_npc_archer_shoot_interval( "tf_bot_npc_archer_shoot_interval", "2", FCVAR_CHEAT ); // 2
|
||||
ConVar tf_bot_npc_archer_arrow_damage( "tf_bot_npc_archer_arrow_damage", "75", FCVAR_CHEAT );
|
||||
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
// The Bot NPC
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
LINK_ENTITY_TO_CLASS( bot_npc_archer, CBotNPCArcher );
|
||||
|
||||
PRECACHE_REGISTER( bot_npc_archer );
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
CBotNPCArcher::CBotNPCArcher()
|
||||
{
|
||||
ALLOCATE_INTENTION_INTERFACE( CBotNPCArcher );
|
||||
|
||||
m_locomotor = new NextBotGroundLocomotion( this );
|
||||
m_body = new CBotNPCBody( this );
|
||||
|
||||
m_eyeOffset = vec3_origin;
|
||||
m_homePos = vec3_origin;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
CBotNPCArcher::~CBotNPCArcher()
|
||||
{
|
||||
DEALLOCATE_INTENTION_INTERFACE;
|
||||
|
||||
if ( m_locomotor )
|
||||
delete m_locomotor;
|
||||
|
||||
if ( m_body )
|
||||
delete m_body;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
void CBotNPCArcher::Precache()
|
||||
{
|
||||
BaseClass::Precache();
|
||||
|
||||
PrecacheModel( "models/player/sniper.mdl" );
|
||||
PrecacheModel( "models/weapons/c_models/c_bow/c_bow.mdl" );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
void CBotNPCArcher::Spawn( void )
|
||||
{
|
||||
BaseClass::Spawn();
|
||||
|
||||
SetModel( "models/player/sniper.mdl" );
|
||||
|
||||
m_bow = (CBaseAnimating *)CreateEntityByName( "prop_dynamic" );
|
||||
if ( m_bow )
|
||||
{
|
||||
m_bow->SetModel( "models/weapons/c_models/c_bow/c_bow.mdl" );
|
||||
|
||||
// bonemerge into our model
|
||||
m_bow->FollowEntity( this, true );
|
||||
}
|
||||
|
||||
int health = tf_bot_npc_archer_health.GetInt();
|
||||
SetHealth( health );
|
||||
SetMaxHealth( health );
|
||||
|
||||
ChangeTeam( TF_TEAM_RED );
|
||||
|
||||
Vector headPos;
|
||||
QAngle headAngles;
|
||||
if ( GetAttachment( "head", headPos, headAngles ) )
|
||||
{
|
||||
m_eyeOffset = headPos - GetAbsOrigin();
|
||||
}
|
||||
|
||||
m_homePos = GetAbsOrigin();
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------------------------
|
||||
unsigned int CBotNPCArcher::PhysicsSolidMaskForEntity( void ) const
|
||||
{
|
||||
// Only collide with the other team
|
||||
int teamContents = ( GetTeamNumber() == TF_TEAM_RED ) ? CONTENTS_BLUETEAM : CONTENTS_REDTEAM;
|
||||
|
||||
return BaseClass::PhysicsSolidMaskForEntity() | teamContents;
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------------------------
|
||||
bool CBotNPCArcher::ShouldCollide( int collisionGroup, int contentsMask ) const
|
||||
{
|
||||
if ( collisionGroup == COLLISION_GROUP_PLAYER_MOVEMENT )
|
||||
{
|
||||
switch( GetTeamNumber() )
|
||||
{
|
||||
case TF_TEAM_RED:
|
||||
if ( !( contentsMask & CONTENTS_REDTEAM ) )
|
||||
return false;
|
||||
break;
|
||||
|
||||
case TF_TEAM_BLUE:
|
||||
if ( !( contentsMask & CONTENTS_BLUETEAM ) )
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return BaseClass::ShouldCollide( collisionGroup, contentsMask );
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------------------------
|
||||
//---------------------------------------------------------------------------------------------
|
||||
class CBotNPCArcherSurrender : public Action< CBotNPCArcher >
|
||||
{
|
||||
public:
|
||||
virtual ActionResult< CBotNPCArcher > OnStart( CBotNPCArcher *me, Action< CBotNPCArcher > *priorAction );
|
||||
virtual const char *GetName( void ) const { return "Surrender"; } // return name of this action
|
||||
};
|
||||
|
||||
|
||||
inline ActionResult< CBotNPCArcher > CBotNPCArcherSurrender::OnStart( CBotNPCArcher *me, Action< CBotNPCArcher > *priorAction )
|
||||
{
|
||||
CBaseAnimating *bow = me->GetBow();
|
||||
if ( bow )
|
||||
{
|
||||
bow->AddEffects( EF_NODRAW );
|
||||
}
|
||||
|
||||
me->GetBodyInterface()->StartActivity( ACT_MP_STAND_LOSERSTATE );
|
||||
|
||||
return Continue();
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------------------------
|
||||
//---------------------------------------------------------------------------------------------
|
||||
class CBotNPCArcherShootBow : public Action< CBotNPCArcher >
|
||||
{
|
||||
public:
|
||||
CBotNPCArcherShootBow( CTFPlayer *target )
|
||||
{
|
||||
m_target = target;
|
||||
}
|
||||
|
||||
virtual ActionResult< CBotNPCArcher > OnStart( CBotNPCArcher *me, Action< CBotNPCArcher > *priorAction );
|
||||
virtual ActionResult< CBotNPCArcher > Update( CBotNPCArcher *me, float interval );
|
||||
|
||||
virtual const char *GetName( void ) const { return "ShootBow"; } // return name of this action
|
||||
|
||||
private:
|
||||
CHandle< CTFPlayer > m_target;
|
||||
};
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------------------------
|
||||
ActionResult< CBotNPCArcher > CBotNPCArcherShootBow::OnStart( CBotNPCArcher *me, Action< CBotNPCArcher > *priorAction )
|
||||
{
|
||||
if ( !m_target )
|
||||
{
|
||||
return Done( "No target" );
|
||||
}
|
||||
|
||||
me->GetLocomotionInterface()->FaceTowards( m_target->WorldSpaceCenter() );
|
||||
me->AddGesture( ACT_MP_ATTACK_STAND_ITEM2 );
|
||||
|
||||
// fire arrow
|
||||
const float arrowSpeed = 2000.0f;
|
||||
const float arrowGravity = 0.2f;
|
||||
|
||||
Vector muzzleOrigin;
|
||||
QAngle muzzleAngles;
|
||||
if ( me->GetBow()->GetAttachment( "muzzle", muzzleOrigin, muzzleAngles ) == false )
|
||||
{
|
||||
return Done( "No muzzle attachment!" );
|
||||
}
|
||||
|
||||
// lead target
|
||||
float range = me->GetRangeTo( m_target->EyePosition() );
|
||||
float flightTime = range / arrowSpeed;
|
||||
|
||||
Vector aimSpot = m_target->EyePosition() + m_target->GetAbsVelocity() * flightTime;
|
||||
|
||||
Vector to = aimSpot - muzzleOrigin;
|
||||
VectorAngles( to, muzzleAngles );
|
||||
|
||||
CTFProjectile_Arrow *arrow = CTFProjectile_Arrow::Create( muzzleOrigin, muzzleAngles, arrowSpeed, arrowGravity, TF_PROJECTILE_ARROW, me, me );
|
||||
if ( arrow )
|
||||
{
|
||||
arrow->SetLauncher( me );
|
||||
arrow->SetCritical( false );
|
||||
|
||||
arrow->SetDamage( tf_bot_npc_archer_arrow_damage.GetFloat() );
|
||||
|
||||
me->EmitSound( "Weapon_CompoundBow.Single" );
|
||||
}
|
||||
|
||||
return Continue();
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------------------------
|
||||
ActionResult< CBotNPCArcher > CBotNPCArcherShootBow::Update( CBotNPCArcher *me, float interval )
|
||||
{
|
||||
if ( me->IsSequenceFinished() )
|
||||
{
|
||||
return Done();
|
||||
}
|
||||
|
||||
return Continue();
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------------------------
|
||||
//---------------------------------------------------------------------------------------------
|
||||
class CBotNPCArcherGuardSpot : public Action< CBotNPCArcher >
|
||||
{
|
||||
public:
|
||||
virtual ActionResult< CBotNPCArcher > OnStart( CBotNPCArcher *me, Action< CBotNPCArcher > *priorAction )
|
||||
{
|
||||
me->GetBodyInterface()->StartActivity( ACT_MP_STAND_ITEM2 );
|
||||
|
||||
return Continue();
|
||||
}
|
||||
|
||||
CTFPlayer *GetVictim( CBotNPCArcher *me )
|
||||
{
|
||||
CUtlVector< CTFPlayer * > playerVector;
|
||||
CollectPlayers( &playerVector, TF_TEAM_BLUE, COLLECT_ONLY_LIVING_PLAYERS );
|
||||
|
||||
CTFPlayer *closeVictim = NULL;
|
||||
float victimRangeSq = FLT_MAX;
|
||||
|
||||
for( int i=0; i<playerVector.Count(); ++i )
|
||||
{
|
||||
float rangeSq = me->GetRangeSquaredTo( playerVector[i] );
|
||||
if ( rangeSq < victimRangeSq )
|
||||
{
|
||||
if ( playerVector[i]->m_Shared.IsStealthed() )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( me->IsLineOfSightClear( playerVector[i] ) )
|
||||
{
|
||||
closeVictim = playerVector[i];
|
||||
victimRangeSq = rangeSq;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return closeVictim;
|
||||
}
|
||||
|
||||
virtual ActionResult< CBotNPCArcher > Update( CBotNPCArcher *me, float interval )
|
||||
{
|
||||
if ( TFGameRules()->GetActiveBoss() == NULL )
|
||||
{
|
||||
// the Boss has been defeated - give up
|
||||
return ChangeTo( new CBotNPCArcherSurrender, "The Boss is dead! I give up!" );
|
||||
}
|
||||
|
||||
CTFPlayer *victim = GetVictim( me );
|
||||
|
||||
if ( victim )
|
||||
{
|
||||
// look at visible victim out of range
|
||||
me->GetLocomotionInterface()->FaceTowards( victim->WorldSpaceCenter() );
|
||||
|
||||
if ( m_shootTimer.IsElapsed() )
|
||||
{
|
||||
m_shootTimer.Start( tf_bot_npc_archer_shoot_interval.GetFloat() );
|
||||
|
||||
return SuspendFor( new CBotNPCArcherShootBow( victim ), "Fire!" );
|
||||
}
|
||||
}
|
||||
|
||||
if ( me->GetLocomotionInterface()->IsAttemptingToMove() )
|
||||
{
|
||||
// play running animation
|
||||
if ( !me->GetBodyInterface()->IsActivity( ACT_MP_DEPLOYED_IDLE_ITEM2 ) )
|
||||
{
|
||||
me->GetBodyInterface()->StartActivity( ACT_MP_DEPLOYED_IDLE_ITEM2 );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// standing still
|
||||
if ( !me->GetBodyInterface()->IsActivity( ACT_MP_STAND_ITEM2 ) )
|
||||
{
|
||||
me->GetBodyInterface()->StartActivity( ACT_MP_STAND_ITEM2 );
|
||||
}
|
||||
}
|
||||
|
||||
return Continue();
|
||||
}
|
||||
|
||||
virtual const char *GetName( void ) const { return "GuardSpot"; } // return name of this action
|
||||
|
||||
private:
|
||||
CountdownTimer m_shootTimer;
|
||||
};
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------------------------
|
||||
//---------------------------------------------------------------------------------------------
|
||||
class CBotNPCArcherMoveToMark : public Action< CBotNPCArcher >
|
||||
{
|
||||
public:
|
||||
virtual ActionResult< CBotNPCArcher > OnStart( CBotNPCArcher *me, Action< CBotNPCArcher > *priorAction )
|
||||
{
|
||||
ShortestPathCost cost;
|
||||
m_path.Compute( me, me->GetHomePosition(), cost );
|
||||
|
||||
me->GetBodyInterface()->StartActivity( ACT_MP_RUN_ITEM2 );
|
||||
|
||||
return Continue();
|
||||
}
|
||||
|
||||
virtual ActionResult< CBotNPCArcher > Update( CBotNPCArcher *me, float interval )
|
||||
{
|
||||
m_path.Update( me );
|
||||
|
||||
if ( !m_path.IsValid() )
|
||||
{
|
||||
return ChangeTo( new CBotNPCArcherGuardSpot, "Reached my mark" );
|
||||
}
|
||||
|
||||
return Continue();
|
||||
}
|
||||
|
||||
virtual const char *GetName( void ) const { return "MoveToMark"; } // return name of this action
|
||||
|
||||
private:
|
||||
PathFollower m_path;
|
||||
};
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------------------------
|
||||
//---------------------------------------------------------------------------------------------
|
||||
class CBotNPCArcherBehavior : public Action< CBotNPCArcher >
|
||||
{
|
||||
public:
|
||||
virtual Action< CBotNPCArcher > *InitialContainedAction( CBotNPCArcher *me )
|
||||
{
|
||||
return new CBotNPCArcherMoveToMark;
|
||||
}
|
||||
|
||||
virtual ActionResult< CBotNPCArcher > Update( CBotNPCArcher *me, float interval )
|
||||
{
|
||||
return Continue();
|
||||
}
|
||||
|
||||
virtual EventDesiredResult< CBotNPCArcher > OnKilled( CBotNPCArcher *me, const CTakeDamageInfo &info )
|
||||
{
|
||||
// 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 );
|
||||
}
|
||||
|
||||
me->BecomeRagdoll( info, forceVector );
|
||||
|
||||
return TryDone();
|
||||
}
|
||||
|
||||
virtual const char *GetName( void ) const { return "Behavior"; } // return name of this action
|
||||
};
|
||||
|
||||
|
||||
IMPLEMENT_INTENTION_INTERFACE( CBotNPCArcher, CBotNPCArcherBehavior );
|
||||
@@ -0,0 +1,79 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
// bot_npc_archer.h
|
||||
// A NextBot non-player derived archer
|
||||
// Michael Booth, November 2010
|
||||
|
||||
#ifndef BOT_NPC_ARCHER_H
|
||||
#define BOT_NPC_ARCHER_H
|
||||
|
||||
#include "NextBot.h"
|
||||
#include "NextBotBehavior.h"
|
||||
#include "NextBotGroundLocomotion.h"
|
||||
#include "Path/NextBotPathFollow.h"
|
||||
#include "bot_npc.h"
|
||||
#include "bot_npc_body.h"
|
||||
|
||||
|
||||
class CTFPlayer;
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
class CBotNPCArcher : public NextBotCombatCharacter
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CBotNPCArcher, NextBotCombatCharacter );
|
||||
|
||||
CBotNPCArcher();
|
||||
virtual ~CBotNPCArcher();
|
||||
|
||||
virtual void Precache();
|
||||
virtual void Spawn( void );
|
||||
|
||||
// INextBot
|
||||
DECLARE_INTENTION_INTERFACE( CBotNPCArcher );
|
||||
virtual NextBotGroundLocomotion *GetLocomotionInterface( void ) const { return m_locomotor; }
|
||||
virtual CBotNPCBody *GetBodyInterface( void ) const { return m_body; }
|
||||
|
||||
virtual Vector EyePosition( void );
|
||||
|
||||
virtual unsigned int PhysicsSolidMaskForEntity( void ) const;
|
||||
virtual bool ShouldCollide( int collisionGroup, int contentsMask ) const;
|
||||
|
||||
CBaseAnimating *GetBow( void ) const;
|
||||
|
||||
void SetHomePosition( const Vector &pos );
|
||||
const Vector &GetHomePosition( void ) const;
|
||||
|
||||
private:
|
||||
NextBotGroundLocomotion *m_locomotor;
|
||||
CBotNPCBody *m_body;
|
||||
|
||||
CBaseAnimating *m_bow;
|
||||
Vector m_eyeOffset;
|
||||
|
||||
Vector m_homePos;
|
||||
};
|
||||
|
||||
|
||||
inline void CBotNPCArcher::SetHomePosition( const Vector &pos )
|
||||
{
|
||||
m_homePos = pos;
|
||||
}
|
||||
|
||||
inline const Vector &CBotNPCArcher::GetHomePosition( void ) const
|
||||
{
|
||||
return m_homePos;
|
||||
}
|
||||
|
||||
inline Vector CBotNPCArcher::EyePosition( void )
|
||||
{
|
||||
return GetAbsOrigin() + m_eyeOffset;
|
||||
}
|
||||
|
||||
|
||||
inline CBaseAnimating *CBotNPCArcher::GetBow( void ) const
|
||||
{
|
||||
return m_bow;
|
||||
}
|
||||
|
||||
#endif // BOT_NPC_ARCHER_H
|
||||
@@ -0,0 +1,153 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
#include "cbase.h"
|
||||
|
||||
#include "NextBot.h"
|
||||
//#include "bot_npc.h"
|
||||
#include "bot_npc_body.h"
|
||||
|
||||
//-------------------------------------------------------------------------------------------
|
||||
CBotNPCBody::CBotNPCBody( INextBot *bot ) : IBody( bot )
|
||||
{
|
||||
m_moveXPoseParameter = -1;
|
||||
m_moveYPoseParameter = -1;
|
||||
m_currentActivity = -1;
|
||||
m_desiredAimAngles = vec3_angle;
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------------------------
|
||||
bool CBotNPCBody::StartActivity( Activity act, unsigned int flags )
|
||||
{
|
||||
NextBotCombatCharacter *me = (NextBotCombatCharacter *)GetBot()->GetEntity();
|
||||
|
||||
int animSequence = ::SelectWeightedSequence( me->GetModelPtr(), act, me->GetSequence() );
|
||||
|
||||
if ( animSequence )
|
||||
{
|
||||
m_currentActivity = act;
|
||||
me->SetSequence( animSequence );
|
||||
me->SetPlaybackRate( 1.0f );
|
||||
me->SetCycle( 0 );
|
||||
me->ResetSequenceInfo();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------------------------
|
||||
void CBotNPCBody::Update( void )
|
||||
{
|
||||
NextBotCombatCharacter *me = (NextBotCombatCharacter *)GetBot()->GetEntity();
|
||||
|
||||
if ( m_moveXPoseParameter < 0 )
|
||||
{
|
||||
m_moveXPoseParameter = me->LookupPoseParameter( "move_x" );
|
||||
}
|
||||
|
||||
if ( m_moveYPoseParameter < 0 )
|
||||
{
|
||||
m_moveYPoseParameter = me->LookupPoseParameter( "move_y" );
|
||||
}
|
||||
|
||||
|
||||
// Update the pose parameters
|
||||
float speed = me->GetLocomotionInterface()->GetGroundSpeed(); // me->GetAbsVelocity().Length();
|
||||
|
||||
if ( speed < 0.01f )
|
||||
{
|
||||
// stopped
|
||||
if ( m_moveXPoseParameter >= 0 )
|
||||
{
|
||||
me->SetPoseParameter( m_moveXPoseParameter, 0.0f );
|
||||
}
|
||||
|
||||
if ( m_moveYPoseParameter >= 0 )
|
||||
{
|
||||
me->SetPoseParameter( m_moveYPoseParameter, 0.0f );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Vector forward, right, up;
|
||||
me->GetVectors( &forward, &right, &up );
|
||||
|
||||
const Vector &motionVector = me->GetLocomotionInterface()->GetGroundMotionVector();
|
||||
|
||||
// move_x == 1.0 at full forward motion and -1.0 in full reverse
|
||||
if ( m_moveXPoseParameter >= 0 )
|
||||
{
|
||||
float forwardVel = DotProduct( motionVector, forward );
|
||||
|
||||
me->SetPoseParameter( m_moveXPoseParameter, forwardVel );
|
||||
}
|
||||
|
||||
if ( m_moveYPoseParameter >= 0 )
|
||||
{
|
||||
float sideVel = DotProduct( motionVector, right );
|
||||
|
||||
me->SetPoseParameter( m_moveYPoseParameter, sideVel );
|
||||
}
|
||||
}
|
||||
|
||||
// adjust animation speed to actual movement speed
|
||||
if ( me->m_flGroundSpeed > 0.0f )
|
||||
{
|
||||
// Clamp playback rate to avoid datatable warnings. Anything faster would look silly, anyway.
|
||||
float playbackRate = clamp( speed / me->m_flGroundSpeed, -4.f, 12.f );
|
||||
me->SetPlaybackRate( playbackRate );
|
||||
}
|
||||
|
||||
// move the animation ahead in time
|
||||
me->StudioFrameAdvance();
|
||||
me->DispatchAnimEvents( me );
|
||||
|
||||
// update aim angles
|
||||
QAngle currentAngles = me->GetAbsAngles();
|
||||
|
||||
QAngle angles;
|
||||
const float approachRate = GetMaxHeadAngularVelocity(); // 3000.0f;
|
||||
angles.y = ApproachAngle( m_desiredAimAngles.y, currentAngles.y, approachRate * TICK_INTERVAL );
|
||||
angles.x = ApproachAngle( m_desiredAimAngles.x, currentAngles.x, 0.5f * approachRate * TICK_INTERVAL );
|
||||
angles.z = 0.0f;
|
||||
|
||||
angles.x = AngleNormalize( angles.x );
|
||||
angles.y = AngleNormalize( angles.y );
|
||||
|
||||
me->SetAbsAngles( angles );
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------------------------
|
||||
// return the bot's collision mask (hack until we get a general hull trace abstraction here or in the locomotion interface)
|
||||
unsigned int CBotNPCBody::GetSolidMask( void ) const
|
||||
{
|
||||
return MASK_NPCSOLID | CONTENTS_PLAYERCLIP;
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------------------------
|
||||
void CBotNPCBody::AimHeadTowards( const Vector &lookAtPos, LookAtPriorityType priority, float duration, INextBotReply *replyWhenAimed, const char *reason )
|
||||
{
|
||||
CBaseCombatCharacter *me = GetBot()->GetEntity();
|
||||
|
||||
Vector toTarget = lookAtPos - me->WorldSpaceCenter();
|
||||
VectorAngles( toTarget, m_desiredAimAngles );
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------------------------
|
||||
void CBotNPCBody::AimHeadTowards( CBaseEntity *subject, LookAtPriorityType priority, float duration, INextBotReply *replyWhenAimed, const char *reason )
|
||||
{
|
||||
if ( !subject )
|
||||
return;
|
||||
|
||||
CBaseCombatCharacter *me = GetBot()->GetEntity();
|
||||
|
||||
Vector toTarget = subject->WorldSpaceCenter() - me->WorldSpaceCenter();
|
||||
|
||||
QAngle angles;
|
||||
VectorAngles( toTarget, m_desiredAimAngles );
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
#ifndef BOT_NPC_BODY_H
|
||||
#define BOT_NPC_BODY_H
|
||||
|
||||
#include "animation.h"
|
||||
#include "NextBotBodyInterface.h"
|
||||
|
||||
class INextBot;
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* The interface for control and information about the bot's body state (posture, animation state, etc)
|
||||
*/
|
||||
class CBotNPCBody : public IBody
|
||||
{
|
||||
public:
|
||||
CBotNPCBody( INextBot *bot );
|
||||
virtual ~CBotNPCBody() { }
|
||||
|
||||
virtual void Update( void );
|
||||
|
||||
virtual bool StartActivity( Activity act, unsigned int flags = 0 );
|
||||
virtual Activity GetActivity( void ) const; // return currently animating activity
|
||||
virtual bool IsActivity( Activity act ) const; // return true if currently animating activity matches the given one
|
||||
|
||||
virtual void AimHeadTowards( const Vector &lookAtPos,
|
||||
LookAtPriorityType priority = BORING,
|
||||
float duration = 0.0f,
|
||||
INextBotReply *replyWhenAimed = NULL,
|
||||
const char *reason = NULL ); // aim the bot's head towards the given goal
|
||||
virtual void AimHeadTowards( CBaseEntity *subject,
|
||||
LookAtPriorityType priority = BORING,
|
||||
float duration = 0.0f,
|
||||
INextBotReply *replyWhenAimed = NULL,
|
||||
const char *reason = NULL ); // continually aim the bot's head towards the given subject
|
||||
|
||||
virtual unsigned int GetSolidMask( void ) const; // return the bot's collision mask (hack until we get a general hull trace abstraction here or in the locomotion interface)
|
||||
virtual unsigned int GetCollisionGroup( void ) const;
|
||||
|
||||
private:
|
||||
int m_currentActivity;
|
||||
int m_moveXPoseParameter;
|
||||
int m_moveYPoseParameter;
|
||||
QAngle m_desiredAimAngles;
|
||||
};
|
||||
|
||||
|
||||
inline Activity CBotNPCBody::GetActivity( void ) const
|
||||
{
|
||||
return (Activity)m_currentActivity;
|
||||
}
|
||||
|
||||
inline bool CBotNPCBody::IsActivity( Activity act ) const
|
||||
{
|
||||
return act == m_currentActivity ? true : false;
|
||||
}
|
||||
|
||||
inline unsigned int CBotNPCBody::GetCollisionGroup( void ) const
|
||||
{
|
||||
return COLLISION_GROUP_PLAYER_MOVEMENT;
|
||||
}
|
||||
|
||||
#endif // BOT_NPC_BODY_H
|
||||
@@ -0,0 +1,246 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
// bot_npc_decoy.cpp
|
||||
// A NextBot non-player decoy that imitates a real player
|
||||
// Michael Booth, January 2011
|
||||
|
||||
#include "cbase.h"
|
||||
#include "tf_player.h"
|
||||
#include "tf_gamerules.h"
|
||||
#include "tf_team.h"
|
||||
#include "nav_mesh/tf_nav_area.h"
|
||||
#include "bot_npc_decoy.h"
|
||||
#include "econ_wearable.h"
|
||||
|
||||
LINK_ENTITY_TO_CLASS( bot_npc_decoy, CBotNPCDecoy );
|
||||
PRECACHE_REGISTER( bot_npc_decoy );
|
||||
|
||||
ConVar tf_decoy_lifetime( "tf_decoy_lifetime", "5", FCVAR_CHEAT, "The lifetime of a decoy, in seconds" );
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
CBotNPCDecoy::CBotNPCDecoy()
|
||||
{
|
||||
ALLOCATE_INTENTION_INTERFACE( CBotNPCDecoy );
|
||||
|
||||
m_locomotor = new CBotNPCDecoyLocomotion( this );
|
||||
m_body = new CBotNPCBody( this );
|
||||
|
||||
m_eyeOffset = vec3_origin;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
CBotNPCDecoy::~CBotNPCDecoy()
|
||||
{
|
||||
DEALLOCATE_INTENTION_INTERFACE;
|
||||
|
||||
if ( m_locomotor )
|
||||
delete m_locomotor;
|
||||
|
||||
if ( m_body )
|
||||
delete m_body;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
void CBotNPCDecoy::Precache()
|
||||
{
|
||||
BaseClass::Precache();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
void CBotNPCDecoy::Spawn( void )
|
||||
{
|
||||
BaseClass::Spawn();
|
||||
|
||||
SetCollisionGroup( COLLISION_GROUP_NONE );
|
||||
SetSolid( SOLID_NONE );
|
||||
AddSolidFlags( FSOLID_NOT_SOLID );
|
||||
|
||||
CTFPlayer *owner = ToTFPlayer( GetOwnerEntity() );
|
||||
if ( !owner )
|
||||
{
|
||||
Warning( "Decoy spawned without an owner\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
int ownerClass = owner->m_Shared.InCond( TF_COND_DISGUISED ) ? owner->m_Shared.GetDisguiseClass() : owner->GetPlayerClass()->GetClassIndex();
|
||||
int ownerTeam = owner->m_Shared.InCond( TF_COND_DISGUISED ) ? owner->m_Shared.GetDisguiseTeam() : owner->GetTeamNumber();
|
||||
|
||||
SetModel( GetPlayerClassData( ownerClass )->m_szModelName );
|
||||
ChangeTeam( ownerTeam );
|
||||
|
||||
if ( ownerTeam == TF_TEAM_BLUE )
|
||||
{
|
||||
m_nSkin = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_nSkin = 0;
|
||||
}
|
||||
|
||||
SetAbsOrigin( owner->GetAbsOrigin() );
|
||||
SetAbsAngles( owner->GetAbsAngles() );
|
||||
SetAbsVelocity( owner->GetAbsVelocity() );
|
||||
|
||||
Vector headPos;
|
||||
QAngle headAngles;
|
||||
if ( GetAttachment( "head", headPos, headAngles ) )
|
||||
{
|
||||
m_eyeOffset = headPos - GetAbsOrigin();
|
||||
}
|
||||
|
||||
CTFWeaponBase *theirWeapon = owner->m_Shared.GetDisguiseWeapon();
|
||||
if ( !theirWeapon )
|
||||
{
|
||||
theirWeapon = owner->GetActiveTFWeapon();
|
||||
}
|
||||
|
||||
if ( theirWeapon )
|
||||
{
|
||||
CBaseAnimating *weapon = (CBaseAnimating *)CreateEntityByName( "prop_dynamic" );
|
||||
if ( weapon )
|
||||
{
|
||||
weapon->SetModel( theirWeapon->GetWorldModel() );
|
||||
|
||||
// bonemerge the weapon into our model
|
||||
weapon->FollowEntity( this, true );
|
||||
|
||||
// choose the appropriate run animation for this weapon
|
||||
switch( theirWeapon->GetTFWpnData().m_iWeaponType )
|
||||
{
|
||||
case TF_WPN_TYPE_PRIMARY:
|
||||
m_runActivity = ACT_MP_RUN_PRIMARY;
|
||||
break;
|
||||
|
||||
case TF_WPN_TYPE_SECONDARY:
|
||||
m_runActivity = ACT_MP_RUN_SECONDARY;
|
||||
break;
|
||||
|
||||
case TF_WPN_TYPE_MELEE:
|
||||
default:
|
||||
m_runActivity = ACT_MP_RUN_MELEE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------------------------
|
||||
unsigned int CBotNPCDecoy::PhysicsSolidMaskForEntity( void ) const
|
||||
{
|
||||
// Only collide with the other team
|
||||
int teamContents = ( GetTeamNumber() == TF_TEAM_RED ) ? CONTENTS_BLUETEAM : CONTENTS_REDTEAM;
|
||||
|
||||
return BaseClass::PhysicsSolidMaskForEntity() | teamContents;
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------------------------
|
||||
bool CBotNPCDecoy::ShouldCollide( int collisionGroup, int contentsMask ) const
|
||||
{
|
||||
if ( collisionGroup == COLLISION_GROUP_PLAYER_MOVEMENT )
|
||||
{
|
||||
switch( GetTeamNumber() )
|
||||
{
|
||||
case TF_TEAM_RED:
|
||||
if ( !( contentsMask & CONTENTS_REDTEAM ) )
|
||||
return false;
|
||||
break;
|
||||
|
||||
case TF_TEAM_BLUE:
|
||||
if ( !( contentsMask & CONTENTS_BLUETEAM ) )
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return BaseClass::ShouldCollide( collisionGroup, contentsMask );
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------------------------
|
||||
//---------------------------------------------------------------------------------------------
|
||||
float CBotNPCDecoyLocomotion::GetRunSpeed( void ) const
|
||||
{
|
||||
CTFPlayer *owner = ToTFPlayer( GetBot()->GetEntity()->GetOwnerEntity() );
|
||||
if ( !owner )
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
int ownerClass = owner->m_Shared.InCond( TF_COND_DISGUISED ) ? owner->m_Shared.GetDisguiseClass() : owner->GetPlayerClass()->GetClassIndex();
|
||||
return GetPlayerClassData( ownerClass )->m_flMaxSpeed;
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------------------------
|
||||
// return maximum acceleration of locomotor
|
||||
float CBotNPCDecoyLocomotion::GetMaxAcceleration( void ) const
|
||||
{
|
||||
return 1500.0f;
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------------------------
|
||||
// return maximum deceleration of locomotor
|
||||
float CBotNPCDecoyLocomotion::GetMaxDeceleration( void ) const
|
||||
{
|
||||
return 1500.0f;
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------------------------
|
||||
//---------------------------------------------------------------------------------------------
|
||||
class CBotNPCDecoyBehavior : public Action< CBotNPCDecoy >
|
||||
{
|
||||
public:
|
||||
virtual ActionResult< CBotNPCDecoy > OnStart( CBotNPCDecoy *me, Action< CBotNPCDecoy > *priorAction )
|
||||
{
|
||||
m_timer.Start( tf_decoy_lifetime.GetFloat() );
|
||||
|
||||
// play running animation
|
||||
if ( !me->GetBodyInterface()->IsActivity( me->GetRunActivity() ) )
|
||||
{
|
||||
me->GetBodyInterface()->StartActivity( me->GetRunActivity() );
|
||||
}
|
||||
|
||||
return Continue();
|
||||
}
|
||||
|
||||
virtual ActionResult< CBotNPCDecoy > Update( CBotNPCDecoy *me, float interval )
|
||||
{
|
||||
if ( m_timer.IsElapsed() )
|
||||
{
|
||||
// we're out of time
|
||||
UTIL_Remove( me );
|
||||
return Done( "Lifetime expired" );
|
||||
}
|
||||
|
||||
CTFPlayer *owner = ToTFPlayer( me->GetOwnerEntity() );
|
||||
if ( !owner )
|
||||
{
|
||||
UTIL_Remove( me );
|
||||
return Done( "No owner!" );
|
||||
}
|
||||
|
||||
Vector forward;
|
||||
me->GetVectors( &forward, NULL, NULL );
|
||||
|
||||
me->GetLocomotionInterface()->SetDesiredSpeed( FLT_MAX ); // this is just a rate limiter
|
||||
me->GetLocomotionInterface()->Run();
|
||||
me->GetLocomotionInterface()->Approach( me->GetAbsOrigin() + 100.0f * forward );
|
||||
|
||||
return Continue();
|
||||
}
|
||||
|
||||
virtual const char *GetName( void ) const { return "Behavior"; } // return name of this action
|
||||
|
||||
private:
|
||||
CountdownTimer m_timer;
|
||||
};
|
||||
|
||||
|
||||
IMPLEMENT_INTENTION_INTERFACE( CBotNPCDecoy, CBotNPCDecoyBehavior );
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
// bot_npc_decoy.h
|
||||
// A NextBot non-player decoy that imitates a real player
|
||||
// Michael Booth, January 2011
|
||||
|
||||
#ifndef BOT_NPC_DECOY_H
|
||||
#define BOT_NPC_DECOY_H
|
||||
|
||||
#include "NextBot.h"
|
||||
#include "NextBotBehavior.h"
|
||||
#include "NextBotGroundLocomotion.h"
|
||||
#include "Path/NextBotPathFollow.h"
|
||||
#include "bot_npc.h"
|
||||
#include "bot_npc_body.h"
|
||||
|
||||
|
||||
class CTFPlayer;
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
class CBotNPCDecoyLocomotion : public NextBotGroundLocomotion
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CBotNPCDecoyLocomotion, NextBotGroundLocomotion );
|
||||
|
||||
CBotNPCDecoyLocomotion( INextBot *bot ) : NextBotGroundLocomotion( bot ) { }
|
||||
virtual ~CBotNPCDecoyLocomotion() { }
|
||||
|
||||
virtual float GetRunSpeed( void ) const; // get maximum running speed
|
||||
|
||||
virtual float GetMaxAcceleration( void ) const; // return maximum acceleration of locomotor
|
||||
virtual float GetMaxDeceleration( void ) const; // return maximum deceleration of locomotor
|
||||
};
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
class CBotNPCDecoy : public NextBotCombatCharacter
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CBotNPCDecoy, NextBotCombatCharacter );
|
||||
|
||||
CBotNPCDecoy();
|
||||
virtual ~CBotNPCDecoy();
|
||||
|
||||
virtual void Precache();
|
||||
virtual void Spawn( void );
|
||||
|
||||
// INextBot
|
||||
DECLARE_INTENTION_INTERFACE( CBotNPCDecoy );
|
||||
virtual CBotNPCDecoyLocomotion *GetLocomotionInterface( void ) const { return m_locomotor; }
|
||||
virtual CBotNPCBody *GetBodyInterface( void ) const { return m_body; }
|
||||
|
||||
virtual Vector EyePosition( void );
|
||||
|
||||
virtual unsigned int PhysicsSolidMaskForEntity( void ) const;
|
||||
virtual bool ShouldCollide( int collisionGroup, int contentsMask ) const;
|
||||
|
||||
Activity GetRunActivity( void ) const;
|
||||
|
||||
private:
|
||||
CBotNPCDecoyLocomotion *m_locomotor;
|
||||
CBotNPCBody *m_body;
|
||||
|
||||
Vector m_eyeOffset;
|
||||
Activity m_runActivity;
|
||||
};
|
||||
|
||||
|
||||
inline Activity CBotNPCDecoy::GetRunActivity( void ) const
|
||||
{
|
||||
return m_runActivity;
|
||||
}
|
||||
|
||||
|
||||
inline Vector CBotNPCDecoy::EyePosition( void )
|
||||
{
|
||||
return GetAbsOrigin() + m_eyeOffset;
|
||||
}
|
||||
|
||||
#endif // BOT_NPC_DECOY_H
|
||||
@@ -0,0 +1,101 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
// bot_npc_mini.cpp
|
||||
// A NextBot non-player derived actor
|
||||
// Michael Booth, March 2011
|
||||
|
||||
#include "cbase.h"
|
||||
|
||||
#ifdef TF_RAID_MODE
|
||||
|
||||
#include "tf_player.h"
|
||||
#include "tf_gamerules.h"
|
||||
#include "tf_team.h"
|
||||
#include "tf_projectile_arrow.h"
|
||||
#include "tf_projectile_rocket.h"
|
||||
#include "tf_weapon_grenade_pipebomb.h"
|
||||
#include "tf_ammo_pack.h"
|
||||
#include "tf_obj_sentrygun.h"
|
||||
#include "nav_mesh/tf_nav_area.h"
|
||||
#include "bot_npc_mini.h"
|
||||
#include "NextBot/Path/NextBotChasePath.h"
|
||||
#include "econ_wearable.h"
|
||||
#include "team_control_point_master.h"
|
||||
#include "particle_parse.h"
|
||||
#include "CRagdollMagnet.h"
|
||||
#include "nav_mesh/tf_path_follower.h"
|
||||
#include "bot_npc_minion.h"
|
||||
#include "player_vs_environment/monster_resource.h"
|
||||
|
||||
|
||||
extern ConVar tf_bot_npc_reaction_time;
|
||||
extern ConVar tf_bot_npc_grenade_interval;
|
||||
extern float ModifyBossDamage( const CTakeDamageInfo &info );
|
||||
|
||||
|
||||
ConVar tf_raid_mini_rocket_boss_health( "tf_raid_mini_rocket_boss_health", "5000", 0/*FCVAR_CHEAT*/ );
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
// The Bot NPC mini-boss
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
LINK_ENTITY_TO_CLASS( bot_boss_mini_rockets, CBotNPCMiniRockets );
|
||||
PRECACHE_REGISTER( bot_boss_mini_rockets );
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
void CBotNPCMiniRockets::Precache()
|
||||
{
|
||||
BaseClass::Precache();
|
||||
|
||||
int model = PrecacheModel( "models/bots/knight/knight_mini.mdl" );
|
||||
PrecacheGibsForModel( model );
|
||||
|
||||
PrecacheScriptSound( "RobotMiniBoss.LaunchRocket" );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
void CBotNPCMiniRockets::Spawn( void )
|
||||
{
|
||||
BaseClass::Spawn();
|
||||
|
||||
SetModel( "models/bots/knight/knight_mini.mdl" );
|
||||
|
||||
int health = tf_raid_mini_rocket_boss_health.GetInt();
|
||||
SetHealth( health );
|
||||
SetMaxHealth( health );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
// The Bot NPC mini-boss
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
LINK_ENTITY_TO_CLASS( bot_boss_mini_nuker, CBotNPCMiniNuker );
|
||||
PRECACHE_REGISTER( bot_boss_mini_nuker );
|
||||
|
||||
ConVar tf_raid_mini_nuker_boss_health( "tf_raid_mini_nuker_boss_health", "5000", 0/*FCVAR_CHEAT*/ );
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
void CBotNPCMiniNuker::Precache()
|
||||
{
|
||||
BaseClass::Precache();
|
||||
|
||||
int model = PrecacheModel( "models/bots/knight/knight_mini.mdl" );
|
||||
PrecacheGibsForModel( model );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
void CBotNPCMiniNuker::Spawn( void )
|
||||
{
|
||||
BaseClass::Spawn();
|
||||
|
||||
SetModel( "models/bots/knight/knight_mini.mdl" );
|
||||
|
||||
int health = tf_raid_mini_nuker_boss_health.GetInt();
|
||||
SetHealth( health );
|
||||
SetMaxHealth( health );
|
||||
}
|
||||
|
||||
#endif // TF_RAID_MODE
|
||||
@@ -0,0 +1,83 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
// bot_npc_mini.h
|
||||
// A NextBot non-player derived actor
|
||||
// Michael Booth, March 2011
|
||||
|
||||
#ifndef BOT_NPC_MINI_H
|
||||
#define BOT_NPC_MINI_H
|
||||
|
||||
#ifdef TF_RAID_MODE
|
||||
|
||||
#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"
|
||||
#include "player_vs_environment/boss_alpha/boss_alpha.h"
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
class CBotNPCMiniRockets : public CBossAlpha
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CBotNPCMiniRockets, CBossAlpha );
|
||||
|
||||
virtual void Precache();
|
||||
virtual void Spawn( void );
|
||||
|
||||
virtual bool HasAbility( Ability ability ) const;
|
||||
|
||||
virtual bool IsMiniBoss( void ) const { return true; }
|
||||
|
||||
virtual float GetMoveSpeed( void ) const { return 150.0f; }
|
||||
|
||||
virtual int GetRocketLaunchCount( void ) const { return 3; }
|
||||
virtual float GetRocketDamage( void ) const { return 25.0f; }
|
||||
virtual float GetRocketAimError( void ) const { return 3.0f; }
|
||||
virtual float GetRocketInterval( void ) const { return 0.5f; }
|
||||
virtual const char *GetRocketSoundEffect( void ) const { return "RobotMiniBoss.LaunchRocket"; }
|
||||
|
||||
virtual float GetBecomeStunnedDamage( void ) const { return 300.0f; }
|
||||
};
|
||||
|
||||
inline bool CBotNPCMiniRockets::HasAbility( Ability ability ) const
|
||||
{
|
||||
const int myAbilities = CAN_BE_STUNNED | CAN_FIRE_ROCKETS;
|
||||
|
||||
return myAbilities & ability ? true : false;
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
class CBotNPCMiniNuker : public CBossAlpha
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CBotNPCMiniNuker, CBossAlpha );
|
||||
|
||||
virtual void Precache();
|
||||
virtual void Spawn( void );
|
||||
|
||||
virtual bool HasAbility( Ability ability ) const;
|
||||
|
||||
virtual bool IsMiniBoss( void ) const { return true; }
|
||||
|
||||
virtual float GetMoveSpeed( void ) const { return 150.0f; }
|
||||
|
||||
virtual float GetGrenadeInterval( void ) const { return 2.0f; }
|
||||
|
||||
virtual float GetBecomeStunnedDamage( void ) const { return 300.0f; }
|
||||
};
|
||||
|
||||
inline bool CBotNPCMiniNuker::HasAbility( Ability ability ) const
|
||||
{
|
||||
const int myAbilities = CAN_BE_STUNNED | CAN_NUKE | CAN_LAUNCH_STICKIES;
|
||||
|
||||
return myAbilities & ability ? true : false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif // TF_RAID_MODE
|
||||
|
||||
#endif // BOT_NPC_MINI_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,199 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
// bot_npc_minion.h
|
||||
// Minions for the Boss
|
||||
// Michael Booth, November 2010
|
||||
|
||||
#ifndef BOT_NPC_MINION_H
|
||||
#define BOT_NPC_MINION_H
|
||||
|
||||
#ifdef TF_RAID_MODE
|
||||
|
||||
#include "NextBot.h"
|
||||
#include "NextBotBehavior.h"
|
||||
#include "Path/NextBotPathFollow.h"
|
||||
#include "bot_npc.h"
|
||||
#include "bot_npc_body.h"
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Bypass vision system
|
||||
class CDisableVision : public IVision
|
||||
{
|
||||
public:
|
||||
CDisableVision( INextBot *bot ) : IVision( bot ) { }
|
||||
virtual ~CDisableVision() { }
|
||||
|
||||
virtual void Reset( void ) { }
|
||||
virtual void Update( void ) { }
|
||||
};
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
class CNextBotFlyingLocomotion : public ILocomotion
|
||||
{
|
||||
public:
|
||||
CNextBotFlyingLocomotion( INextBot *bot );
|
||||
virtual ~CNextBotFlyingLocomotion();
|
||||
|
||||
virtual void Reset( void ); // (EXTEND) reset to initial state
|
||||
virtual void Update( void ); // (EXTEND) update internal state
|
||||
|
||||
virtual void Approach( const Vector &goalPos, float goalWeight = 1.0f ); // (EXTEND) move directly towards the given position
|
||||
|
||||
virtual void SetDesiredSpeed( float speed ); // set desired speed for locomotor movement
|
||||
virtual float GetDesiredSpeed( void ) const; // returns the current desired speed
|
||||
|
||||
virtual void SetDesiredAltitude( float height ); // how high above our Approach goal do we float?
|
||||
virtual float GetDesiredAltitude( void ) const;
|
||||
|
||||
virtual const Vector &GetGroundNormal( void ) const; // surface normal of the ground we are in contact with
|
||||
|
||||
virtual const Vector &GetVelocity( void ) const; // return current world space velocity
|
||||
void SetVelocity( const Vector &velocity );
|
||||
|
||||
void Deflect( CBaseEntity *deflector );
|
||||
|
||||
protected:
|
||||
float m_desiredSpeed;
|
||||
float m_currentSpeed;
|
||||
Vector m_forward;
|
||||
|
||||
float m_desiredAltitude;
|
||||
void MaintainAltitude( void );
|
||||
|
||||
Vector m_velocity;
|
||||
Vector m_acceleration;
|
||||
};
|
||||
|
||||
inline const Vector &CNextBotFlyingLocomotion::GetGroundNormal( void ) const
|
||||
{
|
||||
static Vector up( 0, 0, 1.0f );
|
||||
|
||||
return up;
|
||||
}
|
||||
|
||||
inline const Vector &CNextBotFlyingLocomotion::GetVelocity( void ) const
|
||||
{
|
||||
return m_velocity;
|
||||
}
|
||||
|
||||
inline void CNextBotFlyingLocomotion::SetVelocity( const Vector &velocity )
|
||||
{
|
||||
m_velocity = velocity;
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
class CBotNPCMinion : public NextBotCombatCharacter
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CBotNPCMinion, NextBotCombatCharacter );
|
||||
DECLARE_SERVERCLASS();
|
||||
|
||||
CBotNPCMinion();
|
||||
virtual ~CBotNPCMinion();
|
||||
|
||||
virtual void Precache();
|
||||
virtual void Spawn( void );
|
||||
|
||||
virtual int OnTakeDamage_Alive( const CTakeDamageInfo &info );
|
||||
|
||||
virtual bool IsDeflectable() { return true; } // for flamethrower
|
||||
virtual void Deflected( CBaseEntity *pDeflectedBy, Vector &vecDir );
|
||||
|
||||
// INextBot
|
||||
DECLARE_INTENTION_INTERFACE( CBotNPCMinion );
|
||||
virtual CNextBotFlyingLocomotion *GetLocomotionInterface( void ) const { return m_locomotor; }
|
||||
virtual CBotNPCBody *GetBodyInterface( void ) const { return m_body; }
|
||||
virtual IVision *GetVisionInterface( void ) const { return m_vision; }
|
||||
|
||||
virtual Vector EyePosition( void );
|
||||
|
||||
virtual unsigned int PhysicsSolidMaskForEntity( void ) const;
|
||||
virtual bool ShouldCollide( int collisionGroup, int contentsMask ) const;
|
||||
|
||||
void BecomeAmmoPack( void );
|
||||
|
||||
CTFPlayer *FindTarget( void ); // Find the closest living player not already being targeted by another minion
|
||||
|
||||
void UpdateTarget( void );
|
||||
|
||||
void SetTarget( CTFPlayer *target );
|
||||
CTFPlayer *GetTarget( void ) const;
|
||||
bool HasTarget( void ) const;
|
||||
bool IsTarget( CTFPlayer *target ) const;
|
||||
|
||||
const Vector &GetLastKnownTargetPosition( void ) const;
|
||||
|
||||
void StartStunEffects( CTFPlayer *victim );
|
||||
void EndStunEffects( void );
|
||||
|
||||
bool IsAlert( void ) const;
|
||||
void BecomeAlert( void );
|
||||
|
||||
private:
|
||||
CNextBotFlyingLocomotion *m_locomotor;
|
||||
CBotNPCBody *m_body;
|
||||
CDisableVision *m_vision;
|
||||
|
||||
Vector m_eyeOffset;
|
||||
|
||||
CTFPlayer *m_target;
|
||||
Vector m_lastKnownTargetPosition;
|
||||
|
||||
CountdownTimer m_invulnTimer;
|
||||
|
||||
CNetworkHandle( CBaseEntity, m_stunTarget );
|
||||
|
||||
bool m_isAlert;
|
||||
};
|
||||
|
||||
inline bool CBotNPCMinion::IsAlert( void ) const
|
||||
{
|
||||
return m_isAlert;
|
||||
}
|
||||
|
||||
inline Vector CBotNPCMinion::EyePosition( void )
|
||||
{
|
||||
return GetAbsOrigin() + m_eyeOffset;
|
||||
}
|
||||
|
||||
inline bool CBotNPCMinion::HasTarget( void ) const
|
||||
{
|
||||
return m_target == NULL ? false : true;
|
||||
}
|
||||
|
||||
inline bool CBotNPCMinion::IsTarget( CTFPlayer *target ) const
|
||||
{
|
||||
return ( m_target == target ) ? true : false;
|
||||
}
|
||||
|
||||
inline void CBotNPCMinion::SetTarget( CTFPlayer *target )
|
||||
{
|
||||
m_target = target;
|
||||
}
|
||||
|
||||
inline CTFPlayer *CBotNPCMinion::GetTarget( void ) const
|
||||
{
|
||||
return m_target;
|
||||
}
|
||||
|
||||
inline const Vector &CBotNPCMinion::GetLastKnownTargetPosition( void ) const
|
||||
{
|
||||
return m_lastKnownTargetPosition;
|
||||
}
|
||||
|
||||
inline void CBotNPCMinion::StartStunEffects( CTFPlayer *victim )
|
||||
{
|
||||
m_stunTarget = victim;
|
||||
}
|
||||
|
||||
inline void CBotNPCMinion::EndStunEffects( void )
|
||||
{
|
||||
m_stunTarget = NULL;
|
||||
}
|
||||
|
||||
|
||||
#endif // TF_RAID_MODE
|
||||
|
||||
#endif // BOT_NPC_MINION_H
|
||||
Reference in New Issue
Block a user