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.
639 lines
17 KiB
639 lines
17 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
#include "cbase.h" |
|
|
|
#include "tf_gamerules.h" |
|
#include "tf_base_boss.h" |
|
#include "entity_currencypack.h" |
|
#include "tf_gamestats.h" |
|
#include "tf_player.h" |
|
|
|
LINK_ENTITY_TO_CLASS( base_boss, CTFBaseBoss ); |
|
|
|
PRECACHE_REGISTER( base_boss ); |
|
|
|
IMPLEMENT_SERVERCLASS_ST( CTFBaseBoss, DT_TFBaseBoss) |
|
SendPropFloat( SENDINFO(m_lastHealthPercentage), 11, SPROP_NOSCALE, 0.0, 1.0 ), |
|
END_SEND_TABLE() |
|
|
|
BEGIN_DATADESC( CTFBaseBoss ) |
|
|
|
DEFINE_KEYFIELD( m_initialHealth, FIELD_INTEGER, "health" ), |
|
DEFINE_KEYFIELD( m_modelString, FIELD_STRING, "model" ), |
|
DEFINE_KEYFIELD( m_speed, FIELD_FLOAT, "speed" ), |
|
DEFINE_KEYFIELD( m_startDisabled, FIELD_INTEGER, "start_disabled" ), |
|
|
|
DEFINE_INPUTFUNC( FIELD_VOID, "Enable", InputEnable ), |
|
DEFINE_INPUTFUNC( FIELD_VOID, "Disable", InputDisable ), |
|
DEFINE_INPUTFUNC( FIELD_FLOAT, "SetSpeed", InputSetSpeed ), |
|
|
|
DEFINE_INPUTFUNC( FIELD_INTEGER, "SetHealth", InputSetHealth ), |
|
DEFINE_INPUTFUNC( FIELD_INTEGER, "SetMaxHealth", InputSetMaxHealth ), |
|
DEFINE_INPUTFUNC( FIELD_INTEGER, "AddHealth", InputAddHealth ), |
|
DEFINE_INPUTFUNC( FIELD_INTEGER, "RemoveHealth", InputRemoveHealth ), |
|
|
|
DEFINE_OUTPUT( m_outputOnHealthBelow90Percent, "OnHealthBelow90Percent" ), |
|
DEFINE_OUTPUT( m_outputOnHealthBelow80Percent, "OnHealthBelow80Percent" ), |
|
DEFINE_OUTPUT( m_outputOnHealthBelow70Percent, "OnHealthBelow70Percent" ), |
|
DEFINE_OUTPUT( m_outputOnHealthBelow60Percent, "OnHealthBelow60Percent" ), |
|
DEFINE_OUTPUT( m_outputOnHealthBelow50Percent, "OnHealthBelow50Percent" ), |
|
DEFINE_OUTPUT( m_outputOnHealthBelow40Percent, "OnHealthBelow40Percent" ), |
|
DEFINE_OUTPUT( m_outputOnHealthBelow30Percent, "OnHealthBelow30Percent" ), |
|
DEFINE_OUTPUT( m_outputOnHealthBelow20Percent, "OnHealthBelow20Percent" ), |
|
DEFINE_OUTPUT( m_outputOnHealthBelow10Percent, "OnHealthBelow10Percent" ), |
|
|
|
DEFINE_OUTPUT( m_outputOnKilled, "OnKilled" ), |
|
|
|
DEFINE_THINKFUNC( BossThink ), |
|
|
|
END_DATADESC() |
|
|
|
ConVar tf_base_boss_speed( "tf_base_boss_speed", "75", FCVAR_CHEAT ); |
|
ConVar tf_base_boss_max_turn_rate( "tf_base_boss_max_turn_rate", "25", FCVAR_CHEAT ); |
|
|
|
extern void HandleRageGain( CTFPlayer *pPlayer, unsigned int iRequiredBuffFlags, float flDamage, float fInverseRageGainScale ); |
|
|
|
//-------------------------------------------------------------------------------------- |
|
//-------------------------------------------------------------------------------------- |
|
float CTFBaseBossLocomotion::GetRunSpeed( void ) const |
|
{ |
|
CTFBaseBoss *boss = (CTFBaseBoss *)GetBot()->GetEntity(); |
|
return boss->GetMaxSpeed(); |
|
} |
|
|
|
|
|
//-------------------------------------------------------------------------------------- |
|
void CTFBaseBossLocomotion::FaceTowards( const Vector &target ) |
|
{ |
|
CTFBaseBoss *pTank = static_cast< CTFBaseBoss* >( GetBot()->GetEntity() ); |
|
|
|
const float deltaT = GetUpdateInterval(); |
|
|
|
QAngle angles = pTank->GetLocalAngles(); |
|
|
|
float desiredYaw = UTIL_VecToYaw( target - GetFeet() ); |
|
|
|
float angleDiff = UTIL_AngleDiff( desiredYaw, angles.y ); |
|
|
|
float deltaYaw = tf_base_boss_max_turn_rate.GetFloat() * deltaT; |
|
|
|
if ( angleDiff < -deltaYaw ) |
|
{ |
|
angles.y -= deltaYaw; |
|
} |
|
else if ( angleDiff > deltaYaw ) |
|
{ |
|
angles.y += deltaYaw; |
|
} |
|
else |
|
{ |
|
angles.y += angleDiff; |
|
} |
|
|
|
Vector forward, right; |
|
pTank->GetVectors( NULL, &right, NULL ); |
|
|
|
forward = CrossProduct( GetGroundNormal(), right ); |
|
|
|
float desiredPitch = UTIL_VecToPitch( forward ); |
|
|
|
angleDiff = UTIL_AngleDiff( desiredPitch, angles.x ); |
|
|
|
float deltaPitch = tf_base_boss_max_turn_rate.GetFloat() * deltaT; |
|
|
|
if ( angleDiff < -deltaPitch ) |
|
{ |
|
angles.x -= deltaPitch; |
|
} |
|
else if ( angleDiff > deltaPitch ) |
|
{ |
|
angles.x += deltaPitch; |
|
} |
|
else |
|
{ |
|
angles.x += angleDiff; |
|
} |
|
|
|
pTank->SetLocalAngles( angles ); |
|
pTank->UpdateCollisionBounds(); |
|
} |
|
|
|
|
|
//-------------------------------------------------------------------------------------- |
|
//-------------------------------------------------------------------------------------- |
|
CTFBaseBoss::CTFBaseBoss() |
|
{ |
|
m_modelString = NULL_STRING; |
|
m_lastHealthPercentage = 1.0f; |
|
m_speed = tf_base_boss_speed.GetFloat(); |
|
m_locomotor = new CTFBaseBossLocomotion( this ); |
|
m_currencyValue = TF_BASE_BOSS_CURRENCY; |
|
m_initialHealth = 0; |
|
|
|
m_bResolvePlayerCollisions = true; |
|
} |
|
|
|
|
|
//-------------------------------------------------------------------------------------- |
|
CTFBaseBoss::~CTFBaseBoss() |
|
{ |
|
delete m_locomotor; |
|
} |
|
|
|
|
|
//-------------------------------------------------------------------------------------- |
|
void CTFBaseBoss::Precache( void ) |
|
{ |
|
if ( m_modelString != NULL_STRING ) |
|
{ |
|
PrecacheModel( STRING( m_modelString ) ); |
|
} |
|
|
|
BaseClass::Precache(); |
|
} |
|
|
|
|
|
//-------------------------------------------------------------------------------------- |
|
void CTFBaseBoss::Spawn( void ) |
|
{ |
|
Precache(); |
|
|
|
BaseClass::Spawn(); |
|
|
|
if ( m_modelString != NULL_STRING ) |
|
{ |
|
SetModel( STRING( m_modelString ) ); |
|
} |
|
|
|
m_isEnabled = m_startDisabled ? false : true; |
|
|
|
SetHealth( m_initialHealth ); |
|
SetMaxHealth( m_initialHealth ); |
|
|
|
if ( TFGameRules() ) |
|
{ |
|
TFGameRules()->AddActiveBoss( this ); |
|
} |
|
|
|
m_lastHealthPercentage = 1.0f; |
|
m_damagePoseParameter = -1; |
|
|
|
SetThink( &CTFBaseBoss::BossThink ); |
|
SetNextThink( gpGlobals->curtime ); |
|
} |
|
|
|
int CTFBaseBoss::UpdateTransmitState() |
|
{ |
|
// ALWAYS transmit to all clients. |
|
return SetTransmitState( FL_EDICT_ALWAYS ); |
|
} |
|
|
|
|
|
//-------------------------------------------------------------------------------------- |
|
void CTFBaseBoss::ResolvePlayerCollision( CTFPlayer *player ) |
|
{ |
|
Vector bossGlobalMins = WorldAlignMins() + GetAbsOrigin(); |
|
Vector bossGlobalMaxs = WorldAlignMaxs() + GetAbsOrigin(); |
|
|
|
Vector playerGlobalMins = player->WorldAlignMins() + player->GetAbsOrigin(); |
|
Vector playerGlobalMaxs = player->WorldAlignMaxs() + player->GetAbsOrigin(); |
|
|
|
Vector newPlayerPos = player->GetAbsOrigin(); |
|
|
|
|
|
if ( playerGlobalMins.x > bossGlobalMaxs.x || |
|
playerGlobalMaxs.x < bossGlobalMins.x || |
|
playerGlobalMins.y > bossGlobalMaxs.y || |
|
playerGlobalMaxs.y < bossGlobalMins.y || |
|
playerGlobalMins.z > bossGlobalMaxs.z || |
|
playerGlobalMaxs.z < bossGlobalMins.z ) |
|
{ |
|
// no overlap |
|
return; |
|
} |
|
|
|
Vector toPlayer = player->WorldSpaceCenter() - WorldSpaceCenter(); |
|
|
|
Vector overlap; |
|
float signX, signY, signZ; |
|
|
|
if ( toPlayer.x >= 0 ) |
|
{ |
|
overlap.x = bossGlobalMaxs.x - playerGlobalMins.x; |
|
signX = 1.0f; |
|
} |
|
else |
|
{ |
|
overlap.x = playerGlobalMaxs.x - bossGlobalMins.x; |
|
signX = -1.0f; |
|
} |
|
|
|
if ( toPlayer.y >= 0 ) |
|
{ |
|
overlap.y = bossGlobalMaxs.y - playerGlobalMins.y; |
|
signY = 1.0f; |
|
} |
|
else |
|
{ |
|
overlap.y = playerGlobalMaxs.y - bossGlobalMins.y; |
|
signY = -1.0f; |
|
} |
|
|
|
if ( toPlayer.z >= 0 ) |
|
{ |
|
overlap.z = bossGlobalMaxs.z - playerGlobalMins.z; |
|
signZ = 1.0f; |
|
} |
|
else |
|
{ |
|
// don't push player underground |
|
overlap.z = 99999.9f; // playerGlobalMaxs.z - bossGlobalMins.z; |
|
signZ = -1.0f; |
|
} |
|
|
|
float bloat = 5.0f; |
|
|
|
if ( overlap.x < overlap.y ) |
|
{ |
|
if ( overlap.x < overlap.z ) |
|
{ |
|
// X is least overlap |
|
newPlayerPos.x += signX * ( overlap.x + bloat ); |
|
} |
|
else |
|
{ |
|
// Z is least overlap |
|
newPlayerPos.z += signZ * ( overlap.z + bloat ); |
|
} |
|
} |
|
else if ( overlap.z < overlap.y ) |
|
{ |
|
// Z is least overlap |
|
newPlayerPos.z += signZ * ( overlap.z + bloat ); |
|
} |
|
else |
|
{ |
|
// Y is least overlap |
|
newPlayerPos.y += signY * ( overlap.y + bloat ); |
|
} |
|
|
|
// check if new location is valid |
|
trace_t result; |
|
Ray_t ray; |
|
ray.Init( newPlayerPos, newPlayerPos, player->WorldAlignMins(), player->WorldAlignMaxs() ); |
|
UTIL_TraceRay( ray, MASK_PLAYERSOLID, player, COLLISION_GROUP_PLAYER_MOVEMENT, &result ); |
|
|
|
if ( result.DidHit() ) |
|
{ |
|
// Trace down from above to find safe ground |
|
ray.Init( newPlayerPos + Vector( 0.0f, 0.0f, 32.0f ), newPlayerPos, player->WorldAlignMins(), player->WorldAlignMaxs() ); |
|
UTIL_TraceRay( ray, MASK_PLAYERSOLID, player, COLLISION_GROUP_PLAYER_MOVEMENT, &result ); |
|
|
|
if ( result.startsolid ) |
|
{ |
|
// player was crushed against something |
|
player->TakeDamage( CTakeDamageInfo( this, this, 99999.9f, DMG_CRUSH ) ); |
|
return; |
|
} |
|
else |
|
{ |
|
// Use the trace end position |
|
newPlayerPos = result.endpos; |
|
} |
|
} |
|
|
|
player->SetAbsOrigin( newPlayerPos ); |
|
} |
|
|
|
|
|
//-------------------------------------------------------------------------------------- |
|
void CTFBaseBoss::Touch( CBaseEntity *pOther ) |
|
{ |
|
BaseClass::Touch( pOther ); |
|
|
|
if ( pOther && pOther->IsBaseObject() ) |
|
{ |
|
// ran over an engineer building - destroy it |
|
pOther->TakeDamage( CTakeDamageInfo( this, this, 99999.9f, DMG_CRUSH ) ); |
|
} |
|
} |
|
|
|
|
|
//-------------------------------------------------------------------------------------- |
|
void CTFBaseBoss::BossThink( void ) |
|
{ |
|
SetNextThink( gpGlobals->curtime ); |
|
|
|
if ( m_damagePoseParameter < 0 ) |
|
{ |
|
m_damagePoseParameter = LookupPoseParameter( "damage" ); |
|
} |
|
|
|
if ( m_damagePoseParameter >= 0 ) |
|
{ |
|
// Avoid dividing by zero |
|
if ( GetMaxHealth() ) |
|
{ |
|
SetPoseParameter( m_damagePoseParameter, 1.0f - ( (float)GetHealth() / (float)GetMaxHealth() ) ); |
|
} |
|
else |
|
{ |
|
SetPoseParameter( m_damagePoseParameter, 1.0f ); |
|
} |
|
} |
|
|
|
if ( !m_isEnabled ) |
|
{ |
|
return; |
|
} |
|
|
|
Update(); |
|
|
|
if ( m_bResolvePlayerCollisions ) |
|
{ |
|
CUtlVector< CTFPlayer * > playerVector; |
|
CollectPlayers( &playerVector, TEAM_ANY, COLLECT_ONLY_LIVING_PLAYERS ); |
|
for( int i=0; i<playerVector.Count(); ++i ) |
|
{ |
|
ResolvePlayerCollision( playerVector[i] ); |
|
} |
|
} |
|
} |
|
|
|
//-------------------------------------------------------------------------------------- |
|
void CTFBaseBoss::Event_Killed( const CTakeDamageInfo &info ) |
|
{ |
|
m_outputOnKilled.FireOutput( this, this ); |
|
|
|
// drop some loot! |
|
m_currencyValue = GetCurrencyValue(); |
|
|
|
int nRemainingMoney = m_currencyValue; |
|
|
|
QAngle angRand = vec3_angle; |
|
|
|
while( nRemainingMoney > 0 ) |
|
{ |
|
int nAmount = 0; |
|
|
|
if ( nRemainingMoney >= 100 ) |
|
{ |
|
nAmount = 25; |
|
} |
|
else if ( nRemainingMoney >= 40 ) |
|
{ |
|
nAmount = 10; |
|
} |
|
else if ( nRemainingMoney >= 5 ) |
|
{ |
|
nAmount = 5; |
|
} |
|
else |
|
{ |
|
nAmount = nRemainingMoney; |
|
} |
|
|
|
nRemainingMoney -= nAmount; |
|
|
|
angRand.y = RandomFloat( -180.0f, 180.0f ); |
|
|
|
CCurrencyPackCustom *pCurrencyPack = assert_cast< CCurrencyPackCustom* >( CBaseEntity::CreateNoSpawn( "item_currencypack_custom", WorldSpaceCenter(), angRand, this ) ); |
|
|
|
if ( pCurrencyPack ) |
|
{ |
|
pCurrencyPack->SetAmount( nAmount ); |
|
|
|
Vector vecImpulse = RandomVector( -1,1 ); |
|
vecImpulse.z = RandomFloat( 5.0f, 20.0f ); |
|
VectorNormalize( vecImpulse ); |
|
Vector vecVelocity = vecImpulse * 250.0 * RandomFloat( 1.0f, 4.0f ); |
|
|
|
DispatchSpawn( pCurrencyPack ); |
|
pCurrencyPack->DropSingleInstance( vecVelocity, this, 0, 0 ); |
|
} |
|
} |
|
|
|
BaseClass::Event_Killed( info ); |
|
|
|
UTIL_Remove( this ); |
|
} |
|
|
|
void CTFBaseBoss::UpdateOnRemove() |
|
{ |
|
if ( TFGameRules() ) |
|
{ |
|
TFGameRules()->RemoveActiveBoss( this ); |
|
} |
|
|
|
BaseClass::UpdateOnRemove(); |
|
} |
|
|
|
int CTFBaseBoss::OnTakeDamage( const CTakeDamageInfo &rawInfo ) |
|
{ |
|
CTakeDamageInfo info = rawInfo; |
|
|
|
if ( TFGameRules() ) |
|
{ |
|
TFGameRules()->ApplyOnDamageModifyRules( info, this, true ); |
|
} |
|
|
|
// On damage Rage |
|
// Give the soldier/pyro some rage points for dealing/taking damage. |
|
if ( info.GetDamage() && info.GetAttacker() != this ) |
|
{ |
|
CTFPlayer *pAttacker = ToTFPlayer( info.GetAttacker() ); |
|
|
|
// Buff flag 1: we get rage when we deal damage. Here, that means the soldier that attacked |
|
// gets rage when we take damage. |
|
HandleRageGain( pAttacker, kRageBuffFlag_OnDamageDealt, info.GetDamage(), 6.0f ); |
|
|
|
// Buff 5: our pyro attacker get rage when we're damaged by fire |
|
if ( ( info.GetDamageType() & DMG_BURN ) != 0 || ( info.GetDamageType() & DMG_PLASMA ) != 0 ) |
|
{ |
|
HandleRageGain( pAttacker, kRageBuffFlag_OnBurnDamageDealt, info.GetDamage(), 30.f ); |
|
} |
|
|
|
if ( pAttacker && info.GetWeapon() ) |
|
{ |
|
CTFWeaponBase *pWeapon = dynamic_cast<CTFWeaponBase *>( info.GetWeapon() ); |
|
if ( pWeapon ) |
|
{ |
|
pWeapon->ApplyOnHitAttributes( this, pAttacker, info ); |
|
} |
|
} |
|
} |
|
|
|
return BaseClass::OnTakeDamage( info ); |
|
} |
|
|
|
//-------------------------------------------------------------------------------------- |
|
int CTFBaseBoss::OnTakeDamage_Alive( const CTakeDamageInfo &rawInfo ) |
|
{ |
|
if ( !rawInfo.GetAttacker() || rawInfo.GetAttacker()->GetTeamNumber() == GetTeamNumber() ) |
|
{ |
|
// no friendly fire damage |
|
return 0; |
|
} |
|
|
|
CTakeDamageInfo info = rawInfo; |
|
|
|
// weapon-specific damage modification |
|
ModifyDamage( &info ); |
|
|
|
if ( TFGameRules() ) |
|
{ |
|
CTFGameRules::DamageModifyExtras_t outParams; |
|
info.SetDamage( TFGameRules()->ApplyOnDamageAliveModifyRules( info, this, outParams ) ); |
|
} |
|
|
|
// fire event for client combat text, beep, etc. |
|
IGameEvent *event = gameeventmanager->CreateEvent( "npc_hurt" ); |
|
if ( event ) |
|
{ |
|
|
|
event->SetInt( "entindex", entindex() ); |
|
event->SetInt( "health", MAX( 0, GetHealth() ) ); |
|
event->SetInt( "damageamount", info.GetDamage() ); |
|
event->SetBool( "crit", ( info.GetDamageType() & DMG_CRITICAL ) ? true : false ); |
|
|
|
CTFPlayer *attackerPlayer = ToTFPlayer( info.GetAttacker() ); |
|
if ( attackerPlayer ) |
|
{ |
|
event->SetInt( "attacker_player", attackerPlayer->GetUserID() ); |
|
|
|
if ( attackerPlayer->GetActiveTFWeapon() ) |
|
{ |
|
event->SetInt( "weaponid", attackerPlayer->GetActiveTFWeapon()->GetWeaponID() ); |
|
} |
|
else |
|
{ |
|
event->SetInt( "weaponid", 0 ); |
|
} |
|
} |
|
else |
|
{ |
|
// hurt by world |
|
event->SetInt( "attacker_player", 0 ); |
|
event->SetInt( "weaponid", 0 ); |
|
} |
|
|
|
gameeventmanager->FireEvent( event ); |
|
} |
|
|
|
int result = BaseClass::OnTakeDamage_Alive( info ); |
|
|
|
// emit injury outputs |
|
float healthPercentage = (float)GetHealth() / (float)GetMaxHealth(); |
|
|
|
if ( m_lastHealthPercentage > 0.9f && healthPercentage < 0.9f ) |
|
{ |
|
m_outputOnHealthBelow90Percent.FireOutput( this, this ); |
|
} |
|
else if ( m_lastHealthPercentage > 0.8f && healthPercentage < 0.8f ) |
|
{ |
|
m_outputOnHealthBelow80Percent.FireOutput( this, this ); |
|
} |
|
else if ( m_lastHealthPercentage > 0.7f && healthPercentage < 0.7f ) |
|
{ |
|
m_outputOnHealthBelow70Percent.FireOutput( this, this ); |
|
} |
|
else if ( m_lastHealthPercentage > 0.6f && healthPercentage < 0.6f ) |
|
{ |
|
m_outputOnHealthBelow60Percent.FireOutput( this, this ); |
|
} |
|
else if ( m_lastHealthPercentage > 0.5f && healthPercentage < 0.5f ) |
|
{ |
|
m_outputOnHealthBelow50Percent.FireOutput( this, this ); |
|
} |
|
else if ( m_lastHealthPercentage > 0.4f && healthPercentage < 0.4f ) |
|
{ |
|
m_outputOnHealthBelow40Percent.FireOutput( this, this ); |
|
} |
|
else if ( m_lastHealthPercentage > 0.3f && healthPercentage < 0.3f ) |
|
{ |
|
m_outputOnHealthBelow30Percent.FireOutput( this, this ); |
|
} |
|
else if ( m_lastHealthPercentage > 0.2f && healthPercentage < 0.2f ) |
|
{ |
|
m_outputOnHealthBelow20Percent.FireOutput( this, this ); |
|
} |
|
else if ( m_lastHealthPercentage > 0.1f && healthPercentage < 0.1f ) |
|
{ |
|
m_outputOnHealthBelow10Percent.FireOutput( this, this ); |
|
} |
|
|
|
m_lastHealthPercentage = healthPercentage; |
|
|
|
// Let attacker react to the damage they dealt |
|
CTFPlayer *pAttacker = ToTFPlayer( rawInfo.GetAttacker() ); |
|
if ( pAttacker ) |
|
{ |
|
pAttacker->OnDealtDamage( this, info ); |
|
|
|
CTF_GameStats.Event_BossDamage( pAttacker, info.GetDamage() ); |
|
} |
|
|
|
return result; |
|
} |
|
|
|
|
|
//-------------------------------------------------------------------------------------- |
|
void CTFBaseBoss::InputEnable( inputdata_t &inputdata ) |
|
{ |
|
m_isEnabled = true; |
|
} |
|
|
|
|
|
//-------------------------------------------------------------------------------------- |
|
void CTFBaseBoss::InputDisable( inputdata_t &inputdata ) |
|
{ |
|
m_isEnabled = false; |
|
} |
|
|
|
|
|
//------------------------------------------------------------------------------ |
|
void CTFBaseBoss::InputSetSpeed( inputdata_t &inputdata ) |
|
{ |
|
m_speed = inputdata.value.Float(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Set the health of the boss |
|
//----------------------------------------------------------------------------- |
|
void CTFBaseBoss::InputSetHealth( inputdata_t &inputdata ) |
|
{ |
|
m_iHealth = inputdata.value.Int(); |
|
SetHealth( m_iHealth ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Set the max health of the boss |
|
//----------------------------------------------------------------------------- |
|
void CTFBaseBoss::InputSetMaxHealth( inputdata_t &inputdata ) |
|
{ |
|
m_iMaxHealth = inputdata.value.Int(); |
|
SetMaxHealth( m_iMaxHealth ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Add health to the boss |
|
//----------------------------------------------------------------------------- |
|
void CTFBaseBoss::InputAddHealth( inputdata_t &inputdata ) |
|
{ |
|
int iHealth = inputdata.value.Int(); |
|
SetHealth( MIN( GetMaxHealth(), GetHealth() + iHealth ) ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Remove health from the boss |
|
//----------------------------------------------------------------------------- |
|
void CTFBaseBoss::InputRemoveHealth( inputdata_t &inputdata ) |
|
{ |
|
int iDamage = inputdata.value.Int(); |
|
|
|
SetHealth( GetHealth() - iDamage ); |
|
if ( GetHealth() <= 0 ) |
|
{ |
|
CTakeDamageInfo info( inputdata.pCaller, inputdata.pActivator, vec3_origin, GetAbsOrigin(), iDamage, DMG_GENERIC, TF_DMG_CUSTOM_NONE ); |
|
Event_Killed( info ); |
|
} |
|
}
|
|
|