Modified source engine (2017) developed by valve and leaked in 2020. Not for commercial purporses
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

339 lines
8.6 KiB

5 years ago
//========= Copyright Valve Corporation, All rights reserved. ============//
// eyeball_boss.h
// The 2011 Halloween Boss
// Michael Booth, October 2011
#ifndef EYEBALL_BOSS_H
#define EYEBALL_BOSS_H
#include "NextBot.h"
#include "NextBotBehavior.h"
#include "Path/NextBotPathFollow.h"
#include "bot_npc/bot_npc_body.h"
#include "../halloween_base_boss.h"
#define EYEBALL_RADIUS 100.0f
#define EYEBALL_NORMAL_SKIN 0
#define EYEBALL_RED_SKIN 1
#define EYEBALL_TEAM_RED 2
#define EYEBALL_TEAM_BLUE 3
#define PURGATORY_Z -1152
#define EYEBALL_ANGRY 2
#define EYEBALL_GRUMPY 1
#define EYEBALL_CALM 0
extern ConVar tf_eyeball_boss_debug;
extern ConVar tf_eyeball_boss_debug_orientation;
extern ConVar tf_eyeball_boss_lifetime;
extern ConVar tf_eyeball_boss_lifetime_spell;
extern ConVar tf_eyeball_boss_speed;
extern ConVar tf_eyeball_boss_hover_height;
extern ConVar tf_eyeball_boss_acceleration;
extern ConVar tf_eyeball_boss_horiz_damping;
extern ConVar tf_eyeball_boss_vert_damping;
extern ConVar tf_eyeball_boss_attack_range;
extern ConVar tf_eyeball_boss_health_base;
extern ConVar tf_eyeball_boss_health_per_player;
extern ConVar tf_halloween_bot_min_player_count;
//----------------------------------------------------------------------------
class CEyeballBossBody : public CBotNPCBody
{
public:
CEyeballBossBody( INextBot *bot );
virtual ~CEyeballBossBody() { }
virtual void Update( void );
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 float GetMaxHeadAngularVelocity( void ) const // return max turn rate of head in degrees/second
{
return 3000.0f;
}
private:
int m_leftRightPoseParameter;
int m_upDownPoseParameter;
Vector m_lookAtSpot;
};
//----------------------------------------------------------------------------
// Bypass vision system
class CDisableVision : public IVision
{
public:
CDisableVision( INextBot *bot ) : IVision( bot ) { }
virtual ~CDisableVision() { }
virtual void Reset( void ) { }
virtual void Update( void ) { }
};
//----------------------------------------------------------------------------
class CEyeballBossLocomotion : public ILocomotion
{
public:
CEyeballBossLocomotion( INextBot *bot );
virtual ~CEyeballBossLocomotion();
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 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 GetDeathDropHeight( void ) const; // distance at which we will die if we fall
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 );
virtual void FaceTowards( const Vector &target ); // rotate body to face towards "target"
// return position of "feet" - the driving point where the bot contacts the ground
// for this floating boss, "feet" refers to the ground directly underneath him
virtual const Vector &GetFeet( void ) const;
protected:
float m_desiredSpeed;
float m_currentSpeed;
Vector m_forward;
float m_desiredAltitude;
void MaintainAltitude( void );
Vector m_velocity;
Vector m_acceleration;
};
inline float CEyeballBossLocomotion::GetStepHeight( void ) const
{
return 50.0f;
}
inline float CEyeballBossLocomotion::GetMaxJumpHeight( void ) const
{
return 100.0f;
}
inline float CEyeballBossLocomotion::GetDeathDropHeight( void ) const
{
return 999.9f;
}
inline const Vector &CEyeballBossLocomotion::GetGroundNormal( void ) const
{
static Vector up( 0, 0, 1.0f );
return up;
}
inline const Vector &CEyeballBossLocomotion::GetVelocity( void ) const
{
return m_velocity;
}
inline void CEyeballBossLocomotion::SetVelocity( const Vector &velocity )
{
m_velocity = velocity;
}
DECLARE_AUTO_LIST( IEyeballBossAutoList );
//----------------------------------------------------------------------------
class CEyeballBoss : public CHalloweenBaseBoss, public IEyeballBossAutoList
{
public:
DECLARE_CLASS( CEyeballBoss, CHalloweenBaseBoss );
DECLARE_SERVERCLASS();
CEyeballBoss();
virtual ~CEyeballBoss();
static void PrecacheEyeballBoss();
virtual void Precache();
virtual void Spawn( void );
virtual void UpdateOnRemove( void );
virtual int OnTakeDamage_Alive( const CTakeDamageInfo &info );
virtual void UpdateLastKnownArea( void ); // invoke this to update our last known nav area (since there is no think method chained to CBaseCombatCharacter)
// INextBot
DECLARE_INTENTION_INTERFACE( CEyeballBoss );
virtual CEyeballBossLocomotion *GetLocomotionInterface( void ) const { return m_locomotor; }
virtual CEyeballBossBody *GetBodyInterface( void ) const { return m_body; }
virtual CDisableVision *GetVisionInterface( void ) const { return m_vision; }
virtual void Update( void );
virtual Vector EyePosition( void );
virtual bool ShouldCollide( int collisionGroup, int contentsMask ) const;
virtual float GetCritInjuryMultiplier( void ) const; // when we are hit by a crit, damage is mutiplied by this
const Vector &GetHomePosition( void ) const;
void BecomeEnraged( float duration );
bool IsEnraged( void ) const;
bool IsGrumpy( void ) const;
void SetLookAtTarget( const Vector &spot );
void SetVictim( CBaseCombatCharacter *victim );
CBaseCombatCharacter *GetVictim( void ) const;
bool IsInPurgatory( CBaseEntity *entity ) const;
CBaseCombatCharacter *FindClosestVisibleVictim( void );
const Vector &PickNewSpawnSpot( void ) const;
void JarateNearbyPlayers( float range );
void SetDamageLimit( int limit );
void RemoveDamageLimit( void );
void LogPlayerInteraction( const char *verb, CTFPlayer *player );
void GainLevel( void );
void ResetLevel( void );
virtual int GetLevel( void ) const OVERRIDE;
virtual HalloweenBossType GetBossType() const { return HALLOWEEN_BOSS_MONOCULUS; }
private:
CEyeballBossLocomotion *m_locomotor;
CEyeballBossBody *m_body;
CDisableVision *m_vision;
Vector m_eyeOffset;
Vector m_homePos;
CTFPlayer *m_target;
CountdownTimer m_invulnTimer;
CNetworkVector( m_lookAtSpot );
CNetworkVar( int, m_attitude );
CountdownTimer m_rageTimer;
CHandle< CBaseCombatCharacter > m_victim;
CUtlVector< CHandle< CBaseEntity > > m_spawnSpotVector;
int m_damageLimit;
static int m_level;
};
inline int CEyeballBoss::GetLevel( void ) const
{
return m_level;
}
inline void CEyeballBoss::GainLevel( void )
{
++m_level;
}
inline void CEyeballBoss::ResetLevel( void )
{
m_level = 1;
}
inline void CEyeballBoss::SetDamageLimit( int limit )
{
m_damageLimit = limit;
}
inline void CEyeballBoss::RemoveDamageLimit( void )
{
m_damageLimit = -1;
}
inline float CEyeballBoss::GetCritInjuryMultiplier( void ) const
{
return 2.0f;
}
inline bool CEyeballBoss::IsInPurgatory( CBaseEntity *entity ) const
{
if ( IsSpell() )
return false;
return ( entity->GetAbsOrigin().z < PURGATORY_Z );
}
inline void CEyeballBoss::SetVictim( CBaseCombatCharacter *victim )
{
m_victim = victim;
}
inline bool CEyeballBoss::IsEnraged( void ) const
{
// always enrage if I'm a spell
if ( IsSpell() )
return true;
// being near death always makes me mad
if ( GetHealth() < GetMaxHealth()/3 )
return true;
return m_rageTimer.HasStarted() && !m_rageTimer.IsElapsed();
}
inline bool CEyeballBoss::IsGrumpy( void ) const
{
if ( IsEnraged() )
return false;
return ( GetHealth() < 2*GetMaxHealth()/3 );
}
inline const Vector &CEyeballBoss::GetHomePosition( void ) const
{
return m_homePos;
}
inline Vector CEyeballBoss::EyePosition( void )
{
return GetAbsOrigin() + m_eyeOffset;
}
inline void CEyeballBoss::SetLookAtTarget( const Vector &spot )
{
m_lookAtSpot = spot;
}
#endif // EYEBALL_BOSS_H