combat: minor fixes to the grenade throwing conditions

This commit is contained in:
jeefo 2024-02-12 16:04:22 +03:00
commit ad5352b041
No known key found for this signature in database
GPG key ID: 927BCA0779BEA8ED
3 changed files with 51 additions and 40 deletions

View file

@ -439,6 +439,7 @@ constexpr auto kMaxCollideMoves = 3;
constexpr auto kGameMaxPlayers = 32; constexpr auto kGameMaxPlayers = 32;
constexpr auto kGameTeamNum = 2; constexpr auto kGameTeamNum = 2;
constexpr auto kInvalidNodeIndex = -1; constexpr auto kInvalidNodeIndex = -1;
constexpr auto kGrenadeInventoryEmpty = -1;
constexpr auto kConfigExtension = "cfg"; constexpr auto kConfigExtension = "cfg";
// weapon masks // weapon masks

View file

@ -414,8 +414,9 @@ private:
bool isFriendInLineOfFire (float distance); bool isFriendInLineOfFire (float distance);
bool isGroupOfEnemies (const Vector &location, int numEnemies = 1, float radius = 256.0f); bool isGroupOfEnemies (const Vector &location, int numEnemies = 1, float radius = 256.0f);
bool isPenetrableObstacle (const Vector &dest); bool isPenetrableObstacle (const Vector &dest);
bool isPenetrableObstacle2 (const Vector &dest); bool isPenetrableObstacle1 (const Vector &dest, int penetratePower);
bool isPenetrableObstacle3 (const Vector &dest); bool isPenetrableObstacle2 (const Vector &dest, int penetratePower);
bool isPenetrableObstacle3 (const Vector &dest, int penetratePower);
bool isEnemyBehindShield (edict_t *enemy); bool isEnemyBehindShield (edict_t *enemy);
bool checkChatKeywords (String &reply); bool checkChatKeywords (String &reply);
bool isReplyingToChat (); bool isReplyingToChat ();

View file

@ -7,7 +7,7 @@
#include <yapb.h> #include <yapb.h>
ConVar cv_shoots_thru_walls ("shoots_thru_walls", "2", "Specifies whether bots able to fire at enemies behind the wall, if they hearing or suspecting them.", true, 0.0f, 3.0f); ConVar cv_shoots_thru_walls ("shoots_thru_walls", "1", "Specifies whether bots able to fire at enemies behind the wall, if they hearing or suspecting them.", true, 0.0f, 3.0f);
ConVar cv_ignore_enemies ("ignore_enemies", "0", "Enables or disables searching world for enemies."); ConVar cv_ignore_enemies ("ignore_enemies", "0", "Enables or disables searching world for enemies.");
ConVar cv_check_enemy_rendering ("check_enemy_rendering", "0", "Enables or disables checking enemy rendering flags. Useful for some mods."); ConVar cv_check_enemy_rendering ("check_enemy_rendering", "0", "Enables or disables checking enemy rendering flags. Useful for some mods.");
ConVar cv_check_enemy_invincibility ("check_enemy_invincibility", "0", "Enables or disables checking enemy invincibility. Useful for some mods."); ConVar cv_check_enemy_invincibility ("check_enemy_invincibility", "0", "Enables or disables checking enemy invincibility. Useful for some mods.");
@ -656,21 +656,27 @@ bool Bot::isPenetrableObstacle (const Vector &dest) {
const auto method = cv_shoots_thru_walls.int_ (); const auto method = cv_shoots_thru_walls.int_ ();
if (method == 2) {
return isPenetrableObstacle2 (dest);
}
else if (method == 3) {
return isPenetrableObstacle3 (dest);
}
if (m_isUsingGrenade || m_difficulty < Difficulty::Normal) { if (m_isUsingGrenade || m_difficulty < Difficulty::Normal) {
return false; return false;
} }
auto power = conf.findWeaponById (m_currentWeapon).penetratePower; auto penetratePower = conf.findWeaponById (m_currentWeapon).penetratePower;
if (power == 0) { if (penetratePower == 0) {
return false; return false;
} }
// switch methods
switch (method) {
case 1:
return isPenetrableObstacle1 (dest, penetratePower);
case 3:
return isPenetrableObstacle3 (dest, penetratePower);
};
return isPenetrableObstacle2 (dest, penetratePower);
}
bool Bot::isPenetrableObstacle1 (const Vector &dest, int penetratePower) {
TraceResult tr {}; TraceResult tr {};
float obstacleDistanceSq = 0.0f; float obstacleDistanceSq = 0.0f;
@ -695,10 +701,10 @@ bool Bot::isPenetrableObstacle (const Vector &dest) {
if (obstacleDistanceSq > 0.0f) { if (obstacleDistanceSq > 0.0f) {
constexpr float kMaxDistanceSq = cr::sqrf (75.0f); constexpr float kMaxDistanceSq = cr::sqrf (75.0f);
while (power > 0) { while (penetratePower > 0) {
if (obstacleDistanceSq > kMaxDistanceSq) { if (obstacleDistanceSq > kMaxDistanceSq) {
obstacleDistanceSq -= kMaxDistanceSq; obstacleDistanceSq -= kMaxDistanceSq;
power--; penetratePower--;
continue; continue;
} }
@ -708,15 +714,9 @@ bool Bot::isPenetrableObstacle (const Vector &dest) {
return false; return false;
} }
bool Bot::isPenetrableObstacle2 (const Vector &dest) { bool Bot::isPenetrableObstacle2 (const Vector &dest, int) {
// this function returns if enemy can be shoot through some obstacle // this function returns if enemy can be shoot through some obstacle
auto power = conf.findWeaponById (m_currentWeapon).penetratePower;
if (m_isUsingGrenade || m_difficulty < Difficulty::Normal || !power) {
return false;
}
const Vector &source = getEyesPos (); const Vector &source = getEyesPos ();
const Vector &direction = (dest - source).normalize_apx (); // 1 unit long const Vector &direction = (dest - source).normalize_apx (); // 1 unit long
@ -749,14 +749,9 @@ bool Bot::isPenetrableObstacle2 (const Vector &dest) {
return false; return false;
} }
bool Bot::isPenetrableObstacle3 (const Vector &dest) { bool Bot::isPenetrableObstacle3 (const Vector &dest, int penetratePower) {
// this function returns if enemy can be shoot through some obstacle // this function returns if enemy can be shoot through some obstacle
auto power = conf.findWeaponById (m_currentWeapon).penetratePower;
if (m_isUsingGrenade || m_difficulty < Difficulty::Normal || !power) {
return false;
}
TraceResult tr {}; TraceResult tr {};
Vector source = getEyesPos (); Vector source = getEyesPos ();
@ -777,7 +772,7 @@ bool Bot::isPenetrableObstacle3 (const Vector &dest) {
return true; return true;
} }
if (--power == 0) { if (--penetratePower == 0) {
return false; return false;
} }
source = tr.vecEndPos + dir; source = tr.vecEndPos + dir;
@ -1487,7 +1482,7 @@ int Bot::bestGrenadeCarried () {
else if (pev->weapons & cr::bit (Weapon::Flashbang)) { else if (pev->weapons & cr::bit (Weapon::Flashbang)) {
return Weapon::Flashbang; return Weapon::Flashbang;
} }
return -1; return kGrenadeInventoryEmpty;
} }
bool Bot::rateGroundWeapon (edict_t *ent) { bool Bot::rateGroundWeapon (edict_t *ent) {
@ -1937,7 +1932,7 @@ void Bot::checkGrenadesThrow () {
// check if throwing a grenade is a good thing to do... // check if throwing a grenade is a good thing to do...
const auto throwingCondition = isGrenadeMode const auto throwingCondition = isGrenadeMode
? false ? m_lastEnemyOrigin.empty ()
: (preventibleTasks : (preventibleTasks
|| isInNarrowPlace () || isInNarrowPlace ()
|| cv_ignore_enemies.bool_ () || cv_ignore_enemies.bool_ ()
@ -1945,7 +1940,8 @@ void Bot::checkGrenadesThrow () {
|| m_grenadeRequested || m_grenadeRequested
|| m_isReloading || m_isReloading
|| (isKnifeMode () && !bots.isBombPlanted ()) || (isKnifeMode () && !bots.isBombPlanted ())
|| m_grenadeCheckTime >= game.time ()); || m_grenadeCheckTime >= game.time ()
|| m_lastEnemyOrigin.empty ());
if (throwingCondition) { if (throwingCondition) {
clearThrowStates (m_states); clearThrowStates (m_states);
@ -1966,14 +1962,14 @@ void Bot::checkGrenadesThrow () {
const auto grenadeToThrow = bestGrenadeCarried (); const auto grenadeToThrow = bestGrenadeCarried ();
// if we don't have grenades no need to check it this round again // if we don't have grenades no need to check it this round again
if (grenadeToThrow == -1) { if (grenadeToThrow == kGrenadeInventoryEmpty) {
m_grenadeCheckTime = game.time () + 15.0f; // changed since, czero can drop grenades from dead players m_grenadeCheckTime = game.time () + 15.0f; // changed since, czero can drop grenades from dead players
clearThrowStates (m_states); clearThrowStates (m_states);
return; return;
} }
else { else {
int cancelProb = 20; int cancelProb = m_agressionLevel > m_fearLevel ? 5 : 20;
if (grenadeToThrow == Weapon::Flashbang) { if (grenadeToThrow == Weapon::Flashbang) {
cancelProb = 25; cancelProb = 25;
@ -1989,7 +1985,7 @@ void Bot::checkGrenadesThrow () {
float distanceSq = m_lastEnemyOrigin.distanceSq2d (pev->origin); float distanceSq = m_lastEnemyOrigin.distanceSq2d (pev->origin);
// don't throw grenades at anything that isn't on the ground! // don't throw grenades at anything that isn't on the ground!
if (!(m_lastEnemy->v.flags & FL_ONGROUND) && !m_lastEnemy->v.waterlevel && m_lastEnemyOrigin.z > pev->absmax.z) { if (!(m_lastEnemy->v.flags & (FL_ONGROUND | FL_PARTIALGROUND)) && !m_lastEnemy->v.waterlevel && m_lastEnemyOrigin.z > pev->absmax.z) {
distanceSq = kInfiniteDistance; distanceSq = kInfiniteDistance;
} }
@ -1998,12 +1994,25 @@ void Bot::checkGrenadesThrow () {
distanceSq = kInfiniteDistance; distanceSq = kInfiniteDistance;
} }
// enemy within a good throw distance? // special condition if we're have valid current enemy
const auto grenadeToThrowCondition = isGrenadeMode if (!isGrenadeMode && ((m_states & Sense::SeeingEnemy)
? 100.0f && util.isAlive (m_enemy)
: grenadeToThrow == Weapon::Smoke ? 200.0f : 400.0f; && ((m_enemy->v.button | m_enemy->v.oldbuttons) & IN_ATTACK)
&& util.isInViewCone (pev->origin, m_enemy))) {
if (!m_lastEnemyOrigin.empty () && distanceSq > cr::sqrf (grenadeToThrowCondition) && distanceSq < cr::sqrf (1200.0f)) { // do not throw away grenades if anyone is attacking us
distanceSq = kInfiniteDistance;
}
// don't throw away HE's if just seen the enemy
if (!isGrenadeMode && grenadeToThrow == Weapon::Explosive && m_seeEnemyTime + kGrenadeCheckTime * 0.2f < game.time ()) {
distanceSq = kInfiniteDistance;
}
// enemy within a good throw distance?
const auto grenadeToThrowCondition = isGrenadeMode ? 100.0f : grenadeToThrow == Weapon::Smoke ? 200.0f : 350.0f;
if (distanceSq > cr::sqrf (grenadeToThrowCondition) && distanceSq < cr::sqrf (1200.0f)) {
bool allowThrowing = true; bool allowThrowing = true;
// care about different grenades // care about different grenades
@ -2113,7 +2122,7 @@ void Bot::checkGrenadesThrow () {
clearThrowStates (m_states); clearThrowStates (m_states);
return; return;
} }
const float kMaxThrowTime = game.time () + kGrenadeCheckTime * 6.0f; const float kMaxThrowTime = game.time () + kGrenadeCheckTime * 4.0f;
if (m_states & Sense::ThrowExplosive) { if (m_states & Sense::ThrowExplosive) {
startTask (Task::ThrowExplosive, TaskPri::Throw, kInvalidNodeIndex, kMaxThrowTime, false); startTask (Task::ThrowExplosive, TaskPri::Throw, kInvalidNodeIndex, kMaxThrowTime, false);