From 6604145481dc805d4c95fafbeea3712abad504b2 Mon Sep 17 00:00:00 2001 From: jeefo Date: Wed, 10 Sep 2025 15:32:40 +0300 Subject: [PATCH] fix: hide chatter icon even for players that changed team fix: mark bot as finished buying on csdm spawn (ref #734) fix: do not start any map analysis if already analyzing (ref #726) combat: improved head/body aiming (ref #734) --- inc/yapb.h | 2 +- src/analyze.cpp | 4 ++++ src/botlib.cpp | 22 ++++++++++++++++++---- src/combat.cpp | 29 ++++++++++++++++++++--------- src/tasks.cpp | 9 +++++++-- src/vision.cpp | 6 +++--- 6 files changed, 53 insertions(+), 19 deletions(-) diff --git a/inc/yapb.h b/inc/yapb.h index 23c109d..99aa05d 100644 --- a/inc/yapb.h +++ b/inc/yapb.h @@ -520,7 +520,7 @@ private: void setPathOrigin (); void fireWeapons (); void doFireWeapons (); - void selectWeapons (float distance, int index, int id, int choosen); + void handleWeapons (float distance, int index, int id, int choosen); void focusEnemy (); void selectBestWeapon (); void selectSecondary (); diff --git a/src/analyze.cpp b/src/analyze.cpp index 90c0ae9..361eaf5 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -17,6 +17,10 @@ ConVar cv_graph_analyze_optimize_nodes_on_finish ("graph_analyze_optimize_nodes_ ConVar cv_graph_analyze_mark_goals_on_finish ("graph_analyze_mark_goals_on_finish", "1", "Specifies if the analyzer should mark nodes as map goals automatically upon finishing."); void GraphAnalyze::start () { + if (m_isAnalyzing) { + return; + } + // start analyzer in few seconds after level initialized if (cv_graph_analyze_auto_start) { m_updateInterval = game.time () + 3.0f; diff --git a/src/botlib.cpp b/src/botlib.cpp index 0b38c0f..6010c52 100644 --- a/src/botlib.cpp +++ b/src/botlib.cpp @@ -881,7 +881,9 @@ void Bot::showChatterIcon (bool show, bool disconnect) const { // do not respect timers while disconnecting bot for (auto &client : util.getClients ()) { - if (!(client.flags & ClientFlags::Used) || (client.ent->v.flags & FL_FAKECLIENT) || client.team != m_team) { + if (!(client.flags & ClientFlags::Used) + || (client.ent->v.flags & FL_FAKECLIENT) + || (client.team != m_team && !disconnect)) { continue; } @@ -891,7 +893,7 @@ void Bot::showChatterIcon (bool show, bool disconnect) const { } // do not respect timers while disconnecting bot - if (!show && (client.iconFlags[ownIndex] & ClientFlags::Icon) && (disconnect || client.iconTimestamp[ownIndex] < game.time ())) { + if (!show && (disconnect || (client.iconFlags[ownIndex] & ClientFlags::Icon)) && (disconnect || client.iconTimestamp[ownIndex] < game.time ())) { sendBotVoice (false, client.ent, entindex ()); client.iconTimestamp[ownIndex] = 0.0f; @@ -1828,7 +1830,9 @@ void Bot::syncUpdatePredictedIndex () { const float distToBotSq = botOrigin.distanceSq (graph[index].origin); - if (vistab.visible (currentNodeIndex, index) && distToBotSq < cr::sqrf (2048.0f)) { + if (vistab.visible (currentNodeIndex, index) + && distToBotSq < cr::sqrf (2048.0f) + && distToBotSq > cr::sqrf (128.0f)) { bestIndex = index; return false; } @@ -3283,7 +3287,15 @@ void Bot::checkSpawnConditions () { dropCurrentWeapon (); } else { - selectWeaponById (Weapon::Knife); + bool switchToKnife = true; + + if (m_currentWeapon == Weapon::Scout) { + switchToKnife = rg.chance (25); + } + + if (switchToKnife) { + selectWeaponById (Weapon::Knife); + } } } m_checkKnifeSwitch = false; @@ -3474,6 +3486,8 @@ void Bot::spawned () { if (game.is (GameFlags::CSDM | GameFlags::ZombieMod)) { newRound (); clearTasks (); + + m_buyingFinished = true; } } diff --git a/src/combat.cpp b/src/combat.cpp index 96f9c90..fa355d4 100644 --- a/src/combat.cpp +++ b/src/combat.cpp @@ -710,6 +710,11 @@ Vector Bot::getEnemyBodyOffset () { compensation.clear (); } + // get the correct head origin + const auto &headOrigin = [&] (edict_t *e, const float distance) -> Vector { + return Vector { e->v.origin.x, e->v.origin.y, e->v.absmin.z + e->v.size.z * 0.81f } + getCustomHeight (distance); + }; + // if we only suspect an enemy behind a wall take the worst skill if (!m_enemyParts && (m_states & Sense::SuspectEnemy)) { spot += getBodyOffsetError (distance); @@ -728,11 +733,13 @@ Vector Bot::getEnemyBodyOffset () { } // now check is our skill match to aim at head, else aim at enemy body - if (m_enemyBodyPartSet == m_enemy || rg.chance (headshotPct)) { - spot = m_enemyOrigin + getCustomHeight (distance); + if (m_enemyBodyPartSet == m_enemy + || ((m_enemyBodyPartSet != m_enemy) && rg.chance (headshotPct))) { + + spot = headOrigin (m_enemy, distance); if (usesSniper ()) { - spot.z -= pev->view_ofs.z * 0.5f; + spot.z -= pev->view_ofs.z * 0.35f; } // set's the enemy shooting spot to head, if headshot pct allows, and use head for that @@ -741,6 +748,10 @@ Vector Bot::getEnemyBodyOffset () { } else { spot = m_enemy->v.origin; + + if (m_difficulty == Difficulty::Expert) { + spot.z += pev->view_ofs.z * 0.35f; + } } } else if (m_enemyParts & Visibility::Body) { @@ -750,10 +761,10 @@ Vector Bot::getEnemyBodyOffset () { spot = m_enemyOrigin; } else if (m_enemyParts & Visibility::Head) { - spot = m_enemyOrigin + getCustomHeight (distance); + spot = headOrigin (m_enemy, distance); } } - auto idealSpot = m_enemyOrigin; + auto idealSpot = spot; if (m_difficulty < Difficulty::Hard && isEnemyInSight (idealSpot)) { spot = idealSpot + ((spot - idealSpot) * 0.005f); // gradually adjust the aiming direction @@ -1079,7 +1090,7 @@ bool Bot::checkZoom (float distance) { return zoomChange; } -void Bot::selectWeapons (float distance, int, int id, int choosen) { +void Bot::handleWeapons (float distance, int, int id, int choosen) { const auto tab = conf.getRawWeapons (); // we want to fire weapon, don't reload now @@ -1249,7 +1260,7 @@ void Bot::fireWeapons () { // if knife mode use knife only if (isKnifeMode ()) { - selectWeapons (distance, selectIndex, selectId, choosenWeapon); + handleWeapons (distance, selectIndex, selectId, choosenWeapon); return; } @@ -1263,7 +1274,7 @@ void Bot::fireWeapons () { && !isGroupOfEnemies (pev->origin) && getCurrentTaskId () != Task::Camp) { - selectWeapons (distance, selectIndex, selectId, choosenWeapon); + handleWeapons (distance, selectIndex, selectId, choosenWeapon); return; } @@ -1316,7 +1327,7 @@ void Bot::fireWeapons () { } selectId = Weapon::Knife; // no available ammo, use knife! } - selectWeapons (distance, selectIndex, selectId, choosenWeapon); + handleWeapons (distance, selectIndex, selectId, choosenWeapon); } bool Bot::isWeaponBadAtDistance (int weaponIndex, float distance) { diff --git a/src/tasks.cpp b/src/tasks.cpp index 6333930..5dbac9f 100644 --- a/src/tasks.cpp +++ b/src/tasks.cpp @@ -648,14 +648,19 @@ void Bot::camp_ () { auto pathLength = m_lastPredictLength; auto predictNode = m_lastPredictIndex; - if (isNodeValidForPredict (predictNode) && pathLength > 1) { + if (isNodeValidForPredict (predictNode) + && pathLength > 1 + && vistab.visible (predictNode, m_currentNodeIndex)) { + m_lookAtSafe = graph[predictNode].origin + pev->view_ofs; } else { pathLength = 0; predictNode = findAimingNode (m_lastEnemyOrigin, pathLength); - if (isNodeValidForPredict (predictNode) && pathLength > 1) { + if (isNodeValidForPredict (predictNode) && pathLength > 1 + && vistab.visible ( predictNode, m_currentNodeIndex)) { + m_lookAtSafe = graph[predictNode].origin + pev->view_ofs; } } diff --git a/src/vision.cpp b/src/vision.cpp index c1b9b6f..d016392 100644 --- a/src/vision.cpp +++ b/src/vision.cpp @@ -441,12 +441,12 @@ void Bot::setAimDirection () { // don't switch view right away after loosing focus with current enemy if ((m_shootTime + rg (0.75f, 1.25f) > game.time () - || m_seeEnemyTime + 1.5f > game.time ()) + || m_seeEnemyTime + rg (1.0f, 1.25f) > game.time ()) && m_forgetLastVictimTimer.elapsed () && !m_lastEnemyOrigin.empty () - && util.isAlive (m_lastEnemy) - && game.isNullEntity (m_enemy)) { + && util.isPlayer (m_lastEnemy) + && !util.isPlayer (m_enemy)) { flags |= AimFlags::LastEnemy; }