bot: disrupt bot vision in dark areas

This commit is contained in:
jeefo 2024-10-17 22:21:22 +03:00
commit 3d0bb4d7da
No known key found for this signature in database
GPG key ID: D696786B81B667C8
5 changed files with 60 additions and 7 deletions

@ -1 +1 @@
Subproject commit a518be32e2ccf8e2ddb073fe237d1652cd8b185a Subproject commit c0d1357bcd6b638368f345489c1a0dc70b4a9b38

View file

@ -435,6 +435,7 @@ private:
bool isEnemyHidden (edict_t *enemy); bool isEnemyHidden (edict_t *enemy);
bool isEnemyInvincible (edict_t *enemy); bool isEnemyInvincible (edict_t *enemy);
bool isEnemyNoTarget (edict_t *enemy); bool isEnemyNoTarget (edict_t *enemy);
bool isEnemyInDarkArea (edict_t *enemy);
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);
@ -925,6 +926,7 @@ extern ConVar cv_ignore_enemies_after_spawn_time;
extern ConVar cv_camping_time_min; extern ConVar cv_camping_time_min;
extern ConVar cv_camping_time_max; extern ConVar cv_camping_time_max;
extern ConVar cv_smoke_grenade_checks; extern ConVar cv_smoke_grenade_checks;
extern ConVar cv_check_darkness;
extern ConVar mp_freezetime; extern ConVar mp_freezetime;
extern ConVar mp_roundtime; extern ConVar mp_roundtime;

View file

@ -98,7 +98,7 @@ void Bot::avoidGrenades () {
if (m_preventFlashing < game.time () if (m_preventFlashing < game.time ()
&& m_personality == Personality::Rusher && m_personality == Personality::Rusher
&& m_difficulty == Difficulty::Expert && cv_whose_your_daddy
&& model == kFlashbangModelName) { && model == kFlashbangModelName) {
// don't look at flash bang // don't look at flash bang

View file

@ -128,10 +128,49 @@ bool Bot::isEnemyNoTarget (edict_t *enemy) {
return !!(enemy->v.flags & FL_NOTARGET); return !!(enemy->v.flags & FL_NOTARGET);
} }
bool Bot::isEnemyInDarkArea (edict_t *enemy) {
if (!cv_check_darkness && game.isNullEntity (enemy)) {
return false;
}
const auto scolor = illum.getSkyColor ();
// check if node near the enemy have a degraded light level
const auto enemyNodeIndex = graph.getNearest (m_enemy->v.origin);
if (!graph.exists (enemyNodeIndex)) {
return false;
}
const auto llevel = graph[enemyNodeIndex].light;
// if light level is higher than 30, do not bother with further tests
if (llevel > 30.0f) {
return false;
}
bool enemySemiTransparent = false;
const bool enemyHasGun = (enemy->v.weapons & kPrimaryWeaponMask) || (enemy->v.weapons & kSecondaryWeaponMask);
const bool enemyHasFlashlightEnabled = !!(enemy->v.effects & EF_DIMLIGHT);
const bool enemyIsAttacking = !!(enemy->v.oldbuttons & IN_ATTACK);
if (!m_usesNVG && ((llevel < 3.0f && scolor > 50.0f) || (llevel < 25.0f && scolor <= 50.0f))
&& !enemyHasFlashlightEnabled && (!enemyIsAttacking || !enemyHasGun)) {
return false;
}
else if (((llevel < 10.0f && scolor > 50.0f) || (llevel < 30.0f && scolor <= 50.0f)
|| (enemyIsAttacking && enemyHasGun))
&& !m_usesNVG && !enemyHasFlashlightEnabled) {
enemySemiTransparent = true;
}
TraceResult result {};
game.testLine (getEyesPos (), enemy->v.origin, m_isCreature ? TraceIgnore::None : TraceIgnore::Everything, ent (), &result);
return (result.flFraction <= 1.0f && result.pHit == enemy && (m_usesNVG || !enemySemiTransparent));
}
bool Bot::checkBodyParts (edict_t *target) { bool Bot::checkBodyParts (edict_t *target) {
// this function checks visibility of a bot target. // this function checks visibility of a bot target.
if (isEnemyHidden (target) || isEnemyInvincible (target) || isEnemyNoTarget (target)) { if (isEnemyHidden (target) || isEnemyInvincible (target) || isEnemyNoTarget (target) || isEnemyInDarkArea (target)) {
m_enemyParts = Visibility::None; m_enemyParts = Visibility::None;
m_enemyOrigin.clear (); m_enemyOrigin.clear ();
@ -336,6 +375,9 @@ void Bot::trackEnemies () {
bool Bot::lookupEnemies () { bool Bot::lookupEnemies () {
// this function tries to find the best suitable enemy for the bot // this function tries to find the best suitable enemy for the bot
m_enemyParts = Visibility::None;
m_enemyOrigin.clear ();
// do not search for enemies while we're blinded, or shooting disabled by user // do not search for enemies while we're blinded, or shooting disabled by user
if (m_enemyIgnoreTimer > game.time () || m_blindTime > game.time () || cv_ignore_enemies) { if (m_enemyIgnoreTimer > game.time () || m_blindTime > game.time () || cv_ignore_enemies) {
return false; return false;
@ -359,8 +401,6 @@ bool Bot::lookupEnemies () {
m_aimFlags |= AimFlags::LastEnemy; m_aimFlags |= AimFlags::LastEnemy;
} }
} }
m_enemyParts = Visibility::None;
m_enemyOrigin.clear ();
if (!game.isNullEntity (m_enemy)) { if (!game.isNullEntity (m_enemy)) {
player = m_enemy; player = m_enemy;

View file

@ -559,8 +559,19 @@ void Bot::blind_ () {
m_navTimeset = game.time (); m_navTimeset = game.time ();
// if bot remembers last enemy position // if bot remembers last enemy position
if (m_difficulty >= Difficulty::Normal && !m_lastEnemyOrigin.empty () && util.isPlayer (m_lastEnemy) && !usesSniper ()) { if (rg.chance (50)
m_lookAt = m_lastEnemyOrigin; // face last enemy && m_difficulty >= Difficulty::Normal
&& !m_lastEnemyOrigin.empty ()
&& util.isPlayer (m_lastEnemy)
&& !usesSniper ()) {
auto error = kSprayDistance * cr::powf (m_lastEnemyOrigin.distance (pev->origin), 0.5f) / 2048.0f;
auto origin = m_lastEnemyOrigin;
origin.x = origin.x + rg (-error, error);
origin.y = origin.y + rg (-error, error);
m_lookAt = origin; // face last enemy
m_wantsToFire = true; // and shoot it m_wantsToFire = true; // and shoot it
} }