From 8872e0a3173e050cc851e17e67391e9e38393457 Mon Sep 17 00:00:00 2001 From: LightCat Date: Sun, 19 Aug 2018 14:34:22 +0200 Subject: [PATCH] FollowBot things --- data/menu/nullifiedcat/catbot.xml | 22 +- include/hacks/NavBot.hpp | 3 +- src/hacks/Aimbot.cpp | 5 +- src/hacks/AutoReflect.cpp | 3 +- src/hacks/Backtrack.cpp | 18 +- src/hacks/FollowBot.cpp | 14 +- src/hacks/NavBot.cpp | 351 +++++++++++++++++++++++++++--- src/hooks/CreateMove.cpp | 1 + src/hooks/DispatchUserMessage.cpp | 4 +- src/hooks/SendDatagram.cpp | 18 +- 10 files changed, 377 insertions(+), 62 deletions(-) diff --git a/data/menu/nullifiedcat/catbot.xml b/data/menu/nullifiedcat/catbot.xml index 7ff8d279..d5bff376 100755 --- a/data/menu/nullifiedcat/catbot.xml +++ b/data/menu/nullifiedcat/catbot.xml @@ -39,7 +39,7 @@ - + @@ -54,13 +54,27 @@ - - + + - + + + + + + + + + + + + + + + diff --git a/include/hacks/NavBot.hpp b/include/hacks/NavBot.hpp index 4b12c2c4..ce4ade47 100644 --- a/include/hacks/NavBot.hpp +++ b/include/hacks/NavBot.hpp @@ -8,5 +8,6 @@ namespace hacks::tf2::NavBot { void Init(); +void initonce(); void CreateMove(); -} \ No newline at end of file +} // namespace hacks::tf2::NavBot \ No newline at end of file diff --git a/src/hacks/Aimbot.cpp b/src/hacks/Aimbot.cpp index 88358f94..f71e99c1 100644 --- a/src/hacks/Aimbot.cpp +++ b/src/hacks/Aimbot.cpp @@ -159,14 +159,15 @@ void CreateMove() // If zoomed only is on, check if zoomed if (zoomed_only && g_pLocalPlayer->holding_sniper_rifle) { - if (!g_pLocalPlayer->bZoomed && !(current_user_cmd->buttons & IN_ATTACK)) + if (!g_pLocalPlayer->bZoomed && + !(current_user_cmd->buttons & IN_ATTACK)) return; } // Minigun spun up handler if (g_pLocalPlayer->weapon()->m_iClassID() == CL_CLASS(CTFMinigun)) { int weapon_state = - CE_INT(g_pLocalPlayer->weapon(), netvar.iWeaponState); + CE_INT(g_pLocalPlayer->weapon(), netvar.iWeaponState); // If user setting for autospin isnt true, then we check if minigun // is already zoomed if ((weapon_state == MinigunState_t::AC_STATE_IDLE || diff --git a/src/hacks/AutoReflect.cpp b/src/hacks/AutoReflect.cpp index c202079b..ff941ee3 100644 --- a/src/hacks/AutoReflect.cpp +++ b/src/hacks/AutoReflect.cpp @@ -38,7 +38,8 @@ void CreateMove() return; // Check if player is using a flame thrower - if (g_pLocalPlayer->weapon()->m_iClassID() != CL_CLASS(CTFFlameThrower) && CE_INT(LOCAL_W, netvar.iItemDefinitionIndex) != 528) + if (g_pLocalPlayer->weapon()->m_iClassID() != CL_CLASS(CTFFlameThrower) && + CE_INT(LOCAL_W, netvar.iItemDefinitionIndex) != 528) return; // Check for phlogistinator, which is item 594 diff --git a/src/hacks/Backtrack.cpp b/src/hacks/Backtrack.cpp index 71e68a20..5d735d0f 100644 --- a/src/hacks/Backtrack.cpp +++ b/src/hacks/Backtrack.cpp @@ -259,16 +259,22 @@ bool ValidTick(BacktrackData &i, CachedEntity *ent) return true; if (istickinvalid[ent->m_IDX][i.index]) return false; - if (hacks::shared::aimbot::IsBacktracking()) { - if (IsVectorVisible(g_pLocalPlayer->v_Eye, i.hitboxes[head].center, true)) - if (fabsf(NET_FLOAT(RAW_ENT(ent), netvar.m_flSimulationTime) * 1000.0f - - getLatency() - i.simtime * 1000.0f) <= 200.0f) { + if (hacks::shared::aimbot::IsBacktracking()) + { + if (IsVectorVisible(g_pLocalPlayer->v_Eye, i.hitboxes[head].center, + true)) + if (fabsf(NET_FLOAT(RAW_ENT(ent), netvar.m_flSimulationTime) * + 1000.0f - + getLatency() - i.simtime * 1000.0f) <= 200.0f) + { istickvalid[ent->m_IDX][i.index] = true; return true; } } - else if (fabsf(NET_FLOAT(RAW_ENT(ent), netvar.m_flSimulationTime) * 1000.0f - - getLatency() - i.simtime * 1000.0f) <= 200.0f) { + else if (fabsf(NET_FLOAT(RAW_ENT(ent), netvar.m_flSimulationTime) * + 1000.0f - + getLatency() - i.simtime * 1000.0f) <= 200.0f) + { istickvalid[ent->m_IDX][i.index] = true; return true; } diff --git a/src/hacks/FollowBot.cpp b/src/hacks/FollowBot.cpp index f711ed84..7c621b9a 100644 --- a/src/hacks/FollowBot.cpp +++ b/src/hacks/FollowBot.cpp @@ -142,8 +142,8 @@ int ClassPriority(CachedEntity *ent) { switch (g_pPlayerResource->GetClass(ent)) { - if (g_pPlayerResource->GetClass(ent) == tf_spy) - return 0; + case tf_spy: + return 0; case tf_engineer: return 1; case tf_medic: @@ -223,11 +223,11 @@ void WorldTick() Vector indirectOrigin = VischeckCorner(LOCAL_E, entity, *follow_activation / 2, true); // get the corner location that the - // future target is visible from + // future target is visible from std::pair corners; if (!indirectOrigin.z && entity->m_IDX == lastent) // if we couldn't find it, run - // wallcheck instead + // wallcheck instead { corners = VischeckWall(LOCAL_E, entity, float(follow_activation) / 2, true); @@ -314,13 +314,13 @@ void WorldTick() Vector indirectOrigin = VischeckCorner(LOCAL_E, entity, 250, true); // get the corner location that the - // future target is visible from + // future target is visible from std::pair corners; corners.first.z = 0; corners.second.z = 0; if (!indirectOrigin.z && entity->m_IDX == lastent) // if we couldn't find it, run - // wallcheck instead + // wallcheck instead { corners = VischeckWall(LOCAL_E, entity, 250, true); if (!corners.first.z || !corners.second.z) @@ -580,4 +580,4 @@ static CatCommand } }); #endif -} // namespace hacks::shared::followbot +} // namespace hacks::shared::followbot \ No newline at end of file diff --git a/src/hacks/NavBot.cpp b/src/hacks/NavBot.cpp index b10173cd..a4fb4d1d 100644 --- a/src/hacks/NavBot.cpp +++ b/src/hacks/NavBot.cpp @@ -2,7 +2,10 @@ // Created by bencat07 on 17.08.18. // #include "common.hpp" +#include +#include #include "navparser.hpp" +#include "FollowBot.hpp" #include "NavBot.hpp" namespace hacks::tf2::NavBot @@ -12,6 +15,45 @@ static settings::Bool spy_mode("navbot.spy-mode", "false"); static settings::Bool heavy_mode("navbot.heavy-mode", "false"); static settings::Bool primary_only("navbot.primary-only", "true"); +static settings::Bool enable_fb{ "navbot.medbot", "false" }; +static settings::Bool roambot{ "navbot.roaming", "true" }; +static settings::Float follow_activation{ "navbot.max-range", "1000" }; +static settings::Bool mimic_slot{ "navbot.mimic-slot", "false" }; +static settings::Bool always_medigun{ "navbot.always-medigun", "false" }; +static settings::Bool sync_taunt{ "navbot.taunt-sync", "false" }; +static settings::Bool change_tar{ "navbot.change-roaming-target", "false" }; +static settings::Bool autojump{ "navbot.jump-if-stuck", "true" }; +static settings::Bool afk{ "navbot.switch-afk", "true" }; +static settings::Int afktime{ "navbot.afk-time", "15000" }; + +unsigned steamid = 0x0; +CatCommand follow_steam("navbot_steam", "Follow Steam Id", + [](const CCommand &args) { + if (args.ArgC() < 1) + { + steamid = 0x0; + return; + } + steamid = atol(args.Arg(1)); + }); +Timer lastTaunt{}; // time since taunt was last executed, used to avoid kicks +Timer lastJump{}; +std::array 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(60.0f)) + { + afkTicks[i].update(); + } + } +} + bool HasLowAmmo() { int *weapon_list = @@ -115,6 +157,12 @@ void Init() hide.IsExposed()) sniper_spots.push_back(hide.m_pos); } +void initonce() +{ + for (int i = 0; i < afkTicks.size(); i++) + afkTicks[i].update(); + return; +} Timer slot_timer{}; void UpdateSlot() @@ -140,13 +188,14 @@ void UpdateSlot() Timer cdr{}; Timer cd2{}; Timer cd3{}; +int follow_target = 0; void CreateMove() { - if (!enable || !nav::Prepare()) + if ((!enable && !enable_fb) || !nav::Prepare()) return; if (CE_BAD(LOCAL_E) || !LOCAL_E->m_bAlivePlayer()) return; - if (primary_only) + if (primary_only && enable) UpdateSlot(); if (HasLowHealth() && cdr.test_and_set(5000)) { @@ -164,47 +213,287 @@ void CreateMove() nav::NavTo(ammo->m_vecOrigin(), true, true, 6); } } - if (!nav::ReadyForCommands && !spy_mode && !heavy_mode) - cd3.update(); - bool isready = (spy_mode || heavy_mode) ? 1 : nav::ReadyForCommands; - int waittime = (spy_mode || heavy_mode) ? 100 : 5000; - if (isready && cd3.test_and_set(waittime)) + if (enable) { - if (!spy_mode && !heavy_mode) - { + if (!nav::ReadyForCommands && !spy_mode && !heavy_mode) cd3.update(); - Vector random_spot; - if (sniper_spots.empty()) - { - if (cd2.test_and_set(5000)) - Init(); - return; - } - int rng = rand() % sniper_spots.size(); - random_spot = sniper_spots.at(rng); - if (random_spot.z) - nav::NavTo(random_spot, true, true); - } - else if (cdr.check(5000)) + bool isready = (spy_mode || heavy_mode) ? 1 : nav::ReadyForCommands; + int waittime = (spy_mode || heavy_mode) ? 100 : 5000; + if (isready && cd3.test_and_set(waittime)) { - CachedEntity *tar = NearestEnemy(); - if (CE_BAD(tar)) + if (!spy_mode && !heavy_mode) { + cd3.update(); Vector random_spot; - if (sniper_spots.empty()) - { - if (cd2.test_and_set(5000)) - Init(); + if (cd2.test_and_set(20000)) + Init(); + if (!sniper_spots.size()) return; - } int rng = rand() % sniper_spots.size(); random_spot = sniper_spots.at(rng); if (random_spot.z) - nav::NavTo(random_spot, false); + nav::NavTo(random_spot, true, true); + } + else if (cdr.check(5000)) + { + CachedEntity *tar = NearestEnemy(); + if (CE_BAD(tar)) + { + Vector random_spot; + if (cd2.test_and_set(20000)) + Init(); + if (!sniper_spots.size()) + return; + int rng = rand() % sniper_spots.size(); + random_spot = sniper_spots.at(rng); + if (random_spot.z) + nav::NavTo(random_spot, false); + return; + } + nav::NavTo(tar->m_vecOrigin(), false); + } + } + } + else if (enable_fb) + { + // We need a local player to control + if (CE_BAD(LOCAL_E) || !LOCAL_E->m_bAlivePlayer()) + { + follow_target = 0; + nav::NavTo(LOCAL_E->m_vecOrigin(), true, false, 4); + return; + } + + if (afk) + checkAFK(); + + // Still good check + if (follow_target) + if (CE_BAD(ENTITY(follow_target))) + follow_target = 0; + + if (!follow_target) + nav::NavTo(LOCAL_E->m_vecOrigin(), true, + false); // no target == no path + // Target Selection + if (steamid) + { + // Find a target with the steam id, as it is prioritized + auto ent_count = HIGHEST_ENTITY; + for (int i = 0; i < ent_count; i++) + { + auto entity = ENTITY(i); + if (CE_BAD(entity)) // Exist + dormant + continue; + if (i == follow_target) + break; + if (entity->m_Type() != ENTITY_PLAYER) + continue; + if (steamid != entity->player_info.friendsID) // steamid check + continue; + + if (!entity->m_bAlivePlayer()) // Dont follow dead players + continue; + follow_target = entity->m_IDX; + break; + } + } + // If we dont have a follow target from that, we look again for someone + // else who is suitable + if ((!follow_target || change_tar || + (hacks::shared::followbot::ClassPriority(ENTITY(follow_target)) < + 6 && + ENTITY(follow_target)->player_info.friendsID != steamid)) && + roambot) + { + // Try to get a new target + auto ent_count = g_IEngine->GetMaxClients(); + for (int i = 0; i < ent_count; i++) + { + auto entity = ENTITY(i); + if (CE_BAD(entity)) // Exist + dormant + continue; + if (entity->m_Type() != ENTITY_PLAYER) + continue; + if (entity == LOCAL_E) // Follow self lol + 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 + continue; + if (follow_activation && + entity->m_flDistance() > (float) follow_activation) + continue; + const model_t *model = + ENTITY(follow_target)->InternalEntity()->GetModel(); + // FIXME follow cart/point + /*if (followcart && model && + (lagexploit::pointarr[0] || lagexploit::pointarr[1] || + lagexploit::pointarr[2] || lagexploit::pointarr[3] || + lagexploit::pointarr[4]) && + (model == lagexploit::pointarr[0] || + model == lagexploit::pointarr[1] || + model == lagexploit::pointarr[2] || + model == lagexploit::pointarr[3] || + model == lagexploit::pointarr[4])) + follow_target = entity->m_IDX;*/ + if (entity->m_Type() != ENTITY_PLAYER) + continue; + // favor closer entitys + if (follow_target && + ENTITY(follow_target)->m_flDistance() < + entity->m_flDistance()) // favor closer entitys + continue; + // check if new target has a higher priority than current target + if (hacks::shared::followbot::ClassPriority( + ENTITY(follow_target)) >= + hacks::shared::followbot::ClassPriority(ENTITY(i))) + continue; + // ooooo, a target + follow_target = i; + afkTicks[i].update(); // set afk time to 0 + } + } + // last check for entity before we continue + if (!follow_target) + { + nav::NavTo(LOCAL_E->m_vecOrigin(), true, false, 4); + return; + } + + CachedEntity *followtar = ENTITY(follow_target); + // wtf is this needed + if (CE_BAD(followtar) || !followtar->m_bAlivePlayer()) + { + follow_target = 0; + nav::NavTo(LOCAL_E->m_vecOrigin(), true, false, 4); + return; + } + // Check if we are following a disguised/spy + if (IsPlayerDisguised(followtar) || IsPlayerInvisible(followtar)) + { + follow_target = 0; + nav::NavTo(LOCAL_E->m_vecOrigin(), true, false, 4); + return; + } + // check if target is afk + if (afk) + { + if (afkTicks[follow_target].check(int(afktime))) + { + follow_target = 0; + nav::NavTo(LOCAL_E->m_vecOrigin(), true, false, 4); return; } - nav::NavTo(tar->m_vecOrigin(), false); } + + // Update timer on new target + static Timer idle_time{}; + if (nav::ReadyForCommands) + 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 (!CE_VECTOR(followtar, netvar.vVelocity).IsZero(20.0f)) + idle_time.update(); + + // Tauntsync + if (sync_taunt && HasCondition(followtar) && + lastTaunt.test_and_set(1000)) + g_IEngine->ClientCmd("taunt"); + + // Check for jump + if (autojump && lastJump.check(1000) && idle_time.check(2000)) + { + current_user_cmd->buttons |= IN_JUMP; + lastJump.update(); + } + // Check if still moving. 70 HU = Sniper Zoomed Speed + if (idle_time.check(3000) && + CE_VECTOR(g_pLocalPlayer->entity, netvar.vVelocity).IsZero(60.0f)) + { + follow_target = 0; + nav::NavTo(LOCAL_E->m_vecOrigin(), true, false, 4); + return; + } + // Basic idle check + if (idle_time.test_and_set(5000)) + { + follow_target = 0; + nav::NavTo(LOCAL_E->m_vecOrigin(), true, false, 4); + return; + } + + static float last_slot_check = 0.0f; + if (g_GlobalVars->curtime < last_slot_check) + last_slot_check = 0.0f; + if (follow_target && (always_medigun || mimic_slot) && + (g_GlobalVars->curtime - last_slot_check > 1.0f) && + !g_pLocalPlayer->life_state && + !CE_BYTE(ENTITY(follow_target), netvar.iLifeState)) + { + + // We are checking our slot so reset the timer + last_slot_check = g_GlobalVars->curtime; + + // Get the follow targets active weapon + int owner_weapon_eid = + (CE_INT(ENTITY(follow_target), netvar.hActiveWeapon) & 0xFFF); + IClientEntity *owner_weapon = + g_IEntityList->GetClientEntity(owner_weapon_eid); + + // If both the follow targets and the local players weapons arnt + // null or + // dormant + if (owner_weapon && CE_GOOD(g_pLocalPlayer->weapon())) + { + + // IsBaseCombatWeapon() + if (re::C_BaseCombatWeapon::IsBaseCombatWeapon( + RAW_ENT(g_pLocalPlayer->weapon())) && + re::C_BaseCombatWeapon::IsBaseCombatWeapon(owner_weapon)) + { + + // Get the players slot numbers and store in some vars + int my_slot = re::C_BaseCombatWeapon::GetSlot( + RAW_ENT(g_pLocalPlayer->weapon())); + int owner_slot = + re::C_BaseCombatWeapon::GetSlot(owner_weapon); + + // If the local player is a medic and user settings allow, + // then + // keep the medigun out + if (g_pLocalPlayer->clazz == tf_medic && always_medigun) + { + if (my_slot != 1) + { + g_IEngine->ExecuteClientCmd("slot2"); + } + + // Else we attemt to keep our weapon mimiced with our + // follow + // target + } + else + { + if (my_slot != owner_slot) + { + g_IEngine->ExecuteClientCmd( + format("slot", owner_slot + 1).c_str()); + } + } + } + } + } + nav::NavTo(tar_orig, false, true, 5); } } } // namespace hacks::tf2::NavBot diff --git a/src/hooks/CreateMove.cpp b/src/hooks/CreateMove.cpp index 2bbffea3..0456379d 100644 --- a/src/hooks/CreateMove.cpp +++ b/src/hooks/CreateMove.cpp @@ -128,6 +128,7 @@ DEFINE_HOOKED_METHOD(CreateMove, bool, void *this_, float input_sample_time, { DelayTimer.update(); hacks::tf2::NavBot::Init(); + hacks::tf2::NavBot::initonce(); firstcm = false; } tickcount++; diff --git a/src/hooks/DispatchUserMessage.cpp b/src/hooks/DispatchUserMessage.cpp index f16750e2..0e8e66db 100644 --- a/src/hooks/DispatchUserMessage.cpp +++ b/src/hooks/DispatchUserMessage.cpp @@ -182,7 +182,7 @@ DEFINE_HOOKED_METHOD(DispatchUserMessage, bool, void *this_, int type, retrun = true; lastfilter = format(filter); lastname = format(name); - gitgud.update(); + gitgud.update(); } } } @@ -210,7 +210,7 @@ DEFINE_HOOKED_METHOD(DispatchUserMessage, bool, void *this_, int type, retrun = true; lastfilter = format(filter); lastname = format(name); - gitgud.update(); + gitgud.update(); } } } diff --git a/src/hooks/SendDatagram.cpp b/src/hooks/SendDatagram.cpp index 71154e6c..e70bf1af 100644 --- a/src/hooks/SendDatagram.cpp +++ b/src/hooks/SendDatagram.cpp @@ -13,23 +13,25 @@ DEFINE_HOOKED_METHOD(SendDatagram, int, INetChannel *ch, bf_write *buf) #if !LAGBOT_MODE int in; int state; - if (CE_GOOD(LOCAL_E)) { - in = ch->m_nInSequenceNr; + if (CE_GOOD(LOCAL_E)) + { + in = ch->m_nInSequenceNr; state = ch->m_nInReliableState; float latencysend = - round((round((hacks::shared::backtrack::getLatency() - 0.5f) / - 15.1515151515f) - - 0.5f) * - 15.1515151515f); + round((round((hacks::shared::backtrack::getLatency() - 0.5f) / + 15.1515151515f) - + 0.5f) * + 15.1515151515f); hacks::shared::backtrack::AddLatencyToNetchan(ch, latencysend); } #endif int ret = original::SendDatagram(ch, buf); #if !LAGBOT_MODE - if (CE_GOOD(LOCAL_E)) { - ch->m_nInSequenceNr = in; + if (CE_GOOD(LOCAL_E)) + { + ch->m_nInSequenceNr = in; ch->m_nInReliableState = state; }