This commit is contained in:
FluorescentCIAAfricanAmerican
2020-04-22 12:56:21 -04:00
commit 3bf9df6b27
15370 changed files with 5489726 additions and 0 deletions
File diff suppressed because it is too large Load Diff
+541
View File
@@ -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
+402
View File
@@ -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 );
+79
View File
@@ -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
+153
View File
@@ -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 );
}
+64
View File
@@ -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
+246
View File
@@ -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 );
+80
View File
@@ -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
+101
View File
@@ -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
+83
View File
@@ -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
+199
View File
@@ -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