Merge pull request #895 from nullworks/lightcat
Engineer Bot stuff and simple-ipc updates
This commit is contained in:
commit
23c46143f6
2
.gitmodules
vendored
2
.gitmodules
vendored
@ -27,4 +27,4 @@
|
||||
url = https://github.com/sakra/cotire
|
||||
[submodule "external/clip"]
|
||||
path = external/clip
|
||||
url = https://github.com/nullworks/clip
|
||||
url = https://github.com/nullworks/clip
|
||||
|
2
config_data/teamspam.txt
Normal file
2
config_data/teamspam.txt
Normal file
@ -0,0 +1,2 @@
|
||||
CAT
|
||||
HOOK
|
@ -2,6 +2,7 @@
|
||||
<TabContainer width="fill" height="fill">
|
||||
<Include path="nullifiedcat/misc/anticheat.xml"/>
|
||||
<Include path="nullifiedcat/misc/autoequip.xml"/>
|
||||
<Include path="nullifiedcat/misc/buildings.xml"/>
|
||||
<Include path="nullifiedcat/misc/announcer.xml"/>
|
||||
<Include path="nullifiedcat/misc/spyalert.xml"/>
|
||||
<Include path="nullifiedcat/misc/collective.xml"/>
|
||||
|
26
data/menu/nullifiedcat/misc/buildings.xml
Normal file
26
data/menu/nullifiedcat/misc/buildings.xml
Normal file
@ -0,0 +1,26 @@
|
||||
<Tab name="Buildings" padding="4 4 4 4">
|
||||
<Box padding="12 6 6 6" width="content" height="content" name="Buildings">.
|
||||
<List width="200">
|
||||
<AutoVariable width="fill" target="autorepair.enabled" label="Enable Auto Repair"/>
|
||||
<AutoVariable width="fill" target="autorepair.silent" label="Silent"/>
|
||||
<AutoVariable width="fill" target="autorepair.sentry" label="Repair Sentry"/>
|
||||
<AutoVariable width="fill" target="autorepair.dispenser" label="Repair Dispenser"/>
|
||||
<AutoVariable width="fill" target="autorepair.teleport" label="Repair Teleporter"/>
|
||||
<LabeledObject width="fill" label="Priority">
|
||||
<Select target="autorepair.priority">
|
||||
<Option name="None" value="0"/>
|
||||
<Option name="Sentry" value="1"/>
|
||||
<Option name="Dispenser" value="2"/>
|
||||
<Option name="Teleport" value="3"/>
|
||||
</Select>
|
||||
</LabeledObject>
|
||||
<AutoVariable width="fill" target="autoupgrade.enabled" label="Enable Auto Upgrade"/>
|
||||
<AutoVariable width="fill" target="autoupgrade.sentry" label="Upgrade Sentry"/>
|
||||
<AutoVariable width="fill" target="autoupgrade.sentry.level" label="Upgrade Sentry Level" min="1" max="3"/>
|
||||
<AutoVariable width="fill" target="autoupgrade.dispenser" label="Upgrade Dispenser"/>
|
||||
<AutoVariable width="fill" target="autoupgrade.dispenser.level" label="Upgrade Dispenser Level" min="1" max="3"/>
|
||||
<AutoVariable width="fill" target="autoupgrade.teleport" label="Upgrade Teleporter"/>
|
||||
<AutoVariable width="fill" target="autoupgrade.teleport.level" label="Upgrade Teleporter Level" min="1" max="3"/>
|
||||
</List>
|
||||
</Box>
|
||||
</Tab>
|
@ -33,7 +33,7 @@
|
||||
<AutoVariable width="fill" target="misc.pathing.draw" label="Draw Path"/>
|
||||
<AutoVariable width="fill" target="misc.pathing.look-at-path" label="Look at Path"/>
|
||||
<AutoVariable width="fill" target="navbot.enabled" label="Enable Navbot"/>
|
||||
<!--AutoVariable width="fill" target="navbot.scout-mode" label="Enable Scout Mode"/-->
|
||||
<AutoVariable width="fill" target="navbot.engineer-mode" label="Enable Engineer mode">
|
||||
<AutoVariable width="fill" target="navbot.get-health-and-ammo" label="Get Health and Ammo"/>
|
||||
<AutoVariable width="fill" target="navbot.spy-mode" label="Enable Spy Mode"/>
|
||||
<AutoVariable width="fill" target="navbot.other-mode" label="General Mode"/>
|
||||
|
@ -32,6 +32,8 @@ extern settings::Boolean clean_chat;
|
||||
|
||||
extern settings::Boolean clean_screenshots;
|
||||
extern settings::Boolean crypt_chat;
|
||||
extern settings::Boolean nolerp;
|
||||
extern float backup_lerp;
|
||||
extern settings::Boolean disable_visuals;
|
||||
extern settings::Int print_r;
|
||||
extern settings::Int print_g;
|
||||
@ -41,6 +43,10 @@ extern int stored_buttons;
|
||||
#if ENABLE_VISUALS
|
||||
extern bool freecam_is_toggled;
|
||||
#endif
|
||||
namespace hacks::tf2::misc_aimbot
|
||||
{
|
||||
bool ShouldHitBuilding(CachedEntity *ent);
|
||||
}
|
||||
namespace hooked_methods
|
||||
{
|
||||
void sendAchievementKv(int value);
|
||||
|
@ -61,6 +61,7 @@ extern CHud *g_CHUD;
|
||||
extern ISteamClient *g_ISteamClient;
|
||||
extern ISteamFriends *g_ISteamFriends;
|
||||
extern IVEngineClient013 *g_IEngine;
|
||||
extern void *demoplayer;
|
||||
extern IEngineSound *g_ISoundEngine;
|
||||
extern vgui::ISurface *g_ISurface;
|
||||
extern vgui::IPanel *g_IPanel;
|
||||
|
2
include/core/logging.hpp
Executable file → Normal file
2
include/core/logging.hpp
Executable file → Normal file
@ -18,4 +18,4 @@ void Initialize();
|
||||
void Shutdown();
|
||||
void Info(const char *fmt, ...);
|
||||
void File(const char *fmt, ...);
|
||||
}
|
||||
} // namespace logging
|
||||
|
@ -45,6 +45,15 @@ public:
|
||||
offset_t iTeamNum;
|
||||
offset_t iFlags;
|
||||
offset_t iHealth;
|
||||
|
||||
// sentry
|
||||
offset_t m_iAmmoShells; // sentry shells
|
||||
offset_t m_iAmmoRockets; // use only with if (GetLevel() == 3)
|
||||
offset_t m_iSentryState; // sentry state
|
||||
|
||||
// dispenser
|
||||
offset_t m_iAmmoMetal; // dispenser metal reserve
|
||||
|
||||
offset_t iLifeState;
|
||||
offset_t iCond;
|
||||
offset_t iCond1;
|
||||
@ -54,7 +63,11 @@ public:
|
||||
offset_t vViewOffset;
|
||||
offset_t hActiveWeapon;
|
||||
offset_t flChargedDamage;
|
||||
offset_t iUpgradeLevel;
|
||||
|
||||
// any building
|
||||
offset_t m_iUpgradeMetal; // upgrade metal on any building
|
||||
offset_t m_flPercentageConstructed; // use only with if (IsBuilding())
|
||||
offset_t iUpgradeLevel; // any building
|
||||
offset_t m_hBuilder;
|
||||
offset_t m_bCanPlace;
|
||||
offset_t m_iObjectType;
|
||||
@ -62,12 +75,15 @@ public:
|
||||
offset_t m_bHasSapper;
|
||||
offset_t m_bPlacing;
|
||||
offset_t m_bBuilding;
|
||||
offset_t m_iTeleState;
|
||||
|
||||
// teleporter
|
||||
offset_t m_iTeleState; // teleport state [1 = idle, 2 = active, 3 = teleporting, 4 = charging]
|
||||
offset_t m_flTeleRechargeTime;
|
||||
offset_t m_flTeleCurrentRechargeDuration;
|
||||
offset_t m_iTeleTimesUsed;
|
||||
offset_t m_flTeleYawToExit;
|
||||
offset_t m_bMatchBuilding;
|
||||
|
||||
offset_t iPipeType;
|
||||
offset_t iBuildingHealth;
|
||||
offset_t iBuildingMaxHealth;
|
||||
|
@ -176,6 +176,10 @@ struct offsets
|
||||
{
|
||||
return PlatformOffset(47, undefined, 47);
|
||||
}
|
||||
static constexpr uint32_t IsPlayingTimeDemo()
|
||||
{
|
||||
return PlatformOffset(8, undefined, 8);
|
||||
}
|
||||
static constexpr uint32_t RegisterFileWhitelist()
|
||||
{
|
||||
return PlatformOffset(94, undefined, undefined);
|
||||
|
@ -18,7 +18,7 @@ void CreateMove();
|
||||
#if ENABLE_VISUALS
|
||||
void DrawText();
|
||||
#endif
|
||||
|
||||
int getCarriedBuilding();
|
||||
extern int last_number;
|
||||
|
||||
extern float last_bucket;
|
||||
|
@ -6,6 +6,7 @@ namespace hacks::tf2::NavBot
|
||||
bool init(bool first_cm);
|
||||
namespace task
|
||||
{
|
||||
|
||||
enum task : uint8_t
|
||||
{
|
||||
none = 0,
|
||||
@ -15,28 +16,49 @@ enum task : uint8_t
|
||||
ammo,
|
||||
dispenser,
|
||||
followbot,
|
||||
outofbounds
|
||||
outofbounds,
|
||||
engineer
|
||||
};
|
||||
|
||||
enum engineer_task : uint8_t
|
||||
{
|
||||
nothing = 0,
|
||||
// Build a new building
|
||||
goto_build_spot,
|
||||
// Go to an existing building
|
||||
goto_building,
|
||||
build_building,
|
||||
// Originally were going to be added seperately, but we already have autorepair and upgrade seperately
|
||||
// upgrade_building,
|
||||
// repair_building,
|
||||
upgradeorrepair_building,
|
||||
// Well time to just run at people and gun them (Rip old name: YEEEEEEEEEEEEEEHAW)
|
||||
staynear_engineer
|
||||
};
|
||||
|
||||
extern engineer_task current_engineer_task;
|
||||
|
||||
struct Task
|
||||
{
|
||||
task id;
|
||||
int priority;
|
||||
Task(task _id)
|
||||
Task(task id)
|
||||
{
|
||||
id = _id;
|
||||
priority = _id == none ? 0 : 5;
|
||||
this->id = id;
|
||||
priority = id == none ? 0 : 5;
|
||||
}
|
||||
Task(task _id, int _priority)
|
||||
Task(task id, int priority)
|
||||
{
|
||||
id = _id;
|
||||
priority = _priority;
|
||||
this->id = id;
|
||||
this->priority = priority;
|
||||
}
|
||||
operator task()
|
||||
{
|
||||
return id;
|
||||
}
|
||||
};
|
||||
constexpr std::array<task, 2> blocking_tasks{ followbot, outofbounds };
|
||||
|
||||
constexpr std::array<task, 3> blocking_tasks{ followbot, outofbounds, engineer };
|
||||
extern Task current_task;
|
||||
} // namespace task
|
||||
struct bot_class_config
|
||||
|
@ -36,6 +36,11 @@ constexpr float RADPI = 57.295779513082f;
|
||||
|
||||
#include <core/sdk.hpp>
|
||||
|
||||
#define TICK_INTERVAL (g_GlobalVars->interval_per_tick)
|
||||
#define TIME_TO_TICKS(dt) ((int) (0.5f + (float) (dt) / TICK_INTERVAL))
|
||||
#define TICKS_TO_TIME(t) (TICK_INTERVAL * (t))
|
||||
#define ROUND_TO_TICKS(t) (TICK_INTERVAL * TIME_TO_TICKS(t))
|
||||
|
||||
// typedef void ( *FnCommandCallback_t )( const CCommand &command );
|
||||
|
||||
template <typename Iter, typename RandomGenerator> Iter select_randomly(Iter start, Iter end, RandomGenerator &g)
|
||||
|
@ -59,6 +59,7 @@ extern VMTHook client;
|
||||
extern VMTHook inventory;
|
||||
extern VMTHook chathud;
|
||||
extern VMTHook engine;
|
||||
extern VMTHook demoplayer;
|
||||
extern VMTHook netchannel;
|
||||
extern VMTHook firebullets;
|
||||
extern VMTHook clientdll;
|
||||
|
@ -58,6 +58,7 @@ DECLARE_HOOKED_METHOD(Paint, void, IEngineVGui *, PaintMode_t);
|
||||
DECLARE_HOOKED_METHOD(FireEvent, bool, IGameEventManager2 *, IGameEvent *, bool);
|
||||
DECLARE_HOOKED_METHOD(FireEventClientSide, bool, IGameEventManager2 *, IGameEvent *);
|
||||
// g_IEngine
|
||||
DECLARE_HOOKED_METHOD(IsPlayingTimeDemo, bool, void *);
|
||||
DECLARE_HOOKED_METHOD(ServerCmdKeyValues, void, IVEngineClient013 *, KeyValues *);
|
||||
#if ENABLE_VISUALS || ENABLE_TEXTMODE
|
||||
// vgui::IPanel
|
||||
|
2
include/localplayer.hpp
Executable file → Normal file
2
include/localplayer.hpp
Executable file → Normal file
@ -43,7 +43,7 @@ public:
|
||||
bool bAttackLastTick;
|
||||
|
||||
bool isFakeAngleCM = false;
|
||||
Vector realAngles{0.0f, 0.0f, 0.0f};
|
||||
Vector realAngles{ 0.0f, 0.0f, 0.0f };
|
||||
};
|
||||
|
||||
#define LOCAL_E g_pLocalPlayer->entity
|
||||
|
@ -5,8 +5,8 @@
|
||||
* Author: nullifiedcat
|
||||
*/
|
||||
|
||||
#ifndef CH_TIMER_HPP
|
||||
#define CH_TIMER_HPP
|
||||
#ifndef CH_TIMER_HPP
|
||||
#define CH_TIMER_HPP
|
||||
#include <chrono>
|
||||
|
||||
class Timer
|
||||
|
@ -24,6 +24,12 @@ settings::Boolean clean_chat{ "chat.clean", "false" };
|
||||
|
||||
settings::Boolean crypt_chat{ "chat.crypto", "true" };
|
||||
settings::Boolean clean_screenshots{ "visual.clean-screenshots", "false" };
|
||||
#if ENABLE_TEXTMODE
|
||||
settings::Boolean nolerp{ "misc.no-lerp", "true" };
|
||||
#else
|
||||
settings::Boolean nolerp{ "misc.no-lerp", "false" };
|
||||
#endif
|
||||
float backup_lerp = 0.0f;
|
||||
static settings::Boolean no_zoom{ "remove.scope", "false" };
|
||||
settings::Boolean disable_visuals{ "visual.disable", "false" };
|
||||
settings::Int print_r{ "print.rgb.r", "183" };
|
||||
@ -35,7 +41,7 @@ void color_callback(settings::VariableBase<int> &, int)
|
||||
{
|
||||
menu_color = Color(*print_r, *print_g, *print_b, 255);
|
||||
}
|
||||
static InitRoutine color_init([]() {
|
||||
static InitRoutine misc_init([]() {
|
||||
print_r.installChangeCallback(color_callback);
|
||||
print_g.installChangeCallback(color_callback);
|
||||
print_b.installChangeCallback(color_callback);
|
||||
@ -43,4 +49,36 @@ static InitRoutine color_init([]() {
|
||||
static BytePatch patch(gSignatures.GetClientSignature, "81 EC ? ? ? ? A1 ? ? ? ? 8B 7D 08 8B 10 89 04 24 FF 92", 0x0, { 0x5B, 0x5E, 0x5F, 0x5D, 0xC3 });
|
||||
after ? patch.Patch() : patch.Shutdown();
|
||||
});
|
||||
nolerp.installChangeCallback([](settings::VariableBase<bool> &, bool after) {
|
||||
if (!after)
|
||||
{
|
||||
if (backup_lerp)
|
||||
{
|
||||
cl_interp->SetValue(backup_lerp);
|
||||
backup_lerp = 0.0f;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
backup_lerp = cl_interp->GetFloat();
|
||||
// We should adjust cl_interp to be as low as possible
|
||||
if (cl_interp->GetFloat() > 0.152f)
|
||||
cl_interp->SetValue(0.152f);
|
||||
}
|
||||
});
|
||||
EC::Register(
|
||||
EC::Shutdown,
|
||||
[]() {
|
||||
if (backup_lerp)
|
||||
{
|
||||
cl_interp->SetValue(backup_lerp);
|
||||
backup_lerp = 0.0f;
|
||||
}
|
||||
},
|
||||
"misctemp_shutdown");
|
||||
#if ENABLE_TEXTMODE
|
||||
// Ensure that we trigger the callback for textmode builds
|
||||
nolerp = false;
|
||||
nolerp = true;
|
||||
#endif
|
||||
});
|
||||
|
@ -97,7 +97,8 @@ std::optional<colors::rgba_t> forceEspColor(CachedEntity *entity)
|
||||
|
||||
void onKilledBy(unsigned id)
|
||||
{
|
||||
if (!shouldTargetSteamId(id))
|
||||
auto &pl = playerlist::AccessData(id);
|
||||
if (!shouldTargetSteamId(id) && !playerlist::IsFriendly(pl.state))
|
||||
{
|
||||
// We ignored the gamer, but they still shot us
|
||||
if (betrayal_list.find(id) == betrayal_list.end())
|
||||
@ -110,4 +111,32 @@ void onKilledBy(CachedEntity *entity)
|
||||
{
|
||||
onKilledBy(entity->player_info.friendsID);
|
||||
}
|
||||
|
||||
class PlayerToolsEventListener : public IGameEventListener2
|
||||
{
|
||||
void FireGameEvent(IGameEvent *event) override
|
||||
{
|
||||
|
||||
int killer_id = g_IEngine->GetPlayerForUserID(event->GetInt("attacker"));
|
||||
int victim_id = g_IEngine->GetPlayerForUserID(event->GetInt("userid"));
|
||||
|
||||
if (victim_id == g_IEngine->GetLocalPlayer())
|
||||
{
|
||||
onKilledBy(ENTITY(killer_id));
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
PlayerToolsEventListener &listener()
|
||||
{
|
||||
static PlayerToolsEventListener object{};
|
||||
return object;
|
||||
}
|
||||
|
||||
static InitRoutine register_event([]() {
|
||||
g_IEventManager2->AddListener(&listener(), "player_death", false);
|
||||
EC::Register(
|
||||
EC::Shutdown, []() { g_IEventManager2->RemoveListener(&listener()); }, "playerlist_shutdown");
|
||||
});
|
||||
} // namespace player_tools
|
||||
|
@ -22,6 +22,7 @@ IVModelRender *g_IVModelRender = nullptr;
|
||||
ISteamClient *g_ISteamClient = nullptr;
|
||||
ISteamFriends *g_ISteamFriends = nullptr;
|
||||
IVEngineClient013 *g_IEngine = nullptr;
|
||||
void *demoplayer = nullptr;
|
||||
IEngineSound *g_ISoundEngine = nullptr;
|
||||
vgui::ISurface *g_ISurface = nullptr;
|
||||
vgui::IPanel *g_IPanel = nullptr;
|
||||
@ -93,6 +94,7 @@ void CreateInterfaces()
|
||||
{
|
||||
g_ICvar = BruteforceInterface<ICvar>("VEngineCvar", sharedobj::vstdlib());
|
||||
g_IEngine = BruteforceInterface<IVEngineClient013>("VEngineClient", sharedobj::engine());
|
||||
demoplayer = **(unsigned ***) (gSignatures.GetEngineSignature("89 15 ? ? ? ? BA ? ? ? ? 83 38 01") + 2);
|
||||
g_ISoundEngine = BruteforceInterface<IEngineSound>("IEngineSoundClient", sharedobj::engine());
|
||||
g_AppID = g_IEngine->GetAppID();
|
||||
g_IEntityList = BruteforceInterface<IClientEntityList>("VClientEntityList", sharedobj::client());
|
||||
|
@ -30,6 +30,7 @@ void NetVars::Init()
|
||||
this->m_Collision = gNetvars.get_offset("DT_BaseEntity", "m_Collision");
|
||||
this->m_flSimulationTime = gNetvars.get_offset("DT_BaseEntity", "m_flSimulationTime");
|
||||
this->m_angRotation = gNetvars.get_offset("DT_BaseEntity", "m_angRotation");
|
||||
|
||||
IF_GAME(IsTF2())
|
||||
{
|
||||
res_iTeam = gNetvars.get_offset("DT_TFPlayerResource", "baseclass", "m_iTeam");
|
||||
@ -65,33 +66,49 @@ void NetVars::Init()
|
||||
this->res_iScore = gNetvars.get_offset("DT_TFPlayerResource", "baseclass", "m_iScore");
|
||||
IF_GAME(IsTF())
|
||||
{
|
||||
this->res_iMaxHealth = gNetvars.get_offset("DT_TFPlayerResource", "m_iMaxHealth");
|
||||
this->res_iPlayerClass = gNetvars.get_offset("DT_TFPlayerResource", "m_iPlayerClass");
|
||||
this->m_bReadyToBackstab = gNetvars.get_offset("DT_TFWeaponKnife", "m_bReadyToBackstab");
|
||||
this->m_bDucked = gNetvars.get_offset("DT_TFPlayer", "localdata", "m_Local", "m_bDucked");
|
||||
this->m_flDuckTimer = gNetvars.get_offset("DT_TFPlayer", "m_Shared", "m_flDuckTimer");
|
||||
this->iCond = gNetvars.get_offset("DT_TFPlayer", "m_Shared", "m_nPlayerCond");
|
||||
this->iCond1 = gNetvars.get_offset("DT_TFPlayer", "m_Shared", "m_nPlayerCondEx");
|
||||
this->iCond2 = gNetvars.get_offset("DT_TFPlayer", "m_Shared", "m_nPlayerCondEx2");
|
||||
this->iCond3 = gNetvars.get_offset("DT_TFPlayer", "m_Shared", "m_nPlayerCondEx3");
|
||||
this->iClass = gNetvars.get_offset("DT_TFPlayer", "m_PlayerClass", "m_iClass");
|
||||
this->flChargedDamage = gNetvars.get_offset("DT_TFSniperRifle", "SniperRifleLocalData", "m_flChargedDamage");
|
||||
this->iUpgradeLevel = gNetvars.get_offset("DT_BaseObject", "m_iUpgradeLevel");
|
||||
this->m_hBuilder = gNetvars.get_offset("DT_BaseObject", "m_hBuilder");
|
||||
this->m_bCanPlace = gNetvars.get_offset("DT_BaseObject", "m_bServerOverridePlacement");
|
||||
this->m_bBuilding = gNetvars.get_offset("DT_BaseObject", "m_bBuilding");
|
||||
this->m_iObjectType = gNetvars.get_offset("DT_BaseObject", "m_iObjectType");
|
||||
this->m_bHasSapper = gNetvars.get_offset("DT_BaseObject", "m_bHasSapper");
|
||||
this->m_bPlacing = gNetvars.get_offset("DT_BaseObject", "m_bPlacing");
|
||||
this->m_bMiniBuilding = gNetvars.get_offset("DT_BaseObject", "m_bMiniBuilding");
|
||||
this->res_iMaxHealth = gNetvars.get_offset("DT_TFPlayerResource", "m_iMaxHealth");
|
||||
this->res_iPlayerClass = gNetvars.get_offset("DT_TFPlayerResource", "m_iPlayerClass");
|
||||
this->m_bReadyToBackstab = gNetvars.get_offset("DT_TFWeaponKnife", "m_bReadyToBackstab");
|
||||
this->m_bDucked = gNetvars.get_offset("DT_TFPlayer", "localdata", "m_Local", "m_bDucked");
|
||||
this->m_flDuckTimer = gNetvars.get_offset("DT_TFPlayer", "m_Shared", "m_flDuckTimer");
|
||||
this->iCond = gNetvars.get_offset("DT_TFPlayer", "m_Shared", "m_nPlayerCond");
|
||||
this->iCond1 = gNetvars.get_offset("DT_TFPlayer", "m_Shared", "m_nPlayerCondEx");
|
||||
this->iCond2 = gNetvars.get_offset("DT_TFPlayer", "m_Shared", "m_nPlayerCondEx2");
|
||||
this->iCond3 = gNetvars.get_offset("DT_TFPlayer", "m_Shared", "m_nPlayerCondEx3");
|
||||
this->iClass = gNetvars.get_offset("DT_TFPlayer", "m_PlayerClass", "m_iClass");
|
||||
this->flChargedDamage = gNetvars.get_offset("DT_TFSniperRifle", "SniperRifleLocalData", "m_flChargedDamage");
|
||||
|
||||
// sentry
|
||||
this->m_iAmmoShells = gNetvars.get_offset("DT_ObjectSentrygun", "m_iAmmoShells");
|
||||
this->m_iAmmoRockets = gNetvars.get_offset("DT_ObjectSentrygun", "m_iAmmoRockets");
|
||||
this->m_iSentryState = gNetvars.get_offset("DT_ObjectSentrygun", "m_iState");
|
||||
|
||||
// dispenser
|
||||
this->m_iAmmoMetal = gNetvars.get_offset("DT_ObjectDispenser", "m_iAmmoMetal");
|
||||
|
||||
// any building
|
||||
this->m_iUpgradeMetal = gNetvars.get_offset("DT_BaseObject", "m_iUpgradeMetal");
|
||||
this->m_flPercentageConstructed = gNetvars.get_offset("DT_BaseObject", "m_flPercentageConstructed");
|
||||
|
||||
// any building
|
||||
this->iUpgradeLevel = gNetvars.get_offset("DT_BaseObject", "m_iUpgradeLevel");
|
||||
this->m_hBuilder = gNetvars.get_offset("DT_BaseObject", "m_hBuilder");
|
||||
this->m_bCanPlace = gNetvars.get_offset("DT_BaseObject", "m_bServerOverridePlacement");
|
||||
this->m_bBuilding = gNetvars.get_offset("DT_BaseObject", "m_bBuilding");
|
||||
this->m_iObjectType = gNetvars.get_offset("DT_BaseObject", "m_iObjectType");
|
||||
this->m_bHasSapper = gNetvars.get_offset("DT_BaseObject", "m_bHasSapper");
|
||||
this->m_bPlacing = gNetvars.get_offset("DT_BaseObject", "m_bPlacing");
|
||||
this->m_bMiniBuilding = gNetvars.get_offset("DT_BaseObject", "m_bMiniBuilding");
|
||||
|
||||
// teleporter
|
||||
this->m_iTeleState = gNetvars.get_offset("DT_ObjectTeleporter", "m_iState");
|
||||
this->m_flTeleRechargeTime = gNetvars.get_offset("DT_ObjectTeleporter", "m_flRechargeTime");
|
||||
this->m_flTeleCurrentRechargeDuration = gNetvars.get_offset("DT_ObjectTeleporter", "m_flCurrentRechargeDuration");
|
||||
this->m_iTeleTimesUsed = gNetvars.get_offset("DT_ObjectTeleporter", "m_iTimesUsed");
|
||||
this->m_flTeleYawToExit = gNetvars.get_offset("DT_ObjectTeleporter", "m_flYawToExit");
|
||||
this->m_bMatchBuilding = gNetvars.get_offset("DT_ObjectTeleporter", "m_bMatchBuilding");
|
||||
this->m_DmgRadius = gNetvars.get_offset("DT_BaseGrenade", "m_DmgRadius");
|
||||
|
||||
this->m_DmgRadius = gNetvars.get_offset("DT_BaseGrenade", "m_DmgRadius");
|
||||
this->iPipeType = gNetvars.get_offset("DT_TFProjectile_Pipebomb", "m_iType");
|
||||
this->iBuildingHealth = gNetvars.get_offset("DT_BaseObject", "m_iHealth");
|
||||
this->iBuildingMaxHealth = gNetvars.get_offset("DT_BaseObject", "m_iMaxHealth");
|
||||
|
@ -255,6 +255,10 @@ void hack::Hook()
|
||||
hooks::engine.HookMethod(HOOK_ARGS(ServerCmdKeyValues));
|
||||
hooks::engine.Apply();
|
||||
|
||||
hooks::demoplayer.Set(demoplayer);
|
||||
hooks::demoplayer.HookMethod(HOOK_ARGS(IsPlayingTimeDemo));
|
||||
hooks::demoplayer.Apply();
|
||||
|
||||
hooks::eventmanager2.Set(g_IEventManager2);
|
||||
hooks::eventmanager2.HookMethod(HOOK_ARGS(FireEvent));
|
||||
hooks::eventmanager2.HookMethod(HOOK_ARGS(FireEventClientSide));
|
||||
|
@ -826,6 +826,9 @@ void Aim(CachedEntity *entity)
|
||||
|
||||
if (silent && !slow_aim)
|
||||
g_pLocalPlayer->bUseSilentAngles = true;
|
||||
// Set tick count to target's (backtrack messes with this)
|
||||
if (!bt::isBacktrackEnabled && nolerp && entity->m_IDX <= g_IEngine->GetMaxClients())
|
||||
current_user_cmd->tick_count = TIME_TO_TICKS(CE_FLOAT(entity, netvar.m_flSimulationTime));
|
||||
// Finish function
|
||||
return;
|
||||
}
|
||||
|
@ -373,10 +373,11 @@ void ProcessUserCmd(CUserCmd *cmd)
|
||||
bool clamp = !no_clamping;
|
||||
|
||||
static int ticksUntilSwap = 0;
|
||||
static bool swap = true;
|
||||
static bool swap = true;
|
||||
|
||||
if (ticksUntilSwap > 0 && *yaw_mode != 18) {
|
||||
swap = true;
|
||||
if (ticksUntilSwap > 0 && *yaw_mode != 18)
|
||||
{
|
||||
swap = true;
|
||||
ticksUntilSwap = 0;
|
||||
}
|
||||
switch ((int) yaw_mode)
|
||||
@ -492,9 +493,10 @@ void ProcessUserCmd(CUserCmd *cmd)
|
||||
}
|
||||
break;
|
||||
case 18: // Fake sideways
|
||||
if (g_pLocalPlayer->isFakeAngleCM && ticksUntilSwap--) {
|
||||
if (g_pLocalPlayer->isFakeAngleCM && ticksUntilSwap--)
|
||||
{
|
||||
ticksUntilSwap = UniformRandomInt(*yaw_sideways_min, *yaw_sideways_max);
|
||||
swap = !swap;
|
||||
swap = !swap;
|
||||
}
|
||||
y += g_pLocalPlayer->isFakeAngleCM ^ swap ? 90.0f : -90.0f;
|
||||
break;
|
||||
|
@ -23,7 +23,6 @@ static settings::Boolean auto_disguise{ "misc.autodisguise", "true" };
|
||||
static settings::Int abandon_if_ipc_bots_gte{ "cat-bot.abandon-if.ipc-bots-gte", "0" };
|
||||
static settings::Int abandon_if_humans_lte{ "cat-bot.abandon-if.humans-lte", "0" };
|
||||
static settings::Int abandon_if_players_lte{ "cat-bot.abandon-if.players-lte", "0" };
|
||||
static settings::Int mark_human_threshold{ "cat-bot.mark-human-after-kills", "2" };
|
||||
|
||||
static settings::Boolean micspam{ "cat-bot.micspam.enable", "false" };
|
||||
static settings::Int micspam_on{ "cat-bot.micspam.interval-on", "3" };
|
||||
@ -74,6 +73,7 @@ int globerr(const char *path, int eerrno)
|
||||
// let glob() keep going
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool hasEnding(std::string const &fullString, std::string const &ending)
|
||||
{
|
||||
if (fullString.length() >= ending.length())
|
||||
@ -191,24 +191,6 @@ void on_killed_by(int userid)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!catbotmode)
|
||||
return;
|
||||
CachedEntity *player = ENTITY(g_IEngine->GetPlayerForUserID(userid));
|
||||
|
||||
if (CE_BAD(player))
|
||||
return;
|
||||
|
||||
unsigned steamID = player->player_info.friendsID;
|
||||
|
||||
if (playerlist::AccessData(steamID).state != playerlist::k_EState::CAT)
|
||||
return;
|
||||
|
||||
// if (human_detecting_map[steamID].has_bot_name)
|
||||
human_detecting_map[steamID].treacherous_kills++;
|
||||
logging::Info("Treacherous kill #%d: %s [U:1:%u]", human_detecting_map[steamID].treacherous_kills, player->player_info.name, player->player_info.friendsID);
|
||||
if (human_detecting_map[steamID].treacherous_kills >= *mark_human_threshold)
|
||||
playerlist::ChangeState(steamID, playerlist::k_EState::RAGE, true);
|
||||
}
|
||||
|
||||
void do_random_votekick()
|
||||
@ -531,7 +513,7 @@ CatBotEventListener &listener()
|
||||
|
||||
class CatBotEventListener2 : public IGameEventListener2
|
||||
{
|
||||
void FireGameEvent(IGameEvent *event) override
|
||||
void FireGameEvent(IGameEvent *) override
|
||||
{
|
||||
// vote for current map if catbot mode and autovote is on
|
||||
if (catbotmode && autovote_map)
|
||||
|
@ -39,6 +39,9 @@ static settings::Boolean god_mode{ "misc.god-mode", "false" };
|
||||
static settings::Boolean debug_info{ "misc.debug-info", "false" };
|
||||
static settings::Boolean no_homo{ "misc.no-homo", "true" };
|
||||
static settings::Boolean show_spectators{ "misc.show-spectators", "false" };
|
||||
static settings::Boolean misc_drawhitboxes{ "misc.draw-hitboxes", "false" };
|
||||
// Useful for debugging with showlagcompensation
|
||||
static settings::Boolean misc_drawhitboxes_dead{ "misc.draw-hitboxes.dead-players", "false" };
|
||||
#endif
|
||||
|
||||
#if !ENFORCE_STREAM_SAFETY && ENABLE_VISUALS
|
||||
@ -109,7 +112,7 @@ static ConVar *teammatesPushaway{ nullptr };
|
||||
|
||||
int getCarriedBuilding()
|
||||
{
|
||||
if (CE_BYTE(LOCAL_E, netvar.m_bCarryingObject))
|
||||
if (CE_INT(LOCAL_E, netvar.m_bCarryingObject))
|
||||
return HandleToIDX(CE_INT(LOCAL_E, netvar.m_hCarriedObject));
|
||||
for (int i = 1; i < MAX_ENTITIES; i++)
|
||||
{
|
||||
@ -118,15 +121,57 @@ int getCarriedBuilding()
|
||||
continue;
|
||||
if (HandleToIDX(CE_INT(ent, netvar.m_hBuilder)) != LOCAL_E->m_IDX)
|
||||
continue;
|
||||
if (!CE_BYTE(ent, netvar.m_bPlacing))
|
||||
if (!CE_INT(ent, netvar.m_bPlacing))
|
||||
continue;
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
#if ENABLE_VISUALS
|
||||
|
||||
struct wireframe_data
|
||||
{
|
||||
Vector raw_min;
|
||||
Vector raw_max;
|
||||
Vector rotation;
|
||||
Vector origin;
|
||||
};
|
||||
|
||||
std::vector<wireframe_data> wireframe_queue;
|
||||
void QueueWireframeHitboxes(hitbox_cache::EntityHitboxCache &hb_cache)
|
||||
{
|
||||
for (int i = 0; i < hb_cache.GetNumHitboxes(); i++)
|
||||
{
|
||||
auto hb = hb_cache.GetHitbox(i);
|
||||
Vector raw_min = hb->bbox->bbmin;
|
||||
Vector raw_max = hb->bbox->bbmax;
|
||||
auto transform = hb_cache.GetBones()[hb->bbox->bone];
|
||||
Vector rotation;
|
||||
Vector origin;
|
||||
|
||||
MatrixAngles(transform, *(QAngle *) &rotation, origin);
|
||||
wireframe_queue.push_back(wireframe_data{ raw_min, raw_max, rotation, origin });
|
||||
}
|
||||
}
|
||||
void DrawWireframeHitbox(wireframe_data data)
|
||||
{
|
||||
g_IVDebugOverlay->AddBoxOverlay2(data.origin, data.raw_min, data.raw_max, VectorToQAngle(data.rotation), Color(0, 0, 0, 0), Color(255, 0, 0, 255), g_GlobalVars->interval_per_tick * 2);
|
||||
}
|
||||
#endif
|
||||
void CreateMove()
|
||||
{
|
||||
#if ENABLE_VISUALS
|
||||
if (misc_drawhitboxes)
|
||||
{
|
||||
for (int i = 0; i <= g_IEngine->GetMaxClients(); i++)
|
||||
{
|
||||
auto ent = ENTITY(i);
|
||||
if (CE_INVALID(ent) || ent == LOCAL_E || (!misc_drawhitboxes_dead && !ent->m_bAlivePlayer()))
|
||||
continue;
|
||||
QueueWireframeHitboxes(ent->hitboxes);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (current_user_cmd->command_number)
|
||||
last_number = current_user_cmd->command_number;
|
||||
// AntiAfk That after a certian time without movement keys depressed, causes
|
||||
@ -222,8 +267,14 @@ void CreateMove()
|
||||
|
||||
#if ENABLE_VISUALS
|
||||
// Timer ussr{};
|
||||
void DrawText()
|
||||
void Draw()
|
||||
{
|
||||
if (misc_drawhitboxes)
|
||||
{
|
||||
for (auto &entry : wireframe_queue)
|
||||
DrawWireframeHitbox(entry);
|
||||
wireframe_queue.clear();
|
||||
}
|
||||
/*if (ussr.test_and_set(207000))
|
||||
{
|
||||
g_ISurface->PlaySound()
|
||||
@ -773,7 +824,7 @@ static InitRoutine init([]() {
|
||||
EC::Register(EC::Shutdown, Shutdown, "draw_local_player", EC::average);
|
||||
EC::Register(EC::CreateMove, CreateMove, "cm_misc_hacks", EC::average);
|
||||
#if ENABLE_VISUALS
|
||||
EC::Register(EC::Draw, DrawText, "draw_misc_hacks", EC::average);
|
||||
EC::Register(EC::Draw, Draw, "draw_misc_hacks", EC::average);
|
||||
#if !ENFORCE_STREAM_SAFETY
|
||||
if (render_zoomed)
|
||||
tryPatchLocalPlayerShouldDraw(true);
|
||||
|
@ -18,6 +18,7 @@ static settings::Int sandwichaim_aimkey_mode{ "sandwichaim.aimkey-mode", "0" };
|
||||
float sandwich_speed = 350.0f;
|
||||
float grav = 0.25f;
|
||||
int prevent = -1;
|
||||
|
||||
std::pair<CachedEntity *, Vector> FindBestEnt(bool teammate, bool Predict, bool zcheck)
|
||||
{
|
||||
CachedEntity *bestent = nullptr;
|
||||
@ -190,9 +191,11 @@ static void SandwichAim()
|
||||
g_pLocalPlayer->bUseSilentAngles = true;
|
||||
}
|
||||
}
|
||||
|
||||
static bool charge_aimbotted = false;
|
||||
static settings::Boolean charge_aim{ "chargeaim.enable", "false" };
|
||||
static settings::Button charge_key{ "chargeaim.key", "<null>" };
|
||||
|
||||
static void ChargeAimbot()
|
||||
{
|
||||
charge_aimbotted = false;
|
||||
@ -269,12 +272,243 @@ static void SapperAimbot()
|
||||
}
|
||||
}
|
||||
}
|
||||
// auto repair
|
||||
static settings::Int autorepair_priority{ "autorepair.priority", "0" };
|
||||
static settings::Boolean autorepair_enabled("autorepair.enabled", "false");
|
||||
static settings::Boolean autorepair_silent("autorepair.silent", "true");
|
||||
static settings::Boolean autorepair_repair_sentry("autorepair.sentry", "false");
|
||||
static settings::Boolean autorepair_repair_dispenser("autorepair.dispenser", "false");
|
||||
static settings::Boolean autorepair_repair_teleport("autorepair.teleport", "false");
|
||||
|
||||
// auto upgrade
|
||||
static settings::Boolean autoupgrade_enabled("autoupgrade.enabled", "false");
|
||||
static settings::Boolean autoupgrade_sentry("autoupgrade.sentry", "false");
|
||||
static settings::Boolean autoupgrade_dispenser("autoupgrade.dispenser", "false");
|
||||
static settings::Boolean autoupgrade_teleport("autoupgrade.teleport", "false");
|
||||
static settings::Int autoupgrade_sentry_level("autoupgrade.sentry.level", "3");
|
||||
static settings::Int autoupgrade_dispenser_level("autoupgrade.dispenser.level", "3");
|
||||
static settings::Int autoupgrade_teleport_level("autoupgrade.teleport.level", "2");
|
||||
|
||||
bool ShouldHitBuilding(CachedEntity *ent)
|
||||
{
|
||||
if (!autoupgrade_enabled && !autorepair_enabled)
|
||||
return false;
|
||||
// Current Metal
|
||||
int cur_ammo = CE_INT(LOCAL_E, netvar.m_iAmmo + 12);
|
||||
// Autorepair is on
|
||||
if (autorepair_enabled)
|
||||
{
|
||||
// Special Sentry logic
|
||||
if (ent->m_iClassID() == CL_CLASS(CObjectSentrygun))
|
||||
{
|
||||
// Current sentry ammo
|
||||
int sentry_ammo = CE_INT(ent, netvar.m_iAmmoShells);
|
||||
// Max Sentry ammo
|
||||
int max_ammo = 0;
|
||||
|
||||
// Set Ammo depending on level
|
||||
switch (CE_INT(ent, netvar.iUpgradeLevel))
|
||||
{
|
||||
case 1:
|
||||
max_ammo = 150;
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
max_ammo = 200;
|
||||
}
|
||||
|
||||
// Sentry needs ammo
|
||||
if (sentry_ammo < max_ammo)
|
||||
return true;
|
||||
}
|
||||
// Buildings needs to be repaired
|
||||
if (cur_ammo && ent->m_iHealth() != ent->m_iMaxHealth())
|
||||
return true;
|
||||
}
|
||||
// Autoupgrade is on
|
||||
if (autoupgrade_enabled)
|
||||
{
|
||||
// Upgrade lvel
|
||||
int upgrade_level = CE_INT(ent, netvar.iUpgradeLevel);
|
||||
|
||||
// Don't upgrade mini sentries
|
||||
if (CE_BYTE(ent, netvar.m_bMiniBuilding))
|
||||
return false;
|
||||
|
||||
// Rvar to check
|
||||
int level = 0;
|
||||
|
||||
// Pick The right rvar to check depending on building type
|
||||
switch (ent->m_iClassID())
|
||||
{
|
||||
|
||||
case CL_CLASS(CObjectSentrygun):
|
||||
// Enabled check
|
||||
if (!autoupgrade_sentry)
|
||||
return false;
|
||||
level = *autoupgrade_sentry_level;
|
||||
break;
|
||||
|
||||
case CL_CLASS(CObjectDispenser):
|
||||
// Enabled check
|
||||
if (!autoupgrade_dispenser)
|
||||
return false;
|
||||
level = *autoupgrade_dispenser_level;
|
||||
break;
|
||||
|
||||
case CL_CLASS(CObjectTeleporter):
|
||||
// Enabled check
|
||||
if (!autoupgrade_teleport)
|
||||
return false;
|
||||
level = *autoupgrade_teleport_level;
|
||||
break;
|
||||
}
|
||||
|
||||
// Can be upgraded
|
||||
if (upgrade_level < level && cur_ammo)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
CachedEntity *targetBuilding(bool priority)
|
||||
{
|
||||
float wrench_range = re::C_TFWeaponBaseMelee::GetSwingRange(RAW_ENT(LOCAL_W));
|
||||
CachedEntity *target = nullptr;
|
||||
float distance = FLT_MAX;
|
||||
for (int i = 0; i < entity_cache::max; i++)
|
||||
{
|
||||
CachedEntity *ent = ENTITY(i);
|
||||
|
||||
if (CE_BAD(ent))
|
||||
continue;
|
||||
|
||||
// can't exactly repair Merasmus
|
||||
if (ent->m_Type() != ENTITY_BUILDING)
|
||||
continue;
|
||||
|
||||
// yes, repair enemy buildings
|
||||
if (ent->m_bEnemy())
|
||||
continue;
|
||||
|
||||
float new_distance = g_pLocalPlayer->v_Eye.DistTo(GetBuildingPosition(ent));
|
||||
|
||||
// Further away than old one
|
||||
if (new_distance >= distance)
|
||||
continue;
|
||||
|
||||
auto id = ent->m_iClassID();
|
||||
|
||||
switch (id)
|
||||
{
|
||||
|
||||
case CL_CLASS(CObjectSentrygun):
|
||||
{
|
||||
if (priority && *autorepair_priority != 1)
|
||||
continue;
|
||||
// Don't repair sentries
|
||||
if (!autorepair_repair_sentry && !autoupgrade_sentry)
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
|
||||
case CL_CLASS(CObjectDispenser):
|
||||
{
|
||||
if (priority && *autorepair_priority != 2)
|
||||
continue;
|
||||
// Repair Dispensers check
|
||||
if (!autorepair_repair_dispenser && !autoupgrade_dispenser)
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
|
||||
case CL_CLASS(CObjectTeleporter):
|
||||
{
|
||||
if (priority && *autorepair_priority != 3)
|
||||
continue;
|
||||
// Repair Teleporters check
|
||||
if (!autorepair_repair_teleport && !autoupgrade_teleport)
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
|
||||
float s_distance = ent->m_vecOrigin().DistTo(LOCAL_E->m_vecOrigin());
|
||||
|
||||
if (!ShouldHitBuilding(ent))
|
||||
continue;
|
||||
|
||||
if (s_distance > wrench_range)
|
||||
continue;
|
||||
|
||||
target = ent;
|
||||
|
||||
distance = new_distance;
|
||||
}
|
||||
return target;
|
||||
};
|
||||
|
||||
static void BuildingAimbot()
|
||||
{
|
||||
if (!autorepair_enabled && !autoupgrade_enabled)
|
||||
return;
|
||||
|
||||
if (CE_BAD(LOCAL_E) || CE_BAD(LOCAL_W))
|
||||
return;
|
||||
|
||||
CachedEntity *target = nullptr;
|
||||
// Metal
|
||||
int cur_ammo = CE_INT(LOCAL_E, netvar.m_iAmmo + 12);
|
||||
float wrench_range = re::C_TFWeaponBaseMelee::GetSwingRange(RAW_ENT(LOCAL_W));
|
||||
// Center is further away than actual hit range for buildings, so add some more
|
||||
wrench_range += 50.f;
|
||||
|
||||
if (cur_ammo == 0)
|
||||
return;
|
||||
|
||||
if (g_pLocalPlayer->clazz != tf_engineer)
|
||||
return;
|
||||
|
||||
if (GetWeaponMode() != weaponmode::weapon_melee)
|
||||
return;
|
||||
|
||||
// Get priority buildings
|
||||
if (autorepair_priority)
|
||||
target = targetBuilding(true);
|
||||
// No building found
|
||||
if (!target)
|
||||
targetBuilding(false);
|
||||
|
||||
// We have a target
|
||||
if (target)
|
||||
{
|
||||
Vector angle = GetAimAtAngles(g_pLocalPlayer->v_Eye, GetBuildingPosition(target));
|
||||
Vector forward = GetForwardVector(g_pLocalPlayer->v_Eye, angle, wrench_range);
|
||||
|
||||
trace_t trace;
|
||||
|
||||
if (IsEntityVectorVisible(target, forward, MASK_SHOT, &trace))
|
||||
{
|
||||
if (trace.DidHit() && (IClientEntity *) trace.m_pEnt == RAW_ENT(target))
|
||||
{
|
||||
current_user_cmd->viewangles = angle;
|
||||
if (autorepair_silent)
|
||||
g_pLocalPlayer->bUseSilentAngles = true;
|
||||
current_user_cmd->buttons |= IN_ATTACK;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void CreateMove()
|
||||
{
|
||||
SandwichAim();
|
||||
ChargeAimbot();
|
||||
SapperAimbot();
|
||||
BuildingAimbot();
|
||||
}
|
||||
|
||||
static InitRoutine init([]() {
|
||||
|
@ -5,6 +5,8 @@
|
||||
#include "Aimbot.hpp"
|
||||
#include "FollowBot.hpp"
|
||||
#include "soundcache.hpp"
|
||||
#include "Misc.hpp"
|
||||
#include "MiscTemporary.hpp"
|
||||
|
||||
namespace hacks::tf2::NavBot
|
||||
{
|
||||
@ -13,6 +15,7 @@ static settings::Boolean enabled("navbot.enabled", "false");
|
||||
static settings::Boolean stay_near("navbot.stay-near", "true");
|
||||
static settings::Boolean heavy_mode("navbot.other-mode", "false");
|
||||
static settings::Boolean spy_mode("navbot.spy-mode", "false");
|
||||
static settings::Boolean engineer_mode("navbot.engineer-mode", "false");
|
||||
static settings::Boolean get_health("navbot.get-health-and-ammo", "true");
|
||||
static settings::Float jump_distance("navbot.autojump.trigger-distance", "300");
|
||||
static settings::Boolean autojump("navbot.autojump.enabled", "false");
|
||||
@ -22,31 +25,88 @@ static settings::Int spy_ignore_time("navbot.spy-ignore-time", "5000");
|
||||
// -Forward declarations-
|
||||
bool init(bool first_cm);
|
||||
static bool navToSniperSpot();
|
||||
static bool navToBuildingSpot();
|
||||
static bool stayNear();
|
||||
static bool getDispenserHealthAndAmmo();
|
||||
static bool getHealthAndAmmo();
|
||||
static bool stayNearEngineer();
|
||||
static bool getDispenserHealthAndAmmo(int metal = -1);
|
||||
static bool getHealthAndAmmo(int metal = -1);
|
||||
static void autoJump();
|
||||
static void updateSlot();
|
||||
static void update_building_spots();
|
||||
static bool engineerLogic();
|
||||
static std::pair<CachedEntity *, float> getNearestPlayerDistance(bool vischeck = true);
|
||||
using task::current_engineer_task;
|
||||
using task::current_task;
|
||||
|
||||
// -Variables-
|
||||
static std::vector<std::pair<CNavArea *, Vector>> sniper_spots;
|
||||
static std::vector<std::pair<CNavArea *, Vector>> building_spots;
|
||||
static std::vector<CNavArea *> blacklisted_build_spots;
|
||||
// Our Buildings. We need this so we can remove them on object_destroyed.
|
||||
static std::vector<CachedEntity *> local_buildings;
|
||||
// Needed for blacklisting
|
||||
static CNavArea *current_build_area;
|
||||
// How long should the bot wait until pathing again?
|
||||
static Timer wait_until_path{};
|
||||
// Engineer version of above
|
||||
static Timer wait_until_path_engineer{};
|
||||
// Time before following target cloaked spy again
|
||||
static std::array<Timer, PLAYER_ARRAY_SIZE> spy_cloak{};
|
||||
// Don't spam spy path thanks
|
||||
static Timer spy_path{};
|
||||
// Big wait between updating Engineer building spots
|
||||
static Timer engineer_update{};
|
||||
// Recheck Building Area
|
||||
static Timer engineer_recheck{};
|
||||
// Timer for resetting Build attempts
|
||||
static Timer build_timer{};
|
||||
// Timer for wait between rotation and checking if we can place
|
||||
static Timer rotation_timer{};
|
||||
// Uses to check how long until we should resend the "build" command
|
||||
static Timer build_command_timer{};
|
||||
// Dispenser Nav cooldown
|
||||
static Timer dispenser_nav_timer{};
|
||||
// Last Yaw used for building
|
||||
static float build_current_rotation = -180.0f;
|
||||
// How many times have we tried to place?
|
||||
static int build_attempts = 0;
|
||||
// Enum for Building types
|
||||
enum Building
|
||||
{
|
||||
None = -1,
|
||||
Dispenser = 0,
|
||||
TP_Entrace,
|
||||
Sentry,
|
||||
TP_Exit
|
||||
};
|
||||
|
||||
// Successfully built? (Unknown == Bot is still trying to build and isn't sure if it will work or not yet)
|
||||
enum success_build
|
||||
{
|
||||
Failure = 0,
|
||||
Unknown,
|
||||
Success
|
||||
};
|
||||
|
||||
// What is the bot currently doing
|
||||
namespace task
|
||||
{
|
||||
Task current_task = task::none;
|
||||
}
|
||||
Task current_task = task::none;
|
||||
engineer_task current_engineer_task = engineer_task::nothing;
|
||||
} // namespace task
|
||||
|
||||
constexpr bot_class_config DIST_SPY{ 10.0f, 50.0f, 1000.0f };
|
||||
constexpr bot_class_config DIST_OTHER{ 100.0f, 200.0f, 300.0f };
|
||||
constexpr bot_class_config DIST_SNIPER{ 1000.0f, 1500.0f, 3000.0f };
|
||||
constexpr bot_class_config DIST_ENGINEER{ 600.0f, 1000.0f, 2500.0f };
|
||||
|
||||
// Gunslinger Engineers really don't care at all
|
||||
constexpr bot_class_config DIST_GUNSLINGER_ENGINEER{ 100.0f, 300.0f, 500.0f };
|
||||
|
||||
inline bool HasGunslinger(CachedEntity *ent)
|
||||
{
|
||||
return HasWeapon(ent, 142);
|
||||
}
|
||||
static void CreateMove()
|
||||
{
|
||||
if (CE_BAD(LOCAL_E) || !LOCAL_E->m_bAlivePlayer() || !LOCAL_E->m_bAlivePlayer())
|
||||
@ -65,17 +125,42 @@ static void CreateMove()
|
||||
autoJump();
|
||||
if (primary_only)
|
||||
updateSlot();
|
||||
if (engineer_mode)
|
||||
{
|
||||
if (CE_GOOD(LOCAL_E))
|
||||
{
|
||||
for (int i = g_IEngine->GetMaxClients() + 1; i < MAX_ENTITIES; i++)
|
||||
{
|
||||
CachedEntity *ent = ENTITY(i);
|
||||
if (!ent || CE_BAD(ent) || ent->m_bEnemy() || !ent->m_bAlivePlayer())
|
||||
continue;
|
||||
if (HandleToIDX(CE_INT(ent, netvar.m_hBuilder)) != LOCAL_E->m_IDX)
|
||||
continue;
|
||||
if (std::find(local_buildings.begin(), local_buildings.end(), ent) == local_buildings.end())
|
||||
local_buildings.push_back(ent);
|
||||
}
|
||||
update_building_spots();
|
||||
}
|
||||
}
|
||||
|
||||
if (get_health)
|
||||
{
|
||||
if (getDispenserHealthAndAmmo())
|
||||
int metal = -1;
|
||||
if (engineer_mode && g_pLocalPlayer->clazz == tf_engineer)
|
||||
metal = CE_INT(LOCAL_E, netvar.m_iAmmo + 12);
|
||||
if ((dispenser_nav_timer.test_and_set(1000) && getDispenserHealthAndAmmo(metal)))
|
||||
return;
|
||||
if (getHealthAndAmmo())
|
||||
if (getHealthAndAmmo(metal))
|
||||
return;
|
||||
}
|
||||
|
||||
// Engineer stuff
|
||||
if (engineer_mode && g_pLocalPlayer->clazz == tf_engineer)
|
||||
if (engineerLogic())
|
||||
return;
|
||||
|
||||
if (blocking)
|
||||
return;
|
||||
|
||||
// Spy can just walk into the enemy
|
||||
if (spy_mode)
|
||||
{
|
||||
@ -127,6 +212,8 @@ bool init(bool first_cm)
|
||||
return false;
|
||||
if (!inited)
|
||||
{
|
||||
blacklisted_build_spots.clear();
|
||||
local_buildings.clear();
|
||||
sniper_spots.clear();
|
||||
// Add all sniper spots to vector
|
||||
for (auto &area : nav::navfile->m_areas)
|
||||
@ -140,6 +227,115 @@ bool init(bool first_cm)
|
||||
return true;
|
||||
}
|
||||
|
||||
struct area_struct
|
||||
{
|
||||
// The Area
|
||||
CNavArea *navarea;
|
||||
// Distance away from enemies
|
||||
float min_distance;
|
||||
// Valid enemies to area
|
||||
std::vector<Vector *> enemy_list;
|
||||
};
|
||||
|
||||
void update_building_spots()
|
||||
{
|
||||
if (engineer_update.test_and_set(10000))
|
||||
{
|
||||
building_spots.clear();
|
||||
// Store in here to reduce operations
|
||||
std::vector<Vector> enemy_positions;
|
||||
// Stores valid areas, the float is the minimum distance away from enemies, needed for sorting later
|
||||
std::vector<area_struct> areas;
|
||||
|
||||
for (int i = 0; i <= g_IEngine->GetMaxClients(); i++)
|
||||
{
|
||||
CachedEntity *ent = ENTITY(i);
|
||||
// Grab only Enemies and only if they are in soundcache
|
||||
if (!ent || CE_INVALID(ent) || !ent->m_bAlivePlayer() || !ent->m_bEnemy())
|
||||
continue;
|
||||
if (ent->m_vecDormantOrigin())
|
||||
enemy_positions.push_back(*ent->m_vecDormantOrigin());
|
||||
}
|
||||
auto config = &DIST_ENGINEER;
|
||||
if (HasGunslinger(LOCAL_E))
|
||||
config = &DIST_GUNSLINGER_ENGINEER;
|
||||
for (auto &area : nav::navfile->m_areas)
|
||||
{
|
||||
// Blacklisted for building
|
||||
if (std::find(blacklisted_build_spots.begin(), blacklisted_build_spots.end(), &area) != blacklisted_build_spots.end())
|
||||
continue;
|
||||
|
||||
// These positions we should vischeck
|
||||
std::vector<Vector *> vischeck_positions;
|
||||
|
||||
// Minimum distance the area was away from enemies
|
||||
float min_dist_away = FLT_MAX;
|
||||
|
||||
// Area Center
|
||||
auto area_pos = area.m_center;
|
||||
// Don't want to instantly hit the floor
|
||||
area_pos.z += 42.0f;
|
||||
|
||||
// Found enemy below min/above max range away from area
|
||||
bool enemy_found = false;
|
||||
bool out_of_reach = true;
|
||||
|
||||
for (auto &pos : enemy_positions)
|
||||
{
|
||||
auto dist = area_pos.DistTo(pos);
|
||||
if (dist < config->min)
|
||||
{
|
||||
enemy_found = true;
|
||||
break;
|
||||
}
|
||||
// Found someone within min and max range
|
||||
if (dist < config->max)
|
||||
{
|
||||
out_of_reach = false;
|
||||
// Should vischeck this one
|
||||
vischeck_positions.push_back(&pos);
|
||||
if (dist < min_dist_away)
|
||||
min_dist_away = dist;
|
||||
}
|
||||
}
|
||||
// Too close/Too far away
|
||||
if (enemy_found || out_of_reach)
|
||||
continue;
|
||||
|
||||
// Area is valid (Distance wise)
|
||||
areas.push_back({ &area, min_dist_away, vischeck_positions });
|
||||
}
|
||||
|
||||
// Sort, be as close to preferred as possible
|
||||
std::sort(areas.begin(), areas.end(), [&](area_struct a, area_struct b) { return std::abs(a.min_distance - config->preferred) < std::abs(b.min_distance - config->preferred); });
|
||||
|
||||
// Still need to do vischeck stuff
|
||||
for (auto &area : areas)
|
||||
{
|
||||
// Is the enemy able to see the area?
|
||||
bool can_see_area = false;
|
||||
// Area Center
|
||||
auto area_pos = area.navarea->m_center;
|
||||
// Don't want to instantly hit the floor
|
||||
area_pos.z += 42.0f;
|
||||
// Loop all valid enemies
|
||||
for (auto pos : area.enemy_list)
|
||||
{
|
||||
if (IsVectorVisible(area_pos, *pos))
|
||||
{
|
||||
can_see_area = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Someone can see the area. Abort! (Gunslinger Engineer does not care)
|
||||
if (can_see_area && !HasGunslinger(LOCAL_E))
|
||||
continue;
|
||||
// All good!
|
||||
building_spots.push_back(std::pair<CNavArea *, Vector>(area.navarea, area.navarea->m_center));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool navToSniperSpot()
|
||||
{
|
||||
// Don't path if you already have commands. But also don't error out.
|
||||
@ -165,6 +361,315 @@ static bool navToSniperSpot()
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool navToBuildingSpot()
|
||||
{
|
||||
// Don't path if you already have commands. But also don't error out.
|
||||
if (!nav::ReadyForCommands || (current_task != task::engineer && current_task != task::none))
|
||||
return true;
|
||||
// Wait a bit before pathing again
|
||||
if (!wait_until_path_engineer.test_and_set(2000))
|
||||
return false;
|
||||
// Max 10 attempts
|
||||
for (int attempts = 0; attempts < 10 && attempts < building_spots.size(); attempts++)
|
||||
{
|
||||
// Get a Building spot
|
||||
auto &area = building_spots[attempts];
|
||||
// Check if spot is considered safe (no sentry, no sticky)
|
||||
if (!nav::isSafe(area.first))
|
||||
continue;
|
||||
// Try to nav there
|
||||
if (nav::navTo(area.second, 5, true, true, false))
|
||||
{
|
||||
current_task = { task::engineer, 5 };
|
||||
current_build_area = area.first;
|
||||
current_engineer_task = task::engineer_task::goto_build_spot;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static Building selectBuilding()
|
||||
{
|
||||
int metal = CE_INT(LOCAL_E, netvar.m_iAmmo + 12);
|
||||
int metal_sentry = 130;
|
||||
|
||||
// We have a mini sentry, costs less
|
||||
if (HasGunslinger(LOCAL_E))
|
||||
metal_sentry = 100;
|
||||
|
||||
// Do we already have these?
|
||||
bool sentry_built = false;
|
||||
bool dispenser_built = false;
|
||||
// Loop all buildings
|
||||
for (auto &building : local_buildings)
|
||||
{
|
||||
if (building->m_iClassID() == CL_CLASS(CObjectSentrygun))
|
||||
sentry_built = true;
|
||||
else if (building->m_iClassID() == CL_CLASS(CObjectDispenser))
|
||||
dispenser_built = true;
|
||||
}
|
||||
|
||||
if (metal >= metal_sentry && !sentry_built)
|
||||
return Sentry;
|
||||
else if (metal >= 100 && !dispenser_built)
|
||||
return Dispenser;
|
||||
return None;
|
||||
}
|
||||
|
||||
static success_build buildBuilding()
|
||||
{
|
||||
int metal = CE_INT(LOCAL_E, netvar.m_iAmmo + 12);
|
||||
// Out of Metal
|
||||
if (metal < 100)
|
||||
return Failure;
|
||||
// Last building
|
||||
static Building last_building = selectBuilding();
|
||||
// Get best building to build right now
|
||||
Building building = selectBuilding();
|
||||
// Reset Rotation on these conditions
|
||||
if (building != last_building || build_timer.check(1000))
|
||||
{
|
||||
// We changed the target building, means it was successful!
|
||||
if (!build_timer.check(1000))
|
||||
return Success;
|
||||
|
||||
// No building
|
||||
if (building == None)
|
||||
return Failure;
|
||||
|
||||
build_attempts = 0;
|
||||
build_current_rotation = -180.0f;
|
||||
build_timer.update();
|
||||
}
|
||||
// No building
|
||||
if (building == None)
|
||||
return Failure;
|
||||
|
||||
last_building = building;
|
||||
build_timer.update();
|
||||
if (rotation_timer.test_and_set(300))
|
||||
{
|
||||
// Look slightly downwards for building process
|
||||
current_user_cmd->viewangles.x = 20.0f;
|
||||
// Set Yaw
|
||||
current_user_cmd->viewangles.y = build_current_rotation;
|
||||
// Rotate
|
||||
build_current_rotation += 20.0f;
|
||||
build_attempts++;
|
||||
// Put building in hand if not already
|
||||
if (hacks::shared::misc::getCarriedBuilding() == -1 && build_command_timer.test_and_set(50))
|
||||
g_IEngine->ClientCmd_Unrestricted(format("build ", building).c_str());
|
||||
}
|
||||
else if (rotation_timer.check(200))
|
||||
{
|
||||
if (hacks::shared::misc::getCarriedBuilding() != -1)
|
||||
{
|
||||
int carried_building = hacks::shared::misc::getCarriedBuilding();
|
||||
// It works! Place building
|
||||
if (CE_INT(ENTITY(carried_building), netvar.m_bCanPlace))
|
||||
current_user_cmd->buttons |= IN_ATTACK;
|
||||
}
|
||||
}
|
||||
// Bad area
|
||||
if (build_attempts >= 14)
|
||||
{
|
||||
blacklisted_build_spots.push_back(current_build_area);
|
||||
return Failure;
|
||||
}
|
||||
return Unknown;
|
||||
}
|
||||
|
||||
static bool navToBuilding(CachedEntity *target = nullptr)
|
||||
{
|
||||
if (local_buildings.size())
|
||||
{
|
||||
int priority = 5;
|
||||
if (current_engineer_task == task::staynear_engineer)
|
||||
priority = 7;
|
||||
// Just grab target and nav there
|
||||
if (target)
|
||||
if (nav::navTo(target->m_vecOrigin(), priority, true))
|
||||
{
|
||||
current_task = { task::engineer, priority };
|
||||
current_engineer_task = task::engineer_task::goto_building;
|
||||
return true;
|
||||
}
|
||||
// Nav to random building
|
||||
for (auto &building : local_buildings)
|
||||
{
|
||||
if (nav::navTo(building->m_vecOrigin(), priority, true))
|
||||
{
|
||||
current_task = { task::engineer, priority };
|
||||
current_engineer_task = task::engineer_task::goto_building;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool engineerLogic()
|
||||
{
|
||||
std::vector<CachedEntity *> new_building_list;
|
||||
for (auto &building : local_buildings)
|
||||
if (CE_VALID(building) && !CE_INT(building, netvar.m_bPlacing))
|
||||
new_building_list.push_back(building);
|
||||
local_buildings = new_building_list;
|
||||
|
||||
// Overwrites and Not yet running engineer task
|
||||
if ((current_task != task::engineer || current_engineer_task == task::engineer_task::nothing || current_engineer_task == task::engineer_task::staynear_engineer) && current_task != task::health && current_task != task::ammo)
|
||||
{
|
||||
// Already have a building
|
||||
if (local_buildings.size())
|
||||
{
|
||||
int metal = CE_INT(LOCAL_E, netvar.m_iAmmo + 12);
|
||||
if (metal)
|
||||
for (auto &building : local_buildings)
|
||||
// Hey hit the building thanks (gunslinger engineer shouldn't care)
|
||||
if (hacks::tf2::misc_aimbot::ShouldHitBuilding(building) && !HasGunslinger(LOCAL_E))
|
||||
{
|
||||
if (navToBuilding(building))
|
||||
return true;
|
||||
}
|
||||
|
||||
// Let's terrify some people (gunslinger engineer)
|
||||
if (HasGunslinger(LOCAL_E))
|
||||
stayNearEngineer();
|
||||
|
||||
else if (selectBuilding() != None)
|
||||
{
|
||||
// If we're near our buildings and have the metal, build another one
|
||||
for (auto &building : local_buildings)
|
||||
if (building->m_vecOrigin().DistTo(LOCAL_E->m_vecOrigin()) <= 300.0f)
|
||||
{
|
||||
current_task = { task::engineer, 4 };
|
||||
current_engineer_task = task::engineer_task::build_building;
|
||||
return true;
|
||||
}
|
||||
// We're too far away, go to building
|
||||
else if (navToBuilding())
|
||||
return true;
|
||||
}
|
||||
// If it's metal we're missing, get some metal
|
||||
/*else if (metal < 100)
|
||||
{
|
||||
if ((dispenser_nav_timer.test_and_set(1000) && getDispenserHealthAndAmmo(metal)) || getHealthAndAmmo(metal))
|
||||
return true;
|
||||
}*/
|
||||
// Else just Roam around the map and kill people
|
||||
else if (stayNearEngineer())
|
||||
return true;
|
||||
}
|
||||
// Nav to a Building spot
|
||||
else if (navToBuildingSpot())
|
||||
{
|
||||
engineer_recheck.update();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// Metal
|
||||
int metal = CE_INT(LOCAL_E, netvar.m_iAmmo + 12);
|
||||
/*if ((dispenser_nav_timer.test_and_set(1000) && getDispenserHealthAndAmmo(metal)) || getHealthAndAmmo(metal))
|
||||
return true;*/
|
||||
switch (current_engineer_task)
|
||||
{
|
||||
// Upgrade/repair
|
||||
case (task::engineer_task::upgradeorrepair_building):
|
||||
{
|
||||
if (metal)
|
||||
if (local_buildings.size())
|
||||
for (auto &building : local_buildings)
|
||||
{
|
||||
if (building->m_vecOrigin().DistTo(LOCAL_E->m_vecOrigin()) <= 300.0f)
|
||||
{
|
||||
if (hacks::tf2::misc_aimbot::ShouldHitBuilding(building))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
current_task = { task::engineer, 4 };
|
||||
current_engineer_task = task::engineer_task::nothing;
|
||||
}
|
||||
// Going to existing building
|
||||
case (task::engineer_task::goto_building):
|
||||
{
|
||||
if (nav::ReadyForCommands)
|
||||
{
|
||||
bool found = false;
|
||||
if (local_buildings.size())
|
||||
for (auto &building : local_buildings)
|
||||
{
|
||||
if (building->m_vecOrigin().DistTo(LOCAL_E->m_vecOrigin()) <= 300.0f)
|
||||
{
|
||||
if (metal && hacks::tf2::misc_aimbot::ShouldHitBuilding(building))
|
||||
{
|
||||
current_task = { task::engineer, 4 };
|
||||
current_engineer_task = task::engineer_task::upgradeorrepair_building;
|
||||
}
|
||||
if (current_engineer_task != task::engineer_task::upgradeorrepair_building)
|
||||
{
|
||||
current_task = { task::engineer, 4 };
|
||||
current_engineer_task = task::engineer_task::nothing;
|
||||
}
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
if (found)
|
||||
break;
|
||||
|
||||
current_task = { task::engineer, 4 };
|
||||
current_engineer_task = task::engineer_task::nothing;
|
||||
}
|
||||
break;
|
||||
}
|
||||
// Going to spot to build
|
||||
case (task::engineer_task::goto_build_spot):
|
||||
{
|
||||
// We Arrived, time to (try) to build!
|
||||
if (nav::ReadyForCommands)
|
||||
{
|
||||
current_task = { task::engineer, 4 };
|
||||
current_engineer_task = task::engineer_task::build_building;
|
||||
}
|
||||
else if (engineer_recheck.test_and_set(15000))
|
||||
{
|
||||
if (navToBuildingSpot())
|
||||
{
|
||||
engineer_recheck.update();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
// Build building
|
||||
case (task::engineer_task::build_building):
|
||||
{
|
||||
auto status = buildBuilding();
|
||||
// Failed, Get a new Task
|
||||
if (status == Failure)
|
||||
{
|
||||
current_task = { task::engineer, 4 };
|
||||
current_engineer_task = task::engineer_task::nothing;
|
||||
}
|
||||
else if (status == Success)
|
||||
{
|
||||
|
||||
current_task = { task::engineer, 4 };
|
||||
current_engineer_task = task::engineer_task::nothing;
|
||||
return true;
|
||||
}
|
||||
// Still building
|
||||
else if (status == Unknown)
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static std::pair<CachedEntity *, float> getNearestPlayerDistance(bool vischeck)
|
||||
{
|
||||
float distance = FLT_MAX;
|
||||
@ -204,7 +709,7 @@ static bool isValidNearPosition(Vector vec, Vector target, const bot_class_confi
|
||||
}
|
||||
|
||||
// Returns true if began pathing
|
||||
static bool stayNearPlayer(CachedEntity *&ent, const bot_class_config &config, CNavArea *&result)
|
||||
static bool stayNearPlayer(CachedEntity *&ent, const bot_class_config &config, CNavArea *&result, bool engineer = false)
|
||||
{
|
||||
if (!CE_VALID(ent))
|
||||
return false;
|
||||
@ -244,8 +749,14 @@ static bool stayNearPlayer(CachedEntity *&ent, const bot_class_config &config, C
|
||||
{
|
||||
if (nav::navTo(i->m_center, 7, true, false))
|
||||
{
|
||||
result = i;
|
||||
current_task = task::stay_near;
|
||||
result = i;
|
||||
if (engineer)
|
||||
{
|
||||
current_task = { task::engineer, 4 };
|
||||
current_engineer_task = task::staynear_engineer;
|
||||
}
|
||||
else
|
||||
current_task = task::stay_near;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -255,8 +766,14 @@ static bool stayNearPlayer(CachedEntity *&ent, const bot_class_config &config, C
|
||||
auto it = select_randomly(areas.begin(), areas.end());
|
||||
if (nav::navTo((*it.base())->m_center, 7, true, false))
|
||||
{
|
||||
result = *it.base();
|
||||
current_task = task::stay_near;
|
||||
result = *it.base();
|
||||
if (engineer)
|
||||
{
|
||||
current_task = { task::engineer, 4 };
|
||||
current_engineer_task = task::staynear_engineer;
|
||||
}
|
||||
else
|
||||
current_task = task::stay_near;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -300,6 +817,97 @@ static bool stayNearPlayers(const bot_class_config &config, CachedEntity *&resul
|
||||
}
|
||||
} // namespace stayNearHelpers
|
||||
|
||||
// stayNear()'s Little Texan brother
|
||||
static bool stayNearEngineer()
|
||||
{
|
||||
static CachedEntity *last_target = nullptr;
|
||||
static CNavArea *last_area = nullptr;
|
||||
|
||||
// What distances do we have to use?
|
||||
bot_class_config config = DIST_ENGINEER;
|
||||
if (HasGunslinger(LOCAL_E))
|
||||
config = DIST_GUNSLINGER_ENGINEER;
|
||||
|
||||
// Check if someone is too close to us and then target them instead
|
||||
std::pair<CachedEntity *, float> nearest = getNearestPlayerDistance();
|
||||
if (nearest.first && nearest.first != last_target && nearest.second < config.min)
|
||||
if (stayNearHelpers::stayNearPlayer(nearest.first, config, last_area, true))
|
||||
{
|
||||
last_target = nearest.first;
|
||||
return true;
|
||||
}
|
||||
bool valid_dormant = false;
|
||||
if (CE_VALID(last_target) && RAW_ENT(last_target)->IsDormant())
|
||||
{
|
||||
if (last_target->m_vecDormantOrigin())
|
||||
valid_dormant = true;
|
||||
}
|
||||
if (current_task == task::stay_near)
|
||||
{
|
||||
static Timer invalid_area_time{};
|
||||
static Timer invalid_target_time{};
|
||||
// Do we already have a stay near target? Check if its still good.
|
||||
if (CE_GOOD(last_target) || valid_dormant)
|
||||
invalid_target_time.update();
|
||||
else
|
||||
invalid_area_time.update();
|
||||
// Check if we still have LOS and are close enough/far enough
|
||||
Vector position;
|
||||
if (CE_GOOD(last_target) || valid_dormant)
|
||||
{
|
||||
position = *last_target->m_vecDormantOrigin();
|
||||
}
|
||||
if ((CE_GOOD(last_target) || valid_dormant) && stayNearHelpers::isValidNearPosition(last_area->m_center, position, config))
|
||||
invalid_area_time.update();
|
||||
|
||||
if ((CE_GOOD(last_target) || valid_dormant) && (!g_pPlayerResource->isAlive(last_target->m_IDX) || !last_target->m_bEnemy() || !player_tools::shouldTarget(last_target) || !spy_cloak[last_target->m_IDX].check(*spy_ignore_time) || (hacks::shared::aimbot::ignore_cloak && IsPlayerInvisible(last_target))))
|
||||
{
|
||||
if (hacks::shared::aimbot::ignore_cloak && IsPlayerInvisible(last_target))
|
||||
spy_cloak[last_target->m_IDX].update();
|
||||
nav::clearInstructions();
|
||||
current_engineer_task = task::engineer_task::nothing;
|
||||
}
|
||||
else if (invalid_area_time.test_and_set(300))
|
||||
{
|
||||
current_engineer_task = task::engineer_task::nothing;
|
||||
}
|
||||
else if (invalid_target_time.test_and_set(5000))
|
||||
{
|
||||
current_engineer_task = task::engineer_task::nothing;
|
||||
}
|
||||
}
|
||||
// Are we doing nothing? Check if our current location can still attack our
|
||||
// last target
|
||||
if (current_engineer_task != task::engineer_task::staynear_engineer && (CE_GOOD(last_target) || valid_dormant) && g_pPlayerResource->isAlive(last_target->m_IDX) && last_target->m_bEnemy())
|
||||
{
|
||||
if (hacks::shared::aimbot::ignore_cloak && IsPlayerInvisible(last_target))
|
||||
spy_cloak[last_target->m_IDX].update();
|
||||
if (spy_cloak[last_target->m_IDX].check(*spy_ignore_time))
|
||||
{
|
||||
Vector position = *last_target->m_vecDormantOrigin();
|
||||
|
||||
if (stayNearHelpers::isValidNearPosition(g_pLocalPlayer->v_Origin, position, config))
|
||||
return true;
|
||||
// If not, can we try pathing to our last target again?
|
||||
if (stayNearHelpers::stayNearPlayer(last_target, config, last_area, true))
|
||||
return true;
|
||||
}
|
||||
last_target = nullptr;
|
||||
}
|
||||
|
||||
static Timer wait_until_stay_near{};
|
||||
if (current_task == task::engineer_task::staynear_engineer)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if (wait_until_stay_near.test_and_set(4000))
|
||||
{
|
||||
// We're doing nothing? Do something!
|
||||
return stayNearHelpers::stayNearPlayers(config, last_target, last_area);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
// Main stay near function
|
||||
static bool stayNear()
|
||||
{
|
||||
@ -439,13 +1047,17 @@ static std::vector<Vector> getDispensers()
|
||||
continue;
|
||||
if (CE_BYTE(ent, netvar.m_bHasSapper))
|
||||
continue;
|
||||
if (CE_BYTE(ent, netvar.m_bBuilding))
|
||||
continue;
|
||||
if (CE_BYTE(ent, netvar.m_bPlacing))
|
||||
continue;
|
||||
dispensers.push_back(*ent->m_vecDormantOrigin());
|
||||
}
|
||||
std::sort(dispensers.begin(), dispensers.end(), [](Vector &a, Vector &b) { return g_pLocalPlayer->v_Origin.DistTo(a) < g_pLocalPlayer->v_Origin.DistTo(b); });
|
||||
return dispensers;
|
||||
}
|
||||
|
||||
static bool getDispenserHealthAndAmmo()
|
||||
static bool getDispenserHealthAndAmmo(int metal)
|
||||
{
|
||||
// Timeout for standing next to dispenser
|
||||
static Timer dispenser_timeout{};
|
||||
@ -453,6 +1065,12 @@ static bool getDispenserHealthAndAmmo()
|
||||
static Timer dispenser_cooldown{};
|
||||
float health = static_cast<float>(LOCAL_E->m_iHealth()) / LOCAL_E->m_iMaxHealth();
|
||||
bool lowAmmo = hasLowAmmo();
|
||||
if (metal != -1)
|
||||
{
|
||||
lowAmmo = metal < 100 && selectBuilding() == None;
|
||||
if (current_engineer_task == task::engineer_task::upgradeorrepair_building)
|
||||
lowAmmo = metal == 0;
|
||||
}
|
||||
// Check if we should cancel this task
|
||||
if (current_task == task::dispenser)
|
||||
{
|
||||
@ -510,10 +1128,16 @@ static bool getDispenserHealthAndAmmo()
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool getHealthAndAmmo()
|
||||
static bool getHealthAndAmmo(int metal)
|
||||
{
|
||||
float health = static_cast<float>(LOCAL_E->m_iHealth()) / LOCAL_E->m_iMaxHealth();
|
||||
bool lowAmmo = hasLowAmmo();
|
||||
if (metal != -1)
|
||||
{
|
||||
lowAmmo = metal < 100 && selectBuilding() == None;
|
||||
if (current_engineer_task == task::engineer_task::upgradeorrepair_building)
|
||||
lowAmmo = metal == 0;
|
||||
}
|
||||
// Check if we should cancel this task
|
||||
if (current_task == task::health || current_task == task::ammo)
|
||||
{
|
||||
@ -551,7 +1175,7 @@ static bool getHealthAndAmmo()
|
||||
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); });
|
||||
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, health < 0.64f || lowAmmo ? 10 : 3, true, false))
|
||||
@ -572,7 +1196,7 @@ static bool getHealthAndAmmo()
|
||||
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); });
|
||||
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, health < 0.64f || lowAmmo ? 9 : 3, true, false))
|
||||
@ -643,6 +1267,19 @@ static slots getBestSlot(slots active_slot)
|
||||
else
|
||||
return secondary;
|
||||
}
|
||||
case tf_engineer:
|
||||
{
|
||||
if (current_task == task::engineer)
|
||||
{
|
||||
// We cannot build the building if we keep switching away from the PDA
|
||||
if (current_engineer_task == task::engineer_task::build_building)
|
||||
return active_slot;
|
||||
// Use wrench to repair/upgrade
|
||||
if (current_engineer_task == task::engineer_task::upgradeorrepair_building)
|
||||
return melee;
|
||||
}
|
||||
return primary;
|
||||
}
|
||||
default:
|
||||
{
|
||||
if (nearest.second <= 400)
|
||||
@ -674,7 +1311,36 @@ static void updateSlot()
|
||||
}
|
||||
}
|
||||
|
||||
static InitRoutine runinit([]() { EC::Register(EC::CreateMove, CreateMove, "navbot", EC::early); });
|
||||
class ObjectDestroyListener : public IGameEventListener2
|
||||
{
|
||||
virtual void FireGameEvent(IGameEvent *event)
|
||||
{
|
||||
if (!isHackActive() || !engineer_mode)
|
||||
return;
|
||||
// Get index of destroyed object
|
||||
int index = event->GetInt("index");
|
||||
// Destroyed Entity
|
||||
CachedEntity *ent = ENTITY(index);
|
||||
// Get Entry in the vector
|
||||
auto it = std::find(local_buildings.begin(), local_buildings.end(), ent);
|
||||
// If found, erase
|
||||
if (it != local_buildings.end())
|
||||
local_buildings.erase(it);
|
||||
}
|
||||
};
|
||||
|
||||
ObjectDestroyListener &listener()
|
||||
{
|
||||
static ObjectDestroyListener object{};
|
||||
return object;
|
||||
}
|
||||
|
||||
static InitRoutine runinit([]() {
|
||||
g_IEventManager2->AddListener(&listener(), "object_destroyed", false);
|
||||
EC::Register(EC::CreateMove, CreateMove, "navbot", EC::early);
|
||||
EC::Register(
|
||||
EC::Shutdown, []() { g_IEventManager2->RemoveListener(&listener()); }, "navbot_shutdown");
|
||||
});
|
||||
|
||||
void change(settings::VariableBase<bool> &, bool)
|
||||
{
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
#include <hacks/Spam.hpp>
|
||||
#include <settings/Bool.hpp>
|
||||
#include <settings/String.hpp>
|
||||
#include "common.hpp"
|
||||
#include "MiscTemporary.hpp"
|
||||
|
||||
@ -18,6 +19,7 @@ static settings::String filename{ "spam.filename", "spam.txt" };
|
||||
static settings::Int spam_delay{ "spam.delay", "800" };
|
||||
static settings::Int voicecommand_spam{ "spam.voicecommand", "0" };
|
||||
static settings::Boolean teamname_spam{ "spam.teamname", "0" };
|
||||
static settings::String teamname_file{ "spam.teamname.file", "teamspam.txt" };
|
||||
static settings::Boolean team_only{ "spam.teamchat", "false" };
|
||||
|
||||
static int last_index;
|
||||
@ -234,6 +236,11 @@ bool FormatSpamMessage(std::string &message)
|
||||
return SubstituteQueries(message);
|
||||
}
|
||||
|
||||
// What to spam
|
||||
static std::vector<std::string> teamspam_text = { "CAT", "HOOK" };
|
||||
// Current spam index
|
||||
static int current_teamspam_idx = 0;
|
||||
|
||||
void createMove()
|
||||
{
|
||||
IF_GAME(IsTF2())
|
||||
@ -243,16 +250,13 @@ void createMove()
|
||||
{
|
||||
if (!(g_GlobalVars->tickcount % 10))
|
||||
{
|
||||
static bool teamname_swap = false;
|
||||
if (teamname_swap)
|
||||
if (teamspam_text.size())
|
||||
{
|
||||
teamname_swap = false;
|
||||
g_IEngine->ServerCmd("tournament_teamname Cat");
|
||||
}
|
||||
else
|
||||
{
|
||||
teamname_swap = true;
|
||||
g_IEngine->ServerCmd("tournament_teamname Hook");
|
||||
g_IEngine->ServerCmd(format("tournament_teamname ", teamspam_text.at(current_teamspam_idx)).c_str());
|
||||
current_teamspam_idx++;
|
||||
// We've hit the end of the vector
|
||||
if (current_teamspam_idx == teamspam_text.size())
|
||||
current_teamspam_idx = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -391,10 +395,34 @@ const std::vector<std::string> builtin_nonecore = { "NULL CORE - REDUCE YOUR RIS
|
||||
const std::vector<std::string> builtin_lmaobox = { "GET GOOD, GET LMAOBOX!", "LMAOBOX - WAY TO THE TOP", "WWW.LMAOBOX.NET - BEST FREE TF2 HACK!" };
|
||||
const std::vector<std::string> builtin_lithium = { "CHECK OUT www.YouTube.com/c/DurRud FOR MORE INFORMATION!", "PWNING AIMBOTS WITH OP ANTI-AIMS SINCE 2015 - LITHIUMCHEAT", "STOP GETTING MAD AND STABILIZE YOUR MOOD WITH LITHIUMCHEAT!", "SAVE YOUR MONEY AND GET LITHIUMCHEAT! IT IS FREE!", "GOT ROLLED BY LITHIUM? HEY, THAT MEANS IT'S TIME TO GET LITHIUMCHEAT!!" };
|
||||
|
||||
void teamspam_reload(std::string after)
|
||||
{
|
||||
// Clear spam vector
|
||||
teamspam_text.clear();
|
||||
// Reset Spam idx
|
||||
current_teamspam_idx = 0;
|
||||
if (after != "")
|
||||
{
|
||||
static TextFile teamspam;
|
||||
if (teamspam.TryLoad(after))
|
||||
{
|
||||
teamspam_text = teamspam.lines;
|
||||
for (auto &text : teamspam_text)
|
||||
ReplaceSpecials(text);
|
||||
}
|
||||
}
|
||||
}
|
||||
void teamspam_reload_command()
|
||||
{
|
||||
teamspam_reload(*teamname_file);
|
||||
}
|
||||
static InitRoutine EC([]() {
|
||||
teamname_file.installChangeCallback([](settings::VariableBase<std::string> &, std::string after) { teamspam_reload(after); });
|
||||
EC::Register(EC::CreateMove, createMove, "spam", EC::average);
|
||||
init();
|
||||
});
|
||||
|
||||
static CatCommand reload_ts("teamspam_reload", "Relaod teamspam file", teamspam_reload_command);
|
||||
|
||||
static CatCommand reload_cc("spam_reload", "Reload spam file", hacks::shared::spam::reloadSpamFile);
|
||||
} // namespace hacks::shared::spam
|
||||
|
@ -518,7 +518,7 @@ void ReplaceString(std::string &input, const std::string &what, const std::strin
|
||||
|
||||
void ReplaceSpecials(std::string &str)
|
||||
{
|
||||
int val, i;
|
||||
int val;
|
||||
size_t c = 0, len = str.size();
|
||||
for (int i = 0; i + c < len; ++i)
|
||||
{
|
||||
@ -685,6 +685,58 @@ bool GetHitbox(CachedEntity *entity, int hb, Vector &out)
|
||||
return true;
|
||||
}
|
||||
|
||||
void MatrixGetColumn(const matrix3x4_t &in, int column, Vector &out)
|
||||
{
|
||||
out.x = in[0][column];
|
||||
out.y = in[1][column];
|
||||
out.z = in[2][column];
|
||||
}
|
||||
|
||||
inline void MatrixAngles(const matrix3x4_t &matrix, float *angles)
|
||||
{
|
||||
float forward[3];
|
||||
float left[3];
|
||||
float up[3];
|
||||
|
||||
//
|
||||
// Extract the basis vectors from the matrix. Since we only need the Z
|
||||
// component of the up vector, we don't get X and Y.
|
||||
//
|
||||
forward[0] = matrix[0][0];
|
||||
forward[1] = matrix[1][0];
|
||||
forward[2] = matrix[2][0];
|
||||
left[0] = matrix[0][1];
|
||||
left[1] = matrix[1][1];
|
||||
left[2] = matrix[2][1];
|
||||
up[2] = matrix[2][2];
|
||||
|
||||
float xyDist = std::sqrt(forward[0] * forward[0] + forward[1] * forward[1]);
|
||||
|
||||
// enough here to get angles?
|
||||
if (xyDist > 0.001f)
|
||||
{
|
||||
// (yaw) y = ATAN( forward.y, forward.x ); -- in our space, forward is the X axis
|
||||
angles[1] = RAD2DEG(atan2f(forward[1], forward[0]));
|
||||
|
||||
// (pitch) x = ATAN( -forward.z, sqrt(forward.x*forward.x+forward.y*forward.y) );
|
||||
angles[0] = RAD2DEG(atan2f(-forward[2], xyDist));
|
||||
|
||||
// (roll) z = ATAN( left.z, up.z );
|
||||
angles[2] = RAD2DEG(atan2f(left[2], up[2]));
|
||||
}
|
||||
else
|
||||
{
|
||||
// (yaw) y = ATAN( -left.x, left.y ); -- forward is mostly z, so use right for yaw
|
||||
angles[1] = RAD2DEG(atan2f(-left[0], left[1]));
|
||||
|
||||
// (pitch) x = ATAN( -forward.z, sqrt(forward.x*forward.x+forward.y*forward.y) );
|
||||
angles[0] = RAD2DEG(atan2f(-forward[2], xyDist));
|
||||
|
||||
// Assume no roll in this case as one degree of freedom has been lost (i.e. yaw == roll)
|
||||
angles[2] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void VectorAngles(Vector &forward, Vector &angles)
|
||||
{
|
||||
float tmp, yaw, pitch;
|
||||
@ -1485,7 +1537,6 @@ void ChangeName(std::string name)
|
||||
ch->SendNetMsg(setname, false);
|
||||
}
|
||||
}
|
||||
|
||||
const char *powerups[] = { "STRENGTH", "RESISTANCE", "VAMPIRE", "REFLECT", "HASTE", "REGENERATION", "PRECISION", "AGILITY", "KNOCKOUT", "KING", "PLAGUE", "SUPERNOVA", "CRITS" };
|
||||
|
||||
const std::string classes[] = { "Scout", "Sniper", "Soldier", "Demoman", "Medic", "Heavy", "Pyro", "Spy", "Engineer" };
|
||||
|
@ -105,6 +105,7 @@ VMTHook client{};
|
||||
VMTHook inventory{};
|
||||
VMTHook chathud{};
|
||||
VMTHook engine{};
|
||||
VMTHook demoplayer{};
|
||||
VMTHook netchannel{};
|
||||
VMTHook firebullets{};
|
||||
VMTHook clientdll{};
|
||||
|
@ -127,13 +127,7 @@ namespace hooked_methods
|
||||
{
|
||||
DEFINE_HOOKED_METHOD(CreateMove, bool, void *this_, float input_sample_time, CUserCmd *cmd)
|
||||
{
|
||||
#define TICK_INTERVAL (g_GlobalVars->interval_per_tick)
|
||||
#define TIME_TO_TICKS(dt) ((int) (0.5f + (float) (dt) / TICK_INTERVAL))
|
||||
#define TICKS_TO_TIME(t) (TICK_INTERVAL * (t))
|
||||
#define ROUND_TO_TICKS(t) (TICK_INTERVAL * TIME_TO_TICKS(t))
|
||||
volatile uintptr_t **fp;
|
||||
__asm__ volatile("mov %%ebp, %0" : "=r"(fp));
|
||||
bSendPackets = reinterpret_cast<bool *>(**fp - 8);
|
||||
bSendPackets = reinterpret_cast<bool *>((uintptr_t) __builtin_frame_address(2) - 8);
|
||||
|
||||
g_Settings.is_create_move = true;
|
||||
bool time_replaced, ret, speedapplied;
|
||||
@ -289,7 +283,7 @@ DEFINE_HOOKED_METHOD(CreateMove, bool, void *this_, float input_sample_time, CUs
|
||||
if (current_user_cmd->buttons & IN_ATTACK)
|
||||
if (attackticks % *fullauto + 1 < *fullauto)
|
||||
current_user_cmd->buttons &= ~IN_ATTACK;
|
||||
static int fakelag_queue = 0;
|
||||
static int fakelag_queue = 0;
|
||||
g_pLocalPlayer->isFakeAngleCM = false;
|
||||
if (CE_GOOD(LOCAL_E))
|
||||
if (fakelag_amount || (hacks::shared::antiaim::force_fakelag && hacks::shared::antiaim::isEnabled()))
|
||||
@ -396,19 +390,6 @@ DEFINE_HOOKED_METHOD(CreateMove, bool, void *this_, float input_sample_time, CUs
|
||||
|
||||
ret = false;
|
||||
}
|
||||
for (int i = 1; i <= g_IEngine->GetMaxClients(); i++)
|
||||
{
|
||||
|
||||
CachedEntity *ent = ENTITY(i);
|
||||
if (CE_GOOD(LOCAL_E))
|
||||
if (ent == LOCAL_E)
|
||||
continue;
|
||||
if (CE_BAD(ent) || !ent->m_bAlivePlayer())
|
||||
continue;
|
||||
INetChannel *ch = (INetChannel *) g_IEngine->GetNetChannelInfo();
|
||||
if (NET_FLOAT(RAW_ENT(ent), netvar.m_flSimulationTime) <= 1.5f)
|
||||
continue;
|
||||
}
|
||||
g_pLocalPlayer->UpdateEnd();
|
||||
}
|
||||
|
||||
@ -419,6 +400,18 @@ DEFINE_HOOKED_METHOD(CreateMove, bool, void *this_, float input_sample_time, CUs
|
||||
}
|
||||
g_pLocalPlayer->bAttackLastTick = (cmd->buttons & IN_ATTACK);
|
||||
g_Settings.is_create_move = false;
|
||||
if (nolerp && !hacks::shared::backtrack::isBacktrackEnabled)
|
||||
{
|
||||
static const ConVar *pUpdateRate = g_pCVar->FindVar("cl_updaterate");
|
||||
if (!pUpdateRate)
|
||||
pUpdateRate = g_pCVar->FindVar("cl_updaterate");
|
||||
else
|
||||
{
|
||||
|
||||
float interp = MAX(cl_interp->GetFloat(), cl_interp_ratio->GetFloat() / pUpdateRate->GetFloat());
|
||||
cmd->tick_count += TIME_TO_TICKS(interp);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
} // namespace hooked_methods
|
||||
|
@ -11,6 +11,18 @@ static settings::Boolean enable_debug_servercmd{ "debug.servercmdkeyvalues", "fa
|
||||
namespace hooked_methods
|
||||
{
|
||||
std::vector<KeyValues *> Iterate(KeyValues *event, int depth);
|
||||
DEFINE_HOOKED_METHOD(IsPlayingTimeDemo, bool, void *_this)
|
||||
{
|
||||
if (nolerp)
|
||||
{
|
||||
uintptr_t ret_addr = (uintptr_t) __builtin_return_address(1);
|
||||
static auto wanted_addr = gSignatures.GetClientSignature("84 C0 0F 85 ? ? ? ? E9 ? ? ? ? 8D 76 00 C6 05");
|
||||
if (ret_addr == wanted_addr && CE_GOOD(LOCAL_E) && LOCAL_E->m_bAlivePlayer())
|
||||
return true;
|
||||
}
|
||||
return original::IsPlayingTimeDemo(_this);
|
||||
}
|
||||
|
||||
DEFINE_HOOKED_METHOD(ServerCmdKeyValues, void, IVEngineClient013 *_this, KeyValues *kv)
|
||||
{
|
||||
if (!enable_debug_servercmd)
|
||||
|
@ -17,7 +17,7 @@ DEFINE_HOOKED_METHOD(SendDatagram, int, INetChannel *ch, bf_write *buf)
|
||||
int state = ch->m_nInReliableState;
|
||||
hacks::shared::backtrack::AddLatencyToNetchan(ch);
|
||||
|
||||
int ret = original::SendDatagram(ch, buf);
|
||||
int ret = original::SendDatagram(ch, buf);
|
||||
ch->m_nInSequenceNr = in;
|
||||
ch->m_nInReliableState = state;
|
||||
|
||||
|
Reference in New Issue
Block a user