Merge pull request #515 from TotallyNotElite/master
Followbot improvements (+ some other stuff)
This commit is contained in:
commit
61f7077e50
@ -36,7 +36,7 @@ public:
|
|||||||
void SetEntityColor(CachedEntity *ent, rgba_t color);
|
void SetEntityColor(CachedEntity *ent, rgba_t color);
|
||||||
rgba_t ChamsColor(IClientEntity *entity);
|
rgba_t ChamsColor(IClientEntity *entity);
|
||||||
bool ShouldRenderChams(IClientEntity *entity);
|
bool ShouldRenderChams(IClientEntity *entity);
|
||||||
void RenderChams(int idx);
|
void RenderChams(IClientEntity *entity);
|
||||||
void BeginRenderChams();
|
void BeginRenderChams();
|
||||||
void EndRenderChams();
|
void EndRenderChams();
|
||||||
void RenderChamsRecursive(IClientEntity *entity);
|
void RenderChamsRecursive(IClientEntity *entity);
|
||||||
|
@ -24,7 +24,7 @@ int m_iNewTarget{ 0 };
|
|||||||
static CatVar pop_uber_auto(CV_SWITCH, "autoheal_uber", "1", "AutoUber",
|
static CatVar pop_uber_auto(CV_SWITCH, "autoheal_uber", "1", "AutoUber",
|
||||||
"Use ubercharge automatically");
|
"Use ubercharge automatically");
|
||||||
static CatVar
|
static CatVar
|
||||||
pop_uber_percent(CV_FLOAT, "autoheal_uber_health", "30",
|
pop_uber_percent(CV_FLOAT, "autoheal_uber_health", "0",
|
||||||
"Pop uber if health% <",
|
"Pop uber if health% <",
|
||||||
"When under a percentage of health, use ubercharge");
|
"When under a percentage of health, use ubercharge");
|
||||||
static CatVar share_uber(
|
static CatVar share_uber(
|
||||||
@ -351,9 +351,17 @@ bool IsPopped()
|
|||||||
bool ShouldChargePlayer(int idx)
|
bool ShouldChargePlayer(int idx)
|
||||||
{
|
{
|
||||||
CachedEntity *target = ENTITY(idx);
|
CachedEntity *target = ENTITY(idx);
|
||||||
|
const int health = target->m_iHealth();
|
||||||
|
if (float(pop_uber_percent) > 0)
|
||||||
|
{
|
||||||
|
const float pophealth = target->m_iMaxHealth() * (float(pop_uber_percent) / 100);
|
||||||
|
if (health < pophealth)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
const float damage_accum_duration =
|
const float damage_accum_duration =
|
||||||
g_GlobalVars->curtime - data[idx].accum_damage_start;
|
g_GlobalVars->curtime - data[idx].accum_damage_start;
|
||||||
const int health = target->m_iHealth();
|
|
||||||
if (!data[idx].accum_damage_start)
|
if (!data[idx].accum_damage_start)
|
||||||
return false;
|
return false;
|
||||||
if (health > 30 && data[idx].accum_damage < 45)
|
if (health > 30 && data[idx].accum_damage < 45)
|
||||||
@ -367,6 +375,8 @@ bool ShouldChargePlayer(int idx)
|
|||||||
return true;
|
return true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool ShouldPop()
|
bool ShouldPop()
|
||||||
{
|
{
|
||||||
|
@ -23,7 +23,7 @@ static CatVar draw_crumb(CV_SWITCH, "fb_draw", "1", "Draw crumbs",
|
|||||||
"Self explanitory");
|
"Self explanitory");
|
||||||
static CatVar follow_distance(CV_INT, "fb_distance", "175", "Follow Distance",
|
static CatVar follow_distance(CV_INT, "fb_distance", "175", "Follow Distance",
|
||||||
"How close the bots should stay to the target");
|
"How close the bots should stay to the target");
|
||||||
static CatVar follow_activation(CV_INT, "fb_activation", "175",
|
static CatVar follow_activation(CV_INT, "fb_activation", "1000",
|
||||||
"Activation Distance",
|
"Activation Distance",
|
||||||
"How close a player should be until the "
|
"How close a player should be until the "
|
||||||
"followbot will pick them as a target");
|
"followbot will pick them as a target");
|
||||||
@ -45,14 +45,49 @@ static CatVar always_medigun(CV_SWITCH, "fb_always_medigun", "0",
|
|||||||
"Always Medigun", "Always use medigun");
|
"Always Medigun", "Always use medigun");
|
||||||
static CatVar sync_taunt(CV_SWITCH, "fb_sync_taunt", "0", "Synced taunt",
|
static CatVar sync_taunt(CV_SWITCH, "fb_sync_taunt", "0", "Synced taunt",
|
||||||
"Taunt when follow target does");
|
"Taunt when follow target does");
|
||||||
static CatVar change(CV_SWITCH, "fb_switch", "1", "Change followbot target",
|
static CatVar change(CV_SWITCH, "fb_switch", "0", "Change followbot target",
|
||||||
"Always change roaming target when possible");
|
"Always change roaming target when possible");
|
||||||
|
static CatVar autojump(CV_SWITCH, "fb_autojump", "1", "Autojump",
|
||||||
|
"Automatically jump if stuck");
|
||||||
|
static CatVar afk(CV_SWITCH, "fb_afk", "1", "Switch target if AFK",
|
||||||
|
"Automatically switch target if the target is afk");
|
||||||
|
static CatVar afktime(
|
||||||
|
CV_INT, "fb_afk_time", "15000", "Max AFK Time",
|
||||||
|
"Max time in ms spent standing still before player gets declared afk");
|
||||||
|
|
||||||
// Something to store breadcrumbs created by followed players
|
// Something to store breadcrumbs created by followed players
|
||||||
static std::vector<Vector> breadcrumbs;
|
static std::vector<Vector> breadcrumbs;
|
||||||
static const int crumb_limit = 64; // limit
|
static const int crumb_limit = 64; // limit
|
||||||
|
|
||||||
// Followed entity, externed for highlight color
|
// Followed entity, externed for highlight color
|
||||||
int follow_target = 0;
|
int follow_target = 0;
|
||||||
|
bool inited;
|
||||||
|
|
||||||
|
Timer lastTaunt{}; //time since taunt was last executed, used to avoid kicks
|
||||||
|
std::array<Timer, 32> afkTicks; //for how many ms the player hasn't been moving
|
||||||
|
|
||||||
|
void checkAFK()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < g_GlobalVars->maxClients; i++)
|
||||||
|
{
|
||||||
|
auto entity = ENTITY(i);
|
||||||
|
if (CE_BAD(entity))
|
||||||
|
continue;
|
||||||
|
if (!CE_VECTOR(entity, netvar.vVelocity).IsZero(5.0f))
|
||||||
|
{
|
||||||
|
afkTicks[i].update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void init()
|
||||||
|
{
|
||||||
|
for (int i; i < afkTicks.size(); i++)
|
||||||
|
{
|
||||||
|
afkTicks[i].update();
|
||||||
|
}
|
||||||
|
inited = true;
|
||||||
|
}
|
||||||
|
|
||||||
void WorldTick()
|
void WorldTick()
|
||||||
{
|
{
|
||||||
@ -61,6 +96,8 @@ void WorldTick()
|
|||||||
follow_target = 0;
|
follow_target = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (!inited)
|
||||||
|
init();
|
||||||
|
|
||||||
// We need a local player to control
|
// We need a local player to control
|
||||||
if (CE_BAD(LOCAL_E) || !LOCAL_E->m_bAlivePlayer())
|
if (CE_BAD(LOCAL_E) || !LOCAL_E->m_bAlivePlayer())
|
||||||
@ -69,6 +106,9 @@ void WorldTick()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (afk)
|
||||||
|
checkAFK();
|
||||||
|
|
||||||
// Still good check
|
// Still good check
|
||||||
if (follow_target)
|
if (follow_target)
|
||||||
{
|
{
|
||||||
@ -122,6 +162,12 @@ void WorldTick()
|
|||||||
continue;
|
continue;
|
||||||
if (entity == LOCAL_E) // Follow self lol
|
if (entity == LOCAL_E) // Follow self lol
|
||||||
continue;
|
continue;
|
||||||
|
if (entity->m_bEnemy())
|
||||||
|
continue;
|
||||||
|
if (afk && afkTicks[i].check(int(afktime))) //don't follow target that was determined afk
|
||||||
|
continue;
|
||||||
|
if (IsPlayerDisguised(entity) || IsPlayerInvisible(entity))
|
||||||
|
continue;
|
||||||
if (!entity->m_bAlivePlayer()) // Dont follow dead players
|
if (!entity->m_bAlivePlayer()) // Dont follow dead players
|
||||||
continue;
|
continue;
|
||||||
if (follow_activation &&
|
if (follow_activation &&
|
||||||
@ -148,29 +194,51 @@ void WorldTick()
|
|||||||
entity->m_flDistance()) // favor closer entitys
|
entity->m_flDistance()) // favor closer entitys
|
||||||
continue;
|
continue;
|
||||||
// ooooo, a target
|
// ooooo, a target
|
||||||
follow_target = entity->m_IDX;
|
follow_target = i;
|
||||||
|
afkTicks[i].update(); //set afk time to 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// last check for entity before we continue
|
// last check for entity before we continue
|
||||||
if (!follow_target)
|
if (!follow_target)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// If the player is close enough, we dont need to follow the path
|
|
||||||
CachedEntity *followtar = ENTITY(follow_target);
|
CachedEntity *followtar = ENTITY(follow_target);
|
||||||
// wtf is this needed
|
// wtf is this needed
|
||||||
if (CE_BAD(followtar))
|
if (CE_BAD(followtar))
|
||||||
return;
|
return;
|
||||||
auto tar_orig = followtar->m_vecOrigin();
|
// Check if we are following a disguised/spy
|
||||||
auto loc_orig = LOCAL_E->m_vecOrigin();
|
if (IsPlayerDisguised(followtar) || IsPlayerInvisible(followtar))
|
||||||
auto dist_to_target = loc_orig.DistTo(tar_orig);
|
{
|
||||||
if (dist_to_target < 30)
|
follow_target = 0;
|
||||||
breadcrumbs.clear();
|
return;
|
||||||
|
}
|
||||||
|
//check if target is afk
|
||||||
|
if (afk)
|
||||||
|
{
|
||||||
|
if (afkTicks[follow_target].check(int(afktime)))
|
||||||
|
{
|
||||||
|
follow_target = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// Update timer on new target
|
// Update timer on new target
|
||||||
static Timer idle_time{};
|
static Timer idle_time{};
|
||||||
if (breadcrumbs.empty())
|
if (breadcrumbs.empty())
|
||||||
idle_time.update();
|
idle_time.update();
|
||||||
|
|
||||||
|
// If the player is close enough, we dont need to follow the path
|
||||||
|
auto tar_orig = followtar->m_vecOrigin();
|
||||||
|
auto loc_orig = LOCAL_E->m_vecOrigin();
|
||||||
|
auto dist_to_target = loc_orig.DistTo(tar_orig);
|
||||||
|
|
||||||
|
if ((dist_to_target < (float) follow_distance) &&
|
||||||
|
VisCheckEntFromEnt(LOCAL_E, followtar))
|
||||||
|
{
|
||||||
|
idle_time.update();
|
||||||
|
}
|
||||||
|
|
||||||
// New crumbs, we add one if its empty so we have something to follow
|
// New crumbs, we add one if its empty so we have something to follow
|
||||||
if ((breadcrumbs.empty() ||
|
if ((breadcrumbs.empty() ||
|
||||||
tar_orig.DistTo(breadcrumbs.at(breadcrumbs.size() - 1)) > 40.0F) &&
|
tar_orig.DistTo(breadcrumbs.at(breadcrumbs.size() - 1)) > 40.0F) &&
|
||||||
@ -179,26 +247,32 @@ void WorldTick()
|
|||||||
|
|
||||||
// Prune old and close crumbs that we wont need anymore, update idle timer
|
// Prune old and close crumbs that we wont need anymore, update idle timer
|
||||||
// too
|
// too
|
||||||
while (breadcrumbs.size() > 1 && loc_orig.DistTo(breadcrumbs.at(0)) < 60.f)
|
for (int i = 0; i < breadcrumbs.size(); i++)
|
||||||
|
{
|
||||||
|
if (loc_orig.DistTo(breadcrumbs.at(i)) < 60.f)
|
||||||
{
|
{
|
||||||
idle_time.update();
|
idle_time.update();
|
||||||
|
for (int j = 0; j <= i; j++)
|
||||||
breadcrumbs.erase(breadcrumbs.begin());
|
breadcrumbs.erase(breadcrumbs.begin());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//moved because its worthless otherwise
|
||||||
|
if (sync_taunt && HasCondition<TFCond_Taunting>(followtar) && lastTaunt.test_and_set(1000)) {
|
||||||
|
g_IEngine->ClientCmd("taunt");
|
||||||
|
}
|
||||||
|
|
||||||
// Follow the crumbs when too far away, or just starting to follow
|
// Follow the crumbs when too far away, or just starting to follow
|
||||||
if (dist_to_target > (float) follow_distance)
|
if (dist_to_target > (float) follow_distance)
|
||||||
{
|
{
|
||||||
// Check for idle
|
// Check for idle
|
||||||
if (idle_time.check(3000) ||
|
if (autojump && idle_time.check(3000))
|
||||||
(breadcrumbs.size() > 1 && LOCAL_E->m_vecVelocity.IsZero(5.0f)))
|
|
||||||
g_pUserCmd->buttons |= IN_JUMP;
|
g_pUserCmd->buttons |= IN_JUMP;
|
||||||
if (idle_time.test_and_set(5000))
|
if (idle_time.test_and_set(5000))
|
||||||
{
|
{
|
||||||
follow_target = 0;
|
follow_target = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (sync_taunt && HasCondition<TFCond_Taunting>(ENTITY(follow_target)))
|
|
||||||
g_IEngine->ClientCmd("taunt");
|
|
||||||
static float last_slot_check = 0.0f;
|
static float last_slot_check = 0.0f;
|
||||||
if (g_GlobalVars->curtime < last_slot_check)
|
if (g_GlobalVars->curtime < last_slot_check)
|
||||||
last_slot_check = 0.0f;
|
last_slot_check = 0.0f;
|
||||||
|
@ -227,8 +227,6 @@ bool EffectChams::ShouldRenderChams(IClientEntity *entity)
|
|||||||
if (entity->entindex() < 0)
|
if (entity->entindex() < 0)
|
||||||
return false;
|
return false;
|
||||||
CachedEntity *ent = ENTITY(entity->entindex());
|
CachedEntity *ent = ENTITY(entity->entindex());
|
||||||
if (CE_BAD(ent))
|
|
||||||
return false;
|
|
||||||
if (ent->m_IDX == LOCAL_E->m_IDX && !chamsself)
|
if (ent->m_IDX == LOCAL_E->m_IDX && !chamsself)
|
||||||
return false;
|
return false;
|
||||||
switch (ent->m_Type())
|
switch (ent->m_Type())
|
||||||
@ -319,12 +317,9 @@ void EffectChams::RenderChamsRecursive(IClientEntity *entity)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void EffectChams::RenderChams(int idx)
|
void EffectChams::RenderChams(IClientEntity *entity)
|
||||||
{
|
{
|
||||||
CMatRenderContextPtr ptr(GET_RENDER_CONTEXT);
|
CMatRenderContextPtr ptr(GET_RENDER_CONTEXT);
|
||||||
IClientEntity *entity = g_IEntityList->GetClientEntity(idx);
|
|
||||||
if (entity && !entity->IsDormant())
|
|
||||||
{
|
|
||||||
if (ShouldRenderChams(entity))
|
if (ShouldRenderChams(entity))
|
||||||
{
|
{
|
||||||
rgba_t color = ChamsColor(entity);
|
rgba_t color = ChamsColor(entity);
|
||||||
@ -351,7 +346,6 @@ void EffectChams::RenderChams(int idx)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void EffectChams::Render(int x, int y, int w, int h)
|
void EffectChams::Render(int x, int y, int w, int h)
|
||||||
{
|
{
|
||||||
@ -366,11 +360,10 @@ void EffectChams::Render(int x, int y, int w, int h)
|
|||||||
BeginRenderChams();
|
BeginRenderChams();
|
||||||
for (int i = 1; i < HIGHEST_ENTITY; i++)
|
for (int i = 1; i < HIGHEST_ENTITY; i++)
|
||||||
{
|
{
|
||||||
IClientEntity *ent = g_IEntityList->GetClientEntity(i);
|
IClientEntity *entity = g_IEntityList->GetClientEntity(i);
|
||||||
if (ent && !ent->IsDormant())
|
if (!entity || entity->IsDormant() || CE_BAD(ENTITY(i)))
|
||||||
{
|
return;
|
||||||
RenderChams(i);
|
RenderChams(entity);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
EndRenderChams();
|
EndRenderChams();
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user