diff options
| author | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
|---|---|---|
| committer | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
| commit | 3bf9df6b2785fa6d951086978a3e66f49427166a (patch) | |
| tree | 2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /game/server/tf/halloween/zombie/zombie_behavior | |
| download | archived-source-engine-2018-hl2-src-master.tar.xz archived-source-engine-2018-hl2-src-master.zip | |
Diffstat (limited to 'game/server/tf/halloween/zombie/zombie_behavior')
6 files changed, 483 insertions, 0 deletions
diff --git a/game/server/tf/halloween/zombie/zombie_behavior/zombie_attack.cpp b/game/server/tf/halloween/zombie/zombie_behavior/zombie_attack.cpp new file mode 100644 index 0000000..0438e05 --- /dev/null +++ b/game/server/tf/halloween/zombie/zombie_behavior/zombie_attack.cpp @@ -0,0 +1,303 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// +// +//============================================================================= +#include "cbase.h" + +#include "tf_player.h" +#include "tf_gamerules.h" +#include "tf_team.h" +#include "nav_mesh/tf_nav_area.h" + +#include "../zombie.h" +#include "zombie_attack.h" +#include "zombie_special_attack.h" + +#define ZOMBIE_CHASE_MIN_DURATION 3.0f + +ConVar tf_halloween_zombie_damage( "tf_halloween_zombie_damage", "10", FCVAR_CHEAT, "How much damage a zombie melee hit does." ); + + +//---------------------------------------------------------------------------------- +ActionResult< CZombie > CZombieAttack::OnStart( CZombie *me, Action< CZombie > *priorAction ) +{ + // smooth out the bot's path following by moving toward a point farther down the path + m_path.SetMinLookAheadDistance( 100.0f ); + + // start animation + me->GetBodyInterface()->StartActivity( ACT_MP_RUN_MELEE ); + + m_specialAttackTimer.Start( RandomFloat( 5.f, 10.f ) ); + + return Continue(); +} + + +//---------------------------------------------------------------------------------- +bool CZombieAttack::IsPotentiallyChaseable( CZombie *me, CBaseCombatCharacter *victim ) +{ + if ( !victim ) + { + return false; + } + + if ( !victim->IsAlive() ) + { + // victim is dead - pick a new one + return false; + } + + CTFNavArea *victimArea = (CTFNavArea *)victim->GetLastKnownArea(); + if ( !victimArea || victimArea->HasAttributeTF( TF_NAV_SPAWN_ROOM_BLUE | TF_NAV_SPAWN_ROOM_RED ) ) + { + // unreachable - pick a new victim + return false; + } + + if ( victim->GetGroundEntity() != NULL ) + { + Vector victimAreaPos; + victimArea->GetClosestPointOnArea( victim->GetAbsOrigin(), &victimAreaPos ); + if ( ( victim->GetAbsOrigin() - victimAreaPos ).AsVector2D().IsLengthGreaterThan( 50.0f ) ) + { + // off the mesh and unreachable - pick a new victim + return false; + } + } + + return true; +} + + +//---------------------------------------------------------------------------------- +void CZombieAttack::SelectVictim( CZombie *me ) +{ + if ( IsPotentiallyChaseable( me, m_attackTarget ) && !m_attackTargetFocusTimer.IsElapsed() ) + { + // Continue chasing current target + return; + } + + // pick a new victim to chase + CBaseCombatCharacter *newVictim = NULL; + CUtlVector< CTFPlayer * > playerVector; + + // collect everyone + if ( me->GetTeamNumber() == TF_TEAM_RED ) + { + CollectPlayers( &playerVector, TF_TEAM_BLUE, COLLECT_ONLY_LIVING_PLAYERS ); + } + else if ( me->GetTeamNumber() == TF_TEAM_BLUE ) + { + CollectPlayers( &playerVector, TF_TEAM_RED, COLLECT_ONLY_LIVING_PLAYERS ); + } + else + { + CollectPlayers( &playerVector, TF_TEAM_RED, COLLECT_ONLY_LIVING_PLAYERS ); + CollectPlayers( &playerVector, TF_TEAM_BLUE, COLLECT_ONLY_LIVING_PLAYERS, APPEND_PLAYERS ); + } + + float victimRangeSq = FLT_MAX; + // find closest player + for( int i=0; i<playerVector.Count(); ++i ) + { + CTFPlayer *pPlayer = playerVector[i]; + if ( !IsPotentiallyChaseable( me, pPlayer ) ) + { + continue; + } + + // ignore stealth player + if ( pPlayer->m_Shared.IsStealthed() ) + { + if ( !pPlayer->m_Shared.InCond( TF_COND_BURNING ) && + !pPlayer->m_Shared.InCond( TF_COND_URINE ) && + !pPlayer->m_Shared.InCond( TF_COND_STEALTHED_BLINK ) && + !pPlayer->m_Shared.InCond( TF_COND_BLEEDING ) ) + { + // cloaked spies are invisible to us + continue; + } + } + + // ignore player who disguises as my team + if ( pPlayer->m_Shared.InCond( TF_COND_DISGUISED ) && pPlayer->m_Shared.GetDisguiseTeam() == me->GetTeamNumber() ) + { + continue; + } + + // ignore ghost players + if ( pPlayer->m_Shared.InCond( TF_COND_HALLOWEEN_GHOST_MODE ) ) + { + continue; + } + + float rangeSq = me->GetRangeSquaredTo( pPlayer ); + if ( rangeSq < victimRangeSq ) + { + newVictim = pPlayer; + victimRangeSq = rangeSq; + } + } + + // find closest zombie + for ( int i=0; i<IZombieAutoList::AutoList().Count(); ++i ) + { + CZombie* pZombie = static_cast< CZombie* >( IZombieAutoList::AutoList()[i] ); + if ( pZombie->GetTeamNumber() == me->GetTeamNumber() ) + { + continue; + } + + if ( !IsPotentiallyChaseable( me, pZombie ) ) + { + continue; + } + + float rangeSq = me->GetRangeSquaredTo( pZombie ); + if ( rangeSq < victimRangeSq ) + { + newVictim = pZombie; + victimRangeSq = rangeSq; + } + } + + if ( newVictim ) + { + // we have a new victim + m_attackTargetFocusTimer.Start( ZOMBIE_CHASE_MIN_DURATION ); + } + + m_attackTarget = newVictim; +} + + +//---------------------------------------------------------------------------------- +ActionResult< CZombie > CZombieAttack::Update( CZombie *me, float interval ) +{ + if ( !me->IsAlive() ) + { + return Done(); + } + + if ( !m_tauntTimer.IsElapsed() ) + { + // wait for taunt to finish + return Continue(); + } + + SelectVictim( me ); + + if ( m_attackTarget == NULL || !m_attackTarget->IsAlive() ) + { + return Continue(); + } + + // chase after our chase victim + const float standAndSwingRange = 50.0f; + + bool isLineOfSightClear = me->IsLineOfSightClear( m_attackTarget ); + + if ( me->IsRangeGreaterThan( m_attackTarget, standAndSwingRange ) || !isLineOfSightClear ) + { + if ( m_path.GetAge() > 0.5f ) + { + CZombiePathCost cost( me ); + m_path.Compute( me, m_attackTarget, cost ); + } + + m_path.Update( me ); + } + + // claw at attack target if they are in range + const float zombieSwingRange = 150.0f; + if ( me->IsRangeLessThan( m_attackTarget, zombieSwingRange ) ) + { + me->GetLocomotionInterface()->FaceTowards( m_attackTarget->WorldSpaceCenter() ); + + // swing! + if ( !me->IsPlayingGesture( ACT_MP_ATTACK_STAND_MELEE ) ) + { + me->AddGesture( ACT_MP_ATTACK_STAND_MELEE ); + } + + const float zombieAttackRange = me->GetAttackRange(); + if ( me->IsRangeLessThan( m_attackTarget, zombieAttackRange ) ) + { + if ( me->GetSkeletonType() == 1 && m_specialAttackTimer.IsElapsed() ) + { + m_specialAttackTimer.Start( RandomFloat( 5.f, 10.f ) ); + return SuspendFor( new CZombieSpecialAttack, "Do Special Attack!" ); + } + + if ( m_attackTimer.IsElapsed() ) + { + m_attackTimer.Start( RandomFloat( 0.8f, 1.2f ) ); + + Vector toVictim = m_attackTarget->WorldSpaceCenter() - me->WorldSpaceCenter(); + toVictim.NormalizeInPlace(); + + // hit! + CBaseEntity *pAttacker = me->GetOwnerEntity() ? me->GetOwnerEntity() : me; + CTakeDamageInfo info( pAttacker, pAttacker, me->GetAttackDamage(), DMG_SLASH ); + info.SetDamageCustom( TF_DMG_CUSTOM_SPELL_SKELETON ); + CalculateMeleeDamageForce( &info, toVictim, me->WorldSpaceCenter(), 5.0f ); + m_attackTarget->TakeDamage( info ); + } + } + } + + if ( !me->GetBodyInterface()->IsActivity( ACT_MP_RUN_MELEE ) ) + { + me->GetBodyInterface()->StartActivity( ACT_MP_RUN_MELEE ); + } + + return Continue(); +} + + +//--------------------------------------------------------------------------------------------- +EventDesiredResult< CZombie > CZombieAttack::OnStuck( CZombie *me ) +{ + // if we're stuck just die + CTakeDamageInfo info( me, me, 99999.9f, DMG_SLASH ); + me->TakeDamage( info ); + + return TryContinue( RESULT_TRY ); +} + + +//--------------------------------------------------------------------------------------------- +EventDesiredResult< CZombie > CZombieAttack::OnContact( CZombie *me, CBaseEntity *other, CGameTrace *result ) +{ + if ( other->IsPlayer() ) + { + CTFPlayer *pTFPlayer = ToTFPlayer( other ); + if ( pTFPlayer ) + { + if ( pTFPlayer->IsAlive() && me->GetTeamNumber() != TF_TEAM_HALLOWEEN && me->GetTeamNumber() != pTFPlayer->GetTeamNumber() ) + { + // force attack the thing we bumped into + // this prevents us from being stuck on dispensers, for example + m_attackTarget = pTFPlayer; + m_attackTargetFocusTimer.Start( ZOMBIE_CHASE_MIN_DURATION ); + } + } + } + + return TryContinue( RESULT_TRY ); +} + + +//--------------------------------------------------------------------------------------------- +EventDesiredResult< CZombie > CZombieAttack::OnOtherKilled( CZombie *me, CBaseCombatCharacter *victim, const CTakeDamageInfo &info ) +{ + /*if ( victim && victim->IsPlayer() && me->GetLocomotionInterface()->IsOnGround() ) + { + me->AddGestureSequence( me->LookupSequence( "taunt06" ) ); + m_tauntTimer.Start( 3.0f ); + }*/ + + return TryContinue( RESULT_TRY ); +} diff --git a/game/server/tf/halloween/zombie/zombie_behavior/zombie_attack.h b/game/server/tf/halloween/zombie/zombie_behavior/zombie_attack.h new file mode 100644 index 0000000..476ffc0 --- /dev/null +++ b/game/server/tf/halloween/zombie/zombie_behavior/zombie_attack.h @@ -0,0 +1,36 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// +// +//============================================================================= +#ifndef ZOMBIE_ATTACK_H +#define ZOMBIE_ATTACK_H + +//--------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------- +class CZombieAttack : public Action< CZombie > +{ +public: + virtual ActionResult< CZombie > OnStart( CZombie *me, Action< CZombie > *priorAction ); + virtual ActionResult< CZombie > Update( CZombie *me, float interval ); + + virtual EventDesiredResult< CZombie > OnStuck( CZombie *me ); + virtual EventDesiredResult< CZombie > OnContact( CZombie *me, CBaseEntity *other, CGameTrace *result = NULL ); + virtual EventDesiredResult< CZombie > OnOtherKilled( CZombie *me, CBaseCombatCharacter *victim, const CTakeDamageInfo &info ); + + virtual const char *GetName( void ) const { return "Attack"; } // return name of this action + +private: + PathFollower m_path; + + CHandle< CBaseCombatCharacter > m_attackTarget; + CountdownTimer m_attackTimer; + CountdownTimer m_specialAttackTimer; + CountdownTimer m_attackTargetFocusTimer; + CountdownTimer m_tauntTimer; + + bool IsPotentiallyChaseable( CZombie *me, CBaseCombatCharacter *victim ); + void SelectVictim( CZombie *me ); +}; + +#endif // ZOMBIE_ATTACK_H diff --git a/game/server/tf/halloween/zombie/zombie_behavior/zombie_spawn.cpp b/game/server/tf/halloween/zombie/zombie_behavior/zombie_spawn.cpp new file mode 100644 index 0000000..87d8e43 --- /dev/null +++ b/game/server/tf/halloween/zombie/zombie_behavior/zombie_spawn.cpp @@ -0,0 +1,29 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// +// +//============================================================================= +#include "cbase.h" + +#include "tf_shareddefs.h" +#include "../zombie.h" +#include "zombie_attack.h" +#include "zombie_spawn.h" + +ActionResult< CZombie > CZombieSpawn::OnStart( CZombie *me, Action< CZombie > *priorAction ) +{ + me->GetBodyInterface()->StartActivity( ACT_TRANSITION ); + + return Continue(); +} + + +ActionResult< CZombie > CZombieSpawn::Update( CZombie *me, float interval ) +{ + if ( me->IsActivityFinished() ) + { + return ChangeTo( new CZombieAttack, "Start Attack!" ); + } + + return Continue(); +}
\ No newline at end of file diff --git a/game/server/tf/halloween/zombie/zombie_behavior/zombie_spawn.h b/game/server/tf/halloween/zombie/zombie_behavior/zombie_spawn.h new file mode 100644 index 0000000..863fee6 --- /dev/null +++ b/game/server/tf/halloween/zombie/zombie_behavior/zombie_spawn.h @@ -0,0 +1,22 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// +// +//============================================================================= +#ifndef ZOMBIE_SPAWN_H +#define ZOMBIE_SPAWN_H + +//--------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------- +class CZombieSpawn : public Action< CZombie > +{ +public: + virtual ActionResult< CZombie > OnStart( CZombie *me, Action< CZombie > *priorAction ); + virtual ActionResult< CZombie > Update( CZombie *me, float interval ); + + virtual const char *GetName( void ) const { return "Spawn"; } // return name of this action + +private: +}; + +#endif // ZOMBIE_SPAWN_H diff --git a/game/server/tf/halloween/zombie/zombie_behavior/zombie_special_attack.cpp b/game/server/tf/halloween/zombie/zombie_behavior/zombie_special_attack.cpp new file mode 100644 index 0000000..ee2ca3c --- /dev/null +++ b/game/server/tf/halloween/zombie/zombie_behavior/zombie_special_attack.cpp @@ -0,0 +1,68 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// +// +//============================================================================= +#include "cbase.h" + +#include "tf_player.h" +#include "tf_gamerules.h" +#include "tf_fx.h" + +#include "../zombie.h" +#include "zombie_special_attack.h" + +ActionResult< CZombie > CZombieSpecialAttack::OnStart( CZombie *me, Action< CZombie > *priorAction ) +{ + me->GetBodyInterface()->StartActivity( ACT_SPECIAL_ATTACK1 ); + + m_stompTimer.Start( 1 ); + + return Continue(); +} + + +ActionResult< CZombie > CZombieSpecialAttack::Update( CZombie *me, float interval ) +{ + if ( m_stompTimer.HasStarted() && m_stompTimer.IsElapsed() ) + { + DoSpecialAttack( me ); + m_stompTimer.Invalidate(); + } + + if ( me->IsActivityFinished() ) + { + return Done(); + } + + return Continue(); +} + + +void CZombieSpecialAttack::DoSpecialAttack( CZombie *me ) +{ + CPVSFilter filter( me->GetAbsOrigin() ); + TE_TFParticleEffect( filter, 0.0, "bomibomicon_ring", me->GetAbsOrigin(), vec3_angle ); + + int nTargetTeam = TEAM_ANY; + if ( me->GetTeamNumber() != TF_TEAM_HALLOWEEN ) + { + nTargetTeam = me->GetTeamNumber() == TF_TEAM_RED ? TF_TEAM_BLUE : TF_TEAM_RED; + } + + CUtlVector< CTFPlayer* > pushedPlayers; + TFGameRules()->PushAllPlayersAway( me->GetAbsOrigin(), 200.f, 500.f, nTargetTeam, &pushedPlayers ); + + CBaseEntity *pAttacker = me->GetOwnerEntity() ? me->GetOwnerEntity() : me; + for ( int i=0; i<pushedPlayers.Count(); ++i ) + { + Vector toVictim = pushedPlayers[i]->WorldSpaceCenter() - me->WorldSpaceCenter(); + toVictim.NormalizeInPlace(); + + // hit! + CTakeDamageInfo info( pAttacker, pAttacker, me->GetAttackDamage(), DMG_SLASH ); + info.SetDamageCustom( TF_DMG_CUSTOM_SPELL_SKELETON ); + CalculateMeleeDamageForce( &info, toVictim, me->WorldSpaceCenter(), 5.0f ); + pushedPlayers[i]->TakeDamage( info ); + } +} diff --git a/game/server/tf/halloween/zombie/zombie_behavior/zombie_special_attack.h b/game/server/tf/halloween/zombie/zombie_behavior/zombie_special_attack.h new file mode 100644 index 0000000..b8689fb --- /dev/null +++ b/game/server/tf/halloween/zombie/zombie_behavior/zombie_special_attack.h @@ -0,0 +1,25 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// +// +//============================================================================= +#ifndef ZOMBIE_SPECIAL_ATTACK_H +#define ZOMBIE_SPECIAL_ATTACK_H + +//--------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------- +class CZombieSpecialAttack : public Action< CZombie > +{ +public: + virtual ActionResult< CZombie > OnStart( CZombie *me, Action< CZombie > *priorAction ); + virtual ActionResult< CZombie > Update( CZombie *me, float interval ); + + virtual const char *GetName( void ) const { return "Special Attack"; } // return name of this action +private: + + void DoSpecialAttack( CZombie *me ); + + CountdownTimer m_stompTimer; +}; + +#endif // ZOMBIE_SPECIAL_ATTACK_H |