Health and ammo for navbot
This commit is contained in:
parent
55e93a5627
commit
39473c9992
@ -11,6 +11,8 @@ enum task : uint8_t
|
|||||||
none = 0,
|
none = 0,
|
||||||
sniper_spot,
|
sniper_spot,
|
||||||
stay_near,
|
stay_near,
|
||||||
|
health,
|
||||||
|
ammo
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
struct bot_class_config
|
struct bot_class_config
|
||||||
|
@ -8,11 +8,13 @@ namespace hacks::tf2::NavBot
|
|||||||
static settings::Bool enabled("navbot.enabled", "false");
|
static settings::Bool enabled("navbot.enabled", "false");
|
||||||
static settings::Bool stay_near("navbot.stay-near", "true");
|
static settings::Bool stay_near("navbot.stay-near", "true");
|
||||||
static settings::Bool heavy_mode("navbot.other-mode", "false");
|
static settings::Bool heavy_mode("navbot.other-mode", "false");
|
||||||
|
static settings::Bool get_health("navbot.get-health-and-ammo", "true");
|
||||||
|
|
||||||
// -Forward declarations-
|
// -Forward declarations-
|
||||||
bool init(bool first_cm);
|
bool init(bool first_cm);
|
||||||
static bool navToSniperSpot();
|
static bool navToSniperSpot();
|
||||||
static bool stayNear();
|
static bool stayNear();
|
||||||
|
static bool getHealthAndAmmo();
|
||||||
|
|
||||||
// -Variables-
|
// -Variables-
|
||||||
static std::vector<std::pair<CNavArea *, Vector>> sniper_spots;
|
static std::vector<std::pair<CNavArea *, Vector>> sniper_spots;
|
||||||
@ -34,8 +36,12 @@ static void CreateMove()
|
|||||||
else
|
else
|
||||||
current_task = task::none;
|
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())
|
if (stayNear())
|
||||||
return;
|
return;
|
||||||
// We don't have anything else to do. Just nav to sniper spots.
|
// 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,
|
static bool stayNearPlayer(CachedEntity *ent, const bot_class_config &config,
|
||||||
CNavArea **result)
|
CNavArea **result)
|
||||||
{
|
{
|
||||||
|
// Get some valid areas
|
||||||
std::vector<CNavArea *> areas;
|
std::vector<CNavArea *> areas;
|
||||||
for (auto &area : nav::navfile->m_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())
|
if (areas.empty())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
const Vector ent_orig = ent->m_vecOrigin();
|
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) {
|
std::sort(areas.begin(), areas.end(), [&](CNavArea *a, CNavArea *b) {
|
||||||
return std::abs(a->m_center.DistTo(ent_orig) - config.preferred) <
|
return std::abs(a->m_center.DistTo(ent_orig) - config.preferred) <
|
||||||
std::abs(b->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;
|
size_t size = 20;
|
||||||
if (areas.size() < size)
|
if (areas.size() < size)
|
||||||
size = areas.size();
|
size = areas.size();
|
||||||
|
|
||||||
|
// Get some areas that are close to the player
|
||||||
std::vector<CNavArea *> preferred_areas(areas.begin(),
|
std::vector<CNavArea *> preferred_areas(areas.begin(),
|
||||||
areas.begin() + size / 2);
|
areas.begin() + size / 2);
|
||||||
std::sort(preferred_areas.begin(), preferred_areas.end(),
|
std::sort(preferred_areas.begin(), preferred_areas.end(),
|
||||||
@ -145,10 +156,12 @@ static bool stayNearPlayer(CachedEntity *ent, const bot_class_config &config,
|
|||||||
std::vector<CNavArea *>::iterator it;
|
std::vector<CNavArea *>::iterator it;
|
||||||
if (attempts <= size / 4)
|
if (attempts <= size / 4)
|
||||||
{
|
{
|
||||||
|
// First try getting preferred areas (5 tries)
|
||||||
it = preferred_areas.begin() + attempts;
|
it = preferred_areas.begin() + attempts;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
// Then get random ones
|
||||||
it = select_randomly(areas.begin(), areas.end());
|
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,
|
static bool stayNearPlayers(const bot_class_config &config,
|
||||||
CachedEntity **result_ent, CNavArea **result_area)
|
CachedEntity **result_ent, CNavArea **result_area)
|
||||||
{
|
{
|
||||||
logging::Info("Stay near players called!");
|
|
||||||
for (int i = 0; i < g_IEngine->GetMaxClients(); i++)
|
for (int i = 0; i < g_IEngine->GetMaxClients(); i++)
|
||||||
{
|
{
|
||||||
CachedEntity *ent = ENTITY(i);
|
CachedEntity *ent = ENTITY(i);
|
||||||
@ -185,8 +197,11 @@ static bool stayNearPlayers(const bot_class_config &config,
|
|||||||
// Main stay near function
|
// Main stay near function
|
||||||
static bool stayNear()
|
static bool stayNear()
|
||||||
{
|
{
|
||||||
static CachedEntity *lastTarget = nullptr;
|
static CachedEntity *last_target = nullptr;
|
||||||
static CNavArea *result = 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?
|
// What distances do we have to use?
|
||||||
const bot_class_config *config;
|
const bot_class_config *config;
|
||||||
@ -202,18 +217,18 @@ static bool stayNear()
|
|||||||
if (current_task == task::stay_near)
|
if (current_task == task::stay_near)
|
||||||
{
|
{
|
||||||
// Do we already have a stay near target? Check if its still good.
|
// 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;
|
current_task = task::none;
|
||||||
}
|
}
|
||||||
else if (!lastTarget->m_bAlivePlayer() || !lastTarget->m_bEnemy())
|
else if (!last_target->m_bAlivePlayer() || !last_target->m_bEnemy())
|
||||||
{
|
{
|
||||||
nav::clearInstructions();
|
nav::clearInstructions();
|
||||||
current_task = task::none;
|
current_task = task::none;
|
||||||
}
|
}
|
||||||
// Check if we still have LOS and are close enough/far enough
|
// Check if we still have LOS and are close enough/far enough
|
||||||
else if (!stayNearHelpers::isValidNearPosition(
|
else if (!stayNearHelpers::isValidNearPosition(
|
||||||
result->m_center, lastTarget->m_vecOrigin(), *config))
|
last_area->m_center, last_target->m_vecOrigin(), *config))
|
||||||
{
|
{
|
||||||
current_task = task::none;
|
current_task = task::none;
|
||||||
nav::clearInstructions();
|
nav::clearInstructions();
|
||||||
@ -221,23 +236,125 @@ static bool stayNear()
|
|||||||
}
|
}
|
||||||
// Are we doing nothing? Check if our current location can still attack our
|
// Are we doing nothing? Check if our current location can still attack our
|
||||||
// last target
|
// last target
|
||||||
else if (current_task == task::none && CE_GOOD(lastTarget) &&
|
else if (current_task == task::none && last_target_good)
|
||||||
lastTarget->m_bAlivePlayer() && lastTarget->m_bEnemy())
|
|
||||||
{
|
{
|
||||||
if (stayNearHelpers::isValidNearPosition(
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Timer wait_until_stay_near{};
|
||||||
if (current_task == task::stay_near)
|
if (current_task == task::stay_near)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else if (wait_until_stay_near.test_and_set(1000))
|
||||||
{
|
{
|
||||||
// We're doing nothing? Do something!
|
// 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<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<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,
|
static HookedFunction cm(HookedFunctions_types::HF_CreateMove, "NavBot", 16,
|
||||||
|
Reference in New Issue
Block a user