summaryrefslogtreecommitdiff
path: root/game/server/tf/bot/behavior/scenario/raid/tf_bot_wander.cpp
blob: ffd08f4d3fd5990cc55fc1e7da9736996ad0cf29 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
//========= Copyright Valve Corporation, All rights reserved. ============//
// tf_bot_wander.cpp
// Wanderering/idle enemies for Squad Co-op mode
// Michael Booth, October 2009

#include "cbase.h"

#ifdef TF_RAID_MODE

#include "team.h"
#include "raid/tf_raid_logic.h"
#include "bot/tf_bot.h"
#include "bot/behavior/scenario/raid/tf_bot_wander.h"
#include "bot/behavior/scenario/raid/tf_bot_mob_rush.h"


ConVar tf_raid_wanderer_aggro_range( "tf_raid_wanderer_aggro_range", "500", FCVAR_CHEAT, "If wanderers see a threat closer than this, they attack" );
ConVar tf_raid_wanderer_notice_friend_death_range( "tf_raid_wanderer_notice_friend_death_range", "1000", FCVAR_CHEAT, "If a friend dies within this radius of a wanderer, it wakes up and attacks the attacker" );
ConVar tf_raid_wanderer_reaction_factor( "tf_raid_wanderer_reaction_factor", "1", FCVAR_CHEAT );
ConVar tf_raid_wanderer_vocalize_min_interval( "tf_raid_wanderer_vocalize_min_interval", "20", FCVAR_CHEAT );
ConVar tf_raid_wanderer_vocalize_max_interval( "tf_raid_wanderer_vocalize_max_interval", "30", FCVAR_CHEAT );


//---------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------
CTFBotWander::CTFBotWander( void )
{
}


//---------------------------------------------------------------------------------------------
ActionResult< CTFBot >	CTFBotWander::OnStart( CTFBot *me, Action< CTFBot > *priorAction )
{
	m_vocalizeTimer.Start( RandomFloat( tf_raid_wanderer_vocalize_min_interval.GetFloat(), tf_raid_wanderer_vocalize_max_interval.GetFloat() ) );

	return Continue();
}


//---------------------------------------------------------------------------------------------
ActionResult< CTFBot >	CTFBotWander::Update( CTFBot *me, float interval )
{
	// mobs use only their melee weapons
	CBaseCombatWeapon *meleeWeapon = me->Weapon_GetSlot( TF_WPN_TYPE_MELEE );
	if ( meleeWeapon )
	{
		me->Weapon_Switch( meleeWeapon );
	}


	CTeam *raidingTeam = GetGlobalTeam( TF_TEAM_BLUE );

	if ( me->HasAttribute( CTFBot::AGGRESSIVE ) )
	{
		// I'm a mob rusher - pick a random raider and attack them!
		CTFPlayer *victim = TFGameRules()->GetRaidLogic()->SelectRaiderToAttack();
		if ( victim )
		{
			return SuspendFor( new CTFBotMobRush( victim ), "Rushing a raider" );
		}
	}
	else if ( m_visionTimer.IsElapsed() )
	{
		// I'm a wanderer - look for very nearby threats
		m_visionTimer.Start( RandomFloat( 0.5f, 1.0f ) );

		// find closest visible raider within aggro range
		CTFPlayer *threat = NULL;
		float closeThreatRangeSq = tf_raid_wanderer_aggro_range.GetFloat() * tf_raid_wanderer_aggro_range.GetFloat();

		for( int i=0; i<raidingTeam->GetNumPlayers(); ++i )
		{
			CTFPlayer *player = (CTFPlayer *)raidingTeam->GetPlayer(i);

			if ( !player->IsAlive() )
				continue;

			float rangeSq = me->GetRangeSquaredTo( player );
			if ( rangeSq < closeThreatRangeSq )
			{
				if ( me->GetVisionInterface()->IsLineOfSightClearToEntity( player ) )
				{
					threat = player;
					closeThreatRangeSq = rangeSq;
				}
			}
		}

		if ( threat )
		{
			return SuspendFor( new CTFBotMobRush( threat ), "Attacking threat!" );
		}
	}

	if ( m_vocalizeTimer.IsElapsed() )
	{
		m_vocalizeTimer.Start( RandomFloat( tf_raid_wanderer_vocalize_min_interval.GetFloat(), tf_raid_wanderer_vocalize_max_interval.GetFloat() ) );

		// mouth off
		if ( me->IsPlayerClass( TF_CLASS_SCOUT ) )
			me->EmitSound( "Scout.WanderJabber" );
		else
			me->SpeakConceptIfAllowed( MP_CONCEPT_PLAYER_JEERS );
	}

	return Continue();
}


//---------------------------------------------------------------------------------------------
EventDesiredResult< CTFBot > CTFBotWander::OnContact( CTFBot *me, CBaseEntity *other, CGameTrace *result  )
{
	if ( other && other->IsPlayer() && me->IsEnemy( other ) )
	{
		return TrySuspendFor( new CTFBotMobRush( (CTFPlayer *)other ), RESULT_IMPORTANT, "Attacking threat who touched me!" );
	}

	return TryContinue();
}


//---------------------------------------------------------------------------------------------
EventDesiredResult< CTFBot > CTFBotWander::OnInjured( CTFBot *me, const CTakeDamageInfo &info )
{
	if ( info.GetAttacker() && info.GetAttacker()->IsPlayer() && me->IsEnemy( info.GetAttacker() ) )
	{
		return TrySuspendFor( new CTFBotMobRush( (CTFPlayer *)info.GetAttacker() ), RESULT_IMPORTANT, "Attacking threat who attacked me!" );
	}

	return TryContinue();
}


//---------------------------------------------------------------------------------------------
EventDesiredResult< CTFBot > CTFBotWander::OnOtherKilled( CTFBot *me, CBaseCombatCharacter *victim, const CTakeDamageInfo &info )
{
	if ( victim && me->IsFriend( victim ) )
	{
		if ( info.GetAttacker() && info.GetAttacker()->IsPlayer() && me->IsEnemy( info.GetAttacker() ) )
		{
			if ( me->IsRangeLessThan( victim, tf_raid_wanderer_notice_friend_death_range.GetFloat() ) )
			{
				if ( me->GetVisionInterface()->IsAbleToSee( victim, IVision::DISREGARD_FOV ) && 
					 me->GetVisionInterface()->IsAbleToSee( info.GetAttacker(), IVision::DISREGARD_FOV ) )
				{
					float rangeToAttacker = me->GetRangeTo( info.GetAttacker() );
					float reactionTime;

					if ( rangeToAttacker < tf_raid_wanderer_aggro_range.GetFloat() )
					{
						reactionTime = 0.0f;
					}
					else
					{
						reactionTime = tf_raid_wanderer_reaction_factor.GetFloat() * ( rangeToAttacker - tf_raid_wanderer_aggro_range.GetFloat() ) / tf_raid_wanderer_aggro_range.GetFloat();
					}

					return TrySuspendFor( new CTFBotMobRush( (CTFPlayer *)info.GetAttacker(), reactionTime ), RESULT_IMPORTANT, "Attacking my friend's attacker!" );
				}
			}
		}
	}

	return TryContinue();
}


//---------------------------------------------------------------------------------------------
EventDesiredResult< CTFBot > CTFBotWander::OnCommandAttack( CTFBot *me, CBaseEntity *victim )
{
	return TryContinue();
}


#endif // TF_RAID_MODE