From 39473c9992698e56002234b848edc79e59d90e97 Mon Sep 17 00:00:00 2001 From: TotallyNotElite <1yourexperiment@protonmail.com> Date: Sun, 25 Nov 2018 00:14:01 +0100 Subject: [PATCH] Health and ammo for navbot --- include/hacks/NavBot.hpp | 2 + src/hacks/NavBot.cpp | 143 +++++++++++++++++++++++++++++++++++---- 2 files changed, 132 insertions(+), 13 deletions(-) diff --git a/include/hacks/NavBot.hpp b/include/hacks/NavBot.hpp index 785412c3..ff38021d 100644 --- a/include/hacks/NavBot.hpp +++ b/include/hacks/NavBot.hpp @@ -11,6 +11,8 @@ enum task : uint8_t none = 0, sniper_spot, stay_near, + health, + ammo }; } struct bot_class_config diff --git a/src/hacks/NavBot.cpp b/src/hacks/NavBot.cpp index 0d7bc58d..faa0c5ee 100644 --- a/src/hacks/NavBot.cpp +++ b/src/hacks/NavBot.cpp @@ -8,11 +8,13 @@ namespace hacks::tf2::NavBot static settings::Bool enabled("navbot.enabled", "false"); static settings::Bool stay_near("navbot.stay-near", "true"); static settings::Bool heavy_mode("navbot.other-mode", "false"); +static settings::Bool get_health("navbot.get-health-and-ammo", "true"); // -Forward declarations- bool init(bool first_cm); static bool navToSniperSpot(); static bool stayNear(); +static bool getHealthAndAmmo(); // -Variables- static std::vector> sniper_spots; @@ -34,8 +36,12 @@ static void CreateMove() else current_task = task::none; - // Try to near enemies to increase efficiency - if (stay_near) + + if (get_health) + if (getHealthAndAmmo()) + return; + // Try to stay near enemies to increase efficiency + if (stay_near || heavy_mode) if (stayNear()) return; // We don't have anything else to do. Just nav to sniper spots. @@ -113,6 +119,7 @@ static bool isValidNearPosition(Vector vec, Vector target, static bool stayNearPlayer(CachedEntity *ent, const bot_class_config &config, CNavArea **result) { + // Get some valid areas std::vector areas; for (auto &area : nav::navfile->m_areas) { @@ -122,7 +129,9 @@ static bool stayNearPlayer(CachedEntity *ent, const bot_class_config &config, } if (areas.empty()) return false; + const Vector ent_orig = ent->m_vecOrigin(); + // Area dist to target should be as close as possible to config.preferred std::sort(areas.begin(), areas.end(), [&](CNavArea *a, CNavArea *b) { return std::abs(a->m_center.DistTo(ent_orig) - config.preferred) < std::abs(b->m_center.DistTo(ent_orig) - config.preferred); @@ -131,6 +140,8 @@ static bool stayNearPlayer(CachedEntity *ent, const bot_class_config &config, size_t size = 20; if (areas.size() < size) size = areas.size(); + + // Get some areas that are close to the player std::vector preferred_areas(areas.begin(), areas.begin() + size / 2); std::sort(preferred_areas.begin(), preferred_areas.end(), @@ -145,10 +156,12 @@ static bool stayNearPlayer(CachedEntity *ent, const bot_class_config &config, std::vector::iterator it; if (attempts <= size / 4) { + // First try getting preferred areas (5 tries) it = preferred_areas.begin() + attempts; } else { + // Then get random ones it = select_randomly(areas.begin(), areas.end()); } @@ -166,7 +179,6 @@ static bool stayNearPlayer(CachedEntity *ent, const bot_class_config &config, static bool stayNearPlayers(const bot_class_config &config, CachedEntity **result_ent, CNavArea **result_area) { - logging::Info("Stay near players called!"); for (int i = 0; i < g_IEngine->GetMaxClients(); i++) { CachedEntity *ent = ENTITY(i); @@ -185,8 +197,11 @@ static bool stayNearPlayers(const bot_class_config &config, // Main stay near function static bool stayNear() { - static CachedEntity *lastTarget = nullptr; - static CNavArea *result = nullptr; + static CachedEntity *last_target = nullptr; + static CNavArea *last_area = nullptr; + bool last_target_good = CE_GOOD(last_target) && + last_target->m_bAlivePlayer() && + last_target->m_bEnemy(); // What distances do we have to use? const bot_class_config *config; @@ -202,18 +217,18 @@ static bool stayNear() if (current_task == task::stay_near) { // Do we already have a stay near target? Check if its still good. - if (CE_BAD(lastTarget)) + if (CE_BAD(last_target)) { current_task = task::none; } - else if (!lastTarget->m_bAlivePlayer() || !lastTarget->m_bEnemy()) + else if (!last_target->m_bAlivePlayer() || !last_target->m_bEnemy()) { nav::clearInstructions(); current_task = task::none; } // Check if we still have LOS and are close enough/far enough else if (!stayNearHelpers::isValidNearPosition( - result->m_center, lastTarget->m_vecOrigin(), *config)) + last_area->m_center, last_target->m_vecOrigin(), *config)) { current_task = task::none; nav::clearInstructions(); @@ -221,23 +236,125 @@ static bool stayNear() } // Are we doing nothing? Check if our current location can still attack our // last target - else if (current_task == task::none && CE_GOOD(lastTarget) && - lastTarget->m_bAlivePlayer() && lastTarget->m_bEnemy()) + else if (current_task == task::none && last_target_good) { if (stayNearHelpers::isValidNearPosition( - g_pLocalPlayer->v_Origin, lastTarget->m_vecOrigin(), *config)) + g_pLocalPlayer->v_Origin, last_target->m_vecOrigin(), *config)) + return true; + } + // Can we try pathing to our last target again? + else if (last_target_good) + { + if (stayNearHelpers::stayNearPlayer(last_target, *config, &last_area)) return true; } + static Timer wait_until_stay_near{}; if (current_task == task::stay_near) { return true; } - else + else if (wait_until_stay_near.test_and_set(1000)) { // We're doing nothing? Do something! - return stayNearHelpers::stayNearPlayers(*config, &lastTarget, &result); + return stayNearHelpers::stayNearPlayers(*config, &last_target, + &last_area); } + return false; +} + +static inline bool hasLowAmmo() +{ + if (CE_BAD(LOCAL_W)) + return false; + int *weapon_list = + (int *) ((uint64_t)(RAW_ENT(LOCAL_E)) + netvar.hMyWeapons); + if (g_pLocalPlayer->holding_sniper_rifle && + CE_INT(LOCAL_E, netvar.m_iAmmo + 4) <= 5) + return true; + for (int i = 0; weapon_list[i]; i++) + { + int handle = weapon_list[i]; + int eid = handle & 0xFFF; + if (eid >= 32 && eid <= HIGHEST_ENTITY) + { + IClientEntity *weapon = g_IEntityList->GetClientEntity(eid); + if (weapon and re::C_BaseCombatWeapon::IsBaseCombatWeapon(weapon) && + re::C_TFWeaponBase::UsesPrimaryAmmo(weapon) && + !re::C_TFWeaponBase::HasPrimaryAmmo(weapon)) + return true; + } + } + return false; +} + +static bool getHealthAndAmmo() +{ + static Timer health_ammo_timer{}; + if (!health_ammo_timer.check(3000)) + return false; + if (current_task == task::health) + return true; + + if (float(LOCAL_E->m_iHealth()) / float(LOCAL_E->m_iMaxHealth()) < 0.64f) + { + std::vector healthpacks; + for (int i = 0; i < HIGHEST_ENTITY; i++) + { + CachedEntity *ent = ENTITY(i); + if (CE_BAD(ent) || ent->m_iClassID() != CL_CLASS(CBaseAnimating)) + continue; + if (ent->m_ItemType() != ITEM_HEALTH_SMALL && + ent->m_ItemType() != ITEM_HEALTH_MEDIUM && + ent->m_ItemType() != ITEM_HEALTH_LARGE) + continue; + healthpacks.push_back(ent->m_vecOrigin()); + } + std::sort(healthpacks.begin(), healthpacks.end(), + [](Vector &a, Vector &b) { + return g_pLocalPlayer->v_Origin.DistTo(a) < + g_pLocalPlayer->v_Origin.DistTo(b); + }); + for (auto &pack : healthpacks) + { + if (nav::navTo(pack, 10, true, true)) + { + current_task = task::health; + return true; + } + } + } + + if (current_task == task::ammo) + return true; + if (hasLowAmmo()) + { + std::vector ammopacks; + for (int i = 0; i < HIGHEST_ENTITY; i++) + { + CachedEntity *ent = ENTITY(i); + if (CE_BAD(ent) || ent->m_iClassID() != CL_CLASS(CBaseAnimating)) + continue; + if (ent->m_ItemType() != ITEM_AMMO_SMALL && + ent->m_ItemType() != ITEM_AMMO_MEDIUM && + ent->m_ItemType() != ITEM_AMMO_LARGE) + continue; + ammopacks.push_back(ent->m_vecOrigin()); + } + std::sort(ammopacks.begin(), ammopacks.end(), [](Vector &a, Vector &b) { + return g_pLocalPlayer->v_Origin.DistTo(a) < + g_pLocalPlayer->v_Origin.DistTo(b); + }); + for (auto &pack : ammopacks) + { + if (nav::navTo(pack, 9, true, true)) + { + current_task = task::ammo; + return true; + } + } + } + return false; } static HookedFunction cm(HookedFunctions_types::HF_CreateMove, "NavBot", 16,