diff --git a/ext/crlib b/ext/crlib index a518be3..c0d1357 160000 --- a/ext/crlib +++ b/ext/crlib @@ -1 +1 @@ -Subproject commit a518be32e2ccf8e2ddb073fe237d1652cd8b185a +Subproject commit c0d1357bcd6b638368f345489c1a0dc70b4a9b38 diff --git a/inc/yapb.h b/inc/yapb.h index 3134895..32e5bb0 100644 --- a/inc/yapb.h +++ b/inc/yapb.h @@ -435,6 +435,7 @@ private: bool isEnemyHidden (edict_t *enemy); bool isEnemyInvincible (edict_t *enemy); bool isEnemyNoTarget (edict_t *enemy); + bool isEnemyInDarkArea (edict_t *enemy); bool isFriendInLineOfFire (float distance); bool isGroupOfEnemies (const Vector &location, int numEnemies = 1, float radius = 256.0f); 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_max; extern ConVar cv_smoke_grenade_checks; +extern ConVar cv_check_darkness; extern ConVar mp_freezetime; extern ConVar mp_roundtime; diff --git a/src/botlib.cpp b/src/botlib.cpp index e75bdf4..2f619b3 100644 --- a/src/botlib.cpp +++ b/src/botlib.cpp @@ -98,7 +98,7 @@ void Bot::avoidGrenades () { if (m_preventFlashing < game.time () && m_personality == Personality::Rusher - && m_difficulty == Difficulty::Expert + && cv_whose_your_daddy && model == kFlashbangModelName) { // don't look at flash bang diff --git a/src/combat.cpp b/src/combat.cpp index c650d25..85558fc 100644 --- a/src/combat.cpp +++ b/src/combat.cpp @@ -128,10 +128,49 @@ bool Bot::isEnemyNoTarget (edict_t *enemy) { 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) { // 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_enemyOrigin.clear (); @@ -336,6 +375,9 @@ void Bot::trackEnemies () { bool Bot::lookupEnemies () { // 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 if (m_enemyIgnoreTimer > game.time () || m_blindTime > game.time () || cv_ignore_enemies) { return false; @@ -359,8 +401,6 @@ bool Bot::lookupEnemies () { m_aimFlags |= AimFlags::LastEnemy; } } - m_enemyParts = Visibility::None; - m_enemyOrigin.clear (); if (!game.isNullEntity (m_enemy)) { player = m_enemy; diff --git a/src/tasks.cpp b/src/tasks.cpp index 6661816..4807899 100644 --- a/src/tasks.cpp +++ b/src/tasks.cpp @@ -559,8 +559,19 @@ void Bot::blind_ () { m_navTimeset = game.time (); // if bot remembers last enemy position - if (m_difficulty >= Difficulty::Normal && !m_lastEnemyOrigin.empty () && util.isPlayer (m_lastEnemy) && !usesSniper ()) { - m_lookAt = m_lastEnemyOrigin; // face last enemy + if (rg.chance (50) + && 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 }