fixed move angles not updated when not checking terrain

fixed reporting-in spam
fixed bot-s won't fight in jason mode
added yb_shoots_thru_walls 2 to use old method for checking shootable wall
This commit is contained in:
Dmitry 2015-06-07 19:43:16 +03:00
commit eb13736a00
7 changed files with 328 additions and 294 deletions

View file

@ -487,7 +487,7 @@ enum AimPosition
{
AIM_NAVPOINT = (1 << 0), // aim at nav point
AIM_CAMP = (1 << 1), // aim at camp vector
AIM_PREDICT_ENEMY = (1 << 2), // aim at predicted path
AIM_PREDICT_PATH = (1 << 2), // aim at predicted path
AIM_LAST_ENEMY = (1 << 3), // aim at last enemy
AIM_ENTITY = (1 << 4), // aim at entity like buttons, hostages
AIM_ENEMY = (1 << 5), // aim at enemy
@ -1001,7 +1001,7 @@ private:
int FindDefendWaypoint (Vector origin);
int FindGoal (void);
void FindItem (void);
void CheckTerrain (float movedDistance);
void CheckTerrain (float movedDistance, const Vector &dir, const Vector &dirNormal);
void GetCampDirection (Vector *dest);
void CollectGoalExperience (int damage, int team);
@ -1015,9 +1015,11 @@ private:
bool IsBlockedLeft (void);
bool IsBlockedRight (void);
bool IsPointOccupied (int index);
inline bool IsOnLadder (void) { return pev->movetype == MOVETYPE_FLY; }
inline bool IsOnFloor (void) { return (pev->flags & (FL_ONGROUND | FL_PARTIALGROUND)) != 0; }
inline bool IsInWater (void) { return pev->waterlevel >= 2; }
inline float GetWalkSpeed (void) { return static_cast <float> ((static_cast <int> (pev->maxspeed) / 2) + (static_cast <int> (pev->maxspeed) / 50)) - 18; }
bool ItemIsVisible (const Vector &dest, char *itemName);
@ -1067,7 +1069,10 @@ private:
void SelectPistol (void);
bool IsFriendInLineOfFire (float distance);
bool IsGroupOfEnemies (Vector location, int numEnemies = 1, int radius = 256);
bool IsShootableThruObstacle (Vector dest);
bool IsShootableThruObstacle (const Vector &dest);
bool IsShootableThruObstacleEx (const Vector &dest);
int GetNearbyEnemiesNearPosition (Vector origin, int radius);
int GetNearbyFriendsNearPosition (Vector origin, int radius);
void SelectWeaponByName (const char *name);

View file

@ -33,9 +33,9 @@
<ClCompile Include="..\source\basecode.cpp">
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Level4</WarningLevel>
</ClCompile>
<ClCompile Include="..\source\combat.cpp" />
<ClCompile Include="..\source\manager.cpp" />
<ClCompile Include="..\source\chatlib.cpp" />
<ClCompile Include="..\source\combat.cpp" />
<ClCompile Include="..\source\globals.cpp" />
<ClCompile Include="..\source\interface.cpp" />
<ClCompile Include="..\source\navigate.cpp" />

View file

@ -71,9 +71,6 @@
<ClCompile Include="..\source\chatlib.cpp">
<Filter>source</Filter>
</ClCompile>
<ClCompile Include="..\source\combat.cpp">
<Filter>source</Filter>
</ClCompile>
<ClCompile Include="..\source\globals.cpp">
<Filter>source</Filter>
</ClCompile>
@ -98,6 +95,9 @@
<ClCompile Include="..\source\basecode.cpp">
<Filter>source</Filter>
</ClCompile>
<ClCompile Include="..\source\combat.cpp">
<Filter>source</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="yapb.rc">

View file

@ -1139,8 +1139,9 @@ void Bot::CheckMessageQueue (void)
else
InstantChatterMessage (Chatter_HearSomething);
}
else
else if (g_randGen.Long (0, 100) < 40)
InstantChatterMessage (Chatter_ReportingIn);
break;
case TASK_MOVETOPOSITION:
@ -1828,7 +1829,7 @@ void Bot::SetConditions (void)
if ((pev->origin - m_lastEnemyOrigin).GetLength () < 1600.0 && (tr.flFraction >= 0.2 || tr.pHit != g_worldEdict))
{
m_aimFlags |= AIM_PREDICT_ENEMY;
m_aimFlags |= AIM_PREDICT_PATH;
if (EntityIsVisible (m_lastEnemyOrigin))
m_aimFlags |= AIM_LAST_ENEMY;
@ -2025,7 +2026,7 @@ void Bot::SetConditions (void)
float desireLevel = 0.0;
// calculate desire to attack
if ((m_states & STATE_SEEING_ENEMY) && ReactOnEnemy () && g_taskFilters[TASK_MOVETOPOSITION].desire < TASKPRI_HIDE)
if ((m_states & STATE_SEEING_ENEMY) && ReactOnEnemy ())
g_taskFilters[TASK_ATTACK].desire = TASKPRI_ATTACK;
else
g_taskFilters[TASK_ATTACK].desire = 0;
@ -2324,7 +2325,7 @@ bool Bot::IsLastEnemyViewable (void)
bool Bot::LastEnemyShootable (void)
{
// don't allow shooting through walls
if (!(m_aimFlags & AIM_LAST_ENEMY) || IsEntityNull (m_lastEnemy) || GetTaskId () == TASK_PAUSE && m_lastEnemyOrigin != nullvec)
if (!(m_aimFlags & AIM_LAST_ENEMY) || IsEntityNull (m_lastEnemy) || GetTaskId () == TASK_PAUSE || m_lastEnemyOrigin != nullvec)
return false;
return GetShootingConeDeviation (GetEntity (), &m_lastEnemyOrigin) >= 0.90 && IsShootableThruObstacle (m_lastEnemy->v.origin);
@ -2647,7 +2648,7 @@ void Bot::CheckRadioCommands (void)
break;
case Radio_ReportTeam:
if (g_randGen.Long (0, 100) < 85)
if (g_randGen.Long (0, 100) < 30)
RadioMessage ((GetNearbyEnemiesNearPosition (pev->origin, 400) == 0 && yb_communication_type.GetInt () != 2) ? Radio_SectorClear : Radio_ReportingIn);
break;
@ -2891,19 +2892,19 @@ void Bot::ChooseAimDirection (void)
if ((pev->origin - m_lastEnemyOrigin).GetLength () >= 1600 && IsEntityNull (m_enemy) && !UsesSniper () || (tr.flFraction <= 0.2 && tr.pHit == g_hostEntity) && m_seeEnemyTime + 7.0 < GetWorldTime ())
{
if ((m_aimFlags & (AIM_LAST_ENEMY | AIM_PREDICT_ENEMY)) && m_wantsToFire)
if ((m_aimFlags & (AIM_LAST_ENEMY | AIM_PREDICT_PATH)) && m_wantsToFire)
m_wantsToFire = false;
m_lastEnemyOrigin = nullvec;
m_aimFlags &= ~(AIM_LAST_ENEMY | AIM_PREDICT_ENEMY);
m_aimFlags &= ~(AIM_LAST_ENEMY | AIM_PREDICT_PATH);
flags &= ~(AIM_LAST_ENEMY | AIM_PREDICT_ENEMY);
flags &= ~(AIM_LAST_ENEMY | AIM_PREDICT_PATH);
}
}
else
{
m_aimFlags &= ~(AIM_LAST_ENEMY | AIM_PREDICT_ENEMY);
flags &= ~(AIM_LAST_ENEMY | AIM_PREDICT_ENEMY);
m_aimFlags &= ~(AIM_LAST_ENEMY | AIM_PREDICT_PATH);
flags &= ~(AIM_LAST_ENEMY | AIM_PREDICT_PATH);
}
// don't allow bot to look at danger positions under certain circumstances
@ -2911,7 +2912,7 @@ void Bot::ChooseAimDirection (void)
{
if (IsOnLadder () || IsInWater () || (m_waypointFlags & FLAG_LADDER) || (m_currentTravelFlags & PATHFLAG_JUMP))
{
flags &= ~(AIM_LAST_ENEMY | AIM_PREDICT_ENEMY);
flags &= ~(AIM_LAST_ENEMY | AIM_PREDICT_PATH);
canChooseAimDirection = false;
}
}
@ -2943,7 +2944,7 @@ void Bot::ChooseAimDirection (void)
m_lastEnemyOrigin = nullvec;
}
}
else if (flags & AIM_PREDICT_ENEMY)
else if (flags & AIM_PREDICT_PATH)
{
if (((pev->origin - m_lastEnemyOrigin).GetLength () < 1600 || UsesSniper ()) && (tr.flFraction >= 0.2 || tr.pHit != g_worldEdict))
{
@ -2969,7 +2970,7 @@ void Bot::ChooseAimDirection (void)
}
else // forget an enemy far away
{
m_aimFlags &= ~AIM_PREDICT_ENEMY;
m_aimFlags &= ~AIM_PREDICT_PATH;
if ((pev->origin - m_lastEnemyOrigin).GetLength () >= 1600.0)
m_lastEnemyOrigin = nullvec;
@ -2977,7 +2978,7 @@ void Bot::ChooseAimDirection (void)
}
else if (flags & AIM_CAMP)
m_lookAt = m_camp;
else if ((flags & AIM_NAVPOINT) && !(flags & (AIM_ENTITY | AIM_ENEMY)))
else if (flags & AIM_NAVPOINT)
{
m_lookAt = m_destOrigin;
@ -3505,7 +3506,7 @@ void Bot::RunTask (void)
}
// bots skill higher than 60?
if (yb_walking_allowed.GetBool () && mp_footsteps.GetBool () && m_difficulty >= 1)
if (yb_walking_allowed.GetBool () && mp_footsteps.GetBool () && m_difficulty >= 1 && !yb_jasonmode.GetBool ())
{
// then make him move slow if near enemy
if (!(m_currentTravelFlags & PATHFLAG_JUMP))
@ -3578,8 +3579,8 @@ void Bot::RunTask (void)
if ((m_reloadState == RELOAD_NONE) && (GetAmmoInClip () < 8) && (GetAmmo () != 0))
m_reloadState = RELOAD_PRIMARY;
m_moveSpeed = 0;
m_strafeSpeed = 0;
m_moveSpeed = 0.0f;
m_strafeSpeed = 0.0f;
m_moveToGoal = false;
m_checkTerrain = true;
@ -4170,7 +4171,7 @@ void Bot::RunTask (void)
}
m_aimFlags |= AIM_NAVPOINT;
if (yb_walking_allowed.GetBool () && m_targetEntity->v.maxspeed < m_moveSpeed)
if (yb_walking_allowed.GetBool () && m_targetEntity->v.maxspeed < m_moveSpeed && !yb_jasonmode.GetBool ())
m_moveSpeed = GetWalkSpeed ();
if (IsShieldDrawn ())
@ -4908,10 +4909,22 @@ void Bot::BotAI (void)
// set the reaction time (surprise momentum) different each frame according to skill
SetIdealReactionTimes ();
#if 0
// calculate 2 direction vectors, 1 without the up/down component
Vector directionOld = m_destOrigin - (pev->origin + pev->velocity * m_frameInterval);
Vector directionNormal = directionOld.Normalize ();
Vector direction = directionNormal;
directionNormal.z = 0.0;
m_moveAngles = directionOld.ToAngles ();
m_moveAngles.ClampAngles ();
m_moveAngles.x *= -1.0; // invert for engine
#if 0 // get rid of ugly hack
if (yb_hardcore_mode && GetTaskId () == TASK_NORMAL && ((m_aimFlags & AIM_ENEMY) || (m_states & STATE_SEEING_ENEMY)) && !IsOnLadder ())
CombatFight ();
#else
if (m_difficulty == 4 && ((m_aimFlags & AIM_ENEMY) || (m_states & (STATE_SEEING_ENEMY | STATE_SUSPECT_ENEMY)) || (GetTaskId () == TASK_SEEKCOVER && (m_isReloading || m_isVIP))) && !yb_jasonmode.GetBool () && GetTaskId () != TASK_CAMP && !IsOnLadder ())
{
m_moveToGoal = false; // don't move to goal
@ -4921,6 +4934,7 @@ void Bot::BotAI (void)
CombatFight ();
}
#endif
// check if we need to escape from bomb
if ((g_mapType & MAP_DE) && g_bombPlanted && m_notKilled && GetTaskId () != TASK_ESCAPEFROMBOMB && GetTaskId () != TASK_CAMP && OutOfBombTimer ())
{
@ -4957,7 +4971,7 @@ void Bot::BotAI (void)
}
if (m_checkTerrain) // are we allowed to check blocking terrain (and react to it)?
CheckTerrain (movedDistance);
CheckTerrain (movedDistance, direction, directionNormal);
// must avoid a grenade?
if (m_needAvoidGrenade != 0)
@ -5148,12 +5162,13 @@ void Bot::BotAI (void)
selectTab++;
weaponCount++;
}
memset (aimFlags, 0, sizeof (aimFlags));
// set the aim flags
sprintf (aimFlags, "%s%s%s%s%s%s%s%s",
m_aimFlags & AIM_NAVPOINT ? " NavPoint" : "",
m_aimFlags & AIM_CAMP ? " CampPoint" : "",
m_aimFlags & AIM_PREDICT_ENEMY ? " PredictEnemy" : "",
m_aimFlags & AIM_PREDICT_PATH ? " predictPath" : "",
m_aimFlags & AIM_LAST_ENEMY ? " LastEnemy" : "",
m_aimFlags & AIM_ENTITY ? " Entity" : "",
m_aimFlags & AIM_ENEMY ? " Enemy" : "",
@ -5171,19 +5186,19 @@ void Bot::BotAI (void)
switch (m_currentWeapon)
{
case WEAPON_EXPLOSIVE:
sprintf (weaponName, "weapon_hegrenade");
strcpy (weaponName, "weapon_hegrenade");
break;
case WEAPON_FLASHBANG:
sprintf (weaponName, "weapon_flashbang");
strcpy (weaponName, "weapon_flashbang");
break;
case WEAPON_SMOKE:
sprintf (weaponName, "weapon_smokegrenade");
strcpy (weaponName, "weapon_smokegrenade");
break;
case WEAPON_C4:
sprintf (weaponName, "weapon_c4");
strcpy (weaponName, "weapon_c4");
break;
default:
@ -5400,7 +5415,7 @@ void Bot::TakeBlinded (const Vector &fade, int alpha)
m_blindSidemoveSpeed = -walkSpeed;
if (pev->health < 85)
m_blindMoveSpeed = -GetWalkSpeed ();
m_blindMoveSpeed = -walkSpeed;
else if (m_personality == PERSONALITY_CAREFUL)
{
m_blindMoveSpeed = 0.0;
@ -5819,7 +5834,7 @@ void Bot::RunPlayerMovement (void)
// problems, such as bots getting stuck into each others. That's because the model's
// bounding boxes, which are the boxes the engine uses to compute and detect all the
// collisions of the model, only exist, and are only valid, while in the duration of the
// movement. That's why if you get a pfnRunPlayerMove for one bot that lasts a little too
// movement. That's why if you get a pfnRunPlayerMove for one boINFt that lasts a little too
// short in comparison with the frame's duration, the remaining time until the frame
// elapses, that bot will behave like a ghost : no movement, but bullets and players can
// pass through it. Then, when the next frame will begin, the stucking problem will arise !
@ -5882,7 +5897,7 @@ float Bot::GetBombTimeleft (void)
float Bot::GetEstimatedReachTime (void)
{
float estimatedTime = 3.0f; // time to reach next waypoint
float estimatedTime = 2.0f; // time to reach next waypoint
// calculate 'real' time that we need to get from one waypoint to another
if (m_currentWaypointIndex >= 0 && m_currentWaypointIndex < g_numWaypoints && m_prevWptIndex[0] >= 0 && m_prevWptIndex[0] < g_numWaypoints)
@ -5897,15 +5912,15 @@ float Bot::GetEstimatedReachTime (void)
// check for special waypoints, that can slowdown our movement
if ((m_currentPath->flags & FLAG_CROUCH) || (m_currentPath->flags & FLAG_LADDER) || (pev->button & IN_DUCK))
estimatedTime *= 3.0;
estimatedTime *= 2.0;
// check for too low values
if (estimatedTime < 1.0f)
estimatedTime = 1.0f;
// check for too high values
if (estimatedTime > 8.0f)
estimatedTime = 8.0f;
if (estimatedTime > 5.0f)
estimatedTime = 5.0f;
}
return estimatedTime;
}
@ -6060,31 +6075,6 @@ void Bot::ReactOnSound (void)
return;
}
}
// useless?
#if 0
extern ConVar yb_shoots_thru_walls;
// check if heard enemy can be seen
if (CheckVisibility (VARS (player), &m_lastEnemyOrigin, &m_visibility))
{
m_enemy = player;
m_lastEnemy = player;
m_enemyOrigin = m_lastEnemyOrigin;
m_states |= STATE_SEEING_ENEMY;
m_seeEnemyTime = GetWorldTime ();
}
else if (m_lastEnemy == player && m_seeEnemyTime + 1.0 > GetWorldTime () && yb_shoots_thru_walls.GetBool () && IsShootableThruObstacle (player->v.origin))
{
m_enemy = player;
m_lastEnemy = player;
m_lastEnemyOrigin = player->v.origin;
m_states |= STATE_SEEING_ENEMY;
m_seeEnemyTime = GetWorldTime ();
}
#endif
}
}

View file

@ -254,7 +254,7 @@ bool Bot::LookupEnemy (void)
}
// check if bots should reload...
if ((m_aimFlags <= AIM_PREDICT_ENEMY && m_seeEnemyTime + 3.0 < GetWorldTime () && !(m_states & (STATE_SEEING_ENEMY | STATE_HEARING_ENEMY)) && IsEntityNull (m_lastEnemy) && IsEntityNull (m_enemy) && GetTaskId () != TASK_SHOOTBREAKABLE && GetTaskId () != TASK_PLANTBOMB && GetTaskId () != TASK_DEFUSEBOMB) || g_roundEnded)
if ((m_aimFlags <= AIM_PREDICT_PATH && m_seeEnemyTime + 3.0 < GetWorldTime () && !(m_states & (STATE_SEEING_ENEMY | STATE_HEARING_ENEMY)) && IsEntityNull (m_lastEnemy) && IsEntityNull (m_enemy) && GetTaskId () != TASK_SHOOTBREAKABLE && GetTaskId () != TASK_PLANTBOMB && GetTaskId () != TASK_DEFUSEBOMB) || g_roundEnded)
{
if (!m_reloadState)
m_reloadState = RELOAD_PRIMARY;
@ -430,11 +430,14 @@ bool Bot::IsFriendInLineOfFire (float distance)
return false;
}
bool Bot::IsShootableThruObstacle (Vector dest)
bool Bot::IsShootableThruObstacle (const Vector &dest)
{
// this function returns true if enemy can be shoot through some obstacle, false otherwise.
// credits goes to Immortal_BLG
if (yb_shoots_thru_walls.GetInt () == 2)
return IsShootableThruObstacleEx (dest);
if (m_difficulty < 2)
return false;
@ -478,6 +481,46 @@ bool Bot::IsShootableThruObstacle (Vector dest)
return false;
}
bool Bot::IsShootableThruObstacleEx (const Vector &dest)
{
// this function returns if enemy can be shoot through some obstacle
if (m_difficulty < 2 || GetWeaponPenetrationPower (m_currentWeapon) == 0)
return false;
Vector source = EyePosition ();
Vector direction = (dest - source).Normalize (); // 1 unit long
Vector point = nullvec;
int thikness = 0;
int numHits = 0;
TraceResult tr;
TraceLine (source, dest, true, true, GetEntity (), &tr);
while (tr.flFraction != 1.0 && numHits < 3)
{
numHits++;
thikness++;
point = tr.vecEndPos + direction;
while (POINT_CONTENTS (point) == CONTENTS_SOLID && thikness < 98)
{
point = point + direction;
thikness++;
}
TraceLine (point, dest, true, true, GetEntity (), &tr);
}
if (numHits < 3 && thikness < 98)
{
if ((dest - point).GetLengthSquared () < 13143)
return true;
}
return false;
}
bool Bot::DoFirePause (float distance, FireDelay *fireDelay)
{
// returns true if bot needs to pause between firing to compensate for punchangle & weapon spread
@ -818,8 +861,8 @@ WeaponSelectEnd:
pev->button &= ~IN_ATTACK;
LookupEnemy();
}
pev->button |= IN_ATTACK;
m_shootTime = GetWorldTime () + baseDelay + g_randGen.Float (minDelay, maxDelay);
m_zoomCheckTime = GetWorldTime ();
}
@ -865,7 +908,7 @@ void Bot::FocusEnemy (void)
float distance = enemyOrigin.GetLength (); // how far away is the enemy scum?
if (distance < 128.0f)
if (distance < 256.0f)
{
if (m_currentWeapon == WEAPON_KNIFE)
{
@ -919,11 +962,8 @@ void Bot::CombatFight (void)
float distance = enemyOrigin.GetLength (); // how far away is the enemy scum?
if (m_timeWaypointMove + m_frameInterval + 0.5f < GetWorldTime ())
if (m_timeWaypointMove + m_frameInterval < GetWorldTime ())
{
if (m_currentWeapon == WEAPON_KNIFE)
return;
int approach;
if ((m_states & STATE_SUSPECT_ENEMY) && !(m_states & STATE_SEEING_ENEMY)) // if suspecting enemy stand still
@ -936,11 +976,12 @@ void Bot::CombatFight (void)
{
approach = static_cast <int> (pev->health * m_agressionLevel);
if (UsesSniper () && (approach > 49))
if (UsesSniper () && approach > 49)
approach = 49;
}
if (UsesPistol() && !(m_enemy->v.weapons & (1 << WEAPON_ELITE) || m_enemy->v.weapons & (1 << WEAPON_FIVESEVEN) || m_enemy->v.weapons & (1 << WEAPON_GLOCK) || m_enemy->v.weapons & (1 << WEAPON_USP) || m_enemy->v.weapons & (1 << WEAPON_DEAGLE) || m_enemy->v.weapons & (1 << WEAPON_SG550)) && !g_bombPlanted)
if (UsesPistol() && !((m_enemy->v.weapons & WEAPON_SECONDARY) || (m_enemy->v.weapons & (1 << WEAPON_SG550))) && !g_bombPlanted)
{
m_fearLevel += 0.5;
@ -970,7 +1011,7 @@ void Bot::CombatFight (void)
else
m_moveSpeed = pev->maxspeed;
if (distance < 96 && m_currentWeapon != WEAPON_KNIFE)
if (distance < 96)
m_moveSpeed = -pev->maxspeed;
if (UsesSniper ())
@ -1007,7 +1048,7 @@ void Bot::CombatFight (void)
{
if (m_lastFightStyleCheck + 3.0 < GetWorldTime ())
{
if (g_randGen.Long (0, 100) < 50)
if ( g_randGen.Long (0, 100) < 50)
m_fightStyle = 1;
else
m_fightStyle = 0;
@ -1061,7 +1102,7 @@ void Bot::CombatFight (void)
if (m_difficulty >= 3 && (m_jumpTime + 5.0 < GetWorldTime () && IsOnFloor () && g_randGen.Long (0, 1000) < (m_isReloading ? 8 : 2) && pev->velocity.GetLength2D () > 150.0))
pev->button |= IN_JUMP;
if (m_moveSpeed > 0.0 && distance > 150.0)
if (m_moveSpeed > 0.0 && distance > 150.0 && m_currentWeapon != WEAPON_KNIFE)
m_moveSpeed = 0.0;
}
else if (m_fightStyle == 1)
@ -1072,6 +1113,7 @@ void Bot::CombatFight (void)
float enemyHalfHeight = ((m_enemy->v.flags & FL_DUCKING) == FL_DUCKING ? 36.0 : 72.0) / 2;
// check center/feet
if (!IsVisible (m_enemy->v.origin, GetEntity ()) && !IsVisible (m_enemy->v.origin + Vector (0, 0, -enemyHalfHeight), GetEntity ()))
shouldDuck = false;
@ -1092,7 +1134,7 @@ void Bot::CombatFight (void)
m_strafeSpeed = 0.0;
}
if (m_moveSpeed > 0.0f)
if (m_moveSpeed > 0.0f && m_currentWeapon != WEAPON_KNIFE)
m_moveSpeed = GetWalkSpeed ();
if (m_isReloading)
@ -1254,9 +1296,9 @@ void Bot::SelectBestWeapon (void)
return;
}
if (m_isReloading)
return;
WeaponSelect *selectTab = &g_weaponSelect[0];
int selectIndex = 0;

View file

@ -309,7 +309,7 @@ bool Bot::GoalIsValid (void)
return false;
}
void Bot::CheckTerrain (float movedDistance)
void Bot::CheckTerrain (float movedDistance, const Vector &dir, const Vector &dirNormal)
{
edict_t *ent = NULL;
@ -320,27 +320,17 @@ void Bot::CheckTerrain (float movedDistance)
m_campButtons = pev->button & IN_DUCK;
StartTask (TASK_SHOOTBREAKABLE, TASKPRI_SHOOTBREAKABLE, -1, 0.0, false);
m_breakableCheckTime = GetWorldTime () + 0.7f;
m_breakableCheckTime = GetWorldTime () + 1.0f;
return;
}
// calculate 2 direction vectors, 1 without the up/down component
Vector directionOld = m_destOrigin - (pev->origin + pev->velocity * m_frameInterval);
Vector directionNormal = directionOld.Normalize ();
Vector direction = directionNormal;
directionNormal.z = 0.0;
m_moveAngles = directionOld.ToAngles ();
m_moveAngles.ClampAngles ();
m_moveAngles.x *= -1.0; // invert for engine
m_isStuck = false;
Vector src = nullvec;
Vector destination = nullvec;
Vector dst = nullvec;
Vector direction = dir;
Vector directionNormal = dirNormal;
TraceResult tr;
@ -415,237 +405,237 @@ void Bot::CheckTerrain (float movedDistance)
if (m_collideMoves[m_collStateIndex] == COLLISION_DUCK && IsOnFloor () || IsInWater ())
pev->button |= IN_DUCK;
}
return;
}
else // bot is stuck!
// bot is stuck!
// not yet decided what to do?
if (m_collisionState == COLLISION_NOTDECICED)
{
// not yet decided what to do?
if (m_collisionState == COLLISION_NOTDECICED)
char bits = 0;
if (IsOnLadder ())
bits = PROBE_STRAFE;
else if (IsInWater ())
bits = (PROBE_JUMP | PROBE_STRAFE);
else
bits = ((g_randGen.Long (0, 10) > 7 ? PROBE_JUMP : 0) | PROBE_STRAFE | PROBE_DUCK);
// collision check allowed if not flying through the air
if (IsOnFloor () || IsOnLadder () || IsInWater ())
{
char bits = 0;
char state[8];
int i = 0;
if (IsOnLadder ())
bits = PROBE_STRAFE;
else if (IsInWater ())
bits = (PROBE_JUMP | PROBE_STRAFE);
else
bits = ((g_randGen.Long (0, 10) > 7 ? PROBE_JUMP : 0) | PROBE_STRAFE | PROBE_DUCK);
// first 4 entries hold the possible collision states
state[i++] = COLLISION_JUMP;
state[i++] = COLLISION_DUCK;
state[i++] = COLLISION_STRAFELEFT;
state[i++] = COLLISION_STRAFERIGHT;
// collision check allowed if not flying through the air
if (IsOnFloor () || IsOnLadder () || IsInWater ())
// now weight all possible states
if (bits & PROBE_JUMP)
{
char state[8];
int i = 0;
state[i] = 0;
// first 4 entries hold the possible collision states
state[i++] = COLLISION_JUMP;
state[i++] = COLLISION_DUCK;
state[i++] = COLLISION_STRAFELEFT;
state[i++] = COLLISION_STRAFERIGHT;
if (CanJumpUp (directionNormal))
state[i] += 10;
// now weight all possible states
if (bits & PROBE_JUMP)
if (m_destOrigin.z >= pev->origin.z + 18.0)
state[i] += 5;
if (EntityIsVisible (m_destOrigin))
{
state[i] = 0;
MakeVectors (m_moveAngles);
if (CanJumpUp (directionNormal))
state[i] += 10;
src = EyePosition ();
src = src + (g_pGlobals->v_right * 15);
if (m_destOrigin.z >= pev->origin.z + 18.0)
state[i] += 5;
TraceLine (src, m_destOrigin, true, true, GetEntity (), &tr);
if (EntityIsVisible (m_destOrigin))
if (tr.flFraction >= 1.0)
{
MakeVectors (m_moveAngles);
src = EyePosition ();
src = src + (g_pGlobals->v_right * 15);
src = src - (g_pGlobals->v_right * 15);
TraceLine (src, m_destOrigin, true, true, GetEntity (), &tr);
if (tr.flFraction >= 1.0)
{
src = EyePosition ();
src = src - (g_pGlobals->v_right * 15);
TraceLine (src, m_destOrigin, true, true, GetEntity (), &tr);
if (tr.flFraction >= 1.0)
state[i] += 5;
}
state[i] += 5;
}
if (pev->flags & FL_DUCKING)
src = pev->origin;
else
src = pev->origin + Vector (0, 0, -17);
destination = src + directionNormal * 30;
TraceLine (src, destination, true, true, GetEntity (), &tr);
if (tr.flFraction != 1.0)
state[i] += 10;
}
if (pev->flags & FL_DUCKING)
src = pev->origin;
else
state[i] = 0;
src = pev->origin + Vector (0, 0, -17);
dst = src + directionNormal * 30;
TraceLine (src, dst, true, true, GetEntity (), &tr);
if (tr.flFraction != 1.0)
state[i] += 10;
}
else
state[i] = 0;
i++;
if (bits & PROBE_DUCK)
{
state[i] = 0;
if (CanDuckUnder (directionNormal))
state[i] += 10;
if ((m_destOrigin.z + 36.0 <= pev->origin.z) && EntityIsVisible (m_destOrigin))
state[i] += 5;
}
else
state[i] = 0;
i++;
if (bits & PROBE_STRAFE)
{
state[i] = 0;
state[i + 1] = 0;
// to start strafing, we have to first figure out if the target is on the left side or right side
MakeVectors (m_moveAngles);
Vector dirToPoint = (pev->origin - m_destOrigin).Normalize2D ();
Vector rightSide = g_pGlobals->v_right.Normalize2D ();
bool dirRight = false;
bool dirLeft = false;
bool blockedLeft = false;
bool blockedRight = false;
if ((dirToPoint | rightSide) > 0)
dirRight = true;
else
dirLeft = true;
if (m_moveSpeed > 0)
direction = g_pGlobals->v_forward;
else
direction = -g_pGlobals->v_forward;
// now check which side is blocked
src = pev->origin + (g_pGlobals->v_right * 32);
dst = src + (direction * 32);
TraceHull (src, dst, true, head_hull, GetEntity (), &tr);
if (tr.flFraction != 1.0)
blockedRight = true;
src = pev->origin - (g_pGlobals->v_right * 32);
dst = src + (direction * 32);
TraceHull (src, dst, true, head_hull, GetEntity (), &tr);
if (tr.flFraction != 1.0)
blockedLeft = true;
if (dirLeft)
state[i] += 5;
else
state[i] -= 5;
if (blockedLeft)
state[i] -= 5;
i++;
if (bits & PROBE_DUCK)
{
state[i] = 0;
if (CanDuckUnder (directionNormal))
state[i] += 10;
if ((m_destOrigin.z + 36.0 <= pev->origin.z) && EntityIsVisible (m_destOrigin))
state[i] += 5;
}
if (dirRight)
state[i] += 5;
else
state[i] = 0;
state[i] -= 5;
if (blockedRight)
state[i] -= 5;
}
else
{
state[i] = 0;
i++;
if (bits & PROBE_STRAFE)
state[i] = 0;
}
// weighted all possible moves, now sort them to start with most probable
int temp = 0;
bool isSorting = false;
do
{
isSorting = false;
for (i = 0; i < 3; i++)
{
state[i] = 0;
state[i + 1] = 0;
// to start strafing, we have to first figure out if the target is on the left side or right side
MakeVectors (m_moveAngles);
Vector dirToPoint = (pev->origin - m_destOrigin).Normalize2D ();
Vector rightSide = g_pGlobals->v_right.Normalize2D ();
bool dirRight = false;
bool dirLeft = false;
bool blockedLeft = false;
bool blockedRight = false;
if ((dirToPoint | rightSide) > 0)
dirRight = true;
else
dirLeft = true;
if (m_moveSpeed > 0)
direction = g_pGlobals->v_forward;
else
direction = -g_pGlobals->v_forward;
// now check which side is blocked
src = pev->origin + (g_pGlobals->v_right * 32);
destination = src + (direction * 32);
TraceHull (src, destination, true, head_hull, GetEntity (), &tr);
if (tr.flFraction != 1.0)
blockedRight = true;
src = pev->origin - (g_pGlobals->v_right * 32);
destination = src + (direction * 32);
TraceHull (src, destination, true, head_hull, GetEntity (), &tr);
if (tr.flFraction != 1.0)
blockedLeft = true;
if (dirLeft)
state[i] += 5;
else
state[i] -= 5;
if (blockedLeft)
state[i] -= 5;
i++;
if (dirRight)
state[i] += 5;
else
state[i] -= 5;
if (blockedRight)
state[i] -= 5;
}
else
{
state[i] = 0;
i++;
state[i] = 0;
}
// weighted all possible moves, now sort them to start with most probable
int temp = 0;
bool isSorting = false;
do
{
isSorting = false;
for (i = 0; i < 3; i++)
if (state[i + 4] < state[i + 5])
{
if (state[i + 4] < state[i + 5])
{
temp = state[i];
temp = state[i];
state[i] = state[i + 1];
state[i + 1] = temp;
state[i] = state[i + 1];
state[i + 1] = temp;
temp = state[i + 4];
temp = state[i + 4];
state[i + 4] = state[i + 5];
state[i + 5] = temp;
state[i + 4] = state[i + 5];
state[i + 5] = temp;
isSorting = true;
}
isSorting = true;
}
} while (isSorting);
}
} while (isSorting);
for (i = 0; i < 4; i++)
m_collideMoves[i] = state[i];
for (i = 0; i < 4; i++)
m_collideMoves[i] = state[i];
m_collideTime = GetWorldTime ();
m_probeTime = GetWorldTime () + 0.5;
m_collisionProbeBits = bits;
m_collisionState = COLLISION_PROBING;
m_collStateIndex = 0;
m_collideTime = GetWorldTime ();
m_probeTime = GetWorldTime () + 0.5;
m_collisionProbeBits = bits;
m_collisionState = COLLISION_PROBING;
m_collStateIndex = 0;
}
}
if (m_collisionState == COLLISION_PROBING)
{
if (m_probeTime < GetWorldTime ())
{
m_collStateIndex++;
m_probeTime = GetWorldTime () + 0.5;
if (m_collStateIndex > 4)
{
m_navTimeset = GetWorldTime () - 5.0;
ResetCollideState ();
}
}
if (m_collisionState == COLLISION_PROBING)
if (m_collStateIndex <= 4)
{
if (m_probeTime < GetWorldTime ())
switch (m_collideMoves[m_collStateIndex])
{
m_collStateIndex++;
m_probeTime = GetWorldTime () + 0.5;
case COLLISION_JUMP:
if (IsOnFloor () || IsInWater ())
pev->button |= IN_JUMP;
break;
if (m_collStateIndex > 4)
{
m_navTimeset = GetWorldTime () - 5.0;
ResetCollideState ();
}
}
case COLLISION_DUCK:
if (IsOnFloor () || IsInWater ())
pev->button |= IN_DUCK;
break;
if (m_collStateIndex <= 4)
{
switch (m_collideMoves[m_collStateIndex])
{
case COLLISION_JUMP:
if (IsOnFloor () || IsInWater ())
pev->button |= IN_JUMP;
break;
case COLLISION_STRAFELEFT:
pev->button |= IN_MOVELEFT;
SetStrafeSpeed (directionNormal, -pev->maxspeed);
break;
case COLLISION_DUCK:
if (IsOnFloor () || IsInWater ())
pev->button |= IN_DUCK;
break;
case COLLISION_STRAFELEFT:
pev->button |= IN_MOVELEFT;
SetStrafeSpeed (directionNormal, -pev->maxspeed);
break;
case COLLISION_STRAFERIGHT:
pev->button |= IN_MOVERIGHT;
SetStrafeSpeed (directionNormal, pev->maxspeed);
break;
}
case COLLISION_STRAFERIGHT:
pev->button |= IN_MOVERIGHT;
SetStrafeSpeed (directionNormal, pev->maxspeed);
break;
}
}
}
@ -690,7 +680,7 @@ bool Bot::DoWaypointNav (void)
// pressing the jump button gives the illusion of the bot actual jmping.
if (IsOnFloor () || IsOnLadder ())
{
pev->velocity = m_desiredVelocity;
pev->velocity = m_desiredVelocity + m_desiredVelocity * 0.15; // cheating i know, but something changed in recent cs updates...
pev->button |= IN_JUMP;
m_jumpFinished = true;
@ -1076,7 +1066,7 @@ bool Bot::DoWaypointNav (void)
}
// make sure we are always facing the door when going through it
m_aimFlags &= ~(AIM_LAST_ENEMY | AIM_PREDICT_ENEMY);
m_aimFlags &= ~(AIM_LAST_ENEMY | AIM_PREDICT_PATH);
edict_t *button = FindNearestButton (STRING (tr.pHit->v.targetname));
@ -1818,6 +1808,9 @@ bool Bot::FindWaypoint (void)
if (i == m_currentWaypointIndex || i == m_prevWptIndex[0] || i == m_prevWptIndex[1] || i == m_prevWptIndex[2] || i == m_prevWptIndex[3] || i == m_prevWptIndex[4])
continue;
if ((g_mapType & MAP_CS) && HasHostage () && (g_waypoint->GetPath (i)->flags & FLAG_NOHOSTAGE))
continue;
// ignore non-reacheable waypoints...
if (!g_waypoint->Reachable (this, i))
continue;
@ -1854,21 +1847,25 @@ bool Bot::FindWaypoint (void)
i = g_randGen.Long (0, 0);
else if (coveredWaypoint != -1)
waypointIndeces[i = 0] = coveredWaypoint;
{
i = 0;
waypointIndeces[i] = coveredWaypoint;
}
else
{
i = 0;
Array <int> found;
g_waypoint->FindInRadius (found, 256.0, pev->origin);
g_waypoint->FindInRadius (found, 1024.0f, pev->origin);
if (!found.IsEmpty ())
waypointIndeces[i = 0] = found.GetRandomElement ();
waypointIndeces[i] = found.GetRandomElement ();
else
waypointIndeces[i = 0] = g_randGen.Long (0, g_numWaypoints - 1);
waypointIndeces[i] = g_randGen.Long (0, g_numWaypoints - 1);
}
m_collideTime = GetWorldTime ();
ChangeWptIndex (waypointIndeces[0]);
ChangeWptIndex (waypointIndeces[i]);
return true;
}

View file

@ -1249,7 +1249,7 @@ bool Waypoint::Reachable (Bot *bot, int index)
return false;
Vector src = bot->pev->origin;
Vector dest = GetPath (index)->origin;
Vector dest = m_paths[index]->origin;
float distance = (dest - src).GetLength ();
@ -1262,7 +1262,7 @@ bool Waypoint::Reachable (Bot *bot, int index)
float distance2D = (dest - src).GetLength2D ();
// is destination waypoint higher that source (45 is max jump height), or destination waypoint higher that source
if ((dest.z > src.z + 40.0 || dest.z < src.z - 75.0) && (!(GetPath (index)->flags & FLAG_LADDER) || distance2D >= 16.0))
if ((dest.z > src.z + 40.0 || dest.z < src.z - 75.0) && (!(m_paths[index]->flags & FLAG_LADDER) || distance2D >= 16.0))
return false; // unable to reach this one
}
@ -1451,7 +1451,7 @@ char *Waypoint::GetWaypointInfo (int id)
{
// this function returns path information for waypoint pointed by id.
Path *path = GetPath (id);
Path *path = m_paths[id];
// if this path is null, return
if (path == NULL)