diff --git a/src/analyze.cpp b/src/analyze.cpp index 959587c..3083cbf 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -201,7 +201,9 @@ void GraphAnalyze::optimize () { Array indexes; for (const auto &link : path.links) { - if (graph.exists (link.index) && !m_optimizedNodes[link.index] && !AStarAlgo::cantSkipNode (path.number, link.index, true)) { + if (graph.exists (link.index) && !m_optimizedNodes[link.index] + && !AStarAlgo::cantSkipNode (path.number, link.index, true)) { + indexes.emplace (link.index); } } @@ -339,7 +341,9 @@ void GraphAnalyze::flood (const Vector &pos, const Vector &next, float range) { } auto testPos = m_isCrouch ? Vector { nextPos.x, nextPos.y, nextPos.z - 18.0f } : nextPos; - if ((graph.isNodeReacheable (targetPos, testPos) && graph.isNodeReacheable (testPos, targetPos)) || (graph.isNodeReacheableWithJump (testPos, targetPos) && graph.isNodeReacheableWithJump (targetPos, testPos))) { + if ((graph.isNodeReacheable (targetPos, testPos) + && graph.isNodeReacheable (testPos, targetPos)) || (graph.isNodeReacheableWithJump (testPos, targetPos) + && graph.isNodeReacheableWithJump (targetPos, testPos))) { graph.add (NodeAddFlag::Normal, m_isCrouch ? Vector { nextPos.x, nextPos.y, nextPos.z - 9.0f } : nextPos); } } diff --git a/src/botlib.cpp b/src/botlib.cpp index b8972c4..dd8f57a 100644 --- a/src/botlib.cpp +++ b/src/botlib.cpp @@ -95,7 +95,11 @@ void Bot::avoidGrenades () { } auto model = pent->v.model.str (9); - if (m_preventFlashing < game.time () && m_personality == Personality::Rusher && m_difficulty == Difficulty::Expert && model == kFlashbangModelName) { + if (m_preventFlashing < game.time () + && m_personality == Personality::Rusher + && m_difficulty == Difficulty::Expert + && model == kFlashbangModelName) { + // don't look at flash bang if (!(m_states & Sense::SeeingEnemy)) { m_lookAt.y = cr::wrapAngle ((game.getEntityOrigin (pent) - getEyesPos ()).angles ().y + 180.0f); @@ -165,7 +169,15 @@ void Bot::checkBreakable (edict_t *touch) { } void Bot::checkBreakablesAround () { - if (!m_buyingFinished || !cv_destroy_breakables_around.bool_ () || usesKnife () || rg.chance (25) || !game.hasBreakables () || m_seeEnemyTime + 4.0f > game.time () || !game.isNullEntity (m_enemy) || !hasPrimaryWeapon ()) { + if (!m_buyingFinished + || !cv_destroy_breakables_around.bool_ () + || usesKnife () + || rg.chance (25) + || !game.hasBreakables () + || m_seeEnemyTime + 4.0f > game.time () + || !game.isNullEntity (m_enemy) + || !hasPrimaryWeapon ()) { + return; } const auto radius = cv_object_destroy_radius.float_ (); @@ -403,7 +415,9 @@ void Bot::updatePickups () { allowPickup = true; pickupType = Pickup::DroppedC4; } - else if ((isWeaponBox || classname.startsWith ("armoury_entity") || (isCSDM && classname.startsWith ("csdm"))) && !m_isUsingGrenade) { + else if ((isWeaponBox || classname.startsWith ("armoury_entity") || (isCSDM && classname.startsWith ("csdm"))) + && !m_isUsingGrenade) { + allowPickup = true; pickupType = Pickup::Weapon; @@ -418,10 +432,17 @@ void Bot::updatePickups () { const auto &primaryProp = conf.getWeaponProp (primary.id); const auto &secondaryProp = conf.getWeaponProp (secondary.id); - if (secondaryWeaponCarried < kPrimaryWeaponMinIndex && (getAmmo (secondary.id) > 0.3 * secondaryProp.ammo1Max) && model == "357ammobox.mdl") { + if (secondaryWeaponCarried < kPrimaryWeaponMinIndex + && (getAmmo (secondary.id) > 0.3 * secondaryProp.ammo1Max) + && model == "357ammobox.mdl") { + allowPickup = false; } - else if (!m_isVIP && primaryWeaponCarried >= kPrimaryWeaponMinIndex && (getAmmo (primary.id) > 0.3 * primaryProp.ammo1Max) && !m_isUsingGrenade && !hasShield ()) { + else if (!m_isVIP && + primaryWeaponCarried >= kPrimaryWeaponMinIndex + && (getAmmo (primary.id) > 0.3 * primaryProp.ammo1Max) + && !m_isUsingGrenade && !hasShield ()) { + auto weaponType = conf.getWeaponType (primaryWeaponCarried); const bool isSniperRifle = weaponType == WeaponType::Sniper; @@ -528,7 +549,11 @@ void Bot::updatePickups () { m_itemIgnore = ent; allowPickup = false; - if (!m_defendHostage && m_personality != Personality::Rusher && m_difficulty >= Difficulty::Normal && rg.chance (15) && m_timeCamping + 15.0f < game.time ()) { + if (!m_defendHostage && m_personality + != Personality::Rusher && m_difficulty >= Difficulty::Normal + && rg.chance (15) + && m_timeCamping + 15.0f < game.time ()) { + const int index = findDefendNode (origin); startTask (Task::Camp, TaskPri::Camp, kInvalidNodeIndex, game.time () + rg.get (30.0f, 60.0f), true); // push camp task on to stack @@ -830,7 +855,11 @@ void Bot::showChatterIcon (bool show, bool disconnect) { void Bot::instantChatter (int type) { // this function sends instant chatter messages. - if (!game.is (GameFlags::HasBotVoice) || cv_radio_mode.int_ () != 2 || !conf.hasChatterBank (type) || !conf.hasChatterBank (Chatter::DiePain)) { + if (!game.is (GameFlags::HasBotVoice) + || cv_radio_mode.int_ () != 2 + || !conf.hasChatterBank (type) + || !conf.hasChatterBank (Chatter::DiePain)) { + return; } @@ -873,7 +902,9 @@ void Bot::pushRadioMessage (int message) { if (cv_radio_mode.int_ () == 0 || m_numFriendsLeft == 0) { return; } - m_forceRadio = !game.is (GameFlags::HasBotVoice) || !conf.hasChatterBank (message) || cv_radio_mode.int_ () != 2; // use radio instead voice + m_forceRadio = !game.is (GameFlags::HasBotVoice) + || !conf.hasChatterBank (message) + || cv_radio_mode.int_ () != 2; // use radio instead voice m_radioSelect = message; pushMsgQueue (BotMsg::Radio); @@ -1014,7 +1045,11 @@ void Bot::checkMsgQueue () { } if (m_radioSelect != -1) { - if ((m_radioSelect != Radio::ReportingIn && m_forceRadio) || cv_radio_mode.int_ () != 2 || !conf.hasChatterBank (m_radioSelect) || !game.is (GameFlags::HasBotVoice)) { + if ((m_radioSelect != Radio::ReportingIn && m_forceRadio) + || cv_radio_mode.int_ () != 2 + || !conf.hasChatterBank (m_radioSelect) + || !game.is (GameFlags::HasBotVoice)) { + if (m_radioSelect < Radio::GoGoGo) { issueCommand ("radio1"); } @@ -1282,7 +1317,10 @@ void Bot::buyStuff () { break; } - if (selectedWeapon->id == Weapon::Shield && m_moneyAmount > limit[EcoLimit::ShieldGreater] && rg.chance (disrespectEconomicsPct)) { + if (selectedWeapon->id == Weapon::Shield + && m_moneyAmount > limit[EcoLimit::ShieldGreater] + && rg.chance (disrespectEconomicsPct)) { + ignoreWeapon = true; } } @@ -1382,7 +1420,10 @@ void Bot::buyStuff () { break; case BuyState::ArmorVestHelm: // if armor is damaged and bot has some money, buy some armor - if (pev->armorvalue < rg.get (50.0f, 80.0f) && teamHasGoodEconomics && (isPistolMode || (teamHasGoodEconomics && hasPrimaryWeapon ()))) { + if (pev->armorvalue < rg.get (50.0f, 80.0f) + && teamHasGoodEconomics + && (isPistolMode || (teamHasGoodEconomics && hasPrimaryWeapon ()))) { + // if bot is rich, buy kevlar + helmet, else buy a single kevlar if (m_moneyAmount > 1500 && !isWeaponRestricted (Weapon::ArmorHelm)) { issueCommand ("buyequip;menuselect 2"); @@ -1394,7 +1435,11 @@ void Bot::buyStuff () { break; case BuyState::SecondaryWeapon: // if bot has still some money, buy a better secondary weapon - if (isPistolMode || (isFirstRound && hasDefaultPistols && rg.chance (60)) || (hasDefaultPistols && bots.getLastWinner () == m_team && m_moneyAmount > rg.get (2000, 3000)) || (hasPrimaryWeapon () && hasDefaultPistols && m_moneyAmount > rg.get (7500, 9000))) { + if (isPistolMode + || (isFirstRound && hasDefaultPistols && rg.chance (60)) + || (hasDefaultPistols && bots.getLastWinner () == m_team && m_moneyAmount > rg.get (2000, 3000)) + || (hasPrimaryWeapon () && hasDefaultPistols && m_moneyAmount > rg.get (7500, 9000))) { + do { pref--; @@ -1503,7 +1548,12 @@ void Bot::buyStuff () { break; case BuyState::DefusalKit: // if bot is CT and we're on a bomb map, randomly buy the defuse kit - if (game.mapIs (MapFlags::Demolition) && m_team == Team::CT && rg.chance (80) && m_moneyAmount > 200 && !isWeaponRestricted (Weapon::Defuser)) { + if (game.mapIs (MapFlags::Demolition) + && m_team == Team::CT + && rg.chance (80) + && m_moneyAmount > 200 + && !isWeaponRestricted (Weapon::Defuser)) { + if (isOldGame) { issueCommand ("buyequip;menuselect 6"); } @@ -1569,7 +1619,13 @@ void Bot::overrideConditions () { const auto tid = getCurrentTaskId (); // check if we need to escape from bomb - if (game.mapIs (MapFlags::Demolition) && bots.isBombPlanted () && m_isAlive && tid != Task::EscapeFromBomb && tid != Task::Camp && isOutOfBombTimer ()) { + if (game.mapIs (MapFlags::Demolition) + && bots.isBombPlanted () + && m_isAlive + && tid != Task::EscapeFromBomb + && tid != Task::Camp + && isOutOfBombTimer ()) { + completeTask (); // complete current task // then start escape from bomb immediate @@ -1584,7 +1640,10 @@ void Bot::overrideConditions () { if (length > 250.0f && (m_states & Sense::SeeingEnemy)) { const int nearestToEnemyPoint = graph.getNearest (m_enemy->v.origin); - if (nearestToEnemyPoint != kInvalidNodeIndex && nearestToEnemyPoint != m_currentNodeIndex && cr::abs (graph[nearestToEnemyPoint].origin.z - m_enemy->v.origin.z) < 16.0f) { + if (nearestToEnemyPoint != kInvalidNodeIndex + && nearestToEnemyPoint != m_currentNodeIndex + && cr::abs (graph[nearestToEnemyPoint].origin.z - m_enemy->v.origin.z) < 16.0f) { + if (tid != Task::MoveToPosition && !cr::fequal (getTask ()->desire, TaskPri::Hide)) { startTask (Task::MoveToPosition, TaskPri::Hide, nearestToEnemyPoint, game.time () + length / (m_moveSpeed * 2.0f), true); } @@ -1604,7 +1663,10 @@ void Bot::overrideConditions () { } // special handling for sniping - if (usesSniper () && (m_states & (Sense::SeeingEnemy | Sense::SuspectEnemy)) && m_sniperStopTime > game.time () && tid != Task::SeekCover) { + if (usesSniper () && (m_states & (Sense::SeeingEnemy | Sense::SuspectEnemy)) + && m_sniperStopTime > game.time () + && tid != Task::SeekCover) { + m_moveSpeed = 0.0f; m_strafeSpeed = 0.0f; @@ -1612,7 +1674,13 @@ void Bot::overrideConditions () { } // special handling for reloading - if (!bots.isRoundOver () && tid == Task::Normal && m_reloadState != Reload::None && m_isReloading && !isDucking () && !isInNarrowPlace ()) { + if (!bots.isRoundOver () && + tid == Task::Normal + && m_reloadState != Reload::None + && m_isReloading + && !isDucking () + && !isInNarrowPlace ()) { + if (m_reloadState != Reload::None || m_isReloading) { const auto maxClip = conf.findWeaponById (m_currentWeapon).maxClip; const auto curClip = getAmmoInClip (); @@ -1694,7 +1762,9 @@ void Bot::refreshEnemyPredict () { if (distanceToLastEnemySq > cr::sqrf (256.0f) && (distanceToLastEnemySq < cr::sqrf (2048.0f) || usesSniper ())) { m_aimFlags |= AimFlags::PredictPath; } - const bool denyLastEnemy = pev->velocity.lengthSq2d () > 0.0f && distanceToLastEnemySq < cr::sqrf (256.0f) && m_shootTime + 2.5f > game.time (); + const bool denyLastEnemy = pev->velocity.lengthSq2d () > 0.0f + && distanceToLastEnemySq < cr::sqrf (256.0f) + && m_shootTime + 2.5f > game.time (); if (!denyLastEnemy && seesEntity (m_lastEnemyOrigin, true)) { m_aimFlags |= AimFlags::LastEnemy; @@ -1741,7 +1811,11 @@ void Bot::setConditions () { pushRadioMessage (Radio::EnemyDown); } else if (rg.chance (60)) { - if ((m_lastVictim->v.weapons & cr::bit (Weapon::AWP)) || (m_lastVictim->v.weapons & cr::bit (Weapon::Scout)) || (m_lastVictim->v.weapons & cr::bit (Weapon::G3SG1)) || (m_lastVictim->v.weapons & cr::bit (Weapon::SG550))) { + if ((m_lastVictim->v.weapons & cr::bit (Weapon::AWP)) + || (m_lastVictim->v.weapons & cr::bit (Weapon::Scout)) + || (m_lastVictim->v.weapons & cr::bit (Weapon::G3SG1)) + || (m_lastVictim->v.weapons & cr::bit (Weapon::SG550))) { + pushChatterMessage (Chatter::SniperKilled); } else { @@ -1804,7 +1878,11 @@ void Bot::setConditions () { } // don't listen if seeing enemy, just checked for sounds or being blinded (because its inhuman) - if (!cv_ignore_enemies.bool_ () && m_soundUpdateTime < game.time () && m_blindTime < game.time () && m_seeEnemyTime + 1.0f < game.time ()) { + if (!cv_ignore_enemies.bool_ () + && m_soundUpdateTime < game.time () + && m_blindTime < game.time () + && m_seeEnemyTime + 1.0f < game.time ()) { + updateHearing (); m_soundUpdateTime = game.time () + 0.25f; } @@ -1942,7 +2020,16 @@ void Bot::filterTasks () { } // if half of the round is over, allow hunting - if (getCurrentTaskId () != Task::EscapeFromBomb && game.isNullEntity (m_enemy) && !m_isVIP && bots.getRoundMidTime () < game.time () && !m_hasHostage && !m_isUsingGrenade && m_currentNodeIndex != graph.getNearest (m_lastEnemyOrigin) && m_personality != Personality::Careful && !cv_ignore_enemies.bool_ ()) { + if (getCurrentTaskId () != Task::EscapeFromBomb + && game.isNullEntity (m_enemy) + && !m_isVIP + && bots.getRoundMidTime () < game.time () + && !m_hasHostage + && !m_isUsingGrenade + && m_currentNodeIndex != graph.getNearest (m_lastEnemyOrigin) + && m_personality != Personality::Careful + && !cv_ignore_enemies.bool_ ()) { + float desireLevel = 4096.0f - ((1.0f - tempAgression) * m_lastEnemyOrigin.distance (pev->origin)); desireLevel = (100.0f * desireLevel) / 4096.0f; @@ -2231,7 +2318,10 @@ void Bot::checkRadioQueue () { case Chatter::CoverMe: // check if line of sight to object is not blocked (i.e. visible) if (seesEntity (m_radioEntity->v.origin) || m_radioOrder == Radio::StickTogetherTeam) { - if (game.isNullEntity (m_targetEntity) && game.isNullEntity (m_enemy) && rg.chance (m_personality == Personality::Careful ? 80 : 20)) { + if (game.isNullEntity (m_targetEntity) + && game.isNullEntity (m_enemy) + && rg.chance (m_personality == Personality::Careful ? 80 : 20)) { + int numFollowers = 0; // check if no more followers are allowed @@ -2334,7 +2424,10 @@ void Bot::checkRadioQueue () { case Radio::NeedBackup: case Chatter::ScaredEmotion: case Chatter::PinnedDown: - if (((game.isNullEntity (m_enemy) && seesEntity (m_radioEntity->v.origin)) || distanceSq < cr::sqrf (2048.0f) || !m_moveToC4) && rg.chance (50) && m_seeEnemyTime + 4.0f < game.time ()) { + if (((game.isNullEntity (m_enemy) && seesEntity (m_radioEntity->v.origin)) || distanceSq < cr::sqrf (2048.0f) || !m_moveToC4) + && rg.chance (50) + && m_seeEnemyTime + 4.0f < game.time ()) { + m_fearLevel -= 0.1f; if (m_fearLevel < 0.0f) { @@ -2589,7 +2682,11 @@ void Bot::checkRadioQueue () { } // check if it's a ct command - if (game.getTeam (m_radioEntity) == Team::CT && m_team == Team::CT && util.isFakeClient (m_radioEntity) && bots.getPlantedBombSearchTimestamp () < game.time ()) { + if (game.getTeam (m_radioEntity) == Team::CT + && m_team == Team::CT + && util.isFakeClient (m_radioEntity) + && bots.getPlantedBombSearchTimestamp () < game.time ()) { + float nearestDistanceSq = kInfiniteDistance; int bombPoint = kInvalidNodeIndex; @@ -2684,7 +2781,10 @@ void Bot::tryHeadTowardRadioMessage () { return; } - if ((util.isFakeClient (m_radioEntity) && rg.chance (25) && m_personality == Personality::Normal) || !(m_radioEntity->v.flags & FL_FAKECLIENT)) { + if ((util.isFakeClient (m_radioEntity) + && rg.chance (25) + && m_personality == Personality::Normal) || !(m_radioEntity->v.flags & FL_FAKECLIENT)) { + if (tid == Task::Pause || tid == Task::Camp) { getTask ()->time = game.time (); } @@ -2732,7 +2832,11 @@ void Bot::frame () { if (bots.isBombPlanted () && m_team == Team::CT && m_isAlive) { const Vector &bombPosition = graph.getBombOrigin (); - if (!m_hasProgressBar && getCurrentTaskId () != Task::EscapeFromBomb && pev->origin.distanceSq (bombPosition) < cr::sqrf (1540.0f) && !isBombDefusing (bombPosition)) { + if (!m_hasProgressBar + && getCurrentTaskId () != Task::EscapeFromBomb + && pev->origin.distanceSq (bombPosition) < cr::sqrf (1540.0f) + && !isBombDefusing (bombPosition)) { + m_itemIgnore = nullptr; m_itemCheckTime = game.time (); @@ -2815,7 +2919,11 @@ void Bot::update () { m_voteMap = 0; } } - else if (m_buyingFinished && !(pev->maxspeed < 10.0f && tid != Task::PlantBomb && tid != Task::DefuseBomb) && !cv_freeze_bots.bool_ () && !graph.hasChanged ()) { + else if (m_buyingFinished + && !(pev->maxspeed < 10.0f && tid != Task::PlantBomb && tid != Task::DefuseBomb) + && !cv_freeze_bots.bool_ () + && !graph.hasChanged ()) { + botMovement = true; } checkMsgQueue (); @@ -2886,7 +2994,11 @@ void Bot::checkSpawnConditions () { startTask (Task::Spraypaint, TaskPri::Spraypaint, kInvalidNodeIndex, game.time () + 1.0f, false); } - if (m_difficulty >= Difficulty::Normal && rg.chance (m_personality == Personality::Rusher ? 99 : 50) && !m_isReloading && game.mapIs (MapFlags::HostageRescue | MapFlags::Demolition | MapFlags::Escape | MapFlags::Assassination)) { + if (m_difficulty >= Difficulty::Normal + && rg.chance (m_personality == Personality::Rusher ? 99 : 50) + && !m_isReloading + && game.mapIs (MapFlags::HostageRescue | MapFlags::Demolition | MapFlags::Escape | MapFlags::Assassination)) { + if (isKnifeMode ()) { dropCurrentWeapon (); } @@ -2992,10 +3104,20 @@ void Bot::logic () { else if (!hasFriendNearby && rg.chance (45) && m_team == Team::Terrorist && util.isPlayerVIP (m_enemy)) { pushChatterMessage (Chatter::VIPSpotted); } - else if (!hasFriendNearby && rg.chance (50) && game.getTeam (m_enemy) != m_team && isGroupOfEnemies (m_enemy->v.origin, 2, 384.0f)) { + else if (!hasFriendNearby + && rg.chance (50) + && game.getTeam (m_enemy) != m_team + && isGroupOfEnemies (m_enemy->v.origin, 2, 384.0f)) { + pushChatterMessage (Chatter::ScaredEmotion); } - else if (!hasFriendNearby && rg.chance (40) && ((m_enemy->v.weapons & cr::bit (Weapon::AWP)) || (m_enemy->v.weapons & cr::bit (Weapon::Scout)) || (m_enemy->v.weapons & cr::bit (Weapon::G3SG1)) || (m_enemy->v.weapons & cr::bit (Weapon::SG550)))) { + else if (!hasFriendNearby + && rg.chance (40) + && ((m_enemy->v.weapons & cr::bit (Weapon::AWP)) + || (m_enemy->v.weapons & cr::bit (Weapon::Scout)) + || (m_enemy->v.weapons & cr::bit (Weapon::G3SG1)) + || (m_enemy->v.weapons & cr::bit (Weapon::SG550)))) { + pushChatterMessage (Chatter::SniperWarning); } @@ -3696,7 +3818,13 @@ void Bot::updateHearing () { // loop through all enemy clients to check for hearable stuff for (const auto &client : util.getClients ()) { - if (!(client.flags & ClientFlags::Used) || !(client.flags & ClientFlags::Alive) || client.ent == ent () || client.team == m_team || !client.ent || client.noise.last < game.time ()) { + if (!(client.flags & ClientFlags::Used) + || !(client.flags & ClientFlags::Alive) + || client.ent == ent () + || client.team == m_team + || !client.ent + || client.noise.last < game.time ()) { + continue; } @@ -3718,7 +3846,14 @@ void Bot::updateHearing () { // did the bot hear someone ? if (hearedEnemy != nullptr && util.isPlayer (hearedEnemy)) { // change to best weapon if heard something - if (m_shootTime < game.time () - 5.0f && isOnFloor () && m_currentWeapon != Weapon::C4 && m_currentWeapon != Weapon::Explosive && m_currentWeapon != Weapon::Smoke && m_currentWeapon != Weapon::Flashbang && !isKnifeMode ()) { + if (m_shootTime < game.time () - 5.0f + && isOnFloor () + && m_currentWeapon != Weapon::C4 + && m_currentWeapon != Weapon::Explosive + && m_currentWeapon != Weapon::Smoke + && m_currentWeapon != Weapon::Flashbang + && !isKnifeMode ()) { + selectBestWeapon (); } @@ -3770,7 +3905,13 @@ void Bot::updateHearing () { // check if heard enemy can be shoot through some obstacle else { - if (cv_shoots_thru_walls.bool_ () && m_difficulty >= Difficulty::Normal && m_lastEnemy == hearedEnemy && rg.chance (conf.getDifficultyTweaks (m_difficulty)->hearThruPct) && m_seeEnemyTime + 3.0f > game.time () && isPenetrableObstacle (hearedEnemy->v.origin)) { + if (cv_shoots_thru_walls.bool_ () + && m_difficulty >= Difficulty::Normal + && m_lastEnemy == hearedEnemy + && rg.chance (conf.getDifficultyTweaks (m_difficulty)->hearThruPct) + && m_seeEnemyTime + 3.0f > game.time () + && isPenetrableObstacle (hearedEnemy->v.origin)) { + m_enemy = hearedEnemy; m_lastEnemy = hearedEnemy; m_enemyOrigin = hearedEnemy->v.origin; @@ -3792,7 +3933,13 @@ void Bot::enteredBuyZone (int buyState) { const int *econLimit = conf.getEconLimit (); // if bot is in buy zone, try to buy ammo for this weapon... - if (m_seeEnemyTime + 12.0f < game.time () && m_lastEquipTime + 15.0f < game.time () && m_inBuyZone && (bots.getRoundStartTime () + rg.get (10.0f, 20.0f) + mp_buytime.float_ () < game.time ()) && !bots.isBombPlanted () && m_moneyAmount > econLimit[EcoLimit::PrimaryGreater]) { + if (m_seeEnemyTime + 12.0f < game.time () + && m_lastEquipTime + 15.0f < game.time () + && m_inBuyZone + && (bots.getRoundStartTime () + rg.get (10.0f, 20.0f) + mp_buytime.float_ () < game.time ()) + && !bots.isBombPlanted () + && m_moneyAmount > econLimit[EcoLimit::PrimaryGreater]) { + m_ignoreBuyDelay = true; m_buyingFinished = false; m_buyState = buyState; @@ -3871,7 +4018,19 @@ bool Bot::isBombDefusing (const Vector &bombOrigin) { } float Bot::getShiftSpeed () { - if (getCurrentTaskId () == Task::SeekCover || (m_aimFlags & AimFlags::Enemy) || isDucking () || (pev->button & IN_DUCK) || (m_oldButtons & IN_DUCK) || (m_currentTravelFlags & PathFlag::Jump) || (m_pathFlags & NodeFlag::Ladder) || isOnLadder () || isInWater () || isKnifeMode () || m_isStuck || m_numEnemiesLeft <= 0) { + if (getCurrentTaskId () == Task::SeekCover + || (m_aimFlags & AimFlags::Enemy) + || isDucking () + || (pev->button & IN_DUCK) + || (m_oldButtons & IN_DUCK) + || (m_currentTravelFlags & PathFlag::Jump) + || (m_pathFlags & NodeFlag::Ladder) + || isOnLadder () + || isInWater () + || isKnifeMode () + || m_isStuck + || m_numEnemiesLeft <= 0) { + return pev->maxspeed; } return pev->maxspeed * 0.4f; diff --git a/src/chatlib.cpp b/src/chatlib.cpp index 9bec73c..726f8ed 100644 --- a/src/chatlib.cpp +++ b/src/chatlib.cpp @@ -348,7 +348,11 @@ void Bot::checkForChat () { } // bot chatting turned on? - if (rg.chance (cv_chat_percent.int_ ()) && m_lastChatTime + rg.get (6.0f, 10.0f) < game.time () && bots.getLastChatTimestamp () + rg.get (2.5f, 5.0f) < game.time () && !isReplyingToChat ()) { + if (rg.chance (cv_chat_percent.int_ ()) + && m_lastChatTime + rg.get (6.0f, 10.0f) < game.time () + && bots.getLastChatTimestamp () + rg.get (2.5f, 5.0f) < game.time () + && !isReplyingToChat ()) { + if (conf.hasChatBank (Chat::Dead)) { StringRef phrase = conf.pickRandomFromChatBank (Chat::Dead); bool sayBufferExists = false; diff --git a/src/combat.cpp b/src/combat.cpp index fa6783c..8f0c6da 100644 --- a/src/combat.cpp +++ b/src/combat.cpp @@ -269,7 +269,11 @@ bool Bot::lookupEnemies () { player = m_enemy; // is player is alive - if (m_enemyUpdateTime > game.time () && m_enemy->v.origin.distanceSq (pev->origin) < nearestDistanceSq && util.isAlive (player) && seesEnemy (player)) { + if (m_enemyUpdateTime > game.time () + && m_enemy->v.origin.distanceSq (pev->origin) < nearestDistanceSq + && util.isAlive (player) + && seesEnemy (player)) { + newEnemy = player; } } @@ -309,7 +313,11 @@ bool Bot::lookupEnemies () { // search the world for players... for (const auto &client : util.getClients ()) { - if (!(client.flags & ClientFlags::Used) || !(client.flags & ClientFlags::Alive) || client.team == m_team || client.ent == ent () || !client.ent) { + if (!(client.flags & ClientFlags::Used) + || !(client.flags & ClientFlags::Alive) + || client.team == m_team + || client.ent == ent () + || !client.ent) { continue; } player = client.ent; @@ -400,7 +408,11 @@ bool Bot::lookupEnemies () { continue; } - if (other->m_seeEnemyTime + 2.0f < game.time () && game.isNullEntity (other->m_lastEnemy) && util.isVisible (pev->origin, other->ent ()) && other->isInViewCone (pev->origin)) { + if (other->m_seeEnemyTime + 2.0f < game.time () + && game.isNullEntity (other->m_lastEnemy) + && util.isVisible (pev->origin, other->ent ()) + && other->isInViewCone (pev->origin)) { + other->m_lastEnemy = newEnemy; other->m_lastEnemyOrigin = newEnemy->v.origin; other->m_seeEnemyTime = game.time (); @@ -643,7 +655,8 @@ bool Bot::isFriendInLineOfFire (float distance) { } const auto friendDistanceSq = client.ent->v.origin.distanceSq (pev->origin); - if (friendDistanceSq <= distanceSq && util.getShootingCone (ent (), client.ent->v.origin) > friendDistanceSq / (friendDistanceSq + cr::sqrf (33.0f))) { + if (friendDistanceSq <= distanceSq + && util.getShootingCone (ent (), client.ent->v.origin) > friendDistanceSq / (friendDistanceSq + cr::sqrf (33.0f))) { return true; } } @@ -905,7 +918,10 @@ void Bot::selectWeapons (float distance, int index, int id, int choosen) { } // we're should stand still before firing sniper weapons, else sniping is useless.. - if (usesSniper () && (m_aimFlags & (AimFlags::Enemy | AimFlags::LastEnemy)) && !m_isReloading && pev->velocity.lengthSq () > 0.0f && getCurrentTaskId () != Task::SeekCover) { + if (usesSniper () && (m_aimFlags & (AimFlags::Enemy | AimFlags::LastEnemy)) + && !m_isReloading && pev->velocity.lengthSq () > 0.0f + && getCurrentTaskId () != Task::SeekCover) { + m_moveSpeed = 0.0f; m_strafeSpeed = 0.0f; m_navTimeset = game.time (); @@ -1007,7 +1023,14 @@ void Bot::fireWeapons () { } // use knife if near and good difficulty (l33t dude!) - if (cv_stab_close_enemies.bool_ () && m_difficulty >= Difficulty::Normal && m_healthValue > 80.0f && !game.isNullEntity (m_enemy) && m_healthValue >= m_enemy->v.health && distance < 100.0f && !isOnLadder () && !isGroupOfEnemies (pev->origin)) { + if (cv_stab_close_enemies.bool_ () && m_difficulty >= Difficulty::Normal + && m_healthValue > 80.0f + && !game.isNullEntity (m_enemy) + && m_healthValue >= m_enemy->v.health + && distance < 100.0f + && !isOnLadder () + && !isGroupOfEnemies (pev->origin)) { + selectWeapons (distance, selectIndex, selectId, choosenWeapon); return; } @@ -1327,7 +1350,12 @@ void Bot::attackMovement () { m_moveSpeed = 0.0f; } - if (m_difficulty >= Difficulty::Normal && (m_jumpTime + 5.0f < game.time () && isOnFloor () && rg.get (0, 1000) < (m_isReloading ? 8 : 2) && pev->velocity.length2d () > 150.0f) && !usesSniper ()) { + if (m_difficulty >= Difficulty::Normal + && (m_jumpTime + 5.0f < game.time () + && isOnFloor () + && rg.get (0, 1000) < (m_isReloading ? 8 : 2) + && pev->velocity.length2d () > 150.0f) && !usesSniper ()) { + pev->button |= IN_JUMP; } } @@ -1337,10 +1365,15 @@ void Bot::attackMovement () { if (alreadyDucking) { m_duckTime = game.time () + m_frameInterval * 2.0f; } - else if ((distance > 768.0f && hasPrimaryWeapon ()) && (m_enemyParts & (Visibility::Head | Visibility::Body)) && getCurrentTaskId () != Task::SeekCover && getCurrentTaskId () != Task::Hunt) { + else if ((distance > 768.0f && hasPrimaryWeapon ()) + && (m_enemyParts & (Visibility::Head | Visibility::Body)) + && getCurrentTaskId () != Task::SeekCover + && getCurrentTaskId () != Task::Hunt) { + const int enemyNearestIndex = graph.getNearest (m_enemy->v.origin); - if (vistab.visible (m_currentNodeIndex, enemyNearestIndex, VisIndex::Crouch) && vistab.visible (enemyNearestIndex, m_currentNodeIndex, VisIndex::Crouch)) { + if (vistab.visible (m_currentNodeIndex, enemyNearestIndex, VisIndex::Crouch) + && vistab.visible (enemyNearestIndex, m_currentNodeIndex, VisIndex::Crouch)) { m_duckTime = game.time () + m_frameInterval * 2.0f; } } @@ -1715,7 +1748,12 @@ void Bot::checkReload () { const auto tid = getCurrentTaskId (); // we're should not reload, while doing next tasks - const bool uninterruptibleTask = (tid == Task::PlantBomb || tid == Task::DefuseBomb || tid == Task::PickupItem || tid == Task::ThrowExplosive || tid == Task::ThrowFlashbang || tid == Task::ThrowSmoke); + const bool uninterruptibleTask = (tid == Task::PlantBomb + || tid == Task::DefuseBomb + || tid == Task::PickupItem + || tid == Task::ThrowExplosive + || tid == Task::ThrowFlashbang + || tid == Task::ThrowSmoke); // do not check for reload if (uninterruptibleTask || m_isUsingGrenade || usesKnife ()) { diff --git a/src/control.cpp b/src/control.cpp index a8590ba..5aa948a 100644 --- a/src/control.cpp +++ b/src/control.cpp @@ -1280,7 +1280,10 @@ int BotControl::menuCommands (int item) { switch (item) { case 1: case 2: - if (util.findNearestPlayer (reinterpret_cast (&m_djump), m_ent, 600.0f, true, true, true, true, false) && !m_djump->m_hasC4 && !m_djump->m_hasHostage) { + if (util.findNearestPlayer (reinterpret_cast (&m_djump), m_ent, 600.0f, true, true, true, true, false) + && !m_djump->m_hasC4 + && !m_djump->m_hasHostage) { + if (item == 1) { m_djump->startDoubleJump (m_ent); } diff --git a/src/graph.cpp b/src/graph.cpp index 7dbd4b6..7a9acc0 100644 --- a/src/graph.cpp +++ b/src/graph.cpp @@ -168,7 +168,9 @@ int BotGraph::clearConnections (int index) { if (cur.angles - prev2.angles < 80.0f) { // leave alone ladder connections and don't remove jump connections.. - if (((path.flags & NodeFlag::Ladder) && (m_paths[prev.index].flags & NodeFlag::Ladder)) || (path.links[prev.number].flags & PathFlag::Jump)) { + if (((path.flags & NodeFlag::Ladder) + && (m_paths[prev.index].flags & NodeFlag::Ladder)) || (path.links[prev.number].flags & PathFlag::Jump)) { + return false; } @@ -213,7 +215,11 @@ int BotGraph::clearConnections (int index) { // check pass 1 if (exists (top.index) && exists (sorted[0].index) && exists (sorted[1].index)) { - if ((sorted[1].angles - top.angles < 80.0f || 360.0f - (sorted[1].angles - top.angles) < 80.0f) && (!(m_paths[sorted[0].index].flags & NodeFlag::Ladder) || !(path.flags & NodeFlag::Ladder)) && !(path.links[sorted[0].number].flags & PathFlag::Jump)) { + + if ((sorted[1].angles - top.angles < 80.0f || 360.0f - (sorted[1].angles - top.angles) < 80.0f) + && (!(m_paths[sorted[0].index].flags & NodeFlag::Ladder) || !(path.flags & NodeFlag::Ladder)) + && !(path.links[sorted[0].number].flags & PathFlag::Jump)) { + if ((sorted[1].distance + top.distance) * 1.1f / 2.0f < sorted[0].distance) { if (path.links[sorted[0].number].index == sorted[0].index) { msg ("Removing a useless (P.1.1) connection from index = %d to %d.", index, sorted[0].index); @@ -259,7 +265,9 @@ int BotGraph::clearConnections (int index) { if (prev.distance < cur.distance * 1.1f) { // leave alone ladder connections and don't remove jump connections.. - if (((path.flags & NodeFlag::Ladder) && (m_paths[cur.index].flags & NodeFlag::Ladder)) || (path.links[cur.number].flags & PathFlag::Jump)) { + if (((path.flags & NodeFlag::Ladder) + && (m_paths[cur.index].flags & NodeFlag::Ladder)) || (path.links[cur.number].flags & PathFlag::Jump)) { + return false; } @@ -291,7 +299,10 @@ int BotGraph::clearConnections (int index) { } else if (cur.distance < prev.distance * 1.1f) { // leave alone ladder connections and don't remove jump connections.. - if (((path.flags & NodeFlag::Ladder) && (m_paths[prev.index].flags & NodeFlag::Ladder)) || (path.links[prev.number].flags & PathFlag::Jump)) { + if (((path.flags & NodeFlag::Ladder) + && (m_paths[prev.index].flags & NodeFlag::Ladder)) + || (path.links[prev.number].flags & PathFlag::Jump)) { + return false; } @@ -336,7 +347,11 @@ int BotGraph::clearConnections (int index) { // check pass 3 if (exists (top.index) && exists (sorted[0].index)) { - if ((top.angles - sorted[0].angles < 40.0f || (360.0f - top.angles - sorted[0].angles) < 40.0f) && (!(m_paths[sorted[0].index].flags & NodeFlag::Ladder) || !(path.flags & NodeFlag::Ladder)) && !(path.links[sorted[0].number].flags & PathFlag::Jump)) { + + if ((top.angles - sorted[0].angles < 40.0f || (360.0f - top.angles - sorted[0].angles) < 40.0f) + && (!(m_paths[sorted[0].index].flags & NodeFlag::Ladder) || !(path.flags & NodeFlag::Ladder)) + && !(path.links[sorted[0].number].flags & PathFlag::Jump)) { + if (top.distance * 1.1f < sorted[0].distance) { if (path.links[sorted[0].number].index == sorted[0].index) { msg ("Removing a useless (P.3.1) connection from index = %d to %d.", index, sorted[0].index); @@ -816,7 +831,11 @@ void BotGraph::add (int type, const Vector &pos) { // check if the node is reachable from the new one game.testLine (newOrigin, calc.origin, TraceIgnore::Monsters, m_editor, &tr); - if (cr::fequal (tr.flFraction, 1.0f) && cr::abs (newOrigin.x - calc.origin.x) < 64.0f && cr::abs (newOrigin.y - calc.origin.y) < 64.0f && cr::abs (newOrigin.z - calc.origin.z) < m_autoPathDistance) { + if (cr::fequal (tr.flFraction, 1.0f) + && cr::abs (newOrigin.x - calc.origin.x) < 64.0f + && cr::abs (newOrigin.y - calc.origin.y) < 64.0f + && cr::abs (newOrigin.z - calc.origin.z) < m_autoPathDistance) { + const float distance = newOrigin.distance2d (calc.origin); addPath (index, calc.number, distance); @@ -2073,7 +2092,10 @@ void BotGraph::frame () { const float distanceSq = path.origin.distanceSq (m_editor->v.origin); // check if node is within a distance, and is visible - if (distanceSq < cr::sqrf (cv_graph_draw_distance.float_ ()) && ((util.isVisible (path.origin, m_editor) && util.isInViewCone (path.origin, m_editor)) || !util.isAlive (m_editor) || distanceSq < cr::sqrf (64.0f))) { + if (distanceSq < cr::sqrf (cv_graph_draw_distance.float_ ()) + && ((util.isVisible (path.origin, m_editor) + && util.isInViewCone (path.origin, m_editor)) || !util.isAlive (m_editor) || distanceSq < cr::sqrf (64.0f))) { + // check the distance if (distanceSq < nearestDistanceSq) { nearestIndex = path.number; @@ -2188,7 +2210,9 @@ void BotGraph::frame () { } // draw a paths, camplines and danger directions for nearest node - if (nearestDistanceSq < cr::clamp (m_paths[nearestIndex].radius, cr::sqrf (56.0f), cr::sqrf (90.0f)) && m_pathDisplayTime < game.time ()) { + if (nearestDistanceSq < cr::clamp (m_paths[nearestIndex].radius, cr::sqrf (56.0f), cr::sqrf (90.0f)) + && m_pathDisplayTime < game.time ()) { + m_pathDisplayTime = game.time () + 0.96f; // create path pointer for faster access diff --git a/src/manager.cpp b/src/manager.cpp index 8cb90b7..281c699 100644 --- a/src/manager.cpp +++ b/src/manager.cpp @@ -608,7 +608,8 @@ void BotManager::serverFill (int selection, int personality, int difficulty, int // this function fill server with bots, with specified team & personality // always keep one slot - const int maxClients = cv_autovacate.bool_ () ? game.maxClients () - cv_autovacate_keep_slots.int_ () - (game.isDedicated () ? 0 : getHumansCount ()) : game.maxClients (); + const int maxClients = cv_autovacate.bool_ () + ? game.maxClients () - cv_autovacate_keep_slots.int_ () - (game.isDedicated () ? 0 : getHumansCount ()) : game.maxClients (); if (getBotCount () >= maxClients - getHumansCount ()) { return; @@ -1320,7 +1321,12 @@ void BotManager::handleDeath (edict_t *killer, edict_t *victim) { if (cv_radio_mode.int_ () == 2) { // need to send congrats on well placed shot for (const auto ¬ify : bots) { - if (notify->m_isAlive && killerTeam == notify->m_team && killerTeam != victimTeam && killer != notify->ent () && notify->seesEntity (victim->v.origin)) { + if (notify->m_isAlive + && killerTeam == notify->m_team + && killerTeam != victimTeam + && killer != notify->ent () + && notify->seesEntity (victim->v.origin)) { + if (!(killer->v.flags & FL_FAKECLIENT)) { notify->pushChatterMessage (Chatter::NiceShotCommander); } @@ -1870,7 +1876,12 @@ void BotManager::notifyBombDefuse () { for (const auto &bot : bots) { const auto task = bot->getCurrentTaskId (); - if (!bot->m_defuseNotified && bot->m_isAlive && task != Task::MoveToPosition && task != Task::DefuseBomb && task != Task::EscapeFromBomb) { + if (!bot->m_defuseNotified + && bot->m_isAlive + && task != Task::MoveToPosition + && task != Task::DefuseBomb + && task != Task::EscapeFromBomb) { + if (bot->m_team == Team::Terrorist && bot->pev->origin.distanceSq (bombPos) < cr::sqrf (384.0f)) { bot->clearSearchNodes (); diff --git a/src/navigate.cpp b/src/navigate.cpp index 03bc3be..0daa8b0 100644 --- a/src/navigate.cpp +++ b/src/navigate.cpp @@ -950,7 +950,12 @@ bool Bot::updateNavigation () { // special detection if someone is using the ladder (to prevent to have bots-towers on ladders) for (const auto &client : util.getClients ()) { - if (!(client.flags & ClientFlags::Used) || !(client.flags & ClientFlags::Alive) || (client.ent->v.movetype != MOVETYPE_FLY) || client.team != m_team || client.ent == ent ()) { + if (!(client.flags & ClientFlags::Used) + || !(client.flags & ClientFlags::Alive) + || (client.ent->v.movetype != MOVETYPE_FLY) + || client.team != m_team + || client.ent == ent ()) { + continue; } TraceResult tr {}; @@ -962,7 +967,10 @@ bool Bot::updateNavigation () { game.testHull (getEyesPos (), m_pathOrigin, TraceIgnore::Monsters, isDucking () ? head_hull : human_hull, ent (), &tr); // someone is above or below us and is using the ladder already - if (tr.pHit == client.ent && cr::abs (pev->origin.z - client.ent->v.origin.z) > 15.0f && (client.ent->v.movetype == MOVETYPE_FLY)) { + if (tr.pHit == client.ent + && cr::abs (pev->origin.z - client.ent->v.origin.z) > 15.0f + && (client.ent->v.movetype == MOVETYPE_FLY)) { + const auto numPreviousNode = rg.get (0, 2); for (int i = 0; i < numPreviousNode; ++i) { @@ -1093,7 +1101,10 @@ bool Bot::updateNavigation () { } // needs precise placement - check if we get past the point - if (desiredDistanceSq < cr::sqrf (22.0f) && nodeDistanceSq < cr::sqrf (30.0f) && m_pathOrigin.distanceSq (pev->origin + pev->velocity * m_frameInterval) >= nodeDistanceSq) { + if (desiredDistanceSq < cr::sqrf (22.0f) + && nodeDistanceSq < cr::sqrf (30.0f) + && m_pathOrigin.distanceSq (pev->origin + pev->velocity * m_frameInterval) >= nodeDistanceSq) { + desiredDistanceSq = nodeDistanceSq + 1.0f; } @@ -1131,7 +1142,12 @@ bool Bot::updateNavigation () { } int taskTarget = getTask ()->data; - if (game.mapIs (MapFlags::Demolition) && bots.isBombPlanted () && m_team == Team::CT && getCurrentTaskId () != Task::EscapeFromBomb && taskTarget != kInvalidNodeIndex) { + if (game.mapIs (MapFlags::Demolition) + && bots.isBombPlanted () + && m_team == Team::CT + && getCurrentTaskId () != Task::EscapeFromBomb + && taskTarget != kInvalidNodeIndex) { + const Vector &bombOrigin = isBombAudible (); // bot within 'hearable' bomb tick noises? @@ -1181,7 +1197,11 @@ bool Bot::updateLiftHandling () { // trace line to door game.testLine (pev->origin, m_pathOrigin, TraceIgnore::Everything, ent (), &tr); - if (tr.flFraction < 1.0f && util.isDoorEntity (tr.pHit) && (m_liftState == LiftState::None || m_liftState == LiftState::WaitingFor || m_liftState == LiftState::LookingButtonOutside) && pev->groundentity != tr.pHit) { + if (tr.flFraction < 1.0f + && util.isDoorEntity (tr.pHit) + && (m_liftState == LiftState::None || m_liftState == LiftState::WaitingFor || m_liftState == LiftState::LookingButtonOutside) + && pev->groundentity != tr.pHit) { + if (m_liftState == LiftState::None) { m_liftState = LiftState::LookingButtonOutside; m_liftUsageTime = game.time () + 7.0f; @@ -1199,7 +1219,10 @@ bool Bot::updateLiftHandling () { // if trace result shows us that it is a lift if (!game.isNullEntity (tr.pHit) && !m_pathWalk.empty () && isFunc (tr.pHit->v.classname.str ()) && !liftClosedDoorExists) { - if ((m_liftState == LiftState::None || m_liftState == LiftState::WaitingFor || m_liftState == LiftState::LookingButtonOutside) && cr::fzero (tr.pHit->v.velocity.z)) { + if ((m_liftState == LiftState::None + || m_liftState == LiftState::WaitingFor + || m_liftState == LiftState::LookingButtonOutside) && cr::fzero (tr.pHit->v.velocity.z)) { + if (cr::abs (pev->origin.z - tr.vecEndPos.z) < 70.0f) { m_liftEntity = tr.pHit; m_liftState = LiftState::EnteringIn; @@ -1274,7 +1297,12 @@ bool Bot::updateLiftHandling () { bool needWaitForTeammate = false; for (const auto &bot : bots) { - if (!bot->m_isAlive || bot->m_team != m_team || bot->m_targetEntity != ent () || bot->getCurrentTaskId () != Task::FollowUser || bot->m_liftEntity != m_liftEntity) { + if (!bot->m_isAlive + || bot->m_team != m_team + || bot->m_targetEntity != ent () + || bot->getCurrentTaskId () != Task::FollowUser + || bot->m_liftEntity != m_liftEntity) { + continue; } @@ -1305,7 +1333,12 @@ bool Bot::updateLiftHandling () { auto button = lookupButton (m_liftEntity->v.targetname.str ()); // got a valid button entity ? - if (!game.isNullEntity (button) && pev->groundentity == m_liftEntity && m_buttonPushTime + 1.0f < game.time () && cr::fzero (m_liftEntity->v.velocity.z) && isOnFloor ()) { + if (!game.isNullEntity (button) + && pev->groundentity == m_liftEntity + && m_buttonPushTime + 1.0f < game.time () + && cr::fzero (m_liftEntity->v.velocity.z) + && isOnFloor ()) { + m_pickupItem = button; m_pickupType = Pickup::Button; @@ -1314,8 +1347,16 @@ bool Bot::updateLiftHandling () { } // is lift activated and bot is standing on it and lift is moving ? - if (m_liftState == LiftState::LookingButtonInside || m_liftState == LiftState::EnteringIn || m_liftState == LiftState::WaitingForTeammates || m_liftState == LiftState::WaitingFor) { - if (pev->groundentity == m_liftEntity && !cr::fzero (m_liftEntity->v.velocity.z) && isOnFloor () && ((graph[m_previousNodes[0]].flags & NodeFlag::Lift) || !game.isNullEntity (m_targetEntity))) { + if (m_liftState == LiftState::LookingButtonInside + || m_liftState == LiftState::EnteringIn + || m_liftState == LiftState::WaitingForTeammates + || m_liftState == LiftState::WaitingFor) { + + if (pev->groundentity == m_liftEntity + && !cr::fzero (m_liftEntity->v.velocity.z) + && isOnFloor () + && ((graph[m_previousNodes[0]].flags & NodeFlag::Lift) || !game.isNullEntity (m_targetEntity))) { + m_liftState = LiftState::TravelingBy; m_liftUsageTime = game.time () + 14.0f; @@ -1419,7 +1460,10 @@ bool Bot::updateLiftHandling () { if (m_liftState == LiftState::WaitingFor || m_liftState == LiftState::EnteringIn) { // bot fall down somewhere inside the lift's groove :) if (pev->groundentity != m_liftEntity && graph.exists (m_previousNodes[0])) { - if ((graph[m_previousNodes[0]].flags & NodeFlag::Lift) && (m_path->origin.z - pev->origin.z) > 50.0f && (graph[m_previousNodes[0]].origin.z - pev->origin.z) > 50.0f) { + if ((graph[m_previousNodes[0]].flags & NodeFlag::Lift) + && (m_path->origin.z - pev->origin.z) > 50.0f + && (graph[m_previousNodes[0]].origin.z - pev->origin.z) > 50.0f) { + m_liftState = LiftState::None; m_liftEntity = nullptr; m_liftUsageTime = 0.0f; @@ -1627,7 +1671,10 @@ float Bot::getEstimatedNodeReachTime () { // caclulate estimated time estimatedTime = 5.0f * (distanceSq / cr::sqrf (m_moveSpeed + 1.0f)); - const bool longTermReachability = (m_pathFlags & NodeFlag::Crouch) || (m_pathFlags & NodeFlag::Ladder) || (pev->button & IN_DUCK) || (m_oldButtons & IN_DUCK); + const bool longTermReachability = (m_pathFlags & NodeFlag::Crouch) + || (m_pathFlags & NodeFlag::Ladder) + || (pev->button & IN_DUCK) + || (m_oldButtons & IN_DUCK); // check for special nodes, that can slowdown our movement if (longTermReachability) { @@ -1923,7 +1970,10 @@ int Bot::findDefendNode (const Vector &origin) { IntArray found; for (const auto &path : graph) { - if (origin.distanceSq (path.origin) < cr::sqrf (kMaxDistance) && vistab.visible (path.number, posIndex) && !isOccupiedNode (path.number)) { + if (origin.distanceSq (path.origin) < cr::sqrf (kMaxDistance) + && vistab.visible (path.number, posIndex) + && !isOccupiedNode (path.number)) { + found.push (path.number); } } @@ -2170,7 +2220,15 @@ bool Bot::advanceMovement () { const auto tid = getCurrentTaskId (); // only if we in normal task and bomb is not planted - if (tid == Task::Normal && bots.getRoundMidTime () + 5.0f < game.time () && m_timeCamping + 5.0f < game.time () && !bots.isBombPlanted () && m_personality != Personality::Rusher && !m_hasC4 && !m_isVIP && m_loosedBombNodeIndex == kInvalidNodeIndex && !m_hasHostage && !m_isCreature) { + if (tid == Task::Normal + && bots.getRoundMidTime () + 5.0f < game.time () + && m_timeCamping + 5.0f < game.time () + && !bots.isBombPlanted () + && m_personality != Personality::Rusher + && !m_hasC4 && !m_isVIP + && m_loosedBombNodeIndex == kInvalidNodeIndex + && !m_hasHostage && !m_isCreature) { + m_campButtons = 0; const int nextIndex = m_pathWalk.next (); @@ -2280,7 +2338,12 @@ bool Bot::advanceMovement () { } // is there a jump node right ahead and do we need to draw out the light weapon ? - if (willJump && !usesKnife () && m_currentWeapon != Weapon::Scout && !m_isReloading && !usesPistol () && (jumpDistanceSq > cr::sqrf (145.0f) || (dst.z - 32.0f > src.z && jumpDistanceSq > cr::sqrf (125.0f))) && !(m_states & Sense::SeeingEnemy)) { + if (willJump && !usesKnife () + && m_currentWeapon != Weapon::Scout + && !m_isReloading && !usesPistol () + && (jumpDistanceSq > cr::sqrf (145.0f) || (dst.z - 32.0f > src.z && jumpDistanceSq > cr::sqrf (125.0f))) + && !(m_states & Sense::SeeingEnemy)) { + selectWeaponById (Weapon::Knife); // draw out the knife if we needed } diff --git a/src/storage.cpp b/src/storage.cpp index c41e73b..de0b422 100644 --- a/src/storage.cpp +++ b/src/storage.cpp @@ -169,7 +169,9 @@ template bool BotStorage::load (SmallArray &data, ExtenHeader * if (extenSize <= actuallyRead) { // write modified by, only if the name is different - if (!strings.isEmpty (extenHeader.author) && strncmp (extenHeader.author, exten->modified, cr::bufsize (extenHeader.author)) != 0) { + if (!strings.isEmpty (extenHeader.author) + && strncmp (extenHeader.author, exten->modified, cr::bufsize (extenHeader.author)) != 0) { + strings.copy (extenHeader.modified, exten->modified, cr::bufsize (exten->modified)); } } diff --git a/src/tasks.cpp b/src/tasks.cpp index 3e781c4..fbee557 100644 --- a/src/tasks.cpp +++ b/src/tasks.cpp @@ -45,7 +45,13 @@ void Bot::normal_ () { } // if bomb planted and it's a CT calculate new path to bomb point if he's not already heading for - if (!m_bombSearchOverridden && bots.isBombPlanted () && m_team == Team::CT && getTask ()->data != kInvalidNodeIndex && !(graph[getTask ()->data].flags & NodeFlag::Goal) && getCurrentTaskId () != Task::EscapeFromBomb) { + if (!m_bombSearchOverridden + && bots.isBombPlanted () + && m_team == Team::CT + && getTask ()->data != kInvalidNodeIndex + && !(graph[getTask ()->data].flags & NodeFlag::Goal) + && getCurrentTaskId () != Task::EscapeFromBomb) { + clearSearchNodes (); getTask ()->data = kInvalidNodeIndex; } @@ -53,7 +59,12 @@ void Bot::normal_ () { // reached the destination (goal) node? if (updateNavigation ()) { // if we're reached the goal, and there is not enemies, notify the team - if (!bots.isBombPlanted () && m_currentNodeIndex != kInvalidNodeIndex && (m_pathFlags & NodeFlag::Goal) && rg.chance (15) && numEnemiesNear (pev->origin, 650.0f) == 0) { + if (!bots.isBombPlanted () + && m_currentNodeIndex != kInvalidNodeIndex + && (m_pathFlags & NodeFlag::Goal) + && rg.chance (15) + && numEnemiesNear (pev->origin, 650.0f) == 0) { + pushRadioMessage (Radio::SectorClear); } @@ -61,7 +72,14 @@ void Bot::normal_ () { m_prevGoalIndex = kInvalidNodeIndex; // spray logo sometimes if allowed to do so - if (!(m_states & (Sense::SeeingEnemy | Sense::SuspectEnemy)) && m_seeEnemyTime + 5.0f < game.time () && !m_reloadState && m_timeLogoSpray < game.time () && cv_spraypaints.bool_ () && rg.chance (50) && m_moveSpeed > getShiftSpeed () && game.isNullEntity (m_pickupItem)) { + if (!(m_states & (Sense::SeeingEnemy | Sense::SuspectEnemy)) + && m_seeEnemyTime + 5.0f < game.time () + && !m_reloadState && m_timeLogoSpray < game.time () + && cv_spraypaints.bool_ () + && rg.chance (50) + && m_moveSpeed > getShiftSpeed () + && game.isNullEntity (m_pickupItem)) { + if (!(game.mapIs (MapFlags::Demolition) && bots.isBombPlanted () && m_team == Team::CT)) { startTask (Task::Spraypaint, TaskPri::Spraypaint, kInvalidNodeIndex, game.time () + 1.0f, false); } @@ -69,7 +87,9 @@ void Bot::normal_ () { // reached node is a camp node if ((m_pathFlags & NodeFlag::Camp) && !game.is (GameFlags::CSDM) && cv_camping_allowed.bool_ () && !isKnifeMode ()) { - const bool allowedCampWeapon = hasPrimaryWeapon () || hasShield () || (hasSecondaryWeapon () && !hasPrimaryWeapon () && m_numFriendsLeft > game.maxClients () / 6); + const bool allowedCampWeapon = hasPrimaryWeapon () + || hasShield () + || (hasSecondaryWeapon () && !hasPrimaryWeapon () && m_numFriendsLeft > game.maxClients () / 6); // check if bot has got a primary weapon and hasn't camped before if (allowedCampWeapon && m_timeCamping + 10.0f < game.time () && !m_hasHostage) { @@ -88,7 +108,8 @@ void Bot::normal_ () { } // don't allow vip on as_ maps to camp + don't allow terrorist carrying c4 to camp - if (campingAllowed && (m_isVIP || (game.mapIs (MapFlags::Demolition) && m_team == Team::Terrorist && !bots.isBombPlanted () && m_hasC4))) { + if (campingAllowed + && (m_isVIP || (game.mapIs (MapFlags::Demolition)&& m_team == Team::Terrorist && !bots.isBombPlanted () && m_hasC4))) { campingAllowed = false; } @@ -228,12 +249,24 @@ void Bot::normal_ () { } const float shiftSpeed = getShiftSpeed (); - if ((!cr::fzero (m_moveSpeed) && m_moveSpeed > shiftSpeed) && (cv_walking_allowed.bool_ () && mp_footsteps.bool_ ()) && m_difficulty >= Difficulty::Normal && (m_heardSoundTime + 6.0f >= game.time () || (m_states & Sense::HearingEnemy)) && pev->origin.distanceSq (m_lastEnemyOrigin) < cr::sqrf (768.0f) && !isKnifeMode () && !bots.isBombPlanted ()) { + if ((!cr::fzero (m_moveSpeed) && m_moveSpeed > shiftSpeed) && (cv_walking_allowed.bool_ () && mp_footsteps.bool_ ()) + && m_difficulty >= Difficulty::Normal + && (m_heardSoundTime + 6.0f >= game.time () || (m_states & Sense::HearingEnemy)) + && pev->origin.distanceSq (m_lastEnemyOrigin) < cr::sqrf (768.0f) + && !isKnifeMode () + && !bots.isBombPlanted ()) { + m_moveSpeed = shiftSpeed; } // bot hasn't seen anything in a long time and is asking his teammates to report in - if (cv_radio_mode.int_ () > 1 && bots.getLastRadio (m_team) != Radio::ReportInTeam && bots.getRoundStartTime () + 20.0f < game.time () && m_askCheckTime < game.time () && rg.chance (15) && m_seeEnemyTime + rg.get (45.0f, 80.0f) < game.time () && numFriendsNear (pev->origin, 1024.0f) == 0) { + if (cv_radio_mode.int_ () > 1 + && bots.getLastRadio (m_team) != Radio::ReportInTeam + && bots.getRoundStartTime () + 20.0f < game.time () + && m_askCheckTime < game.time () && rg.chance (15) + && m_seeEnemyTime + rg.get (45.0f, 80.0f) < game.time () + && numFriendsNear (pev->origin, 1024.0f) == 0) { + pushRadioMessage (Radio::ReportInTeam); m_askCheckTime = game.time () + rg.get (45.0f, 80.0f); @@ -884,7 +917,10 @@ void Bot::defuseBomb_ () { // bot is reloading and we close enough to start defusing if (m_isReloading && bombPos.distanceSq2d (pev->origin) < cr::sqrf (80.0f)) { - if (m_numEnemiesLeft == 0 || timeToBlowUp < fullDefuseTime + 7.0f || ((getAmmoInClip () > 8 && m_reloadState == Reload::Primary) || (getAmmoInClip () > 5 && m_reloadState == Reload::Secondary))) { + if (m_numEnemiesLeft == 0 + || timeToBlowUp < fullDefuseTime + 7.0f + || ((getAmmoInClip () > 8 && m_reloadState == Reload::Primary)|| (getAmmoInClip () > 5 && m_reloadState == Reload::Secondary))) { + const int weaponIndex = bestWeaponCarried (); // just select knife and then select weapon @@ -1251,7 +1287,9 @@ void Bot::throwSmoke_ () { } void Bot::doublejump_ () { - if (!util.isAlive (m_doubleJumpEntity) || (m_aimFlags & AimFlags::Enemy) || (m_travelStartIndex != kInvalidNodeIndex && getTask ()->time + (graph.calculateTravelTime (pev->maxspeed, graph[m_travelStartIndex].origin, m_doubleJumpOrigin) + 11.0f) < game.time ())) { + if (!util.isAlive (m_doubleJumpEntity) + || (m_aimFlags & AimFlags::Enemy) + || (m_travelStartIndex != kInvalidNodeIndex && getTask ()->time + (graph.calculateTravelTime (pev->maxspeed, graph[m_travelStartIndex].origin, m_doubleJumpOrigin) + 11.0f) < game.time ())) { resetDoubleJump (); return; } diff --git a/src/vision.cpp b/src/vision.cpp index bb2bc7d..77a8e26 100644 --- a/src/vision.cpp +++ b/src/vision.cpp @@ -177,7 +177,14 @@ void Bot::setAimDirection () { else if (flags & AimFlags::Nav) { m_lookAt = m_destOrigin; - if (m_moveToGoal && m_seeEnemyTime + 4.0f < game.time () && !m_isStuck && m_moveSpeed > getShiftSpeed () && !(pev->button & IN_DUCK) && m_currentNodeIndex != kInvalidNodeIndex && !(m_pathFlags & (NodeFlag::Ladder | NodeFlag::Crouch)) && m_pathWalk.hasNext () && pev->origin.distanceSq (m_destOrigin) < cr::sqrf (512.0f)) { + if (m_moveToGoal && m_seeEnemyTime + 4.0f < game.time () + && !m_isStuck && m_moveSpeed > getShiftSpeed () + && !(pev->button & IN_DUCK) + && m_currentNodeIndex != kInvalidNodeIndex + && !(m_pathFlags & (NodeFlag::Ladder | NodeFlag::Crouch)) + && m_pathWalk.hasNext () + && pev->origin.distanceSq (m_destOrigin) < cr::sqrf (512.0f)) { + const auto nextPathIndex = m_pathWalk.next (); const auto doubleNextPath = m_pathWalk.doubleNext (); @@ -199,7 +206,10 @@ void Bot::setAimDirection () { if (m_canChooseAimDirection && m_seeEnemyTime + 4.0f < game.time () && m_currentNodeIndex != kInvalidNodeIndex && !onLadder) { const auto dangerIndex = practice.getIndex (m_team, m_currentNodeIndex, m_currentNodeIndex); - if (graph.exists (dangerIndex) && vistab.visible (m_currentNodeIndex, dangerIndex) && !(graph[dangerIndex].flags & NodeFlag::Crouch)) { + if (graph.exists (dangerIndex) + && vistab.visible (m_currentNodeIndex, dangerIndex) + && !(graph[dangerIndex].flags & NodeFlag::Crouch)) { + if (pev->origin.distanceSq (graph[dangerIndex].origin) < cr::sqrf (512.0f)) { m_lookAt = m_destOrigin; } @@ -256,10 +266,19 @@ void Bot::checkDarkness () { if (mp_flashlight.bool_ () && !m_hasNVG) { const auto tid = getCurrentTaskId (); - if (!flashOn && tid != Task::Camp && tid != Task::Attack && m_heardSoundTime + 3.0f < game.time () && m_flashLevel > 30 && ((skyColor > 50.0f && lightLevel < 10.0f) || (skyColor <= 50.0f && lightLevel < 40.0f))) { + if (!flashOn && + tid != Task::Camp + && tid != Task::Attack + && m_heardSoundTime + 3.0f < game.time () + && m_flashLevel > 30 + && ((skyColor > 50.0f && lightLevel < 10.0f) || (skyColor <= 50.0f && lightLevel < 40.0f))) { + pev->impulse = 100; } - else if (flashOn && (((lightLevel > 15.0f && skyColor > 50.0f) || (lightLevel > 45.0f && skyColor <= 50.0f)) || tid == Task::Camp || tid == Task::Attack || m_flashLevel <= 0 || m_heardSoundTime + 3.0f >= game.time ())) { + else if (flashOn + && (((lightLevel > 15.0f && skyColor > 50.0f) || (lightLevel > 45.0f && skyColor <= 50.0f)) + || tid == Task::Camp || tid == Task::Attack || m_flashLevel <= 0 || m_heardSoundTime + 3.0f >= game.time ())) { + pev->impulse = 100; } } @@ -367,7 +386,11 @@ void Bot::updateLookAngles () { } // just force directioon - if (m_difficulty == Difficulty::Expert && (m_aimFlags & AimFlags::Enemy) && (m_wantsToFire || usesSniper ()) && cv_whose_your_daddy.bool_ ()) { + if (m_difficulty == Difficulty::Expert + && (m_aimFlags & AimFlags::Enemy) + && (m_wantsToFire || usesSniper ()) + && cv_whose_your_daddy.bool_ ()) { + pev->v_angle = direction; pev->v_angle.clampAngles (); @@ -439,7 +462,10 @@ void Bot::updateLookAnglesNewbie (const Vector &direction, float delta) { } else { // is it time for bot to randomize the aim direction again (more often where moving) ? - if (m_randomizeAnglesTime < game.time () && ((pev->velocity.length () > 1.0f && m_angularDeviation.length () < 5.0f) || m_angularDeviation.length () < 1.0f)) { + if (m_randomizeAnglesTime < game.time () + && ((pev->velocity.length () > 1.0f + && m_angularDeviation.length () < 5.0f) || m_angularDeviation.length () < 1.0f)) { + // is the bot standing still ? if (pev->velocity.length () < 1.0f) { randomize = randomization * 0.2f; // randomize less