2015-06-04 11:52:48 +03:00
//
2014-09-09 18:29:42 +04:00
// Yet Another POD-Bot, based on PODBot by Markus Klinge ("CountFloyd").
// Copyright (c) YaPB Development Team.
2014-07-30 14:17:46 +04:00
//
2014-09-09 18:29:42 +04:00
// This software is licensed under the BSD-style license.
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
// http://yapb.jeefo.net/license
2014-07-30 14:17:46 +04:00
//
# include <core.h>
2016-01-16 11:00:40 +03:00
ConVar yb_whose_your_daddy ( " yb_whose_your_daddy " , " 0 " ) ;
2015-06-24 15:38:48 +03:00
2014-07-30 14:17:46 +04:00
int Bot : : FindGoal ( void )
{
// chooses a destination (goal) waypoint for a bot
2015-06-04 11:52:48 +03:00
if ( ! g_bombPlanted & & m_team = = TEAM_TF & & ( g_mapType & MAP_DE ) )
2014-07-30 14:17:46 +04:00
{
edict_t * pent = NULL ;
2015-06-04 11:52:48 +03:00
while ( ! IsEntityNull ( pent = FIND_ENTITY_BY_STRING ( pent , " classname " , " weaponbox " ) ) )
2014-07-30 14:17:46 +04:00
{
if ( strcmp ( STRING ( pent - > v . model ) , " models/w_backpack.mdl " ) = = 0 )
{
2015-07-24 15:10:51 +03:00
int index = waypoints . FindNearest ( GetEntityOrigin ( pent ) ) ;
2014-07-30 14:17:46 +04:00
if ( index > = 0 & & index < g_numWaypoints )
2015-06-04 11:52:48 +03:00
return m_loosedBombWptIndex = index ;
2014-07-30 14:17:46 +04:00
break ;
}
}
}
2015-06-04 11:52:48 +03:00
int tactic ;
2014-07-30 14:17:46 +04:00
// path finding behaviour depending on map type
2015-06-09 22:16:08 +03:00
float offensive ;
float defensive ;
2014-07-30 14:17:46 +04:00
2015-06-09 22:16:08 +03:00
float goalDesire ;
float forwardDesire ;
float campDesire ;
float backoffDesire ;
float tacticChoice ;
2014-07-30 14:17:46 +04:00
Array < int > offensiveWpts ;
Array < int > defensiveWpts ;
2014-08-06 00:03:50 +04:00
switch ( m_team )
2014-07-30 14:17:46 +04:00
{
case TEAM_TF :
2015-07-24 15:10:51 +03:00
offensiveWpts = waypoints . m_ctPoints ;
defensiveWpts = waypoints . m_terrorPoints ;
2014-07-30 14:17:46 +04:00
break ;
case TEAM_CF :
2015-07-24 15:10:51 +03:00
offensiveWpts = waypoints . m_terrorPoints ;
defensiveWpts = waypoints . m_ctPoints ;
2014-07-30 14:17:46 +04:00
break ;
}
// terrorist carrying the C4?
2014-09-17 20:36:42 +04:00
if ( m_hasC4 | | m_isVIP )
2014-07-30 14:17:46 +04:00
{
tactic = 3 ;
goto TacticChoosen ;
}
2015-06-04 11:52:48 +03:00
else if ( m_team = = TEAM_CF & & HasHostage ( ) )
2014-07-30 14:17:46 +04:00
{
tactic = 2 ;
2015-07-24 15:10:51 +03:00
offensiveWpts = waypoints . m_rescuePoints ;
2014-07-30 14:17:46 +04:00
goto TacticChoosen ;
}
2015-08-15 18:09:15 +03:00
offensive = m_agressionLevel * 100.0f ;
defensive = m_fearLevel * 100.0f ;
2014-07-30 14:17:46 +04:00
if ( g_mapType & ( MAP_AS | MAP_CS ) )
{
2014-08-06 00:03:50 +04:00
if ( m_team = = TEAM_TF )
2014-07-30 14:17:46 +04:00
{
defensive + = 25.0f ;
offensive - = 25.0f ;
}
2014-08-06 00:03:50 +04:00
else if ( m_team = = TEAM_CF )
2014-07-30 14:17:46 +04:00
{
2015-06-09 22:16:08 +03:00
// on hostage maps force more bots to save hostages
if ( g_mapType & MAP_CS )
{
defensive - = 25.0f - m_difficulty * 0.5f ;
offensive + = 25.0f + m_difficulty * 5.0f ;
}
else // on AS leave as is
{
defensive - = 25.0f ;
offensive + = 25.0f ;
}
2014-07-30 14:17:46 +04:00
}
}
2014-08-06 00:03:50 +04:00
else if ( ( g_mapType & MAP_DE ) & & m_team = = TEAM_CF )
2014-07-30 14:17:46 +04:00
{
2015-08-15 18:09:15 +03:00
if ( g_bombPlanted & & GetTaskId ( ) ! = TASK_ESCAPEFROMBOMB & & ! waypoints . GetBombPosition ( ) . IsZero ( ) )
2014-07-30 14:17:46 +04:00
{
if ( g_bombSayString )
{
ChatMessage ( CHAT_BOMBPLANT ) ;
g_bombSayString = false ;
}
return m_chosenGoalIndex = ChooseBombWaypoint ( ) ;
}
2015-07-31 20:32:08 +03:00
defensive + = 25.0f + m_difficulty * 2.0f ;
offensive - = 25.0f - m_difficulty * 0.5f ;
2015-07-17 19:23:31 +03:00
if ( m_personality ! = PERSONALITY_RUSHER )
defensive + = 10.0f ;
2014-07-30 14:17:46 +04:00
}
2014-09-17 20:36:42 +04:00
else if ( ( g_mapType & MAP_DE ) & & m_team = = TEAM_TF & & g_timeRoundStart + 10.0f < GetWorldTime ( ) )
2014-07-30 14:17:46 +04:00
{
2016-01-04 18:26:06 +03:00
// send some terrorists to guard planted bomb
if ( ! m_defendedBomb & & g_bombPlanted & & GetTaskId ( ) ! = TASK_ESCAPEFROMBOMB & & GetBombTimeleft ( ) > = 15.0 )
2015-07-24 15:10:51 +03:00
return m_chosenGoalIndex = FindDefendWaypoint ( waypoints . GetBombPosition ( ) ) ;
2014-07-30 14:17:46 +04:00
}
2015-06-09 22:16:08 +03:00
goalDesire = Random . Float ( 0.0f , 100.0f ) + offensive ;
forwardDesire = Random . Float ( 0.0f , 100.0f ) + offensive ;
campDesire = Random . Float ( 0.0f , 100.0f ) + defensive ;
backoffDesire = Random . Float ( 0.0f , 100.0f ) + defensive ;
2014-07-30 14:17:46 +04:00
2014-09-17 20:36:42 +04:00
if ( ! UsesCampGun ( ) )
2015-07-17 19:23:31 +03:00
campDesire * = 0.5f ;
2014-09-17 20:36:42 +04:00
2014-07-30 14:17:46 +04:00
tacticChoice = backoffDesire ;
tactic = 0 ;
if ( campDesire > tacticChoice )
{
tacticChoice = campDesire ;
tactic = 1 ;
}
2015-06-04 11:52:48 +03:00
2014-07-30 14:17:46 +04:00
if ( forwardDesire > tacticChoice )
{
tacticChoice = forwardDesire ;
tactic = 2 ;
}
2015-06-04 11:52:48 +03:00
2014-07-30 14:17:46 +04:00
if ( goalDesire > tacticChoice )
tactic = 3 ;
TacticChoosen :
int goalChoices [ 4 ] = { - 1 , - 1 , - 1 , - 1 } ;
if ( tactic = = 0 & & ! defensiveWpts . IsEmpty ( ) ) // careful goal
2015-06-09 22:16:08 +03:00
FilterGoals ( defensiveWpts , goalChoices ) ;
2015-07-24 15:10:51 +03:00
else if ( tactic = = 1 & & ! waypoints . m_campPoints . IsEmpty ( ) ) // camp waypoint goal
2014-07-30 14:17:46 +04:00
{
// pickup sniper points if possible for sniping bots
2015-07-24 15:10:51 +03:00
if ( ! waypoints . m_sniperPoints . IsEmpty ( ) & & UsesSniper ( ) )
FilterGoals ( waypoints . m_sniperPoints , goalChoices ) ;
2014-07-30 14:17:46 +04:00
else
2015-07-24 15:10:51 +03:00
FilterGoals ( waypoints . m_campPoints , goalChoices ) ;
2014-07-30 14:17:46 +04:00
}
else if ( tactic = = 2 & & ! offensiveWpts . IsEmpty ( ) ) // offensive goal
2015-06-09 22:16:08 +03:00
FilterGoals ( offensiveWpts , goalChoices ) ;
2015-07-24 15:10:51 +03:00
else if ( tactic = = 3 & & ! waypoints . m_goalPoints . IsEmpty ( ) ) // map goal waypoint
2014-07-30 14:17:46 +04:00
{
2015-08-02 20:31:14 +03:00
// force bomber to select closest goal, if round-start goal was reset by something
2016-01-05 20:29:34 +03:00
if ( m_hasC4 & & g_timeRoundStart + 10.0f < GetWorldTime ( ) )
2014-07-30 14:17:46 +04:00
{
2016-01-05 20:29:34 +03:00
float minDist = 99999.0f ;
2015-06-06 14:19:19 +03:00
int count = 0 ;
2016-01-05 20:29:34 +03:00
FOR_EACH_AE ( waypoints . m_goalPoints , i )
2015-06-06 14:19:19 +03:00
{
2016-01-05 20:29:34 +03:00
Path * path = waypoints . GetPath ( waypoints . m_goalPoints [ i ] ) ;
2015-06-06 14:19:19 +03:00
2016-01-05 20:29:34 +03:00
float distance = ( path - > origin - pev - > origin ) . GetLength ( ) ;
2015-06-06 14:19:19 +03:00
2016-01-05 20:29:34 +03:00
if ( distance > 1024.0f )
continue ;
2015-06-06 14:19:19 +03:00
if ( distance < minDist )
{
2016-01-05 20:29:34 +03:00
goalChoices [ count ] = i ;
if ( + + count > 3 )
count = 0 ;
2015-06-06 14:19:19 +03:00
minDist = distance ;
}
}
for ( int i = 0 ; i < 4 ; i + + )
{
if ( goalChoices [ i ] = = - 1 )
{
2015-07-24 15:10:51 +03:00
goalChoices [ i ] = waypoints . m_goalPoints . GetRandomElement ( ) ;
2015-06-06 14:19:19 +03:00
InternalAssert ( goalChoices [ i ] > = 0 & & goalChoices [ i ] < g_numWaypoints ) ;
}
}
2015-06-04 11:52:48 +03:00
}
else
2015-07-24 15:10:51 +03:00
FilterGoals ( waypoints . m_goalPoints , goalChoices ) ;
2014-07-30 14:17:46 +04:00
}
if ( m_currentWaypointIndex = = - 1 | | m_currentWaypointIndex > = g_numWaypoints )
2015-07-24 15:10:51 +03:00
m_currentWaypointIndex = ChangeWptIndex ( waypoints . FindNearest ( pev - > origin ) ) ;
2014-07-30 14:17:46 +04:00
if ( goalChoices [ 0 ] = = - 1 )
2015-06-09 15:45:34 +03:00
return m_chosenGoalIndex = Random . Long ( 0 , g_numWaypoints - 1 ) ;
2014-07-30 14:17:46 +04:00
bool isSorting = false ;
do
{
isSorting = false ;
for ( int i = 0 ; i < 3 ; i + + )
{
int testIndex = goalChoices [ i + 1 ] ;
if ( testIndex < 0 )
break ;
2015-06-09 22:16:08 +03:00
int goal1 = m_team = = TEAM_TF ? ( g_experienceData + ( m_currentWaypointIndex * g_numWaypoints ) + goalChoices [ i ] ) - > team0Value : ( g_experienceData + ( m_currentWaypointIndex * g_numWaypoints ) + goalChoices [ i ] ) - > team1Value ;
int goal2 = m_team = = TEAM_TF ? ( g_experienceData + ( m_currentWaypointIndex * g_numWaypoints ) + goalChoices [ i + 1 ] ) - > team0Value : ( g_experienceData + ( m_currentWaypointIndex * g_numWaypoints ) + goalChoices [ i + 1 ] ) - > team1Value ;
2014-07-30 14:17:46 +04:00
2015-06-09 22:16:08 +03:00
if ( goal1 < goal2 )
2014-07-30 14:17:46 +04:00
{
2015-06-09 22:16:08 +03:00
goalChoices [ i + 1 ] = goalChoices [ i ] ;
goalChoices [ i ] = testIndex ;
2014-07-30 14:17:46 +04:00
2015-06-09 22:16:08 +03:00
isSorting = true ;
2014-07-30 14:17:46 +04:00
}
}
} while ( isSorting ) ;
2015-06-09 22:16:08 +03:00
return m_chosenGoalIndex = goalChoices [ 0 ] ; // return and store goal
}
void Bot : : FilterGoals ( const Array < int > & goals , int * result )
{
// this function filters the goals, so new goal is not bot's old goal, and array of goals doesn't contains duplicate goals
int searchCount = 0 ;
for ( int index = 0 ; index < 4 ; index + + )
{
int rand = goals . GetRandomElement ( ) ;
2015-08-01 00:18:50 +03:00
if ( searchCount < = 8 & & ( m_prevGoalIndex = = rand | | ( ( result [ 0 ] = = rand | | result [ 1 ] = = rand | | result [ 2 ] = = rand | | result [ 3 ] = = rand ) & & goals . GetElementNumber ( ) > 4 ) ) & & ! IsPointOccupied ( rand ) )
2015-06-09 22:16:08 +03:00
{
if ( index > 0 )
index - - ;
2015-06-24 15:38:48 +03:00
searchCount + + ;
2015-06-09 22:16:08 +03:00
continue ;
}
result [ index ] = rand ;
}
2014-07-30 14:17:46 +04:00
}
bool Bot : : GoalIsValid ( void )
{
int goal = GetTask ( ) - > data ;
if ( goal = = - 1 ) // not decided about a goal
return false ;
else if ( goal = = m_currentWaypointIndex ) // no nodes needed
return true ;
else if ( m_navNode = = NULL ) // no path calculated
return false ;
// got path - check if still valid
PathNode * node = m_navNode ;
while ( node - > next ! = NULL )
node = node - > next ;
if ( node - > index = = goal )
return true ;
return false ;
}
2015-06-24 17:25:39 +03:00
void Bot : : ResetCollideState ( void )
{
2015-08-15 18:09:15 +03:00
m_collideTime = 0.0f ;
m_probeTime = 0.0f ;
2015-06-24 17:25:39 +03:00
m_collisionProbeBits = 0 ;
m_collisionState = COLLISION_NOTDECICED ;
m_collStateIndex = 0 ;
for ( int i = 0 ; i < MAX_COLLIDE_MOVES ; i + + )
m_collideMoves [ i ] = 0 ;
}
2015-07-20 21:26:20 +03:00
void Bot : : IgnoreCollisionShortly ( void )
{
ResetCollideState ( ) ;
m_lastCollTime = GetWorldTime ( ) + 0.35f ;
m_isStuck = false ;
m_checkTerrain = false ;
}
2015-07-01 00:47:39 +03:00
void Bot : : CheckCloseAvoidance ( const Vector & dirNormal )
2015-06-04 11:52:48 +03:00
{
2015-07-20 21:26:20 +03:00
if ( m_seeEnemyTime + 1.5f < GetWorldTime ( ) )
2015-07-01 00:47:39 +03:00
return ;
2015-06-04 11:52:48 +03:00
2015-07-01 00:47:39 +03:00
edict_t * nearest = NULL ;
float nearestDist = 99999.0f ;
int playerCount = 0 ;
2015-06-07 19:43:16 +03:00
2015-07-01 00:47:39 +03:00
for ( int i = 0 ; i < GetMaxClients ( ) ; i + + )
{
Client * cl = & g_clients [ i ] ;
2015-06-04 11:52:48 +03:00
2015-07-01 00:51:50 +03:00
if ( ! ( cl - > flags & ( CF_USED | CF_ALIVE ) ) | | cl - > ent = = GetEntity ( ) | | cl - > team ! = m_team )
2015-07-01 00:47:39 +03:00
continue ;
2015-06-04 11:52:48 +03:00
2015-07-01 00:47:39 +03:00
float distance = ( cl - > ent - > v . origin - pev - > origin ) . GetLength ( ) ;
if ( distance < nearestDist & & distance < pev - > maxspeed )
{
nearestDist = distance ;
nearest = cl - > ent ;
playerCount + + ;
}
}
2015-07-20 21:26:20 +03:00
if ( playerCount < 4 & & IsValidPlayer ( nearest ) )
2015-06-04 11:52:48 +03:00
{
MakeVectors ( m_moveAngles ) ; // use our movement angles
// try to predict where we should be next frame
Vector moved = pev - > origin + g_pGlobals - > v_forward * m_moveSpeed * m_frameInterval ;
2015-07-01 00:47:39 +03:00
moved + = g_pGlobals - > v_right * m_strafeSpeed * m_frameInterval ;
moved + = pev - > velocity * m_frameInterval ;
2015-06-04 11:52:48 +03:00
2015-06-09 15:45:34 +03:00
float nearestDistance = ( nearest - > v . origin - pev - > origin ) . GetLength2D ( ) ;
float nextFrameDistance = ( ( nearest - > v . origin + nearest - > v . velocity * m_frameInterval ) - pev - > origin ) . GetLength2D ( ) ;
2015-06-04 11:52:48 +03:00
// is player that near now or in future that we need to steer away?
2015-08-15 18:09:15 +03:00
if ( ( nearest - > v . origin - moved ) . GetLength2D ( ) < = 48.0f | | ( nearestDistance < = 56.0f & & nextFrameDistance < nearestDistance ) )
2015-06-04 11:52:48 +03:00
{
// to start strafing, we have to first figure out if the target is on the left side or right side
2015-07-20 21:26:20 +03:00
const Vector & dirToPoint = ( pev - > origin - nearest - > v . origin ) . Get2D ( ) ;
2015-06-04 11:52:48 +03:00
2015-07-20 21:26:20 +03:00
if ( ( dirToPoint | g_pGlobals - > v_right . Get2D ( ) ) > 0.0f )
2015-07-01 00:47:39 +03:00
SetStrafeSpeed ( dirNormal , pev - > maxspeed ) ;
2015-06-04 11:52:48 +03:00
else
2015-07-01 00:47:39 +03:00
SetStrafeSpeed ( dirNormal , - pev - > maxspeed ) ;
2015-06-04 11:52:48 +03:00
2015-08-15 18:09:15 +03:00
if ( nearestDistance < 56.0f & & ( dirToPoint | g_pGlobals - > v_forward . Get2D ( ) ) < 0.0f )
2015-06-04 11:52:48 +03:00
m_moveSpeed = - pev - > maxspeed ;
}
}
2015-07-01 00:47:39 +03:00
}
void Bot : : CheckTerrain ( float movedDistance , const Vector & dirNormal )
{
m_isStuck = false ;
TraceResult tr ;
CheckCloseAvoidance ( dirNormal ) ;
2015-06-04 11:52:48 +03:00
// Standing still, no need to check?
// FIXME: doesn't care for ladder movement (handled separately) should be included in some way
2015-08-15 18:09:15 +03:00
if ( ( m_moveSpeed > = 10.0f | | m_strafeSpeed > = 10.0f ) & & m_lastCollTime < GetWorldTime ( ) & & m_seeEnemyTime + 0.8f < GetWorldTime ( ) & & GetTaskId ( ) ! = TASK_ATTACK )
2015-06-04 11:52:48 +03:00
{
2015-06-24 15:38:48 +03:00
bool cantMoveForward = false ;
2015-07-20 21:26:20 +03:00
if ( movedDistance < 2.0f & & m_prevSpeed > = 20.0f ) // didn't we move enough previously?
2015-06-04 11:52:48 +03:00
{
// Then consider being stuck
m_prevTime = GetWorldTime ( ) ;
m_isStuck = true ;
if ( m_firstCollideTime = = 0.0 )
2015-07-20 21:26:20 +03:00
m_firstCollideTime = GetWorldTime ( ) + 0.2f ;
2015-06-04 11:52:48 +03:00
}
else // not stuck yet
{
// test if there's something ahead blocking the way
2015-07-01 00:47:39 +03:00
if ( ( cantMoveForward = CantMoveForward ( dirNormal , & tr ) ) & & ! IsOnLadder ( ) )
2015-06-04 11:52:48 +03:00
{
2015-08-15 18:09:15 +03:00
if ( m_firstCollideTime = = 0.0f )
2015-07-20 21:26:20 +03:00
m_firstCollideTime = GetWorldTime ( ) + 0.2f ;
2015-06-04 11:52:48 +03:00
else if ( m_firstCollideTime < = GetWorldTime ( ) )
m_isStuck = true ;
}
else
2015-08-15 18:09:15 +03:00
m_firstCollideTime = 0.0f ;
2015-06-04 11:52:48 +03:00
}
if ( ! m_isStuck ) // not stuck?
{
2015-07-01 00:47:39 +03:00
if ( m_probeTime + 0.5f < GetWorldTime ( ) )
2015-06-04 11:52:48 +03:00
ResetCollideState ( ) ; // reset collision memory if not being stuck for 0.5 secs
else
{
// remember to keep pressing duck if it was necessary ago
2015-06-24 15:38:48 +03:00
if ( m_collideMoves [ m_collStateIndex ] = = COLLISION_DUCK & & ( IsOnFloor ( ) | | IsInWater ( ) ) )
2015-06-04 11:52:48 +03:00
pev - > button | = IN_DUCK ;
}
2015-06-07 19:43:16 +03:00
return ;
2015-06-04 11:52:48 +03:00
}
2015-06-07 19:43:16 +03:00
// bot is stuck!
2015-08-15 18:09:15 +03:00
Vector src ;
Vector dst ;
2015-06-07 19:43:16 +03:00
// not yet decided what to do?
if ( m_collisionState = = COLLISION_NOTDECICED )
2015-06-04 11:52:48 +03:00
{
2015-06-24 17:25:39 +03:00
int bits = 0 ;
2015-06-07 19:43:16 +03:00
if ( IsOnLadder ( ) )
2015-06-29 20:51:25 +03:00
bits | = PROBE_STRAFE ;
2015-06-07 19:43:16 +03:00
else if ( IsInWater ( ) )
2015-06-29 20:51:25 +03:00
bits | = ( PROBE_JUMP | PROBE_STRAFE ) ;
2015-06-07 19:43:16 +03:00
else
2015-07-22 19:14:07 +03:00
bits | = ( PROBE_STRAFE | ( m_jumpStateTimer < GetWorldTime ( ) ? PROBE_JUMP : 0 ) ) ;
2015-06-07 19:43:16 +03:00
// collision check allowed if not flying through the air
if ( IsOnFloor ( ) | | IsOnLadder ( ) | | IsInWater ( ) )
2015-06-04 11:52:48 +03:00
{
2015-12-26 17:19:20 +03:00
char state [ MAX_COLLIDE_MOVES * 2 + 1 ] ;
2015-06-07 19:43:16 +03:00
int i = 0 ;
2015-06-04 11:52:48 +03:00
2015-06-07 19:43:16 +03:00
// first 4 entries hold the possible collision states
state [ i + + ] = COLLISION_STRAFELEFT ;
state [ i + + ] = COLLISION_STRAFERIGHT ;
2015-07-20 21:26:20 +03:00
state [ i + + ] = COLLISION_JUMP ;
2015-12-26 17:19:20 +03:00
// state[i++] = COLLISION_DUCK;
2015-06-04 11:52:48 +03:00
2015-06-07 19:43:16 +03:00
if ( bits & PROBE_STRAFE )
{
state [ i ] = 0 ;
state [ i + 1 ] = 0 ;
2015-06-04 11:52:48 +03:00
2015-06-07 19:43:16 +03:00
// to start strafing, we have to first figure out if the target is on the left side or right side
MakeVectors ( m_moveAngles ) ;
2015-06-04 11:52:48 +03:00
2015-06-07 19:43:16 +03:00
Vector dirToPoint = ( pev - > origin - m_destOrigin ) . Normalize2D ( ) ;
Vector rightSide = g_pGlobals - > v_right . Normalize2D ( ) ;
2015-06-04 11:52:48 +03:00
2015-06-07 19:43:16 +03:00
bool dirRight = false ;
bool dirLeft = false ;
bool blockedLeft = false ;
bool blockedRight = false ;
2015-06-04 11:52:48 +03:00
2015-08-15 18:09:15 +03:00
if ( ( dirToPoint | rightSide ) > 0.0f )
2015-06-07 19:43:16 +03:00
dirRight = true ;
else
dirLeft = true ;
2015-06-04 11:52:48 +03:00
2015-07-01 00:47:39 +03:00
const Vector & testDir = m_moveSpeed > 0.0f ? g_pGlobals - > v_forward : - g_pGlobals - > v_forward ;
2015-06-04 11:52:48 +03:00
2015-06-07 19:43:16 +03:00
// now check which side is blocked
2015-08-15 18:09:15 +03:00
src = pev - > origin + g_pGlobals - > v_right * 32.0f ;
dst = src + testDir * 32.0f ;
2015-06-04 11:52:48 +03:00
2015-06-07 19:43:16 +03:00
TraceHull ( src , dst , true , head_hull , GetEntity ( ) , & tr ) ;
2015-06-04 11:52:48 +03:00
2016-01-04 18:26:06 +03:00
if ( tr . flFraction ! = 1.0f )
2015-06-07 19:43:16 +03:00
blockedRight = true ;
2015-06-04 11:52:48 +03:00
2015-08-15 18:09:15 +03:00
src = pev - > origin - g_pGlobals - > v_right * 32.0f ;
dst = src + testDir * 32.0f ;
2015-06-04 11:52:48 +03:00
2015-06-07 19:43:16 +03:00
TraceHull ( src , dst , true , head_hull , GetEntity ( ) , & tr ) ;
2015-06-04 11:52:48 +03:00
2016-01-04 18:26:06 +03:00
if ( tr . flFraction ! = 1.0f )
2015-06-07 19:43:16 +03:00
blockedLeft = true ;
2015-06-04 11:52:48 +03:00
2015-06-07 19:43:16 +03:00
if ( dirLeft )
state [ i ] + = 5 ;
else
state [ i ] - = 5 ;
2015-06-04 11:52:48 +03:00
2015-06-07 19:43:16 +03:00
if ( blockedLeft )
state [ i ] - = 5 ;
2015-06-04 11:52:48 +03:00
2015-06-07 19:43:16 +03:00
i + + ;
if ( dirRight )
state [ i ] + = 5 ;
2015-06-04 11:52:48 +03:00
else
2015-06-07 19:43:16 +03:00
state [ i ] - = 5 ;
2015-06-04 11:52:48 +03:00
2015-06-07 19:43:16 +03:00
if ( blockedRight )
state [ i ] - = 5 ;
}
2015-07-01 00:47:39 +03:00
2015-07-20 21:26:20 +03:00
// now weight all possible states
if ( bits & PROBE_JUMP )
{
state [ i ] = 0 ;
if ( CanJumpUp ( dirNormal ) )
state [ i ] + = 10 ;
2015-08-15 18:09:15 +03:00
if ( m_destOrigin . z > = pev - > origin . z + 18.0f )
2015-07-20 21:26:20 +03:00
state [ i ] + = 5 ;
if ( EntityIsVisible ( m_destOrigin ) )
{
MakeVectors ( m_moveAngles ) ;
src = EyePosition ( ) ;
2015-08-15 18:09:15 +03:00
src = src + g_pGlobals - > v_right * 15.0f ;
2015-07-20 21:26:20 +03:00
TraceLine ( src , m_destOrigin , true , true , GetEntity ( ) , & tr ) ;
2016-01-04 18:26:06 +03:00
if ( tr . flFraction > = 1.0f )
2015-07-20 21:26:20 +03:00
{
src = EyePosition ( ) ;
2015-08-15 18:09:15 +03:00
src = src - g_pGlobals - > v_right * 15.0f ;
2015-07-20 21:26:20 +03:00
TraceLine ( src , m_destOrigin , true , true , GetEntity ( ) , & tr ) ;
2016-01-04 18:26:06 +03:00
if ( tr . flFraction > = 1.0f )
2015-07-20 21:26:20 +03:00
state [ i ] + = 5 ;
}
}
if ( pev - > flags & FL_DUCKING )
src = pev - > origin ;
else
2015-08-15 18:09:15 +03:00
src = pev - > origin + Vector ( 0.0f , 0.0f , - 17.0f ) ;
2015-07-20 21:26:20 +03:00
2015-08-15 18:09:15 +03:00
dst = src + dirNormal * 30.0f ;
2015-07-20 21:26:20 +03:00
TraceLine ( src , dst , true , true , GetEntity ( ) , & tr ) ;
2016-01-04 18:26:06 +03:00
if ( tr . flFraction ! = 1.0f )
2015-07-20 21:26:20 +03:00
state [ i ] + = 10 ;
}
else
state [ i ] = 0 ;
i + + ;
if ( bits & PROBE_DUCK )
{
state [ i ] = 0 ;
if ( CanDuckUnder ( dirNormal ) )
state [ i ] + = 10 ;
2015-08-15 18:09:15 +03:00
if ( ( m_destOrigin . z + 36.0f < = pev - > origin . z ) & & EntityIsVisible ( m_destOrigin ) )
2015-07-20 21:26:20 +03:00
state [ i ] + = 5 ;
}
else
state [ i ] = 0 ;
i + + ;
2015-06-29 21:49:52 +03:00
2015-06-07 19:43:16 +03:00
// weighted all possible moves, now sort them to start with most probable
bool isSorting = false ;
do
{
isSorting = false ;
2015-06-24 17:25:39 +03:00
for ( i = 0 ; i < 3 ; i + + )
2015-06-04 11:52:48 +03:00
{
2015-06-24 17:25:39 +03:00
if ( state [ i + MAX_COLLIDE_MOVES ] < state [ i + MAX_COLLIDE_MOVES + 1 ] )
2015-06-04 11:52:48 +03:00
{
2015-06-24 17:25:39 +03:00
int temp = state [ i ] ;
2015-06-04 11:52:48 +03:00
2015-06-07 19:43:16 +03:00
state [ i ] = state [ i + 1 ] ;
state [ i + 1 ] = temp ;
2015-06-04 11:52:48 +03:00
2015-06-24 17:25:39 +03:00
temp = state [ i + MAX_COLLIDE_MOVES ] ;
2015-06-04 11:52:48 +03:00
2015-06-24 17:25:39 +03:00
state [ i + MAX_COLLIDE_MOVES ] = state [ i + MAX_COLLIDE_MOVES + 1 ] ;
state [ i + MAX_COLLIDE_MOVES + 1 ] = temp ;
2015-06-04 11:52:48 +03:00
2015-06-07 19:43:16 +03:00
isSorting = true ;
2015-06-04 11:52:48 +03:00
}
2015-06-07 19:43:16 +03:00
}
} while ( isSorting ) ;
2015-06-04 11:52:48 +03:00
2015-06-24 17:25:39 +03:00
for ( i = 0 ; i < MAX_COLLIDE_MOVES ; i + + )
2015-06-07 19:43:16 +03:00
m_collideMoves [ i ] = state [ i ] ;
2015-06-04 11:52:48 +03:00
2015-06-07 19:43:16 +03:00
m_collideTime = GetWorldTime ( ) ;
2015-08-15 18:09:15 +03:00
m_probeTime = GetWorldTime ( ) + 0.5f ;
2015-06-07 19:43:16 +03:00
m_collisionProbeBits = bits ;
m_collisionState = COLLISION_PROBING ;
m_collStateIndex = 0 ;
2015-06-04 11:52:48 +03:00
}
2015-06-07 19:43:16 +03:00
}
2015-06-04 11:52:48 +03:00
2015-06-07 19:43:16 +03:00
if ( m_collisionState = = COLLISION_PROBING )
{
if ( m_probeTime < GetWorldTime ( ) )
2015-06-04 11:52:48 +03:00
{
2015-06-07 19:43:16 +03:00
m_collStateIndex + + ;
2015-08-15 18:09:15 +03:00
m_probeTime = GetWorldTime ( ) + 0.5f ;
2015-06-04 11:52:48 +03:00
2015-06-28 19:43:31 +03:00
if ( m_collStateIndex > MAX_COLLIDE_MOVES )
2015-06-07 19:43:16 +03:00
{
2015-08-15 18:09:15 +03:00
m_navTimeset = GetWorldTime ( ) - 5.0f ;
2015-06-07 19:43:16 +03:00
ResetCollideState ( ) ;
2015-06-04 11:52:48 +03:00
}
2015-06-07 19:43:16 +03:00
}
2015-06-04 11:52:48 +03:00
2015-06-28 19:43:31 +03:00
if ( m_collStateIndex < MAX_COLLIDE_MOVES )
2015-06-07 19:43:16 +03:00
{
switch ( m_collideMoves [ m_collStateIndex ] )
2015-06-04 11:52:48 +03:00
{
2015-06-07 19:43:16 +03:00
case COLLISION_JUMP :
if ( IsOnFloor ( ) | | IsInWater ( ) )
2015-07-22 19:14:07 +03:00
{
2015-06-07 19:43:16 +03:00
pev - > button | = IN_JUMP ;
2015-07-22 19:14:07 +03:00
m_jumpStateTimer = Random . Float ( 1.0f , 2.0f ) ;
}
2015-06-07 19:43:16 +03:00
break ;
2015-06-04 11:52:48 +03:00
2015-06-07 19:43:16 +03:00
case COLLISION_DUCK :
if ( IsOnFloor ( ) | | IsInWater ( ) )
pev - > button | = IN_DUCK ;
break ;
2015-06-04 11:52:48 +03:00
2015-06-07 19:43:16 +03:00
case COLLISION_STRAFELEFT :
pev - > button | = IN_MOVELEFT ;
2015-07-01 00:47:39 +03:00
SetStrafeSpeed ( dirNormal , - pev - > maxspeed ) ;
2015-06-07 19:43:16 +03:00
break ;
2015-06-04 11:52:48 +03:00
2015-06-07 19:43:16 +03:00
case COLLISION_STRAFERIGHT :
pev - > button | = IN_MOVERIGHT ;
2015-07-01 00:47:39 +03:00
SetStrafeSpeed ( dirNormal , pev - > maxspeed ) ;
2015-06-07 19:43:16 +03:00
break ;
2015-06-04 11:52:48 +03:00
}
}
}
}
}
2014-07-30 14:17:46 +04:00
bool Bot : : DoWaypointNav ( void )
{
// this function is a main path navigation
TraceResult tr , tr2 ;
// check if we need to find a waypoint...
if ( m_currentWaypointIndex = = - 1 )
{
GetValidWaypoint ( ) ;
m_waypointOrigin = m_currentPath - > origin ;
// if wayzone radios non zero vary origin a bit depending on the body angles
if ( m_currentPath - > radius > 0 )
{
2015-08-15 18:09:15 +03:00
MakeVectors ( Vector ( pev - > angles . x , AngleNormalize ( pev - > angles . y + Random . Float ( - 90.0f , 90.0f ) ) , 0.0f ) ) ;
2015-06-09 15:45:34 +03:00
m_waypointOrigin = m_waypointOrigin + g_pGlobals - > v_forward * Random . Float ( 0 , m_currentPath - > radius ) ;
2014-07-30 14:17:46 +04:00
}
m_navTimeset = GetWorldTime ( ) ;
}
if ( pev - > flags & FL_DUCKING )
m_destOrigin = m_waypointOrigin ;
else
m_destOrigin = m_waypointOrigin + pev - > view_ofs ;
float waypointDistance = ( pev - > origin - m_waypointOrigin ) . GetLength ( ) ;
// this waypoint has additional travel flags - care about them
if ( m_currentTravelFlags & PATHFLAG_JUMP )
{
// bot is not jumped yet?
if ( ! m_jumpFinished )
{
// if bot's on the ground or on the ladder we're free to jump. actually setting the correct velocity is cheating.
// pressing the jump button gives the illusion of the bot actual jmping.
if ( IsOnFloor ( ) | | IsOnLadder ( ) )
{
2015-06-09 22:16:08 +03:00
if ( m_desiredVelocity . x ! = 0.0f & & m_desiredVelocity . y ! = 0.0f )
2015-08-15 18:09:15 +03:00
pev - > velocity = m_desiredVelocity + m_desiredVelocity * 0.046f ;
2015-06-08 16:18:55 +03:00
2014-07-30 14:17:46 +04:00
pev - > button | = IN_JUMP ;
m_jumpFinished = true ;
m_checkTerrain = false ;
2015-08-15 18:09:15 +03:00
m_desiredVelocity . Zero ( ) ;
2014-07-30 14:17:46 +04:00
}
}
else if ( ! yb_jasonmode . GetBool ( ) & & m_currentWeapon = = WEAPON_KNIFE & & IsOnFloor ( ) )
SelectBestWeapon ( ) ;
}
if ( m_currentPath - > flags & FLAG_LADDER )
{
2015-08-15 18:09:15 +03:00
if ( m_waypointOrigin . z > = ( pev - > origin . z + 16.0f ) )
m_waypointOrigin = m_currentPath - > origin + Vector ( 0.0f , 0.0f , 16.0f ) ;
else if ( m_waypointOrigin . z < pev - > origin . z + 16.0f & & ! IsOnLadder ( ) & & IsOnFloor ( ) & & ! ( pev - > flags & FL_DUCKING ) )
2014-07-30 14:17:46 +04:00
{
m_moveSpeed = waypointDistance ;
2015-08-15 18:09:15 +03:00
if ( m_moveSpeed < 150.0f )
m_moveSpeed = 150.0f ;
2014-07-30 14:17:46 +04:00
else if ( m_moveSpeed > pev - > maxspeed )
m_moveSpeed = pev - > maxspeed ;
}
}
// special lift handling (code merged from podbotmm)
if ( m_currentPath - > flags & FLAG_LIFT )
{
bool liftClosedDoorExists = false ;
// update waypoint time set
m_navTimeset = GetWorldTime ( ) ;
// trace line to door
TraceLine ( pev - > origin , m_currentPath - > origin , true , true , GetEntity ( ) , & tr2 ) ;
2016-01-04 18:26:06 +03:00
if ( tr2 . flFraction < 1.0f & & strcmp ( STRING ( tr2 . pHit - > v . classname ) , " func_door " ) = = 0 & & ( m_liftState = = LIFT_NO_NEARBY | | m_liftState = = LIFT_WAITING_FOR | | m_liftState = = LIFT_LOOKING_BUTTON_OUTSIDE ) & & pev - > groundentity ! = tr2 . pHit )
2014-07-30 14:17:46 +04:00
{
if ( m_liftState = = LIFT_NO_NEARBY )
{
m_liftState = LIFT_LOOKING_BUTTON_OUTSIDE ;
m_liftUsageTime = GetWorldTime ( ) + 7.0 ;
}
liftClosedDoorExists = true ;
}
// trace line down
2015-08-15 18:09:15 +03:00
TraceLine ( m_currentPath - > origin , m_currentPath - > origin + Vector ( 0.0f , 0.0f , - 50.0f ) , true , true , GetEntity ( ) , & tr ) ;
2014-07-30 14:17:46 +04:00
// if trace result shows us that it is a lift
2015-06-04 11:52:48 +03:00
if ( ! IsEntityNull ( tr . pHit ) & & m_navNode ! = NULL & & ( strcmp ( STRING ( tr . pHit - > v . classname ) , " func_door " ) = = 0 | | strcmp ( STRING ( tr . pHit - > v . classname ) , " func_plat " ) = = 0 | | strcmp ( STRING ( tr . pHit - > v . classname ) , " func_train " ) = = 0 ) & & ! liftClosedDoorExists )
2014-07-30 14:17:46 +04:00
{
2015-08-15 18:09:15 +03:00
if ( ( m_liftState = = LIFT_NO_NEARBY | | m_liftState = = LIFT_WAITING_FOR | | m_liftState = = LIFT_LOOKING_BUTTON_OUTSIDE ) & & tr . pHit - > v . velocity . z = = 0.0f )
2014-07-30 14:17:46 +04:00
{
2015-08-15 18:09:15 +03:00
if ( fabsf ( pev - > origin . z - tr . vecEndPos . z ) < 70.0f )
2014-07-30 14:17:46 +04:00
{
m_liftEntity = tr . pHit ;
m_liftState = LIFT_ENTERING_IN ;
m_liftTravelPos = m_currentPath - > origin ;
2015-08-15 18:09:15 +03:00
m_liftUsageTime = GetWorldTime ( ) + 5.0f ;
2014-07-30 14:17:46 +04:00
}
}
else if ( m_liftState = = LIFT_TRAVELING_BY )
{
m_liftState = LIFT_LEAVING ;
2015-08-15 18:09:15 +03:00
m_liftUsageTime = GetWorldTime ( ) + 7.0f ;
2014-07-30 14:17:46 +04:00
}
}
else if ( m_navNode ! = NULL ) // no lift found at waypoint
{
if ( ( m_liftState = = LIFT_NO_NEARBY | | m_liftState = = LIFT_WAITING_FOR ) & & m_navNode - > next ! = NULL )
{
2015-07-24 15:10:51 +03:00
if ( m_navNode - > next - > index > = 0 & & m_navNode - > next - > index < g_numWaypoints & & ( waypoints . GetPath ( m_navNode - > next - > index ) - > flags & FLAG_LIFT ) )
2014-07-30 14:17:46 +04:00
{
2015-07-24 15:10:51 +03:00
TraceLine ( m_currentPath - > origin , waypoints . GetPath ( m_navNode - > next - > index ) - > origin , true , true , GetEntity ( ) , & tr ) ;
2014-07-30 14:17:46 +04:00
2015-06-04 11:52:48 +03:00
if ( ! IsEntityNull ( tr . pHit ) & & ( strcmp ( STRING ( tr . pHit - > v . classname ) , " func_door " ) = = 0 | | strcmp ( STRING ( tr . pHit - > v . classname ) , " func_plat " ) = = 0 | | strcmp ( STRING ( tr . pHit - > v . classname ) , " func_train " ) = = 0 ) )
2014-07-30 14:17:46 +04:00
m_liftEntity = tr . pHit ;
}
m_liftState = LIFT_LOOKING_BUTTON_OUTSIDE ;
2015-08-15 18:09:15 +03:00
m_liftUsageTime = GetWorldTime ( ) + 15.0f ;
2014-07-30 14:17:46 +04:00
}
}
// bot is going to enter the lift
if ( m_liftState = = LIFT_ENTERING_IN )
{
m_destOrigin = m_liftTravelPos ;
// check if we enough to destination
if ( ( pev - > origin - m_destOrigin ) . GetLengthSquared ( ) < 225 )
{
2015-07-12 12:58:20 +03:00
m_moveSpeed = 0.0f ;
m_strafeSpeed = 0.0f ;
m_navTimeset = GetWorldTime ( ) ;
m_aimFlags | = AIM_NAVPOINT ;
ResetCollideState ( ) ;
2014-07-30 14:17:46 +04:00
// need to wait our following teammate ?
bool needWaitForTeammate = false ;
// if some bot is following a bot going into lift - he should take the same lift to go
for ( int i = 0 ; i < GetMaxClients ( ) ; i + + )
{
2015-07-24 15:10:51 +03:00
Bot * bot = bots . GetBot ( i ) ;
2014-07-30 14:17:46 +04:00
if ( bot = = NULL | | bot = = this )
continue ;
2014-08-06 00:03:50 +04:00
if ( ! IsAlive ( bot - > GetEntity ( ) ) | | GetTeam ( bot - > GetEntity ( ) ) ! = m_team | | bot - > m_targetEntity ! = GetEntity ( ) | | bot - > GetTaskId ( ) ! = TASK_FOLLOWUSER )
2014-07-30 14:17:46 +04:00
continue ;
if ( bot - > pev - > groundentity = = m_liftEntity & & bot - > IsOnFloor ( ) )
break ;
bot - > m_liftEntity = m_liftEntity ;
bot - > m_liftState = LIFT_ENTERING_IN ;
bot - > m_liftTravelPos = m_liftTravelPos ;
needWaitForTeammate = true ;
}
if ( needWaitForTeammate )
{
m_liftState = LIFT_WAIT_FOR_TEAMMATES ;
2015-08-15 18:09:15 +03:00
m_liftUsageTime = GetWorldTime ( ) + 8.0f ;
2014-07-30 14:17:46 +04:00
}
else
{
m_liftState = LIFT_LOOKING_BUTTON_INSIDE ;
2015-08-15 18:09:15 +03:00
m_liftUsageTime = GetWorldTime ( ) + 10.0f ;
2014-07-30 14:17:46 +04:00
}
}
}
// bot is waiting for his teammates
if ( m_liftState = = LIFT_WAIT_FOR_TEAMMATES )
{
// need to wait our following teammate ?
bool needWaitForTeammate = false ;
for ( int i = 0 ; i < GetMaxClients ( ) ; i + + )
{
2015-07-24 15:10:51 +03:00
Bot * bot = bots . GetBot ( i ) ;
2014-07-30 14:17:46 +04:00
if ( bot = = NULL )
continue ; // skip invalid bots
2014-08-06 00:03:50 +04:00
if ( ! IsAlive ( bot - > GetEntity ( ) ) | | GetTeam ( bot - > GetEntity ( ) ) ! = m_team | | bot - > m_targetEntity ! = GetEntity ( ) | | bot - > GetTaskId ( ) ! = TASK_FOLLOWUSER | | bot - > m_liftEntity ! = m_liftEntity )
2014-07-30 14:17:46 +04:00
continue ;
if ( bot - > pev - > groundentity = = m_liftEntity | | ! bot - > IsOnFloor ( ) )
{
needWaitForTeammate = true ;
break ;
}
}
// need to wait for teammate
if ( needWaitForTeammate )
{
m_destOrigin = m_liftTravelPos ;
2015-08-15 18:09:15 +03:00
if ( ( pev - > origin - m_destOrigin ) . GetLengthSquared ( ) < 225.0f )
2014-07-30 14:17:46 +04:00
{
2015-07-12 12:58:20 +03:00
m_moveSpeed = 0.0f ;
m_strafeSpeed = 0.0f ;
m_navTimeset = GetWorldTime ( ) ;
m_aimFlags | = AIM_NAVPOINT ;
ResetCollideState ( ) ;
2014-07-30 14:17:46 +04:00
}
}
// else we need to look for button
2015-08-15 18:09:15 +03:00
if ( ! needWaitForTeammate | | m_liftUsageTime < GetWorldTime ( ) )
2014-07-30 14:17:46 +04:00
{
m_liftState = LIFT_LOOKING_BUTTON_INSIDE ;
m_liftUsageTime = GetWorldTime ( ) + 10.0 ;
}
}
// bot is trying to find button inside a lift
if ( m_liftState = = LIFT_LOOKING_BUTTON_INSIDE )
{
edict_t * button = FindNearestButton ( STRING ( m_liftEntity - > v . targetname ) ) ;
// got a valid button entity ?
2015-08-15 18:09:15 +03:00
if ( ! IsEntityNull ( button ) & & pev - > groundentity = = m_liftEntity & & m_buttonPushTime + 1.0f < GetWorldTime ( ) & & m_liftEntity - > v . velocity . z = = 0.0f & & IsOnFloor ( ) )
2014-07-30 14:17:46 +04:00
{
m_pickupItem = button ;
m_pickupType = PICKUP_BUTTON ;
m_navTimeset = GetWorldTime ( ) ;
}
}
// is lift activated and bot is standing on it and lift is moving ?
if ( m_liftState = = LIFT_LOOKING_BUTTON_INSIDE | | m_liftState = = LIFT_ENTERING_IN | | m_liftState = = LIFT_WAIT_FOR_TEAMMATES | | m_liftState = = LIFT_WAITING_FOR )
{
2015-08-15 18:09:15 +03:00
if ( pev - > groundentity = = m_liftEntity & & m_liftEntity - > v . velocity . z ! = 0.0f & & IsOnFloor ( ) & & ( ( waypoints . GetPath ( m_prevWptIndex [ 0 ] ) - > flags & FLAG_LIFT ) | | ! IsEntityNull ( m_targetEntity ) ) )
2014-07-30 14:17:46 +04:00
{
m_liftState = LIFT_TRAVELING_BY ;
2015-08-15 18:09:15 +03:00
m_liftUsageTime = GetWorldTime ( ) + 14.0f ;
2014-07-30 14:17:46 +04:00
2015-08-15 18:09:15 +03:00
if ( ( pev - > origin - m_destOrigin ) . GetLengthSquared ( ) < 225.0f )
2014-07-30 14:17:46 +04:00
{
2015-07-12 12:58:20 +03:00
m_moveSpeed = 0.0f ;
m_strafeSpeed = 0.0f ;
m_navTimeset = GetWorldTime ( ) ;
m_aimFlags | = AIM_NAVPOINT ;
ResetCollideState ( ) ;
2014-07-30 14:17:46 +04:00
}
}
}
// bots is currently moving on lift
if ( m_liftState = = LIFT_TRAVELING_BY )
{
m_destOrigin = Vector ( m_liftTravelPos . x , m_liftTravelPos . y , pev - > origin . z ) ;
2015-08-15 18:09:15 +03:00
if ( ( pev - > origin - m_destOrigin ) . GetLengthSquared ( ) < 225.0f )
2014-07-30 14:17:46 +04:00
{
2015-07-12 12:58:20 +03:00
m_moveSpeed = 0.0f ;
m_strafeSpeed = 0.0f ;
m_navTimeset = GetWorldTime ( ) ;
m_aimFlags | = AIM_NAVPOINT ;
ResetCollideState ( ) ;
2014-07-30 14:17:46 +04:00
}
}
// need to find a button outside the lift
if ( m_liftState = = LIFT_LOOKING_BUTTON_OUTSIDE )
{
// button has been pressed, lift should come
2015-08-15 18:09:15 +03:00
if ( m_buttonPushTime + 8.0f > = GetWorldTime ( ) )
2014-07-30 14:17:46 +04:00
{
2015-08-15 18:09:15 +03:00
if ( m_prevWptIndex [ 0 ] > = 0 & & m_prevWptIndex [ 0 ] < g_numWaypoints )
2015-07-24 15:10:51 +03:00
m_destOrigin = waypoints . GetPath ( m_prevWptIndex [ 0 ] ) - > origin ;
2014-07-30 14:17:46 +04:00
else
m_destOrigin = pev - > origin ;
2015-08-15 18:09:15 +03:00
if ( ( pev - > origin - m_destOrigin ) . GetLengthSquared ( ) < 225.0f )
2014-07-30 14:17:46 +04:00
{
2015-07-12 12:58:20 +03:00
m_moveSpeed = 0.0f ;
m_strafeSpeed = 0.0f ;
m_navTimeset = GetWorldTime ( ) ;
m_aimFlags | = AIM_NAVPOINT ;
ResetCollideState ( ) ;
2014-07-30 14:17:46 +04:00
}
}
2015-07-12 12:58:20 +03:00
else if ( ! IsEntityNull ( m_liftEntity ) )
2014-07-30 14:17:46 +04:00
{
edict_t * button = FindNearestButton ( STRING ( m_liftEntity - > v . targetname ) ) ;
// if we got a valid button entity
2015-06-04 11:52:48 +03:00
if ( ! IsEntityNull ( button ) )
2014-07-30 14:17:46 +04:00
{
2015-06-28 19:43:31 +03:00
// lift is already used ?
bool liftUsed = false ;
2014-07-30 14:17:46 +04:00
// iterate though clients, and find if lift already used
for ( int i = 0 ; i < GetMaxClients ( ) ; i + + )
{
2015-06-04 11:52:48 +03:00
if ( ! ( g_clients [ i ] . flags & CF_USED ) | | ! ( g_clients [ i ] . flags & CF_ALIVE ) | | g_clients [ i ] . team ! = m_team | | g_clients [ i ] . ent = = GetEntity ( ) | | IsEntityNull ( g_clients [ i ] . ent - > v . groundentity ) )
2014-07-30 14:17:46 +04:00
continue ;
if ( g_clients [ i ] . ent - > v . groundentity = = m_liftEntity )
{
liftUsed = true ;
break ;
}
}
// lift is currently used
if ( liftUsed )
{
if ( m_prevWptIndex [ 0 ] > = 0 & & m_prevWptIndex [ 0 ] < g_numWaypoints )
2015-07-24 15:10:51 +03:00
m_destOrigin = waypoints . GetPath ( m_prevWptIndex [ 0 ] ) - > origin ;
2014-07-30 14:17:46 +04:00
else
m_destOrigin = button - > v . origin ;
2015-08-15 18:09:15 +03:00
if ( ( pev - > origin - m_destOrigin ) . GetLengthSquared ( ) < 225.0f )
2014-07-30 14:17:46 +04:00
{
2015-08-15 18:09:15 +03:00
m_moveSpeed = 0.0f ;
m_strafeSpeed = 0.0f ;
2014-07-30 14:17:46 +04:00
}
}
else
{
m_pickupItem = button ;
m_pickupType = PICKUP_BUTTON ;
m_liftState = LIFT_WAITING_FOR ;
m_navTimeset = GetWorldTime ( ) ;
2015-08-15 18:09:15 +03:00
m_liftUsageTime = GetWorldTime ( ) + 20.0f ;
2014-07-30 14:17:46 +04:00
}
}
else
{
m_liftState = LIFT_WAITING_FOR ;
2015-08-15 18:09:15 +03:00
m_liftUsageTime = GetWorldTime ( ) + 15.0f ;
2014-07-30 14:17:46 +04:00
}
}
}
// bot is waiting for lift
if ( m_liftState = = LIFT_WAITING_FOR )
{
2015-08-15 18:09:15 +03:00
if ( m_prevWptIndex [ 0 ] > = 0 & & m_prevWptIndex [ 0 ] < g_numWaypoints )
2014-07-30 14:17:46 +04:00
{
2015-07-24 15:10:51 +03:00
if ( ! ( waypoints . GetPath ( m_prevWptIndex [ 0 ] ) - > flags & FLAG_LIFT ) )
m_destOrigin = waypoints . GetPath ( m_prevWptIndex [ 0 ] ) - > origin ;
2015-08-15 18:09:15 +03:00
else if ( m_prevWptIndex [ 1 ] > = 0 & & m_prevWptIndex [ 1 ] < g_numWaypoints )
2015-07-24 15:10:51 +03:00
m_destOrigin = waypoints . GetPath ( m_prevWptIndex [ 1 ] ) - > origin ;
2014-07-30 14:17:46 +04:00
}
2015-08-15 18:09:15 +03:00
if ( ( pev - > origin - m_destOrigin ) . GetLengthSquared ( ) < 100.0f )
2014-07-30 14:17:46 +04:00
{
2015-07-12 12:58:20 +03:00
m_moveSpeed = 0.0f ;
m_strafeSpeed = 0.0f ;
m_navTimeset = GetWorldTime ( ) ;
m_aimFlags | = AIM_NAVPOINT ;
ResetCollideState ( ) ;
2014-07-30 14:17:46 +04:00
}
}
// if bot is waiting for lift, or going to it
if ( m_liftState = = LIFT_WAITING_FOR | | m_liftState = = LIFT_ENTERING_IN )
{
// bot fall down somewhere inside the lift's groove :)
if ( pev - > groundentity ! = m_liftEntity & & m_prevWptIndex [ 0 ] > = 0 & & m_prevWptIndex [ 0 ] < g_numWaypoints )
{
2015-08-15 18:09:15 +03:00
if ( ( waypoints . GetPath ( m_prevWptIndex [ 0 ] ) - > flags & FLAG_LIFT ) & & ( m_currentPath - > origin . z - pev - > origin . z ) > 50.0f & & ( waypoints . GetPath ( m_prevWptIndex [ 0 ] ) - > origin . z - pev - > origin . z ) > 50.0f )
2014-07-30 14:17:46 +04:00
{
m_liftState = LIFT_NO_NEARBY ;
m_liftEntity = NULL ;
2015-08-15 18:09:15 +03:00
m_liftUsageTime = 0.0f ;
2014-07-30 14:17:46 +04:00
DeleteSearchNodes ( ) ;
FindWaypoint ( ) ;
if ( m_prevWptIndex [ 2 ] > = 0 & & m_prevWptIndex [ 2 ] < g_numWaypoints )
FindShortestPath ( m_currentWaypointIndex , m_prevWptIndex [ 2 ] ) ;
return false ;
}
}
}
}
2015-06-04 11:52:48 +03:00
if ( ! IsEntityNull ( m_liftEntity ) & & ! ( m_currentPath - > flags & FLAG_LIFT ) )
2014-07-30 14:17:46 +04:00
{
if ( m_liftState = = LIFT_TRAVELING_BY )
{
m_liftState = LIFT_LEAVING ;
2015-08-15 18:09:15 +03:00
m_liftUsageTime = GetWorldTime ( ) + 10.0f ;
2014-07-30 14:17:46 +04:00
}
if ( m_liftState = = LIFT_LEAVING & & m_liftUsageTime < GetWorldTime ( ) & & pev - > groundentity ! = m_liftEntity )
{
m_liftState = LIFT_NO_NEARBY ;
2015-08-15 18:09:15 +03:00
m_liftUsageTime = 0.0f ;
2014-07-30 14:17:46 +04:00
m_liftEntity = NULL ;
}
}
2015-08-15 18:09:15 +03:00
if ( m_liftUsageTime < GetWorldTime ( ) & & m_liftUsageTime ! = 0.0f )
2014-07-30 14:17:46 +04:00
{
m_liftEntity = NULL ;
m_liftState = LIFT_NO_NEARBY ;
2015-08-15 18:09:15 +03:00
m_liftUsageTime = 0.0f ;
2014-07-30 14:17:46 +04:00
DeleteSearchNodes ( ) ;
if ( m_prevWptIndex [ 0 ] > = 0 & & m_prevWptIndex [ 0 ] < g_numWaypoints )
{
2015-07-24 15:10:51 +03:00
if ( ! ( waypoints . GetPath ( m_prevWptIndex [ 0 ] ) - > flags & FLAG_LIFT ) )
2014-07-30 14:17:46 +04:00
ChangeWptIndex ( m_prevWptIndex [ 0 ] ) ;
else
FindWaypoint ( ) ;
}
else
FindWaypoint ( ) ;
return false ;
}
// check if we are going through a door...
TraceLine ( pev - > origin , m_waypointOrigin , true , GetEntity ( ) , & tr ) ;
2015-06-04 11:52:48 +03:00
if ( ! IsEntityNull ( tr . pHit ) & & IsEntityNull ( m_liftEntity ) & & strncmp ( STRING ( tr . pHit - > v . classname ) , " func_door " , 9 ) = = 0 )
2014-07-30 14:17:46 +04:00
{
// if the door is near enough...
2015-08-15 18:09:15 +03:00
if ( ( GetEntityOrigin ( tr . pHit ) - pev - > origin ) . GetLengthSquared ( ) < 2500.0f )
2014-07-30 14:17:46 +04:00
{
2015-07-20 21:26:20 +03:00
IgnoreCollisionShortly ( ) ; // don't consider being stuck
2014-07-30 14:17:46 +04:00
2015-06-09 15:45:34 +03:00
if ( Random . Long ( 1 , 100 ) < 50 )
2014-07-30 14:17:46 +04:00
MDLL_Use ( tr . pHit , GetEntity ( ) ) ; // also 'use' the door randomly
}
// make sure we are always facing the door when going through it
2015-06-07 19:43:16 +03:00
m_aimFlags & = ~ ( AIM_LAST_ENEMY | AIM_PREDICT_PATH ) ;
2014-07-30 14:17:46 +04:00
edict_t * button = FindNearestButton ( STRING ( tr . pHit - > v . targetname ) ) ;
// check if we got valid button
2015-06-04 11:52:48 +03:00
if ( ! IsEntityNull ( button ) )
2014-07-30 14:17:46 +04:00
{
m_pickupItem = button ;
m_pickupType = PICKUP_BUTTON ;
m_navTimeset = GetWorldTime ( ) ;
}
// if bot hits the door, then it opens, so wait a bit to let it open safely
if ( pev - > velocity . GetLength2D ( ) < 2 & & m_timeDoorOpen < GetWorldTime ( ) )
{
2015-07-12 17:18:20 +03:00
PushTask ( TASK_PAUSE , TASKPRI_PAUSE , - 1 , GetWorldTime ( ) + 1 , false ) ;
2014-07-30 14:17:46 +04:00
m_doorOpenAttempt + + ;
2015-08-15 18:09:15 +03:00
m_timeDoorOpen = GetWorldTime ( ) + 1.0f ; // retry in 1 sec until door is open
2014-07-30 14:17:46 +04:00
edict_t * ent = NULL ;
2015-06-20 11:45:59 +03:00
if ( m_doorOpenAttempt > 2 & & ! IsEntityNull ( ent = FIND_ENTITY_IN_SPHERE ( ent , pev - > origin , 256.0f ) ) )
2014-07-30 14:17:46 +04:00
{
2015-06-04 11:52:48 +03:00
if ( IsValidPlayer ( ent ) & & IsAlive ( ent ) & & m_team ! = GetTeam ( ent ) & & GetWeaponPenetrationPower ( m_currentWeapon ) > 0 )
2014-07-30 14:17:46 +04:00
{
m_seeEnemyTime = GetWorldTime ( ) ;
m_states | = STATE_SUSPECT_ENEMY ;
m_aimFlags | = AIM_LAST_ENEMY ;
m_lastEnemy = ent ;
m_enemy = ent ;
m_lastEnemyOrigin = ent - > v . origin ;
}
2014-08-06 00:03:50 +04:00
else if ( IsValidPlayer ( ent ) & & IsAlive ( ent ) & & m_team = = GetTeam ( ent ) )
2014-07-30 14:17:46 +04:00
{
DeleteSearchNodes ( ) ;
ResetTasks ( ) ;
}
else if ( IsValidPlayer ( ent ) & & ( ! IsAlive ( ent ) | | ( ent - > v . deadflag & DEAD_DYING ) ) )
m_doorOpenAttempt = 0 ; // reset count
}
}
}
2015-08-15 18:09:15 +03:00
float desiredDistance = 0.0f ;
2014-07-30 14:17:46 +04:00
// initialize the radius for a special waypoint type, where the wpt is considered to be reached
if ( m_currentPath - > flags & FLAG_LIFT )
2015-08-15 18:09:15 +03:00
desiredDistance = 50.0f ;
2014-07-30 14:17:46 +04:00
else if ( ( pev - > flags & FL_DUCKING ) | | ( m_currentPath - > flags & FLAG_GOAL ) )
2015-08-15 18:09:15 +03:00
desiredDistance = 25.0f ;
2014-07-30 14:17:46 +04:00
else if ( m_currentPath - > flags & FLAG_LADDER )
2015-08-15 18:09:15 +03:00
desiredDistance = 15.0f ;
2014-07-30 14:17:46 +04:00
else if ( m_currentTravelFlags & PATHFLAG_JUMP )
2015-08-15 18:09:15 +03:00
desiredDistance = 0.0f ;
2014-07-30 14:17:46 +04:00
else
desiredDistance = m_currentPath - > radius ;
// check if waypoint has a special travelflag, so they need to be reached more precisely
for ( int i = 0 ; i < MAX_PATH_INDEX ; i + + )
{
if ( m_currentPath - > connectionFlags [ i ] ! = 0 )
{
desiredDistance = 0 ;
break ;
}
}
// needs precise placement - check if we get past the point
2015-08-15 18:09:15 +03:00
if ( desiredDistance < 16.0f & & waypointDistance < 30.0f & & ( pev - > origin + ( pev - > velocity * m_frameInterval ) - m_waypointOrigin ) . GetLength ( ) > waypointDistance )
desiredDistance = waypointDistance + 1.0f ;
2014-07-30 14:17:46 +04:00
if ( waypointDistance < desiredDistance )
{
// Did we reach a destination Waypoint?
if ( GetTask ( ) - > data = = m_currentWaypointIndex )
{
// add goal values
if ( m_chosenGoalIndex ! = - 1 )
{
int waypointValue ;
int startIndex = m_chosenGoalIndex ;
int goalIndex = m_currentWaypointIndex ;
2014-08-06 00:03:50 +04:00
if ( m_team = = TEAM_TF )
2014-07-30 14:17:46 +04:00
{
waypointValue = ( g_experienceData + ( startIndex * g_numWaypoints ) + goalIndex ) - > team0Value ;
2015-08-15 18:09:15 +03:00
waypointValue + = static_cast < int > ( pev - > health * 0.5f ) ;
waypointValue + = static_cast < int > ( m_goalValue * 0.5f ) ;
2014-07-30 14:17:46 +04:00
if ( waypointValue < - MAX_GOAL_VALUE )
waypointValue = - MAX_GOAL_VALUE ;
else if ( waypointValue > MAX_GOAL_VALUE )
waypointValue = MAX_GOAL_VALUE ;
( g_experienceData + ( startIndex * g_numWaypoints ) + goalIndex ) - > team0Value = waypointValue ;
}
else
{
waypointValue = ( g_experienceData + ( startIndex * g_numWaypoints ) + goalIndex ) - > team1Value ;
2015-08-15 18:09:15 +03:00
waypointValue + = static_cast < int > ( pev - > health * 0.5f ) ;
waypointValue + = static_cast < int > ( m_goalValue * 0.5f ) ;
2014-07-30 14:17:46 +04:00
if ( waypointValue < - MAX_GOAL_VALUE )
waypointValue = - MAX_GOAL_VALUE ;
else if ( waypointValue > MAX_GOAL_VALUE )
waypointValue = MAX_GOAL_VALUE ;
( g_experienceData + ( startIndex * g_numWaypoints ) + goalIndex ) - > team1Value = waypointValue ;
}
}
return true ;
}
else if ( m_navNode = = NULL )
return false ;
2014-08-06 00:03:50 +04:00
if ( ( g_mapType & MAP_DE ) & & g_bombPlanted & & m_team = = TEAM_CF & & GetTaskId ( ) ! = TASK_ESCAPEFROMBOMB & & GetTask ( ) - > data ! = - 1 )
2014-07-30 14:17:46 +04:00
{
2016-01-07 18:49:55 +03:00
const Vector & bombOrigin = CheckBombAudible ( ) ;
2014-07-30 14:17:46 +04:00
// bot within 'hearable' bomb tick noises?
2015-08-15 18:09:15 +03:00
if ( ! bombOrigin . IsZero ( ) )
2014-07-30 14:17:46 +04:00
{
2015-07-24 15:10:51 +03:00
float distance = ( bombOrigin - waypoints . GetPath ( GetTask ( ) - > data ) - > origin ) . GetLength ( ) ;
2014-07-30 14:17:46 +04:00
if ( distance > 512.0 )
2015-07-24 15:10:51 +03:00
waypoints . SetGoalVisited ( GetTask ( ) - > data ) ; // doesn't hear so not a good goal
2014-07-30 14:17:46 +04:00
}
else
2015-07-24 15:10:51 +03:00
waypoints . SetGoalVisited ( GetTask ( ) - > data ) ; // doesn't hear so not a good goal
2014-07-30 14:17:46 +04:00
}
HeadTowardWaypoint ( ) ; // do the actual movement checking
}
return false ;
}
void Bot : : FindShortestPath ( int srcIndex , int destIndex )
{
// this function finds the shortest path from source index to destination index
DeleteSearchNodes ( ) ;
m_chosenGoalIndex = srcIndex ;
2015-08-15 18:09:15 +03:00
m_goalValue = 0.0f ;
2014-07-30 14:17:46 +04:00
PathNode * node = new PathNode ;
node - > index = srcIndex ;
node - > next = NULL ;
m_navNodeStart = node ;
m_navNode = m_navNodeStart ;
while ( srcIndex ! = destIndex )
{
2015-07-24 15:10:51 +03:00
srcIndex = * ( waypoints . m_pathMatrix + ( srcIndex * g_numWaypoints ) + destIndex ) ;
2014-07-30 14:17:46 +04:00
if ( srcIndex < 0 )
{
m_prevGoalIndex = - 1 ;
GetTask ( ) - > data = - 1 ;
return ;
}
node - > next = new PathNode ;
node = node - > next ;
if ( node = = NULL )
TerminateOnMalloc ( ) ;
node - > index = srcIndex ;
node - > next = NULL ;
}
}
2015-06-06 14:19:19 +03:00
// priority queue class (smallest item out first, hlsdk)
2014-07-30 14:17:46 +04:00
class PriorityQueue
{
private :
2015-06-06 14:19:19 +03:00
struct Node
2014-07-30 14:17:46 +04:00
{
2015-06-06 14:19:19 +03:00
int id ;
float pri ;
} ;
2014-07-30 14:17:46 +04:00
2015-06-29 21:49:52 +03:00
int m_allocCount ;
2014-07-30 14:17:46 +04:00
int m_size ;
int m_heapSize ;
2015-06-06 14:19:19 +03:00
Node * m_heap ;
2014-07-30 14:17:46 +04:00
2015-06-06 14:19:19 +03:00
public :
2014-08-05 22:26:16 +04:00
2015-06-06 14:19:19 +03:00
inline bool IsEmpty ( void )
{
return m_size = = 0 ;
}
2014-07-30 14:17:46 +04:00
2015-08-15 18:09:15 +03:00
inline PriorityQueue ( int initialSize = MAX_WAYPOINTS * 0.5f )
2014-07-30 14:17:46 +04:00
{
2015-06-06 14:19:19 +03:00
m_size = 0 ;
m_heapSize = initialSize ;
2015-06-29 21:49:52 +03:00
m_allocCount = 0 ;
m_heap = static_cast < Node * > ( malloc ( sizeof ( Node ) * m_heapSize ) ) ;
2015-06-06 14:19:19 +03:00
}
2014-07-30 14:17:46 +04:00
2015-06-06 14:19:19 +03:00
inline ~ PriorityQueue ( void )
{
2015-06-29 20:51:25 +03:00
free ( m_heap ) ;
2015-06-06 14:19:19 +03:00
m_heap = NULL ;
2014-07-30 14:17:46 +04:00
}
2015-06-06 14:19:19 +03:00
// inserts a value into the priority queue
inline void Push ( int value , float pri )
{
2015-06-29 21:49:52 +03:00
if ( m_allocCount > 20 )
{
AddLogEntry ( false , LL_FATAL , " Tried to re-allocate heap too many times in pathfinder. This usually indicates corrupted waypoint file. Please obtain new copy of waypoint. " ) ;
return ;
}
2015-06-28 19:43:31 +03:00
if ( m_heap = = NULL )
return ;
2015-06-06 14:19:19 +03:00
if ( m_size > = m_heapSize )
{
2015-06-29 21:49:52 +03:00
m_allocCount + + ;
2015-06-06 14:19:19 +03:00
m_heapSize + = 100 ;
2015-06-28 19:43:31 +03:00
Node * newHeap = static_cast < Node * > ( realloc ( m_heap , sizeof ( Node ) * m_heapSize ) ) ;
if ( newHeap ! = NULL )
m_heap = newHeap ;
2015-06-06 14:19:19 +03:00
}
2014-07-30 14:17:46 +04:00
2015-06-06 14:19:19 +03:00
m_heap [ m_size ] . pri = pri ;
m_heap [ m_size ] . id = value ;
2014-07-30 14:17:46 +04:00
2015-06-06 14:19:19 +03:00
int child = + + m_size - 1 ;
2014-07-30 14:17:46 +04:00
2015-06-06 14:19:19 +03:00
while ( child )
{
2015-08-15 18:09:15 +03:00
int parent = ( child - 1 ) * 0.5f ;
2014-07-30 14:17:46 +04:00
2015-06-06 14:19:19 +03:00
if ( m_heap [ parent ] . pri < = m_heap [ child ] . pri )
break ;
2014-07-30 14:17:46 +04:00
2015-06-06 14:19:19 +03:00
Node ref = m_heap [ child ] ;
2014-07-30 14:17:46 +04:00
2015-06-06 14:19:19 +03:00
m_heap [ child ] = m_heap [ parent ] ;
m_heap [ parent ] = ref ;
2014-07-30 14:17:46 +04:00
2015-06-06 14:19:19 +03:00
child = parent ;
2014-07-30 14:17:46 +04:00
}
2015-06-06 14:19:19 +03:00
}
2014-07-30 14:17:46 +04:00
2015-06-06 14:19:19 +03:00
// removes the smallest item from the priority queue
inline int Pop ( void )
{
int result = m_heap [ 0 ] . id ;
2014-07-30 14:17:46 +04:00
2015-06-06 14:19:19 +03:00
m_size - - ;
m_heap [ 0 ] = m_heap [ m_size ] ;
2014-07-30 14:17:46 +04:00
2015-06-06 14:19:19 +03:00
int parent = 0 ;
int child = ( 2 * parent ) + 1 ;
2014-07-30 14:17:46 +04:00
2015-06-06 14:19:19 +03:00
Node ref = m_heap [ parent ] ;
2014-07-30 14:17:46 +04:00
2015-06-06 14:19:19 +03:00
while ( child < m_size )
{
int right = ( 2 * parent ) + 2 ;
2014-07-30 14:17:46 +04:00
2015-06-06 14:19:19 +03:00
if ( right < m_size & & m_heap [ right ] . pri < m_heap [ child ] . pri )
child = right ;
2014-07-30 14:17:46 +04:00
2015-06-06 14:19:19 +03:00
if ( ref . pri < = m_heap [ child ] . pri )
break ;
2014-07-30 14:17:46 +04:00
2015-06-06 14:19:19 +03:00
m_heap [ parent ] = m_heap [ child ] ;
2014-07-30 14:17:46 +04:00
2015-06-06 14:19:19 +03:00
parent = child ;
child = ( 2 * parent ) + 1 ;
}
m_heap [ parent ] = ref ;
return result ;
2014-07-30 14:17:46 +04:00
}
2015-06-06 14:19:19 +03:00
} ;
2014-07-30 14:17:46 +04:00
2014-08-05 21:04:43 +04:00
2015-06-06 14:19:19 +03:00
float gfunctionKillsDistT ( int currentIndex , int parentIndex )
2014-07-30 14:17:46 +04:00
{
// least kills and number of nodes to goal for a team
2015-06-06 14:19:19 +03:00
if ( parentIndex = = - 1 )
2015-08-15 18:09:15 +03:00
return 0.0f ;
2015-06-06 14:19:19 +03:00
float cost = ( g_experienceData + ( currentIndex * g_numWaypoints ) + currentIndex ) - > team0Damage + g_highestDamageT ;
2014-08-05 21:04:43 +04:00
2015-07-24 15:10:51 +03:00
Path * current = waypoints . GetPath ( currentIndex ) ;
2014-07-30 14:17:46 +04:00
for ( int i = 0 ; i < MAX_PATH_INDEX ; i + + )
{
2014-08-05 21:04:43 +04:00
int neighbour = current - > index [ i ] ;
2014-07-30 14:17:46 +04:00
if ( neighbour ! = - 1 )
2015-06-06 14:19:19 +03:00
cost + = ( g_experienceData + ( neighbour * g_numWaypoints ) + neighbour ) - > team0Damage ;
2014-07-30 14:17:46 +04:00
}
2014-08-05 21:04:43 +04:00
if ( current - > flags & FLAG_CROUCH )
2015-08-15 18:09:15 +03:00
cost * = 1.5f ;
2014-07-30 14:17:46 +04:00
2016-01-04 18:26:06 +03:00
return static_cast < float > ( waypoints . GetPathDistance ( parentIndex , currentIndex ) ) + cost ;
2014-07-30 14:17:46 +04:00
}
2014-08-05 21:04:43 +04:00
2015-06-06 14:19:19 +03:00
float gfunctionKillsDistCT ( int currentIndex , int parentIndex )
2014-07-30 14:17:46 +04:00
{
2014-08-05 21:04:43 +04:00
// least kills and number of nodes to goal for a team
2014-07-30 14:17:46 +04:00
2015-06-06 14:19:19 +03:00
if ( parentIndex = = - 1 )
2015-08-15 18:09:15 +03:00
return 0.0f ;
2015-06-06 14:19:19 +03:00
float cost = ( g_experienceData + ( currentIndex * g_numWaypoints ) + currentIndex ) - > team1Damage + g_highestDamageCT ;
2014-08-05 21:04:43 +04:00
2015-07-24 15:10:51 +03:00
Path * current = waypoints . GetPath ( currentIndex ) ;
2014-07-30 14:17:46 +04:00
for ( int i = 0 ; i < MAX_PATH_INDEX ; i + + )
{
2014-08-05 21:04:43 +04:00
int neighbour = current - > index [ i ] ;
2014-07-30 14:17:46 +04:00
if ( neighbour ! = - 1 )
2015-06-06 14:19:19 +03:00
cost + = static_cast < int > ( ( g_experienceData + ( neighbour * g_numWaypoints ) + neighbour ) - > team1Damage ) ;
2014-07-30 14:17:46 +04:00
}
2014-08-05 21:04:43 +04:00
if ( current - > flags & FLAG_CROUCH )
2015-08-15 18:09:15 +03:00
cost * = 1.5f ;
2014-08-05 21:04:43 +04:00
2016-01-04 18:26:06 +03:00
return static_cast < float > ( waypoints . GetPathDistance ( parentIndex , currentIndex ) ) + cost ;
2014-07-30 14:17:46 +04:00
}
2015-06-06 14:19:19 +03:00
float gfunctionKillsDistCTWithHostage ( int currentIndex , int parentIndex )
2014-07-30 14:17:46 +04:00
{
// least kills and number of nodes to goal for a team
2015-07-24 15:10:51 +03:00
Path * current = waypoints . GetPath ( currentIndex ) ;
2014-08-05 21:04:43 +04:00
if ( current - > flags & FLAG_NOHOSTAGE )
2015-08-15 18:09:15 +03:00
return 65355.0f ;
2014-08-05 21:04:43 +04:00
else if ( current - > flags & ( FLAG_CROUCH | FLAG_LADDER ) )
2015-08-15 18:09:15 +03:00
return gfunctionKillsDistCT ( currentIndex , parentIndex ) * 500.0f ;
2014-08-05 21:04:43 +04:00
return gfunctionKillsDistCT ( currentIndex , parentIndex ) ;
}
2015-06-28 19:43:31 +03:00
float gfunctionKillsT ( int currentIndex , int )
2014-08-05 21:04:43 +04:00
{
// least kills to goal for a team
2015-06-06 14:19:19 +03:00
float cost = ( g_experienceData + ( currentIndex * g_numWaypoints ) + currentIndex ) - > team0Damage ;
2014-08-05 21:04:43 +04:00
2015-07-24 15:10:51 +03:00
Path * current = waypoints . GetPath ( currentIndex ) ;
2014-07-30 14:17:46 +04:00
for ( int i = 0 ; i < MAX_PATH_INDEX ; i + + )
{
2014-08-05 21:04:43 +04:00
int neighbour = current - > index [ i ] ;
2014-07-30 14:17:46 +04:00
if ( neighbour ! = - 1 )
2015-06-06 14:19:19 +03:00
cost + = ( g_experienceData + ( neighbour * g_numWaypoints ) + neighbour ) - > team0Damage ;
2014-07-30 14:17:46 +04:00
}
2014-08-05 21:04:43 +04:00
if ( current - > flags & FLAG_CROUCH )
2015-07-19 13:39:00 +03:00
cost * = 1.5f ;
2014-07-30 14:17:46 +04:00
2015-06-06 14:19:19 +03:00
return cost ;
2014-07-30 14:17:46 +04:00
}
2015-06-06 14:19:19 +03:00
float gfunctionKillsCT ( int currentIndex , int parentIndex )
2014-07-30 14:17:46 +04:00
{
// least kills to goal for a team
2015-06-06 14:19:19 +03:00
if ( parentIndex = = - 1 )
2015-08-15 18:09:15 +03:00
return 0.0f ;
2015-06-06 14:19:19 +03:00
float cost = ( g_experienceData + ( currentIndex * g_numWaypoints ) + currentIndex ) - > team1Damage ;
2014-08-05 21:04:43 +04:00
2015-07-24 15:10:51 +03:00
Path * current = waypoints . GetPath ( currentIndex ) ;
2014-07-30 14:17:46 +04:00
for ( int i = 0 ; i < MAX_PATH_INDEX ; i + + )
{
2014-08-05 21:04:43 +04:00
int neighbour = current - > index [ i ] ;
2014-07-30 14:17:46 +04:00
if ( neighbour ! = - 1 )
2015-06-06 14:19:19 +03:00
cost + = ( g_experienceData + ( neighbour * g_numWaypoints ) + neighbour ) - > team1Damage ;
2014-07-30 14:17:46 +04:00
}
2014-08-05 21:04:43 +04:00
if ( current - > flags & FLAG_CROUCH )
2015-08-15 18:09:15 +03:00
cost * = 1.5f ;
2014-07-30 14:17:46 +04:00
2015-06-06 14:19:19 +03:00
return cost + 0.5f ;
2014-07-30 14:17:46 +04:00
}
2015-06-06 14:19:19 +03:00
float gfunctionKillsCTWithHostage ( int currentIndex , int parentIndex )
2014-07-30 14:17:46 +04:00
{
2014-08-05 21:04:43 +04:00
// least kills to goal for a team
2014-07-30 14:17:46 +04:00
2015-06-06 14:19:19 +03:00
if ( parentIndex = = - 1 )
2015-08-15 18:09:15 +03:00
return 0.0f ;
2015-06-06 14:19:19 +03:00
2015-07-24 15:10:51 +03:00
Path * current = waypoints . GetPath ( currentIndex ) ;
2014-07-30 14:17:46 +04:00
2014-08-05 21:04:43 +04:00
if ( current - > flags & FLAG_NOHOSTAGE )
2015-08-15 18:09:15 +03:00
return 65355.0f ;
2014-08-05 21:04:43 +04:00
else if ( current - > flags & ( FLAG_CROUCH | FLAG_LADDER ) )
2015-08-15 18:09:15 +03:00
return gfunctionKillsDistCT ( currentIndex , parentIndex ) * 500.0f ;
2014-07-30 14:17:46 +04:00
2014-08-05 21:04:43 +04:00
return gfunctionKillsCT ( currentIndex , parentIndex ) ;
2014-07-30 14:17:46 +04:00
}
2015-06-06 14:19:19 +03:00
float gfunctionPathDist ( int currentIndex , int parentIndex )
2014-08-05 22:26:16 +04:00
{
if ( parentIndex = = - 1 )
2015-08-15 18:09:15 +03:00
return 0.0f ;
2014-08-05 22:26:16 +04:00
2015-07-24 15:10:51 +03:00
Path * parent = waypoints . GetPath ( parentIndex ) ;
Path * current = waypoints . GetPath ( currentIndex ) ;
2014-08-05 22:26:16 +04:00
for ( int i = 0 ; i < MAX_PATH_INDEX ; i + + )
{
if ( parent - > index [ i ] = = currentIndex )
{
// we don't like ladder or crouch point
if ( current - > flags & ( FLAG_CROUCH | FLAG_LADDER ) )
2015-08-15 18:09:15 +03:00
return parent - > distances [ i ] * 1.5f ;
2014-08-05 22:26:16 +04:00
return parent - > distances [ i ] ;
}
}
2015-08-15 18:09:15 +03:00
return 65355.0f ;
2014-08-05 22:26:16 +04:00
}
2015-06-06 14:19:19 +03:00
float gfunctionPathDistWithHostage ( int currentIndex , int parentIndex )
2014-08-05 22:26:16 +04:00
{
2015-07-24 15:10:51 +03:00
Path * current = waypoints . GetPath ( currentIndex ) ;
2014-08-05 22:26:16 +04:00
if ( current - > flags & FLAG_NOHOSTAGE )
2015-08-15 18:09:15 +03:00
return 65355.0f ;
2015-06-06 14:19:19 +03:00
2014-08-05 22:26:16 +04:00
else if ( current - > flags & ( FLAG_CROUCH | FLAG_LADDER ) )
2015-08-15 18:09:15 +03:00
return gfunctionPathDist ( currentIndex , parentIndex ) * 500.0f ;
2014-08-05 22:26:16 +04:00
return gfunctionPathDist ( currentIndex , parentIndex ) ;
}
2015-06-06 14:19:19 +03:00
float hfunctionSquareDist ( int index , int , int goalIndex )
2014-07-30 14:17:46 +04:00
{
2014-08-05 21:04:43 +04:00
// square distance heuristic
2015-07-24 15:10:51 +03:00
Path * start = waypoints . GetPath ( index ) ;
Path * goal = waypoints . GetPath ( goalIndex ) ;
2014-07-30 14:17:46 +04:00
2015-06-07 23:06:23 +03:00
float xDist = fabsf ( start - > origin . x - goal - > origin . x ) ;
float yDist = fabsf ( start - > origin . y - goal - > origin . y ) ;
float zDist = fabsf ( start - > origin . z - goal - > origin . z ) ;
if ( xDist > yDist )
2015-06-24 15:38:48 +03:00
return 1.4f * yDist + ( xDist - yDist ) + zDist ;
2015-06-07 23:06:23 +03:00
2015-06-24 15:38:48 +03:00
return 1.4f * xDist + ( yDist - xDist ) + zDist ;
2014-07-30 14:17:46 +04:00
}
2015-06-06 14:19:19 +03:00
float hfunctionSquareDistWithHostage ( int index , int startIndex , int goalIndex )
2014-07-30 14:17:46 +04:00
{
2014-08-05 21:04:43 +04:00
// square distance heuristic with hostages
2015-07-24 15:10:51 +03:00
if ( waypoints . GetPath ( startIndex ) - > flags & FLAG_NOHOSTAGE )
2015-08-15 18:09:15 +03:00
return 65355.0f ;
2014-08-05 21:04:43 +04:00
2011-01-05 23:28:48 +04:00
return hfunctionSquareDist ( index , startIndex , goalIndex ) ;
2014-07-30 14:17:46 +04:00
}
2015-06-06 14:19:19 +03:00
float hfunctionNone ( int index , int startIndex , int goalIndex )
2014-07-30 14:17:46 +04:00
{
2015-08-15 18:09:15 +03:00
return hfunctionSquareDist ( index , startIndex , goalIndex ) / ( 128.0f * 10.0f ) ;
2014-07-30 14:17:46 +04:00
}
2015-06-06 14:19:19 +03:00
float hfunctionNumberNodes ( int index , int startIndex , int goalIndex )
2014-08-05 22:26:16 +04:00
{
2015-08-15 18:09:15 +03:00
return hfunctionSquareDist ( index , startIndex , goalIndex ) / 128.0f * g_highestKills ;
2014-08-05 22:26:16 +04:00
}
2014-07-30 14:17:46 +04:00
void Bot : : FindPath ( int srcIndex , int destIndex , unsigned char pathType )
{
// this function finds a path from srcIndex to destIndex
if ( srcIndex > g_numWaypoints - 1 | | srcIndex < 0 )
{
AddLogEntry ( true , LL_ERROR , " Pathfinder source path index not valid (%d) " , srcIndex ) ;
return ;
}
if ( destIndex > g_numWaypoints - 1 | | destIndex < 0 )
{
AddLogEntry ( true , LL_ERROR , " Pathfinder destination path index not valid (%d) " , destIndex ) ;
return ;
}
DeleteSearchNodes ( ) ;
m_chosenGoalIndex = srcIndex ;
2015-08-15 18:09:15 +03:00
m_goalValue = 0.0f ;
2014-07-30 14:17:46 +04:00
// A* Stuff
2015-06-06 14:19:19 +03:00
enum AStarState { OPEN , CLOSED , NEW } ;
2014-07-30 14:17:46 +04:00
2015-06-06 14:19:19 +03:00
struct AStar
2014-07-30 14:17:46 +04:00
{
2015-06-06 14:19:19 +03:00
float g ;
float f ;
2014-07-30 14:17:46 +04:00
short parentIndex ;
2015-06-06 14:19:19 +03:00
AStarState state ;
2014-07-30 14:17:46 +04:00
} astar [ MAX_WAYPOINTS ] ;
2015-06-24 15:38:48 +03:00
PriorityQueue openList ;
2014-07-30 14:17:46 +04:00
for ( int i = 0 ; i < MAX_WAYPOINTS ; i + + )
{
2015-08-15 18:09:15 +03:00
astar [ i ] . g = 0.0f ;
astar [ i ] . f = 0.0f ;
2014-07-30 14:17:46 +04:00
astar [ i ] . parentIndex = - 1 ;
astar [ i ] . state = NEW ;
}
2015-06-06 14:19:19 +03:00
float ( * gcalc ) ( int , int ) = NULL ;
float ( * hcalc ) ( int , int , int ) = NULL ;
2014-07-30 14:17:46 +04:00
2014-08-05 21:04:43 +04:00
switch ( pathType )
2014-07-30 14:17:46 +04:00
{
2014-08-05 21:04:43 +04:00
case 0 :
if ( ( g_mapType & MAP_CS ) & & HasHostage ( ) )
{
2014-08-05 22:26:16 +04:00
gcalc = gfunctionPathDistWithHostage ;
2014-08-05 21:04:43 +04:00
hcalc = hfunctionSquareDistWithHostage ;
}
2014-07-30 14:17:46 +04:00
else
2014-08-05 21:04:43 +04:00
{
2014-08-05 22:26:16 +04:00
gcalc = gfunctionPathDist ;
2014-08-05 21:04:43 +04:00
hcalc = hfunctionSquareDist ;
}
break ;
2014-07-30 14:17:46 +04:00
2014-08-05 21:04:43 +04:00
case 1 :
2014-08-06 00:03:50 +04:00
if ( m_team = = TEAM_TF )
2014-08-05 21:04:43 +04:00
{
2014-07-30 14:17:46 +04:00
gcalc = gfunctionKillsDistT ;
2014-08-05 21:04:43 +04:00
hcalc = hfunctionSquareDist ;
}
else if ( ( g_mapType & MAP_CS ) & & HasHostage ( ) )
{
gcalc = gfunctionKillsDistCTWithHostage ;
hcalc = hfunctionSquareDistWithHostage ;
}
2014-07-30 14:17:46 +04:00
else
2014-08-05 21:04:43 +04:00
{
2014-07-30 14:17:46 +04:00
gcalc = gfunctionKillsDistCT ;
2014-08-05 21:04:43 +04:00
hcalc = hfunctionSquareDist ;
}
break ;
2014-07-30 14:17:46 +04:00
2014-08-05 21:04:43 +04:00
case 2 :
2015-06-28 19:43:31 +03:00
default :
2014-08-06 00:03:50 +04:00
if ( m_team = = TEAM_TF )
2014-08-05 21:04:43 +04:00
{
2014-07-30 14:17:46 +04:00
gcalc = gfunctionKillsT ;
2014-08-05 21:04:43 +04:00
hcalc = hfunctionNone ;
}
else if ( ( g_mapType & MAP_CS ) & & HasHostage ( ) )
{
gcalc = gfunctionKillsDistCTWithHostage ;
hcalc = hfunctionNone ;
}
2014-07-30 14:17:46 +04:00
else
2014-08-05 21:04:43 +04:00
{
2014-07-30 14:17:46 +04:00
gcalc = gfunctionKillsCT ;
2014-08-05 21:04:43 +04:00
hcalc = hfunctionNone ;
}
break ;
2014-07-30 14:17:46 +04:00
}
2015-06-06 14:19:19 +03:00
2014-07-30 14:17:46 +04:00
// put start node into open list
2014-08-05 21:04:43 +04:00
astar [ srcIndex ] . g = gcalc ( srcIndex , - 1 ) ;
2011-01-05 23:28:48 +04:00
astar [ srcIndex ] . f = astar [ srcIndex ] . g + hcalc ( srcIndex , srcIndex , destIndex ) ;
2014-07-30 14:17:46 +04:00
astar [ srcIndex ] . state = OPEN ;
2015-06-06 14:19:19 +03:00
openList . Push ( srcIndex , astar [ srcIndex ] . g ) ;
2014-07-30 14:17:46 +04:00
2015-06-06 14:19:19 +03:00
while ( ! openList . IsEmpty ( ) )
2014-07-30 14:17:46 +04:00
{
// remove the first node from the open list
2015-06-06 14:19:19 +03:00
int currentIndex = openList . Pop ( ) ;
2014-07-30 14:17:46 +04:00
// is the current node the goal node?
if ( currentIndex = = destIndex )
{
// build the complete path
m_navNode = NULL ;
do
{
PathNode * path = new PathNode ;
path - > index = currentIndex ;
path - > next = m_navNode ;
m_navNode = path ;
currentIndex = astar [ currentIndex ] . parentIndex ;
} while ( currentIndex ! = - 1 ) ;
m_navNodeStart = m_navNode ;
return ;
}
if ( astar [ currentIndex ] . state ! = OPEN )
continue ;
// put current node into CLOSED list
astar [ currentIndex ] . state = CLOSED ;
// now expand the current node
for ( int i = 0 ; i < MAX_PATH_INDEX ; i + + )
{
2015-07-24 15:10:51 +03:00
int currentChild = waypoints . GetPath ( currentIndex ) - > index [ i ] ;
2014-07-30 14:17:46 +04:00
2014-08-05 21:04:43 +04:00
if ( currentChild = = - 1 )
2014-07-30 14:17:46 +04:00
continue ;
// calculate the F value as F = G + H
2015-06-06 14:19:19 +03:00
float g = astar [ currentIndex ] . g + gcalc ( currentChild , currentIndex ) ;
float h = hcalc ( currentChild , srcIndex , destIndex ) ;
float f = g + h ;
2014-07-30 14:17:46 +04:00
2014-08-05 21:04:43 +04:00
if ( astar [ currentChild ] . state = = NEW | | astar [ currentChild ] . f > f )
2014-07-30 14:17:46 +04:00
{
// put the current child into open list
2014-08-05 21:04:43 +04:00
astar [ currentChild ] . parentIndex = currentIndex ;
astar [ currentChild ] . state = OPEN ;
2014-07-30 14:17:46 +04:00
2014-08-05 21:04:43 +04:00
astar [ currentChild ] . g = g ;
astar [ currentChild ] . f = f ;
2014-07-30 14:17:46 +04:00
2015-06-06 14:19:19 +03:00
openList . Push ( currentChild , g ) ;
2014-07-30 14:17:46 +04:00
}
}
}
FindShortestPath ( srcIndex , destIndex ) ; // A* found no path, try floyd pathfinder instead
}
void Bot : : DeleteSearchNodes ( void )
{
PathNode * deletingNode = NULL ;
PathNode * node = m_navNodeStart ;
while ( node ! = NULL )
{
deletingNode = node - > next ;
delete node ;
node = deletingNode ;
}
m_navNodeStart = NULL ;
m_navNode = NULL ;
m_chosenGoalIndex = - 1 ;
}
2015-06-10 23:41:55 +03:00
int Bot : : GetAimingWaypoint ( const Vector & to )
2014-07-30 14:17:46 +04:00
{
2015-07-12 17:18:20 +03:00
// return the most distant waypoint which is seen from the bot to the target and is within count
2014-07-30 14:17:46 +04:00
if ( m_currentWaypointIndex = = - 1 )
2015-07-24 15:10:51 +03:00
m_currentWaypointIndex = ChangeWptIndex ( waypoints . FindNearest ( pev - > origin ) ) ;
2014-07-30 14:17:46 +04:00
int srcIndex = m_currentWaypointIndex ;
2015-07-24 15:10:51 +03:00
int destIndex = waypoints . FindNearest ( to ) ;
2014-07-30 14:17:46 +04:00
int bestIndex = srcIndex ;
while ( destIndex ! = srcIndex )
{
2015-07-24 15:10:51 +03:00
destIndex = * ( waypoints . m_pathMatrix + ( destIndex * g_numWaypoints ) + srcIndex ) ;
2014-07-30 14:17:46 +04:00
if ( destIndex < 0 )
break ;
2015-07-24 15:10:51 +03:00
if ( waypoints . IsVisible ( m_currentWaypointIndex , destIndex ) )
2014-07-30 14:17:46 +04:00
{
bestIndex = destIndex ;
break ;
}
}
return bestIndex ;
}
bool Bot : : FindWaypoint ( void )
{
// this function find a waypoint in the near of the bot if bot had lost his path of pathfinder needs
// to be restarted over again.
int waypointIndeces [ 3 ] , coveredWaypoint = - 1 , i = 0 ;
float reachDistances [ 3 ] ;
// nullify all waypoint search stuff
2015-06-04 11:52:48 +03:00
for ( i = 0 ; i < 3 ; i + + )
2014-07-30 14:17:46 +04:00
{
waypointIndeces [ i ] = - 1 ;
2015-08-15 18:09:15 +03:00
reachDistances [ i ] = 9999.0f ;
2014-07-30 14:17:46 +04:00
}
// do main search loop
2015-06-04 11:52:48 +03:00
for ( i = 0 ; i < g_numWaypoints ; i + + )
2014-07-30 14:17:46 +04:00
{
// ignore current waypoint and previous recent waypoints...
2015-08-01 00:18:50 +03:00
if ( i = = m_currentWaypointIndex | | i = = m_prevWptIndex [ 0 ] | | i = = m_prevWptIndex [ 1 ] | | i = = m_prevWptIndex [ 2 ] )
2014-07-30 14:17:46 +04:00
continue ;
2015-07-24 15:10:51 +03:00
if ( ( g_mapType & MAP_CS ) & & HasHostage ( ) & & ( waypoints . GetPath ( i ) - > flags & FLAG_NOHOSTAGE ) )
2015-06-07 19:43:16 +03:00
continue ;
2014-07-30 14:17:46 +04:00
// ignore non-reacheable waypoints...
2015-07-24 15:10:51 +03:00
if ( ! waypoints . Reachable ( this , i ) )
2014-07-30 14:17:46 +04:00
continue ;
// check if waypoint is already used by another bot...
2015-06-04 11:52:48 +03:00
if ( IsPointOccupied ( i ) )
2014-07-30 14:17:46 +04:00
{
coveredWaypoint = i ;
continue ;
}
// now pick 1-2 random waypoints that near the bot
2015-07-24 15:10:51 +03:00
float distance = ( waypoints . GetPath ( i ) - > origin - pev - > origin ) . GetLengthSquared ( ) ;
2014-07-30 14:17:46 +04:00
// now fill the waypoint list
for ( int j = 0 ; j < 3 ; j + + )
{
if ( distance < reachDistances [ j ] )
{
waypointIndeces [ j ] = i ;
reachDistances [ j ] = distance ;
}
}
}
// now pick random one from choosen
if ( waypointIndeces [ 2 ] ! = - 1 )
2015-06-09 15:45:34 +03:00
i = Random . Long ( 0 , 2 ) ;
2014-07-30 14:17:46 +04:00
else if ( waypointIndeces [ 1 ] ! = - 1 )
2015-06-09 15:45:34 +03:00
i = Random . Long ( 0 , 1 ) ;
2014-07-30 14:17:46 +04:00
else if ( waypointIndeces [ 0 ] ! = - 1 )
2015-06-09 15:45:34 +03:00
i = Random . Long ( 0 , 0 ) ;
2014-07-30 14:17:46 +04:00
else if ( coveredWaypoint ! = - 1 )
2015-06-07 19:43:16 +03:00
{
i = 0 ;
waypointIndeces [ i ] = coveredWaypoint ;
}
2014-07-30 14:17:46 +04:00
else
{
2015-06-07 19:43:16 +03:00
i = 0 ;
2014-07-30 14:17:46 +04:00
Array < int > found ;
2015-07-24 15:10:51 +03:00
waypoints . FindInRadius ( found , 256.0f , pev - > origin ) ;
2015-06-07 23:06:23 +03:00
2014-07-30 14:17:46 +04:00
if ( ! found . IsEmpty ( ) )
2015-06-07 23:06:23 +03:00
{
bool gotId = false ;
int random = found . GetRandomElement ( ) ; ;
while ( ! found . IsEmpty ( ) )
{
int index = found . Pop ( ) ;
2015-07-24 15:10:51 +03:00
if ( ! waypoints . Reachable ( this , index ) )
2015-06-07 23:06:23 +03:00
continue ;
waypointIndeces [ i ] = index ;
gotId = true ;
break ;
}
if ( ! gotId )
waypointIndeces [ i ] = random ;
}
2014-07-30 14:17:46 +04:00
else
2015-06-09 15:45:34 +03:00
waypointIndeces [ i ] = Random . Long ( 0 , g_numWaypoints - 1 ) ;
2014-07-30 14:17:46 +04:00
}
m_collideTime = GetWorldTime ( ) ;
2015-06-07 19:43:16 +03:00
ChangeWptIndex ( waypointIndeces [ i ] ) ;
2014-07-30 14:17:46 +04:00
return true ;
}
void Bot : : GetValidWaypoint ( void )
{
// checks if the last waypoint the bot was heading for is still valid
// if bot hasn't got a waypoint we need a new one anyway or if time to get there expired get new one as well
if ( m_currentWaypointIndex = = - 1 )
{
DeleteSearchNodes ( ) ;
FindWaypoint ( ) ;
m_waypointOrigin = m_currentPath - > origin ;
// FIXME: Do some error checks if we got a waypoint
}
2015-06-04 11:52:48 +03:00
else if ( m_navTimeset + GetEstimatedReachTime ( ) < GetWorldTime ( ) & & IsEntityNull ( m_enemy ) )
2014-07-30 14:17:46 +04:00
{
2014-08-06 00:03:50 +04:00
if ( m_team = = TEAM_TF )
2014-07-30 14:17:46 +04:00
{
int value = ( g_experienceData + ( m_currentWaypointIndex * g_numWaypoints ) + m_currentWaypointIndex ) - > team0Damage ;
value + = 100 ;
if ( value > MAX_DAMAGE_VALUE )
value = MAX_DAMAGE_VALUE ;
( g_experienceData + ( m_currentWaypointIndex * g_numWaypoints ) + m_currentWaypointIndex ) - > team0Damage = static_cast < unsigned short > ( value ) ;
// affect nearby connected with victim waypoints
for ( int i = 0 ; i < MAX_PATH_INDEX ; i + + )
{
if ( ( m_currentPath - > index [ i ] > - 1 ) & & ( m_currentPath - > index [ i ] < g_numWaypoints ) )
{
value = ( g_experienceData + ( m_currentPath - > index [ i ] * g_numWaypoints ) + m_currentPath - > index [ i ] ) - > team0Damage ;
value + = 2 ;
if ( value > MAX_DAMAGE_VALUE )
value = MAX_DAMAGE_VALUE ;
( g_experienceData + ( m_currentPath - > index [ i ] * g_numWaypoints ) + m_currentPath - > index [ i ] ) - > team0Damage = static_cast < unsigned short > ( value ) ;
}
}
}
else
{
int value = ( g_experienceData + ( m_currentWaypointIndex * g_numWaypoints ) + m_currentWaypointIndex ) - > team1Damage ;
value + = 100 ;
if ( value > MAX_DAMAGE_VALUE )
value = MAX_DAMAGE_VALUE ;
( g_experienceData + ( m_currentWaypointIndex * g_numWaypoints ) + m_currentWaypointIndex ) - > team1Damage = static_cast < unsigned short > ( value ) ;
// affect nearby connected with victim waypoints
for ( int i = 0 ; i < MAX_PATH_INDEX ; i + + )
{
if ( ( m_currentPath - > index [ i ] > - 1 ) & & ( m_currentPath - > index [ i ] < g_numWaypoints ) )
{
value = ( g_experienceData + ( m_currentPath - > index [ i ] * g_numWaypoints ) + m_currentPath - > index [ i ] ) - > team1Damage ;
value + = 2 ;
if ( value > MAX_DAMAGE_VALUE )
value = MAX_DAMAGE_VALUE ;
( g_experienceData + ( m_currentPath - > index [ i ] * g_numWaypoints ) + m_currentPath - > index [ i ] ) - > team1Damage = static_cast < unsigned short > ( value ) ;
}
}
}
DeleteSearchNodes ( ) ;
2015-06-09 22:16:08 +03:00
if ( m_goalFailed > 1 )
{
int newGoal = FindGoal ( ) ;
m_prevGoalIndex = newGoal ;
m_chosenGoalIndex = newGoal ;
// remember index
GetTask ( ) - > data = newGoal ;
2015-06-11 23:22:50 +03:00
// do path finding if it's not the current waypoint
2015-06-09 22:16:08 +03:00
if ( newGoal ! = m_currentWaypointIndex )
FindPath ( m_currentWaypointIndex , newGoal , m_pathType ) ;
m_goalFailed = 0 ;
}
else
{
FindWaypoint ( ) ;
m_goalFailed + + ;
}
2014-07-30 14:17:46 +04:00
m_waypointOrigin = m_currentPath - > origin ;
}
}
2015-06-29 20:51:25 +03:00
int Bot : : ChangeWptIndex ( int waypointIndex )
2014-07-30 14:17:46 +04:00
{
2015-06-09 22:16:08 +03:00
if ( waypointIndex = = - 1 )
2015-06-29 20:51:25 +03:00
return 0 ;
2015-06-09 22:16:08 +03:00
2014-07-30 14:17:46 +04:00
m_prevWptIndex [ 4 ] = m_prevWptIndex [ 3 ] ;
m_prevWptIndex [ 3 ] = m_prevWptIndex [ 2 ] ;
m_prevWptIndex [ 2 ] = m_prevWptIndex [ 1 ] ;
2015-06-04 11:52:48 +03:00
m_prevWptIndex [ 0 ] = m_currentWaypointIndex ;
2014-07-30 14:17:46 +04:00
m_currentWaypointIndex = waypointIndex ;
m_navTimeset = GetWorldTime ( ) ;
2015-07-24 15:10:51 +03:00
m_currentPath = waypoints . GetPath ( m_currentWaypointIndex ) ;
2015-06-09 22:16:08 +03:00
m_waypointFlags = m_currentPath - > flags ;
2015-06-29 20:51:25 +03:00
return m_currentWaypointIndex ; // to satisfy static-code analyzers
2014-07-30 14:17:46 +04:00
}
int Bot : : ChooseBombWaypoint ( void )
{
// this function finds the best goal (bomb) waypoint for CTs when searching for a planted bomb.
2015-07-24 15:10:51 +03:00
Array < int > goals = waypoints . m_goalPoints ;
2014-07-30 14:17:46 +04:00
if ( goals . IsEmpty ( ) )
2015-06-09 15:45:34 +03:00
return Random . Long ( 0 , g_numWaypoints - 1 ) ; // reliability check
2014-07-30 14:17:46 +04:00
Vector bombOrigin = CheckBombAudible ( ) ;
// if bomb returns no valid vector, return the current bot pos
2015-08-15 18:09:15 +03:00
if ( bombOrigin . IsZero ( ) )
2014-07-30 14:17:46 +04:00
bombOrigin = pev - > origin ;
int goal = 0 , count = 0 ;
2016-01-07 18:49:55 +03:00
float lastDistance = 999999.0f ;
2014-07-30 14:17:46 +04:00
// find nearest goal waypoint either to bomb (if "heard" or player)
2015-06-28 19:43:31 +03:00
FOR_EACH_AE ( goals , i )
2014-07-30 14:17:46 +04:00
{
2015-07-24 15:10:51 +03:00
float distance = ( waypoints . GetPath ( goals [ i ] ) - > origin - bombOrigin ) . GetLengthSquared ( ) ;
2014-07-30 14:17:46 +04:00
// check if we got more close distance
if ( distance < lastDistance )
{
goal = goals [ i ] ;
2015-06-04 11:52:48 +03:00
lastDistance = distance ;
2014-07-30 14:17:46 +04:00
}
}
2015-07-24 15:10:51 +03:00
while ( waypoints . IsGoalVisited ( goal ) )
2014-07-30 14:17:46 +04:00
{
goal = goals . GetRandomElement ( ) ;
if ( count + + > = goals . GetElementNumber ( ) )
break ;
}
return goal ;
}
2015-06-10 23:41:55 +03:00
int Bot : : FindDefendWaypoint ( const Vector & origin )
2014-07-30 14:17:46 +04:00
{
// this function tries to find a good position which has a line of sight to a position,
// provides enough cover point, and is far away from the defending position
TraceResult tr ;
int waypointIndex [ MAX_PATH_INDEX ] ;
int minDistance [ MAX_PATH_INDEX ] ;
for ( int i = 0 ; i < MAX_PATH_INDEX ; i + + )
{
waypointIndex [ i ] = - 1 ;
minDistance [ i ] = 128 ;
}
2015-07-24 15:10:51 +03:00
int posIndex = waypoints . FindNearest ( origin ) ;
int srcIndex = waypoints . FindNearest ( pev - > origin ) ;
2014-07-30 14:17:46 +04:00
// some of points not found, return random one
if ( srcIndex = = - 1 | | posIndex = = - 1 )
2015-06-09 15:45:34 +03:00
return Random . Long ( 0 , g_numWaypoints - 1 ) ;
2014-07-30 14:17:46 +04:00
for ( int i = 0 ; i < g_numWaypoints ; i + + ) // find the best waypoint now
{
// exclude ladder & current waypoints
2015-07-24 15:10:51 +03:00
if ( ( waypoints . GetPath ( i ) - > flags & FLAG_LADDER ) | | i = = srcIndex | | ! waypoints . IsVisible ( i , posIndex ) | | IsPointOccupied ( i ) )
2014-07-30 14:17:46 +04:00
continue ;
// use the 'real' pathfinding distances
2016-01-04 18:26:06 +03:00
int distance = waypoints . GetPathDistance ( srcIndex , i ) ;
2014-07-30 14:17:46 +04:00
2016-01-04 18:26:06 +03:00
// skip wayponts with distance more than 512 units
if ( distance > 512 )
2014-07-30 14:17:46 +04:00
continue ;
2015-07-24 15:10:51 +03:00
TraceLine ( waypoints . GetPath ( i ) - > origin , waypoints . GetPath ( posIndex ) - > origin , true , true , GetEntity ( ) , & tr ) ;
2014-07-30 14:17:46 +04:00
// check if line not hit anything
2016-01-04 18:26:06 +03:00
if ( tr . flFraction ! = 1.0f )
2014-07-30 14:17:46 +04:00
continue ;
for ( int j = 0 ; j < MAX_PATH_INDEX ; j + + )
{
2016-01-04 18:26:06 +03:00
if ( distance > minDistance [ j ] )
2014-07-30 14:17:46 +04:00
{
waypointIndex [ j ] = i ;
2016-01-04 18:26:06 +03:00
minDistance [ j ] = distance ;
2014-07-30 14:17:46 +04:00
}
}
}
// use statistic if we have them
for ( int i = 0 ; i < MAX_PATH_INDEX ; i + + )
{
if ( waypointIndex [ i ] ! = - 1 )
{
Experience * exp = ( g_experienceData + ( waypointIndex [ i ] * g_numWaypoints ) + waypointIndex [ i ] ) ;
int experience = - 1 ;
2014-08-06 00:03:50 +04:00
if ( m_team = = TEAM_TF )
2014-07-30 14:17:46 +04:00
experience = exp - > team0Damage ;
else
experience = exp - > team1Damage ;
2014-08-06 00:03:50 +04:00
experience = ( experience * 100 ) / ( m_team = = TEAM_TF ? g_highestDamageT : g_highestDamageCT ) ;
2014-07-30 14:17:46 +04:00
minDistance [ i ] = ( experience * 100 ) / 8192 ;
minDistance [ i ] + = experience ;
}
}
bool isOrderChanged = false ;
// sort results waypoints for farest distance
do
{
isOrderChanged = false ;
// completely sort the data
for ( int i = 0 ; i < 3 & & waypointIndex [ i ] ! = - 1 & & waypointIndex [ i + 1 ] ! = - 1 & & minDistance [ i ] > minDistance [ i + 1 ] ; i + + )
{
int index = waypointIndex [ i ] ;
waypointIndex [ i ] = waypointIndex [ i + 1 ] ;
waypointIndex [ i + 1 ] = index ;
index = minDistance [ i ] ;
minDistance [ i ] = minDistance [ i + 1 ] ;
minDistance [ i + 1 ] = index ;
isOrderChanged = true ;
}
} while ( isOrderChanged ) ;
2016-01-04 18:26:06 +03:00
2015-06-28 19:43:31 +03:00
if ( waypointIndex [ 0 ] = = - 1 )
{
Array < int > found ;
2015-07-01 00:47:39 +03:00
for ( int i = 0 ; i < g_numWaypoints ; i + + )
{
2016-01-04 18:26:06 +03:00
if ( ( waypoints . GetPath ( i ) - > origin - origin ) . GetLength ( ) < = 1248.0f & & ! waypoints . IsVisible ( i , posIndex ) & & ! IsPointOccupied ( i ) )
2015-07-01 00:47:39 +03:00
found . Push ( i ) ;
}
2015-06-28 19:43:31 +03:00
if ( found . IsEmpty ( ) )
return Random . Long ( 0 , g_numWaypoints - 1 ) ; // most worst case, since there a evil error in waypoints
return found . GetRandomElement ( ) ;
}
2014-07-30 14:17:46 +04:00
int index = 0 ;
for ( ; index < MAX_PATH_INDEX ; index + + )
{
if ( waypointIndex [ index ] = = - 1 )
break ;
}
2015-08-15 18:09:15 +03:00
return waypointIndex [ Random . Long ( 0 , ( index - 1 ) * 0.5f ) ] ;
2014-07-30 14:17:46 +04:00
}
int Bot : : FindCoverWaypoint ( float maxDistance )
{
// this function tries to find a good cover waypoint if bot wants to hide
// do not move to a position near to the enemy
if ( maxDistance > ( m_lastEnemyOrigin - pev - > origin ) . GetLength ( ) )
maxDistance = ( m_lastEnemyOrigin - pev - > origin ) . GetLength ( ) ;
2015-08-15 18:09:15 +03:00
if ( maxDistance < 300.0f )
maxDistance = 300.0f ;
2014-07-30 14:17:46 +04:00
int srcIndex = m_currentWaypointIndex ;
2015-07-24 15:10:51 +03:00
int enemyIndex = waypoints . FindNearest ( m_lastEnemyOrigin ) ;
2014-07-30 14:17:46 +04:00
Array < int > enemyIndices ;
int waypointIndex [ MAX_PATH_INDEX ] ;
int minDistance [ MAX_PATH_INDEX ] ;
for ( int i = 0 ; i < MAX_PATH_INDEX ; i + + )
{
waypointIndex [ i ] = - 1 ;
minDistance [ i ] = static_cast < int > ( maxDistance ) ;
}
if ( enemyIndex = = - 1 )
return - 1 ;
// now get enemies neigbouring points
for ( int i = 0 ; i < MAX_PATH_INDEX ; i + + )
{
2015-07-24 15:10:51 +03:00
if ( waypoints . GetPath ( enemyIndex ) - > index [ i ] ! = - 1 )
enemyIndices . Push ( waypoints . GetPath ( enemyIndex ) - > index [ i ] ) ;
2014-07-30 14:17:46 +04:00
}
// ensure we're on valid point
ChangeWptIndex ( srcIndex ) ;
// find the best waypoint now
for ( int i = 0 ; i < g_numWaypoints ; i + + )
{
// exclude ladder, current waypoints and waypoints seen by the enemy
2015-07-24 15:10:51 +03:00
if ( ( waypoints . GetPath ( i ) - > flags & FLAG_LADDER ) | | i = = srcIndex | | waypoints . IsVisible ( enemyIndex , i ) )
2014-07-30 14:17:46 +04:00
continue ;
bool neighbourVisible = false ; // now check neighbour waypoints for visibility
2015-06-28 19:43:31 +03:00
FOR_EACH_AE ( enemyIndices , j )
2014-07-30 14:17:46 +04:00
{
2015-07-24 15:10:51 +03:00
if ( waypoints . IsVisible ( enemyIndices [ j ] , i ) )
2014-07-30 14:17:46 +04:00
{
neighbourVisible = true ;
break ;
}
}
// skip visible points
if ( neighbourVisible )
continue ;
// use the 'real' pathfinding distances
2015-07-24 15:10:51 +03:00
int distances = waypoints . GetPathDistance ( srcIndex , i ) ;
int enemyDistance = waypoints . GetPathDistance ( enemyIndex , i ) ;
2014-07-30 14:17:46 +04:00
if ( distances > = enemyDistance )
continue ;
for ( int j = 0 ; j < MAX_PATH_INDEX ; j + + )
{
if ( distances < minDistance [ j ] )
{
waypointIndex [ j ] = i ;
minDistance [ j ] = distances ;
break ;
}
}
}
// use statistic if we have them
for ( int i = 0 ; i < MAX_PATH_INDEX ; i + + )
{
if ( waypointIndex [ i ] ! = - 1 )
{
Experience * exp = ( g_experienceData + ( waypointIndex [ i ] * g_numWaypoints ) + waypointIndex [ i ] ) ;
int experience = - 1 ;
2014-08-06 00:03:50 +04:00
if ( m_team = = TEAM_TF )
2014-07-30 14:17:46 +04:00
experience = exp - > team0Damage ;
else
experience = exp - > team1Damage ;
experience = ( experience * 100 ) / MAX_DAMAGE_VALUE ;
minDistance [ i ] = ( experience * 100 ) / 8192 ;
minDistance [ i ] + = experience ;
}
}
bool isOrderChanged ;
// sort resulting waypoints for nearest distance
do
{
isOrderChanged = false ;
for ( int i = 0 ; i < 3 & & waypointIndex [ i ] ! = - 1 & & waypointIndex [ i + 1 ] ! = - 1 & & minDistance [ i ] > minDistance [ i + 1 ] ; i + + )
{
int index = waypointIndex [ i ] ;
waypointIndex [ i ] = waypointIndex [ i + 1 ] ;
waypointIndex [ i + 1 ] = index ;
index = minDistance [ i ] ;
minDistance [ i ] = minDistance [ i + 1 ] ;
minDistance [ i + 1 ] = index ;
isOrderChanged = true ;
}
} while ( isOrderChanged ) ;
TraceResult tr ;
// take the first one which isn't spotted by the enemy
for ( int i = 0 ; i < MAX_PATH_INDEX ; i + + )
{
if ( waypointIndex [ i ] ! = - 1 )
{
2015-08-15 18:09:15 +03:00
TraceLine ( m_lastEnemyOrigin + Vector ( 0.0f , 0.0f , 36.0f ) , waypoints . GetPath ( waypointIndex [ i ] ) - > origin , true , true , GetEntity ( ) , & tr ) ;
2014-07-30 14:17:46 +04:00
2016-01-04 18:26:06 +03:00
if ( tr . flFraction < 1.0f )
2014-07-30 14:17:46 +04:00
return waypointIndex [ i ] ;
}
}
// if all are seen by the enemy, take the first one
if ( waypointIndex [ 0 ] ! = - 1 )
return waypointIndex [ 0 ] ;
return - 1 ; // do not use random points
}
bool Bot : : GetBestNextWaypoint ( void )
{
2015-06-11 16:53:21 +03:00
// this function does a realtime post processing of waypoints return from the
2014-07-30 14:17:46 +04:00
// pathfinder, to vary paths and find the best waypoint on our way
InternalAssert ( m_navNode ! = NULL ) ;
InternalAssert ( m_navNode - > next ! = NULL ) ;
2015-06-04 11:52:48 +03:00
if ( ! IsPointOccupied ( m_navNode - > index ) )
2014-07-30 14:17:46 +04:00
return false ;
for ( int i = 0 ; i < MAX_PATH_INDEX ; i + + )
{
int id = m_currentPath - > index [ i ] ;
2015-07-24 15:10:51 +03:00
if ( id ! = - 1 & & waypoints . IsConnected ( id , m_navNode - > next - > index ) & & waypoints . IsConnected ( m_currentWaypointIndex , id ) )
2014-07-30 14:17:46 +04:00
{
2015-07-24 15:10:51 +03:00
if ( waypoints . GetPath ( id ) - > flags & FLAG_LADDER ) // don't use ladder waypoints as alternative
2014-07-30 14:17:46 +04:00
continue ;
2015-06-04 11:52:48 +03:00
if ( ! IsPointOccupied ( id ) )
2014-07-30 14:17:46 +04:00
{
m_navNode - > index = id ;
return true ;
}
}
}
return false ;
}
bool Bot : : HeadTowardWaypoint ( void )
{
// advances in our pathfinding list and sets the appropiate destination origins for this bot
GetValidWaypoint ( ) ; // check if old waypoints is still reliable
// no waypoints from pathfinding?
if ( m_navNode = = NULL )
return false ;
TraceResult tr ;
m_navNode = m_navNode - > next ; // advance in list
m_currentTravelFlags = 0 ; // reset travel flags (jumping etc)
// we're not at the end of the list?
if ( m_navNode ! = NULL )
{
// if in between a route, postprocess the waypoint (find better alternatives)...
if ( m_navNode ! = m_navNodeStart & & m_navNode - > next ! = NULL )
{
GetBestNextWaypoint ( ) ;
m_minSpeed = pev - > maxspeed ;
// only if we in normal task and bomb is not planted
2015-06-11 16:53:21 +03:00
if ( GetTaskId ( ) = = TASK_NORMAL & & g_timeRoundMid + 10.0f < GetWorldTime ( ) & & m_timeCamping + 30.0f < GetWorldTime ( ) & & ! g_bombPlanted & & m_personality ! = PERSONALITY_RUSHER & & ! m_hasC4 & & ! m_isVIP & & m_loosedBombWptIndex = = - 1 & & ! HasHostage ( ) )
2014-07-30 14:17:46 +04:00
{
m_campButtons = 0 ;
2015-07-17 19:23:31 +03:00
int nextIndex = m_navNode - > next - > index ;
2011-01-05 23:28:48 +04:00
float kills = 0 ;
2014-07-30 14:17:46 +04:00
2014-08-06 00:03:50 +04:00
if ( m_team = = TEAM_TF )
2015-07-17 19:23:31 +03:00
kills = ( g_experienceData + ( nextIndex * g_numWaypoints ) + nextIndex ) - > team0Damage / g_highestDamageT ;
2014-07-30 14:17:46 +04:00
else
2015-07-17 19:23:31 +03:00
kills = ( g_experienceData + ( nextIndex * g_numWaypoints ) + nextIndex ) - > team1Damage / g_highestDamageCT ;
2014-07-30 14:17:46 +04:00
2015-06-04 11:52:48 +03:00
// if damage done higher than one
2015-06-11 16:53:21 +03:00
if ( kills > 0.15f & & g_timeRoundMid + 15.0f < GetWorldTime ( ) )
2015-06-04 11:52:48 +03:00
{
2015-06-08 22:55:57 +03:00
switch ( m_personality )
{
case PERSONALITY_NORMAL :
kills * = 0.33f ;
break ;
default :
kills * = 0.5f ;
break ;
}
2015-06-09 22:16:08 +03:00
if ( m_baseAgressionLevel < kills & & HasPrimaryWeapon ( ) )
2014-07-30 14:17:46 +04:00
{
2015-08-15 18:09:15 +03:00
PushTask ( TASK_CAMP , TASKPRI_CAMP , - 1 , GetWorldTime ( ) + Random . Float ( m_difficulty * 0.5f , m_difficulty ) * 5.0f , true ) ;
2015-07-24 15:10:51 +03:00
PushTask ( TASK_MOVETOPOSITION , TASKPRI_MOVETOPOSITION , FindDefendWaypoint ( waypoints . GetPath ( nextIndex ) - > origin ) , GetWorldTime ( ) + Random . Float ( 3.0f , 10.0f ) , true ) ;
2014-07-30 14:17:46 +04:00
}
}
2015-06-08 22:55:57 +03:00
else if ( g_botsCanPause & & ! IsOnLadder ( ) & & ! IsInWater ( ) & & ! m_currentTravelFlags & & IsOnFloor ( ) )
2014-07-30 14:17:46 +04:00
{
if ( static_cast < float > ( kills ) = = m_baseAgressionLevel )
m_campButtons | = IN_DUCK ;
2015-06-09 22:16:08 +03:00
else if ( Random . Long ( 1 , 100 ) > m_difficulty * 25 )
2014-07-30 14:17:46 +04:00
m_minSpeed = GetWalkSpeed ( ) ;
}
}
}
if ( m_navNode ! = NULL )
{
int destIndex = m_navNode - > index ;
// find out about connection flags
if ( m_currentWaypointIndex ! = - 1 )
{
for ( int i = 0 ; i < MAX_PATH_INDEX ; i + + )
{
if ( m_currentPath - > index [ i ] = = m_navNode - > index )
{
m_currentTravelFlags = m_currentPath - > connectionFlags [ i ] ;
m_desiredVelocity = m_currentPath - > connectionVelocity [ i ] ;
m_jumpFinished = false ;
break ;
}
}
// check if bot is going to jump
bool willJump = false ;
2015-08-15 18:09:15 +03:00
float jumpDistance = 0.0f ;
2014-07-30 14:17:46 +04:00
2015-08-15 18:09:15 +03:00
Vector src ;
Vector dst ;
2014-07-30 14:17:46 +04:00
// try to find out about future connection flags
if ( m_navNode - > next ! = NULL )
{
for ( int i = 0 ; i < MAX_PATH_INDEX ; i + + )
{
2015-07-24 15:10:51 +03:00
Path * path = waypoints . GetPath ( m_navNode - > index ) ;
Path * next = waypoints . GetPath ( m_navNode - > next - > index ) ;
2014-07-30 14:17:46 +04:00
if ( path - > index [ i ] = = m_navNode - > next - > index & & ( path - > connectionFlags [ i ] & PATHFLAG_JUMP ) )
{
src = path - > origin ;
2015-08-15 18:09:15 +03:00
dst = next - > origin ;
2014-07-30 14:17:46 +04:00
jumpDistance = ( path - > origin - next - > origin ) . GetLength ( ) ;
willJump = true ;
break ;
}
}
}
// is there a jump waypoint right ahead and do we need to draw out the light weapon ?
2015-08-15 18:09:15 +03:00
if ( willJump & & m_currentWeapon ! = WEAPON_KNIFE & & m_currentWeapon ! = WEAPON_SCOUT & & ! m_isReloading & & ! UsesPistol ( ) & & ( jumpDistance > 210.0f | | ( dst . z + 32.0f > src . z & & jumpDistance > 150.0f ) | | ( ( dst - src ) . GetLength2D ( ) < 60.0f & & jumpDistance > 60.0f ) ) & & IsEntityNull ( m_enemy ) )
2014-07-30 14:17:46 +04:00
SelectWeaponByName ( " weapon_knife " ) ; // draw out the knife if we needed
// bot not already on ladder but will be soon?
2015-07-24 15:10:51 +03:00
if ( ( waypoints . GetPath ( destIndex ) - > flags & FLAG_LADDER ) & & ! IsOnLadder ( ) )
2014-07-30 14:17:46 +04:00
{
// get ladder waypoints used by other (first moving) bots
for ( int c = 0 ; c < GetMaxClients ( ) ; c + + )
{
2015-07-24 15:10:51 +03:00
Bot * otherBot = bots . GetBot ( c ) ;
2014-07-30 14:17:46 +04:00
// if another bot uses this ladder, wait 3 secs
if ( otherBot ! = NULL & & otherBot ! = this & & IsAlive ( otherBot - > GetEntity ( ) ) & & otherBot - > m_currentWaypointIndex = = m_navNode - > index )
{
2015-08-15 18:09:15 +03:00
PushTask ( TASK_PAUSE , TASKPRI_PAUSE , - 1 , GetWorldTime ( ) + 3.0f , false ) ;
2014-07-30 14:17:46 +04:00
return true ;
}
}
}
}
ChangeWptIndex ( destIndex ) ;
}
}
m_waypointOrigin = m_currentPath - > origin ;
// if wayzone radius non zero vary origin a bit depending on the body angles
if ( m_currentPath - > radius > 0.0f )
{
2015-08-15 18:09:15 +03:00
MakeVectors ( Vector ( pev - > angles . x , AngleNormalize ( pev - > angles . y + Random . Float ( - 90.0f , 90.0f ) ) , 0.0f ) ) ;
m_waypointOrigin = m_waypointOrigin + g_pGlobals - > v_forward * Random . Float ( 0.0f , m_currentPath - > radius ) ;
2014-07-30 14:17:46 +04:00
}
if ( IsOnLadder ( ) )
{
TraceLine ( Vector ( pev - > origin . x , pev - > origin . y , pev - > absmin . z ) , m_waypointOrigin , true , true , GetEntity ( ) , & tr ) ;
2016-01-04 18:26:06 +03:00
if ( tr . flFraction < 1.0f )
2015-08-15 18:09:15 +03:00
m_waypointOrigin = m_waypointOrigin + ( pev - > origin - m_waypointOrigin ) * 0.5f + Vector ( 0.0f , 0.0f , 32.0f ) ;
2014-07-30 14:17:46 +04:00
}
m_navTimeset = GetWorldTime ( ) ;
return true ;
}
bool Bot : : CantMoveForward ( const Vector & normal , TraceResult * tr )
{
2015-06-24 15:38:48 +03:00
// checks if bot is blocked in his movement direction (excluding doors)
2014-07-30 14:17:46 +04:00
// use some TraceLines to determine if anything is blocking the current path of the bot.
// first do a trace from the bot's eyes forward...
Vector src = EyePosition ( ) ;
2015-08-15 18:09:15 +03:00
Vector forward = src + normal * 24.0f ;
2014-07-30 14:17:46 +04:00
2015-08-15 18:09:15 +03:00
MakeVectors ( Vector ( 0.0f , pev - > angles . y , 0.0f ) ) ;
2015-07-01 00:47:39 +03:00
2014-07-30 14:17:46 +04:00
// trace from the bot's eyes straight forward...
TraceLine ( src , forward , true , GetEntity ( ) , tr ) ;
// check if the trace hit something...
2016-01-04 18:26:06 +03:00
if ( tr - > flFraction < 1.0f )
2014-07-30 14:17:46 +04:00
{
if ( strncmp ( " func_door " , STRING ( tr - > pHit - > v . classname ) , 9 ) = = 0 )
return false ;
return true ; // bot's head will hit something
}
// bot's head is clear, check at shoulder level...
// trace from the bot's shoulder left diagonal forward to the right shoulder...
2015-08-15 18:09:15 +03:00
src = EyePosition ( ) + Vector ( 0.0f , 0.0f , - 16.0f ) - g_pGlobals - > v_right * - 16.0f ;
forward = EyePosition ( ) + Vector ( 0.0f , 0.0f , - 16.0f ) + g_pGlobals - > v_right * 16.0f + normal * 24.0f ;
2014-07-30 14:17:46 +04:00
TraceLine ( src , forward , true , GetEntity ( ) , tr ) ;
// check if the trace hit something...
2016-01-04 18:26:06 +03:00
if ( tr - > flFraction < 1.0f & & strncmp ( " func_door " , STRING ( tr - > pHit - > v . classname ) , 9 ) ! = 0 )
2014-07-30 14:17:46 +04:00
return true ; // bot's body will hit something
// bot's head is clear, check at shoulder level...
// trace from the bot's shoulder right diagonal forward to the left shoulder...
2015-08-15 18:09:15 +03:00
src = EyePosition ( ) + Vector ( 0.0f , 0.0f , - 16.0f ) + g_pGlobals - > v_right * 16.0f ;
forward = EyePosition ( ) + Vector ( 0.0f , 0.0f , - 16.0f ) - g_pGlobals - > v_right * - 16.0f + normal * 24.0f ;
2014-07-30 14:17:46 +04:00
TraceLine ( src , forward , true , GetEntity ( ) , tr ) ;
// check if the trace hit something...
2016-01-04 18:26:06 +03:00
if ( tr - > flFraction < 1.0f & & strncmp ( " func_door " , STRING ( tr - > pHit - > v . classname ) , 9 ) ! = 0 )
2014-07-30 14:17:46 +04:00
return true ; // bot's body will hit something
// now check below waist
if ( pev - > flags & FL_DUCKING )
{
2015-08-15 18:09:15 +03:00
src = pev - > origin + Vector ( 0.0f , 0.0f , - 19.0f + 19.0f ) ;
forward = src + Vector ( 0.0f , 0.0f , 10.0f ) + normal * 24.0f ;
2014-07-30 14:17:46 +04:00
TraceLine ( src , forward , true , GetEntity ( ) , tr ) ;
// check if the trace hit something...
2016-01-04 18:26:06 +03:00
if ( tr - > flFraction < 1.0f & & strncmp ( " func_door " , STRING ( tr - > pHit - > v . classname ) , 9 ) ! = 0 )
2014-07-30 14:17:46 +04:00
return true ; // bot's body will hit something
src = pev - > origin ;
2015-08-15 18:09:15 +03:00
forward = src + normal * 24.0f ;
2014-07-30 14:17:46 +04:00
TraceLine ( src , forward , true , GetEntity ( ) , tr ) ;
// check if the trace hit something...
2016-01-04 18:26:06 +03:00
if ( tr - > flFraction < 1.0f & & strncmp ( " func_door " , STRING ( tr - > pHit - > v . classname ) , 9 ) ! = 0 )
2014-07-30 14:17:46 +04:00
return true ; // bot's body will hit something
}
else
{
// trace from the left waist to the right forward waist pos
2015-08-15 18:09:15 +03:00
src = pev - > origin + Vector ( 0.0f , 0.0f , - 17.0f ) - g_pGlobals - > v_right * - 16.0f ;
forward = pev - > origin + Vector ( 0.0f , 0.0f , - 17.0f ) + g_pGlobals - > v_right * 16.0f + normal * 24.0f ;
2014-07-30 14:17:46 +04:00
// trace from the bot's waist straight forward...
TraceLine ( src , forward , true , GetEntity ( ) , tr ) ;
// check if the trace hit something...
2016-01-04 18:26:06 +03:00
if ( tr - > flFraction < 1.0f & & strncmp ( " func_door " , STRING ( tr - > pHit - > v . classname ) , 9 ) ! = 0 )
2014-07-30 14:17:46 +04:00
return true ; // bot's body will hit something
// trace from the left waist to the right forward waist pos
2015-08-15 18:09:15 +03:00
src = pev - > origin + Vector ( 0.0f , 0.0f , - 17.0f ) + g_pGlobals - > v_right * 16.0f ;
forward = pev - > origin + Vector ( 0.0f , 0.0f , - 17.0f ) - g_pGlobals - > v_right * - 16.0f + normal * 24.0f ;
2014-07-30 14:17:46 +04:00
TraceLine ( src , forward , true , GetEntity ( ) , tr ) ;
// check if the trace hit something...
2016-01-04 18:26:06 +03:00
if ( tr - > flFraction < 1.0f & & strncmp ( " func_door " , STRING ( tr - > pHit - > v . classname ) , 9 ) ! = 0 )
2014-07-30 14:17:46 +04:00
return true ; // bot's body will hit something
}
return false ; // bot can move forward, return false
}
2015-06-28 19:43:31 +03:00
# ifdef DEAD_CODE
2014-07-30 14:17:46 +04:00
bool Bot : : CanStrafeLeft ( TraceResult * tr )
{
// this function checks if bot can move sideways
MakeVectors ( pev - > v_angle ) ;
Vector src = pev - > origin ;
2015-08-15 18:09:15 +03:00
Vector left = src - g_pGlobals - > v_right * - 40.0f ;
2014-07-30 14:17:46 +04:00
// trace from the bot's waist straight left...
TraceLine ( src , left , true , GetEntity ( ) , tr ) ;
// check if the trace hit something...
2016-01-04 20:18:14 +03:00
if ( tr - > flFraction < 1.0f )
2014-07-30 14:17:46 +04:00
return false ; // bot's body will hit something
src = left ;
2015-08-15 18:09:15 +03:00
left = left + g_pGlobals - > v_forward * 40.0f ;
2014-07-30 14:17:46 +04:00
// trace from the strafe pos straight forward...
TraceLine ( src , left , true , GetEntity ( ) , tr ) ;
// check if the trace hit something...
2016-01-04 20:18:14 +03:00
if ( tr - > flFraction < 1.0f )
2014-07-30 14:17:46 +04:00
return false ; // bot's body will hit something
return true ;
}
bool Bot : : CanStrafeRight ( TraceResult * tr )
{
// this function checks if bot can move sideways
MakeVectors ( pev - > v_angle ) ;
Vector src = pev - > origin ;
2015-08-15 18:09:15 +03:00
Vector right = src + g_pGlobals - > v_right * 40.0f ;
2014-07-30 14:17:46 +04:00
// trace from the bot's waist straight right...
TraceLine ( src , right , true , GetEntity ( ) , tr ) ;
// check if the trace hit something...
2016-01-04 20:18:14 +03:00
if ( tr - > flFraction < 1.0f )
2014-07-30 14:17:46 +04:00
return false ; // bot's body will hit something
src = right ;
2015-08-15 18:09:15 +03:00
right = right + g_pGlobals - > v_forward * 40.0f ;
2014-07-30 14:17:46 +04:00
// trace from the strafe pos straight forward...
TraceLine ( src , right , true , GetEntity ( ) , tr ) ;
// check if the trace hit something...
2016-01-04 20:18:14 +03:00
if ( tr - > flFraction < 1.0f )
2014-07-30 14:17:46 +04:00
return false ; // bot's body will hit something
return true ;
}
2015-06-28 19:43:31 +03:00
# endif
2014-07-30 14:17:46 +04:00
bool Bot : : CanJumpUp ( const Vector & normal )
{
// this function check if bot can jump over some obstacle
TraceResult tr ;
// can't jump if not on ground and not on ladder/swimming
if ( ! IsOnFloor ( ) & & ( IsOnLadder ( ) | | ! IsInWater ( ) ) )
return false ;
// convert current view angle to vectors for traceline math...
2015-08-15 18:09:15 +03:00
MakeVectors ( Vector ( 0.0f , pev - > angles . y , 0.0f ) ) ;
2014-07-30 14:17:46 +04:00
// check for normal jump height first...
2015-08-15 18:09:15 +03:00
Vector src = pev - > origin + Vector ( 0.0f , 0.0f , - 36.0f + 45.0f ) ;
Vector dest = src + normal * 32.0f ;
2014-07-30 14:17:46 +04:00
// trace a line forward at maximum jump height...
TraceLine ( src , dest , true , GetEntity ( ) , & tr ) ;
2016-01-04 18:26:06 +03:00
if ( tr . flFraction < 1.0f )
2014-07-30 14:17:46 +04:00
goto CheckDuckJump ;
else
{
// now trace from jump height upward to check for obstructions...
src = dest ;
2015-08-15 18:09:15 +03:00
dest . z = dest . z + 37.0f ;
2014-07-30 14:17:46 +04:00
TraceLine ( src , dest , true , GetEntity ( ) , & tr ) ;
2016-01-04 18:26:06 +03:00
if ( tr . flFraction < 1.0f )
2014-07-30 14:17:46 +04:00
return false ;
}
// now check same height to one side of the bot...
2015-08-15 18:09:15 +03:00
src = pev - > origin + g_pGlobals - > v_right * 16.0f + Vector ( 0.0f , 0.0f , - 36.0f + 45.0f ) ;
dest = src + normal * 32.0f ;
2014-07-30 14:17:46 +04:00
// trace a line forward at maximum jump height...
TraceLine ( src , dest , true , GetEntity ( ) , & tr ) ;
// if trace hit something, return false
2016-01-04 18:26:06 +03:00
if ( tr . flFraction < 1.0f )
2014-07-30 14:17:46 +04:00
goto CheckDuckJump ;
// now trace from jump height upward to check for obstructions...
src = dest ;
2015-08-15 18:09:15 +03:00
dest . z = dest . z + 37.0f ;
2014-07-30 14:17:46 +04:00
TraceLine ( src , dest , true , GetEntity ( ) , & tr ) ;
// if trace hit something, return false
2016-01-04 18:26:06 +03:00
if ( tr . flFraction < 1.0f )
2014-07-30 14:17:46 +04:00
return false ;
// now check same height on the other side of the bot...
2015-08-15 18:09:15 +03:00
src = pev - > origin + ( - g_pGlobals - > v_right * 16.0f ) + Vector ( 0.0f , 0.0f , - 36.0f + 45.0f ) ;
dest = src + normal * 32.0f ;
2014-07-30 14:17:46 +04:00
// trace a line forward at maximum jump height...
TraceLine ( src , dest , true , GetEntity ( ) , & tr ) ;
// if trace hit something, return false
2016-01-04 18:26:06 +03:00
if ( tr . flFraction < 1.0f )
2014-07-30 14:17:46 +04:00
goto CheckDuckJump ;
// now trace from jump height upward to check for obstructions...
src = dest ;
2015-08-15 18:09:15 +03:00
dest . z = dest . z + 37.0f ;
2014-07-30 14:17:46 +04:00
TraceLine ( src , dest , true , GetEntity ( ) , & tr ) ;
// if trace hit something, return false
2016-01-04 18:26:06 +03:00
return tr . flFraction > 1.0f ;
2014-07-30 14:17:46 +04:00
// here we check if a duck jump would work...
CheckDuckJump :
// use center of the body first... maximum duck jump height is 62, so check one unit above that (63)
2015-08-15 18:09:15 +03:00
src = pev - > origin + Vector ( 0.0f , 0.0f , - 36.0f + 63.0f ) ;
dest = src + normal * 32.0f ;
2014-07-30 14:17:46 +04:00
// trace a line forward at maximum jump height...
TraceLine ( src , dest , true , GetEntity ( ) , & tr ) ;
2016-01-04 18:26:06 +03:00
if ( tr . flFraction < 1.0f )
2014-07-30 14:17:46 +04:00
return false ;
else
{
// now trace from jump height upward to check for obstructions...
src = dest ;
2015-08-15 18:09:15 +03:00
dest . z = dest . z + 37.0f ;
2014-07-30 14:17:46 +04:00
TraceLine ( src , dest , true , GetEntity ( ) , & tr ) ;
// if trace hit something, check duckjump
2016-01-04 18:26:06 +03:00
if ( tr . flFraction < 1.0f )
2014-07-30 14:17:46 +04:00
return false ;
}
// now check same height to one side of the bot...
2015-08-15 18:09:15 +03:00
src = pev - > origin + g_pGlobals - > v_right * 16.0f + Vector ( 0.0f , 0.0f , - 36.0f + 63.0f ) ;
dest = src + normal * 32.0f ;
2014-07-30 14:17:46 +04:00
// trace a line forward at maximum jump height...
TraceLine ( src , dest , true , GetEntity ( ) , & tr ) ;
// if trace hit something, return false
2016-01-04 18:26:06 +03:00
if ( tr . flFraction < 1.0f )
2014-07-30 14:17:46 +04:00
return false ;
// now trace from jump height upward to check for obstructions...
src = dest ;
2015-08-15 18:09:15 +03:00
dest . z = dest . z + 37.0f ;
2014-07-30 14:17:46 +04:00
TraceLine ( src , dest , true , GetEntity ( ) , & tr ) ;
// if trace hit something, return false
2016-01-04 18:26:06 +03:00
if ( tr . flFraction < 1.0f )
2014-07-30 14:17:46 +04:00
return false ;
// now check same height on the other side of the bot...
2015-08-15 18:09:15 +03:00
src = pev - > origin + ( - g_pGlobals - > v_right * 16.0f ) + Vector ( 0.0f , 0.0f , - 36.0f + 63.0f ) ;
dest = src + normal * 32.0f ;
2014-07-30 14:17:46 +04:00
// trace a line forward at maximum jump height...
TraceLine ( src , dest , true , GetEntity ( ) , & tr ) ;
// if trace hit something, return false
2016-01-04 18:26:06 +03:00
if ( tr . flFraction < 1.0f )
2014-07-30 14:17:46 +04:00
return false ;
// now trace from jump height upward to check for obstructions...
src = dest ;
2015-08-15 18:09:15 +03:00
dest . z = dest . z + 37.0f ;
2014-07-30 14:17:46 +04:00
TraceLine ( src , dest , true , GetEntity ( ) , & tr ) ;
// if trace hit something, return false
2016-01-04 18:26:06 +03:00
return tr . flFraction > 1.0f ;
2014-07-30 14:17:46 +04:00
}
bool Bot : : CanDuckUnder ( const Vector & normal )
{
// this function check if bot can duck under obstacle
TraceResult tr ;
Vector baseHeight ;
// convert current view angle to vectors for TraceLine math...
2015-08-15 18:09:15 +03:00
MakeVectors ( Vector ( 0.0f , pev - > angles . y , 0.0f ) ) ;
2014-07-30 14:17:46 +04:00
// use center of the body first...
if ( pev - > flags & FL_DUCKING )
2015-08-15 18:09:15 +03:00
baseHeight = pev - > origin + Vector ( 0.0f , 0.0f , - 17.0f ) ;
2014-07-30 14:17:46 +04:00
else
baseHeight = pev - > origin ;
Vector src = baseHeight ;
2015-08-15 18:09:15 +03:00
Vector dest = src + normal * 32.0f ;
2014-07-30 14:17:46 +04:00
// trace a line forward at duck height...
TraceLine ( src , dest , true , GetEntity ( ) , & tr ) ;
// if trace hit something, return false
2016-01-04 18:26:06 +03:00
if ( tr . flFraction < 1.0f )
2014-07-30 14:17:46 +04:00
return false ;
// now check same height to one side of the bot...
2015-08-15 18:09:15 +03:00
src = baseHeight + g_pGlobals - > v_right * 16.0f ;
dest = src + normal * 32.0f ;
2014-07-30 14:17:46 +04:00
// trace a line forward at duck height...
TraceLine ( src , dest , true , GetEntity ( ) , & tr ) ;
// if trace hit something, return false
2016-01-04 18:26:06 +03:00
if ( tr . flFraction < 1.0f )
2014-07-30 14:17:46 +04:00
return false ;
// now check same height on the other side of the bot...
2015-08-15 18:09:15 +03:00
src = baseHeight + ( - g_pGlobals - > v_right * 16.0f ) ;
dest = src + normal * 32.0f ;
2014-07-30 14:17:46 +04:00
// trace a line forward at duck height...
TraceLine ( src , dest , true , GetEntity ( ) , & tr ) ;
// if trace hit something, return false
2016-01-04 18:26:06 +03:00
return tr . flFraction > 1.0f ;
2014-07-30 14:17:46 +04:00
}
2015-06-28 19:43:31 +03:00
# ifdef DEAD_CODE
2014-07-30 14:17:46 +04:00
bool Bot : : IsBlockedLeft ( void )
{
TraceResult tr ;
int direction = 48 ;
2015-08-15 18:09:15 +03:00
if ( m_moveSpeed < 0.0f )
2014-07-30 14:17:46 +04:00
direction = - 48 ;
MakeVectors ( pev - > angles ) ;
// do a trace to the left...
2015-08-15 18:09:15 +03:00
TraceLine ( pev - > origin , g_pGlobals - > v_forward * direction - g_pGlobals - > v_right * 48.0f , true , GetEntity ( ) , & tr ) ;
2014-07-30 14:17:46 +04:00
// check if the trace hit something...
2016-01-04 18:26:06 +03:00
if ( tr . flFraction < 1.0f & & strncmp ( " func_door " , STRING ( tr . pHit - > v . classname ) , 9 ) ! = 0 )
2014-07-30 14:17:46 +04:00
return true ; // bot's body will hit something
return false ;
}
bool Bot : : IsBlockedRight ( void )
{
TraceResult tr ;
int direction = 48 ;
if ( m_moveSpeed < 0 )
direction = - 48 ;
MakeVectors ( pev - > angles ) ;
// do a trace to the right...
2015-08-15 18:09:15 +03:00
TraceLine ( pev - > origin , pev - > origin + g_pGlobals - > v_forward * direction + g_pGlobals - > v_right * 48.0f , true , GetEntity ( ) , & tr ) ;
2014-07-30 14:17:46 +04:00
// check if the trace hit something...
2016-01-04 18:26:06 +03:00
if ( tr . flFraction < 1.0f & & ( strncmp ( " func_door " , STRING ( tr . pHit - > v . classname ) , 9 ) ! = 0 ) )
2014-07-30 14:17:46 +04:00
return true ; // bot's body will hit something
return false ;
}
2015-06-28 19:43:31 +03:00
# endif
2014-07-30 14:17:46 +04:00
bool Bot : : CheckWallOnLeft ( void )
{
TraceResult tr ;
MakeVectors ( pev - > angles ) ;
2015-08-15 18:09:15 +03:00
TraceLine ( pev - > origin , pev - > origin - g_pGlobals - > v_right * 40.0f , true , GetEntity ( ) , & tr ) ;
2014-07-30 14:17:46 +04:00
// check if the trace hit something...
2016-01-04 18:26:06 +03:00
if ( tr . flFraction < 1.0f )
2014-07-30 14:17:46 +04:00
return true ;
return false ;
}
bool Bot : : CheckWallOnRight ( void )
{
TraceResult tr ;
MakeVectors ( pev - > angles ) ;
// do a trace to the right...
2015-08-15 18:09:15 +03:00
TraceLine ( pev - > origin , pev - > origin + g_pGlobals - > v_right * 40.0f , true , GetEntity ( ) , & tr ) ;
2014-07-30 14:17:46 +04:00
// check if the trace hit something...
2016-01-04 18:26:06 +03:00
if ( tr . flFraction < 1.0f )
2014-07-30 14:17:46 +04:00
return true ;
return false ;
}
2015-06-10 23:41:55 +03:00
bool Bot : : IsDeadlyDrop ( const Vector & to )
2014-07-30 14:17:46 +04:00
{
// this function eturns if given location would hurt Bot with falling damage
Vector botPos = pev - > origin ;
TraceResult tr ;
2015-08-15 18:09:15 +03:00
Vector move ( ( to - botPos ) . ToYaw ( ) , 0.0f , 0.0f ) ;
2014-07-30 14:17:46 +04:00
MakeVectors ( move ) ;
2015-06-10 23:41:55 +03:00
Vector direction = ( to - botPos ) . Normalize ( ) ; // 1 unit long
2014-07-30 14:17:46 +04:00
Vector check = botPos ;
Vector down = botPos ;
2015-08-15 18:09:15 +03:00
down . z = down . z - 1000.0f ; // straight down 1000 units
2014-07-30 14:17:46 +04:00
TraceHull ( check , down , true , head_hull , GetEntity ( ) , & tr ) ;
2016-01-04 20:18:14 +03:00
if ( tr . flFraction > 0.036f ) // we're not on ground anymore?
2015-08-15 18:09:15 +03:00
tr . flFraction = 0.036f ;
2014-07-30 14:17:46 +04:00
2015-08-15 18:09:15 +03:00
float lastHeight = tr . flFraction * 1000.0f ; // height from ground
2014-07-30 14:17:46 +04:00
2015-06-10 23:41:55 +03:00
float distance = ( to - check ) . GetLength ( ) ; // distance from goal
2014-07-30 14:17:46 +04:00
2015-08-15 18:09:15 +03:00
while ( distance > 16.0f )
2014-07-30 14:17:46 +04:00
{
2015-08-15 18:09:15 +03:00
check = check + direction * 16.0f ; // move 10 units closer to the goal...
2014-07-30 14:17:46 +04:00
down = check ;
2015-08-15 18:09:15 +03:00
down . z = down . z - 1000.0f ; // straight down 1000 units
2014-07-30 14:17:46 +04:00
TraceHull ( check , down , true , head_hull , GetEntity ( ) , & tr ) ;
if ( tr . fStartSolid ) // Wall blocking?
return false ;
2015-08-15 18:09:15 +03:00
float height = tr . flFraction * 1000.0f ; // height from ground
2014-07-30 14:17:46 +04:00
2015-08-15 18:09:15 +03:00
if ( lastHeight < height - 100.0f ) // Drops more than 100 Units?
2014-07-30 14:17:46 +04:00
return true ;
lastHeight = height ;
2015-06-10 23:41:55 +03:00
distance = ( to - check ) . GetLength ( ) ; // distance from goal
2014-07-30 14:17:46 +04:00
}
return false ;
}
2015-06-28 19:43:31 +03:00
# ifdef DEAD_CODE
2014-07-30 14:17:46 +04:00
void Bot : : ChangePitch ( float speed )
{
// this function turns a bot towards its ideal_pitch
float idealPitch = AngleNormalize ( pev - > idealpitch ) ;
float curent = AngleNormalize ( pev - > v_angle . x ) ;
// turn from the current v_angle pitch to the idealpitch by selecting
// the quickest way to turn to face that direction
// find the difference in the curent and ideal angle
float normalizePitch = AngleNormalize ( idealPitch - curent ) ;
2015-08-15 18:09:15 +03:00
if ( normalizePitch > 0.0f )
2014-07-30 14:17:46 +04:00
{
if ( normalizePitch > speed )
normalizePitch = speed ;
}
else
{
if ( normalizePitch < - speed )
normalizePitch = - speed ;
}
pev - > v_angle . x = AngleNormalize ( curent + normalizePitch ) ;
2015-08-15 18:09:15 +03:00
if ( pev - > v_angle . x > 89.9f )
pev - > v_angle . x = 89.9f ;
2014-07-30 14:17:46 +04:00
2015-08-15 18:09:15 +03:00
if ( pev - > v_angle . x < - 89.9f )
pev - > v_angle . x = - 89.9f ;
2014-07-30 14:17:46 +04:00
pev - > angles . x = - pev - > v_angle . x / 3 ;
}
void Bot : : ChangeYaw ( float speed )
{
// this function turns a bot towards its ideal_yaw
float idealPitch = AngleNormalize ( pev - > ideal_yaw ) ;
float curent = AngleNormalize ( pev - > v_angle . y ) ;
// turn from the current v_angle yaw to the ideal_yaw by selecting
// the quickest way to turn to face that direction
// find the difference in the curent and ideal angle
float normalizePitch = AngleNormalize ( idealPitch - curent ) ;
2015-08-15 18:09:15 +03:00
if ( normalizePitch > 0.0f )
2014-07-30 14:17:46 +04:00
{
if ( normalizePitch > speed )
normalizePitch = speed ;
}
else
{
if ( normalizePitch < - speed )
normalizePitch = - speed ;
}
pev - > v_angle . y = AngleNormalize ( curent + normalizePitch ) ;
pev - > angles . y = pev - > v_angle . y ;
}
2015-06-28 19:43:31 +03:00
# endif
2014-07-30 14:17:46 +04:00
int Bot : : GetAimingWaypoint ( void )
{
2015-07-12 17:18:20 +03:00
// find a good waypoint to look at when camping
2014-07-30 14:17:46 +04:00
2015-07-19 13:39:00 +03:00
int count = 0 , indices [ 3 ] ;
2014-07-30 14:17:46 +04:00
float distTab [ 3 ] ;
uint16 visibility [ 3 ] ;
2015-07-12 17:18:20 +03:00
int currentWaypoint = m_currentWaypointIndex ;
2014-07-30 14:17:46 +04:00
2015-06-29 20:51:25 +03:00
if ( currentWaypoint = = - 1 )
return Random . Long ( 0 , g_numWaypoints - 1 ) ;
2014-07-30 14:17:46 +04:00
for ( int i = 0 ; i < g_numWaypoints ; i + + )
{
2015-07-24 15:10:51 +03:00
if ( currentWaypoint = = i | | ! waypoints . IsVisible ( currentWaypoint , i ) )
2014-07-30 14:17:46 +04:00
continue ;
2015-07-24 15:10:51 +03:00
Path * path = waypoints . GetPath ( i ) ;
2014-07-30 14:17:46 +04:00
if ( count < 3 )
{
2015-07-19 13:39:00 +03:00
indices [ count ] = i ;
2014-07-30 14:17:46 +04:00
distTab [ count ] = ( pev - > origin - path - > origin ) . GetLengthSquared ( ) ;
visibility [ count ] = path - > vis . crouch + path - > vis . stand ;
count + + ;
}
else
{
float distance = ( pev - > origin - path - > origin ) . GetLengthSquared ( ) ;
uint16 visBits = path - > vis . crouch + path - > vis . stand ;
for ( int j = 0 ; j < 3 ; j + + )
{
if ( visBits > = visibility [ j ] & & distance > distTab [ j ] )
{
2015-07-19 13:39:00 +03:00
indices [ j ] = i ;
2014-07-30 14:17:46 +04:00
distTab [ j ] = distance ;
visibility [ j ] = visBits ;
break ;
}
}
}
}
count - - ;
if ( count > = 0 )
2015-07-19 13:39:00 +03:00
return indices [ Random . Long ( 0 , count ) ] ;
2014-07-30 14:17:46 +04:00
2015-06-09 15:45:34 +03:00
return Random . Long ( 0 , g_numWaypoints - 1 ) ;
2014-07-30 14:17:46 +04:00
}
2015-07-20 00:42:21 +03:00
void Bot : : UpdateBodyAngles ( void )
{
// set the body angles to point the gun correctly
pev - > angles . x = - pev - > v_angle . x * ( 1.0f / 3.0f ) ;
pev - > angles . y = pev - > v_angle . y ;
pev - > angles . ClampAngles ( ) ;
}
2015-07-19 13:39:00 +03:00
void Bot : : UpdateLookAngles ( void )
2014-07-30 14:17:46 +04:00
{
2015-08-03 00:05:27 +03:00
const float delta = Clamp < float > ( GetWorldTime ( ) - m_lookUpdateTime , MATH_EQEPSILON , 0.05f ) ;
2015-07-26 13:02:05 +03:00
m_lookUpdateTime = GetWorldTime ( ) ;
2014-07-30 14:17:46 +04:00
// adjust all body and view angles to face an absolute vector
2015-07-26 13:02:05 +03:00
Vector direction = ( m_lookAt - EyePosition ( ) ) . ToAngles ( ) ;
2015-07-19 13:39:00 +03:00
direction . x * = - 1.0f ; // invert for engine
2014-07-30 14:17:46 +04:00
direction . ClampAngles ( ) ;
2015-07-31 20:32:08 +03:00
// lower skilled bot's have lower aiming
if ( m_difficulty < 3 )
{
UpdateLookAnglesLowSkill ( direction , delta ) ;
UpdateBodyAngles ( ) ;
return ;
}
2015-07-20 00:42:21 +03:00
// this is what makes bot almost godlike (got it from sypb)
2015-07-31 20:32:08 +03:00
if ( m_difficulty > 3 & & ( m_aimFlags & AIM_ENEMY ) & & ( m_wantsToFire | | UsesSniper ( ) ) & & yb_whose_your_daddy . GetBool ( ) )
2014-07-30 14:17:46 +04:00
{
2015-07-20 00:42:21 +03:00
pev - > v_angle = direction ;
UpdateBodyAngles ( ) ;
2014-07-30 14:17:46 +04:00
2015-07-20 00:42:21 +03:00
return ;
}
bool needPreciseAim = ( m_aimFlags & ( AIM_ENEMY | AIM_ENTITY | AIM_GRENADE | AIM_LAST_ENEMY | AIM_CAMP ) | | GetTaskId ( ) = = TASK_SHOOTBREAKABLE ) ;
2014-07-30 14:17:46 +04:00
2015-07-20 00:42:21 +03:00
float accelerate = needPreciseAim ? 3600.0f : 3000.0f ;
float stiffness = needPreciseAim ? 300.0f : 200.0f ;
float damping = needPreciseAim ? 20.0f : 25.0f ;
2014-07-30 14:17:46 +04:00
2015-07-20 00:42:21 +03:00
m_idealAngles = pev - > v_angle ;
2014-07-30 14:17:46 +04:00
2015-08-03 00:05:27 +03:00
float angleDiffYaw = AngleDiff ( direction . y , m_idealAngles . y ) ;
float angleDiffPitch = AngleDiff ( direction . x , m_idealAngles . x ) ;
2014-07-30 14:17:46 +04:00
2015-07-20 00:42:21 +03:00
if ( angleDiffYaw < 1.0f & & angleDiffYaw > - 1.0f )
{
m_lookYawVel = 0.0f ;
m_idealAngles . y = direction . y ;
2014-07-30 14:17:46 +04:00
}
2015-07-20 00:42:21 +03:00
else
2014-07-30 14:17:46 +04:00
{
2015-07-20 00:42:21 +03:00
float accel = stiffness * angleDiffYaw - damping * m_lookYawVel ;
2014-07-30 14:17:46 +04:00
2015-07-20 00:42:21 +03:00
if ( accel > accelerate )
accel = accelerate ;
else if ( accel < - accelerate )
accel = - accelerate ;
2014-07-30 14:17:46 +04:00
2015-07-22 23:04:43 +03:00
m_lookYawVel + = delta * accel ;
m_idealAngles . y + = delta * m_lookYawVel ;
2015-07-20 00:42:21 +03:00
}
float accel = 2.0f * stiffness * angleDiffPitch - damping * m_lookPitchVel ;
2014-07-30 14:17:46 +04:00
2015-07-20 00:42:21 +03:00
if ( accel > accelerate )
accel = accelerate ;
else if ( accel < - accelerate )
accel = - accelerate ;
2014-07-30 14:17:46 +04:00
2015-07-22 23:04:43 +03:00
m_lookPitchVel + = delta * accel ;
m_idealAngles . x + = delta * m_lookPitchVel ;
2014-07-30 14:17:46 +04:00
2015-07-20 00:42:21 +03:00
if ( m_idealAngles . x < - 89.0f )
m_idealAngles . x = - 89.0f ;
else if ( m_idealAngles . x > 89.0f )
m_idealAngles . x = 89.0f ;
2014-07-30 14:17:46 +04:00
2015-07-20 00:42:21 +03:00
pev - > v_angle = m_idealAngles ;
2014-07-30 14:17:46 +04:00
pev - > v_angle . ClampAngles ( ) ;
2015-07-20 00:42:21 +03:00
UpdateBodyAngles ( ) ;
2014-07-30 14:17:46 +04:00
}
2015-07-31 20:32:08 +03:00
void Bot : : UpdateLookAnglesLowSkill ( const Vector & direction , const float delta )
{
Vector spring ( 13.0f , 13.0f , 0.0f ) ;
Vector damperCoefficient ( 0.22f , 0.22f , 0.0f ) ;
Vector influence = Vector ( 0.25f , 0.17f , 0.0f ) * ( ( 100 - ( m_difficulty * 25 ) ) / 100.f ) ;
Vector randomization = Vector ( 2.0f , 0.18f , 0.0f ) * ( ( 100 - ( m_difficulty * 25 ) ) / 100.f ) ;
const float noTargetRatio = 0.3f ;
const float offsetDelay = 1.2f ;
2015-08-15 18:09:15 +03:00
Vector stiffness ;
Vector randomize ;
2015-07-31 20:32:08 +03:00
m_idealAngles = direction . Get2D ( ) ;
m_idealAngles . ClampAngles ( ) ;
if ( m_aimFlags & ( AIM_ENEMY | AIM_ENTITY | AIM_GRENADE | AIM_LAST_ENEMY ) | | GetTaskId ( ) = = TASK_SHOOTBREAKABLE )
{
m_playerTargetTime = GetWorldTime ( ) ;
m_randomizedIdealAngles = m_idealAngles ;
2015-08-15 18:09:15 +03:00
stiffness = spring * ( 0.2f + ( m_difficulty * 25 ) / 125.0f ) ;
2015-07-31 20:32:08 +03:00
}
else
{
// is it time for bot to randomize the aim direction again (more often where moving) ?
2015-08-15 18:09:15 +03:00
if ( m_randomizeAnglesTime < GetWorldTime ( ) & & ( ( pev - > velocity . GetLength ( ) > 1.0f & & m_angularDeviation . GetLength ( ) < 5.0f ) | | m_angularDeviation . GetLength ( ) < 1.0f ) )
2015-07-31 20:32:08 +03:00
{
// is the bot standing still ?
2015-08-15 18:09:15 +03:00
if ( pev - > velocity . GetLength ( ) < 1.0f )
randomize = randomization * 0.2f ; // randomize less
2015-07-31 20:32:08 +03:00
else
randomize = randomization ;
// randomize targeted location a bit (slightly towards the ground)
2015-08-15 18:09:15 +03:00
m_randomizedIdealAngles = m_idealAngles + Vector ( Random . Float ( - randomize . x * 0.5f , randomize . x * 1.5f ) , Random . Float ( - randomize . y , randomize . y ) , 0.0f ) ;
2015-07-31 20:32:08 +03:00
// set next time to do this
m_randomizeAnglesTime = GetWorldTime ( ) + Random . Float ( 0.4f , offsetDelay ) ;
}
float stiffnessMultiplier = noTargetRatio ;
// take in account whether the bot was targeting someone in the last N seconds
2015-08-15 18:09:15 +03:00
if ( GetWorldTime ( ) - ( m_playerTargetTime + offsetDelay ) < noTargetRatio * 10.0f )
2015-07-31 20:32:08 +03:00
{
2015-08-15 18:09:15 +03:00
stiffnessMultiplier = 1.0f - ( GetWorldTime ( ) - m_timeLastFired ) * 0.1f ;
2015-07-31 20:32:08 +03:00
// don't allow that stiffness multiplier less than zero
2015-08-15 18:09:15 +03:00
if ( stiffnessMultiplier < 0.0f )
stiffnessMultiplier = 0.5f ;
2015-07-31 20:32:08 +03:00
}
// also take in account the remaining deviation (slow down the aiming in the last 10°)
2015-08-15 18:09:15 +03:00
stiffnessMultiplier * = m_angularDeviation . GetLength ( ) * 0.1f * 0.5f ;
2015-07-31 20:32:08 +03:00
// but don't allow getting below a certain value
2015-08-15 18:09:15 +03:00
if ( stiffnessMultiplier < 0.35f )
stiffnessMultiplier = 0.35f ;
2015-07-31 20:32:08 +03:00
stiffness = spring * stiffnessMultiplier ; // increasingly slow aim
}
// compute randomized angle deviation this time
m_angularDeviation = m_randomizedIdealAngles - pev - > v_angle ;
m_angularDeviation . ClampAngles ( ) ;
// spring/damper model aiming
2015-08-02 20:31:14 +03:00
m_aimSpeed . x = stiffness . x * m_angularDeviation . x - damperCoefficient . x * m_aimSpeed . x ;
m_aimSpeed . y = stiffness . y * m_angularDeviation . y - damperCoefficient . y * m_aimSpeed . y ;
2015-07-31 20:32:08 +03:00
// influence of y movement on x axis and vice versa (less influence than x on y since it's
// easier and more natural for the bot to "move its mouse" horizontally than vertically)
m_aimSpeed . x + = m_aimSpeed . y * influence . y ;
m_aimSpeed . y + = m_aimSpeed . x * influence . x ;
// move the aim cursor
2015-08-02 20:31:14 +03:00
pev - > v_angle = pev - > v_angle + delta * Vector ( m_aimSpeed . x , m_aimSpeed . y , 0.0f ) ;
2015-07-31 20:32:08 +03:00
pev - > v_angle . ClampAngles ( ) ;
}
2015-07-20 00:42:21 +03:00
2015-06-10 23:41:55 +03:00
void Bot : : SetStrafeSpeed ( const Vector & moveDir , float strafeSpeed )
2014-07-30 14:17:46 +04:00
{
MakeVectors ( pev - > angles ) ;
2015-06-10 23:41:55 +03:00
const Vector & los = ( moveDir - pev - > origin ) . Normalize2D ( ) ;
2015-06-24 15:38:48 +03:00
float dot = los | g_pGlobals - > v_forward . Get2D ( ) ;
2014-07-30 14:17:46 +04:00
2015-08-15 18:09:15 +03:00
if ( dot > 0.0f & & ! CheckWallOnRight ( ) )
2014-07-30 14:17:46 +04:00
m_strafeSpeed = strafeSpeed ;
else if ( ! CheckWallOnLeft ( ) )
m_strafeSpeed = - strafeSpeed ;
}
int Bot : : FindPlantedBomb ( void )
{
// this function tries to find planted c4 on the defuse scenario map and returns nearest to it waypoint
2015-07-19 13:39:00 +03:00
if ( m_team ! = TEAM_TF | | ! ( g_mapType & MAP_DE ) )
2014-07-30 14:17:46 +04:00
return - 1 ; // don't search for bomb if the player is CT, or it's not defusing bomb
edict_t * bombEntity = NULL ; // temporaly pointer to bomb
// search the bomb on the map
2015-06-04 11:52:48 +03:00
while ( ! IsEntityNull ( bombEntity = FIND_ENTITY_BY_CLASSNAME ( bombEntity , " grenade " ) ) )
2014-07-30 14:17:46 +04:00
{
if ( strcmp ( STRING ( bombEntity - > v . model ) + 9 , " c4.mdl " ) = = 0 )
{
2015-07-24 15:10:51 +03:00
int nearestIndex = waypoints . FindNearest ( GetEntityOrigin ( bombEntity ) ) ;
2014-07-30 14:17:46 +04:00
2015-07-19 13:39:00 +03:00
if ( nearestIndex > = 0 & & nearestIndex < g_numWaypoints )
2014-07-30 14:17:46 +04:00
return nearestIndex ;
break ;
}
}
return - 1 ;
}
2015-06-04 11:52:48 +03:00
bool Bot : : IsPointOccupied ( int index )
2014-07-30 14:17:46 +04:00
{
if ( index < 0 | | index > = g_numWaypoints )
return true ;
// first check if current waypoint of one of the bots is index waypoint
for ( int i = 0 ; i < GetMaxClients ( ) ; i + + )
{
2015-07-24 15:10:51 +03:00
Bot * bot = bots . GetBot ( i ) ;
2014-07-30 14:17:46 +04:00
if ( bot = = NULL | | bot = = this )
continue ;
// check if this waypoint is already used
2016-01-04 18:26:06 +03:00
// TODO: take in account real players
2015-07-02 23:46:21 +03:00
if ( bot - > m_notKilled )
2015-06-09 22:16:08 +03:00
{
2015-06-26 23:41:17 +03:00
int occupyId = GetShootingConeDeviation ( bot - > GetEntity ( ) , & pev - > origin ) > = 0.7f ? bot - > m_prevWptIndex [ 0 ] : m_currentWaypointIndex ;
2015-07-20 21:26:20 +03:00
// length check
2015-07-24 15:10:51 +03:00
float length = ( waypoints . GetPath ( occupyId ) - > origin - waypoints . GetPath ( index ) - > origin ) . GetLengthSquared ( ) ;
2015-07-20 21:26:20 +03:00
2016-01-04 18:26:06 +03:00
if ( occupyId = = index | | bot - > GetTask ( ) - > data = = index | | length < GET_SQUARE ( 64.0f ) )
2015-06-09 22:16:08 +03:00
return true ;
}
2014-07-30 14:17:46 +04:00
}
return false ;
}
edict_t * Bot : : FindNearestButton ( const char * targetName )
{
// this function tries to find nearest to current bot button, and returns pointer to
// it's entity, also here must be specified the target, that button must open.
if ( IsNullString ( targetName ) )
return NULL ;
2015-07-12 17:18:20 +03:00
float nearestDistance = 99999.0f ;
2014-07-30 14:17:46 +04:00
edict_t * searchEntity = NULL , * foundEntity = NULL ;
// find the nearest button which can open our target
2015-06-14 12:55:49 +03:00
while ( ! IsEntityNull ( searchEntity = FIND_ENTITY_BY_TARGET ( searchEntity , targetName ) ) )
2014-07-30 14:17:46 +04:00
{
Vector entityOrign = GetEntityOrigin ( searchEntity ) ;
// check if this place safe
if ( ! IsDeadlyDrop ( entityOrign ) )
{
float distance = ( pev - > origin - entityOrign ) . GetLengthSquared ( ) ;
// check if we got more close button
if ( distance < = nearestDistance )
{
nearestDistance = distance ;
foundEntity = searchEntity ;
}
}
}
return foundEntity ;
}