From 85eeffa9e980e1299d0f2313c29b77e90020ead9 Mon Sep 17 00:00:00 2001 From: BenCat07 Date: Fri, 24 Apr 2020 18:04:20 +0200 Subject: [PATCH] Improve crithack and fix nospread with crithack --- include/crits.hpp | 4 ++ include/reclasses/CTFPlayerShared.hpp | 4 +- src/crits.cpp | 62 +++++++++++++++++++-------- src/nospread.cpp | 15 ++++++- 4 files changed, 64 insertions(+), 21 deletions(-) diff --git a/include/crits.hpp b/include/crits.hpp index 465906b9..c7814ca3 100644 --- a/include/crits.hpp +++ b/include/crits.hpp @@ -4,4 +4,8 @@ namespace criticals { extern settings::Boolean enabled; extern settings::Boolean melee; +extern std::vector crit_cmds; +extern int current_index; +extern bool isEnabled(); +extern settings::Boolean old_mode; } // namespace criticals diff --git a/include/reclasses/CTFPlayerShared.hpp b/include/reclasses/CTFPlayerShared.hpp index 3cac0ff1..87e5a3bb 100644 --- a/include/reclasses/CTFPlayerShared.hpp +++ b/include/reclasses/CTFPlayerShared.hpp @@ -12,7 +12,7 @@ public: // Convert IClientEntity to CTFPlayerShared inline static CTFPlayerShared *GetPlayerShared(IClientEntity *ent) { - return (CTFPlayerShared *) ((uintptr_t) ent + 0x5f3); + return (CTFPlayerShared *) (((uintptr_t) ent) + 0x17cc); } inline static bool IsDominatingPlayer(CTFPlayerShared *self, int ent_idx) { @@ -30,7 +30,7 @@ public: { static auto signature = gSignatures.GetClientSignature("55 89 E5 57 56 53 83 EC 6C 8B 7D ? C7 44 24 ? 0B 00 00 00"); typedef bool (*IsCritBoosted_t)(CTFPlayerShared *); - IsCritBoosted_t IsCritBoosted_fn = (IsCritBoosted_t) signature; + static IsCritBoosted_t IsCritBoosted_fn = (IsCritBoosted_t) signature; return IsCritBoosted_fn(self); } }; diff --git a/src/crits.cpp b/src/crits.cpp index 4d5a8b08..5cd8a329 100644 --- a/src/crits.cpp +++ b/src/crits.cpp @@ -10,7 +10,7 @@ settings::Boolean enabled{ "crit.enabled", "false" }; static settings::Boolean draw{ "crit.draw-info", "false" }; settings::Boolean melee{ "crit.melee", "false" }; static settings::Button crit_key{ "crit.key", "" }; -static settings::Boolean old_mode{ "crit.old-mode", "false" }; +settings::Boolean old_mode{ "crit.old-mode", "false" }; // How much is added to bucket per shot? static float added_per_shot = 0.0f; @@ -245,7 +245,7 @@ static bool randomCritEnabled() static int force_ticks = 0; // Is the hack enabled? -static bool isEnabled() +bool isEnabled() { // No crits without random crits if (!randomCritEnabled()) @@ -260,7 +260,7 @@ static bool isEnabled() } // We cycle between the crit cmds so we want to store where we are currently at -static std::vector crit_cmds; +std::vector crit_cmds; // We need to store a bunch of data for when we kill someone with a crit struct player_status @@ -269,6 +269,7 @@ struct player_status bool was_jarated{}; bool was_markedfordeath{}; }; +int current_index = 0; static std::array player_status_list{}; // Main function that forces a crit @@ -284,8 +285,7 @@ void force_crit() // We have valid crit command numbers if (crit_cmds.size()) { - static int current_index = 0; - if (current_index > crit_cmds.size()) + if (current_index >= crit_cmds.size()) current_index = 0; // Magic crit cmds get used to force a crit @@ -315,7 +315,7 @@ void force_crit() } // For everything else, wait for the crit cmd else if (current_late_user_cmd->command_number != next_crit) - current_user_cmd->buttons &= ~IN_ATTACK; + current_late_user_cmd->buttons &= ~IN_ATTACK; } } } @@ -442,9 +442,14 @@ static void fixBucket(IClientEntity *weapon) // Local server needs no fixing if (addr.type == NA_LOOPBACK) return; - // Melee doesn't either + + // Melee doesn't Need fixing either, still needs firetime though if (g_pLocalPlayer->weapon_mode == weapon_melee) + { + if (g_pLocalPlayer->weapon_melee_damage_tick) + shot_weapon_mode = weapon_melee; return; + } static float last_bucket; static int last_weapon; @@ -500,6 +505,9 @@ static void fixBucket(IClientEntity *weapon) info.restore_data(weapon); } +// Beggars +static bool should_crit_beggars = false; +static bool attacked_last_tick = false; void CreateMove() { // We need to update player states regardless, else we can't sync the observed crit chance @@ -541,8 +549,22 @@ void CreateMove() if (!re::C_TFWeaponBase::CanFireCriticalShot(weapon, false, nullptr)) return; + // Beggars check + if (CE_INT(LOCAL_W, netvar.iItemDefinitionIndex) == 730) + { + // Check if we released the barrage by releasing m1, also lock bool so people don't just release m1 and tap it again + if (!should_crit_beggars) + should_crit_beggars = !(current_late_user_cmd->buttons & IN_ATTACK) && attacked_last_tick; + // Update + attacked_last_tick = current_user_cmd->buttons & IN_ATTACK; + if (!CE_INT(LOCAL_W, netvar.m_iClip1)) + { + // Reset + should_crit_beggars = false; + } + } // Should we force crits? - if (force_ticks || (CanShoot() && current_late_user_cmd->buttons & IN_ATTACK)) + if (force_ticks || should_crit_beggars || (CanShoot() && current_late_user_cmd->buttons & IN_ATTACK)) { // Can we crit? if (canWeaponWithdraw(RAW_ENT(LOCAL_W))) @@ -653,23 +675,27 @@ public: int victim = g_IEngine->GetPlayerForUserID(event->GetInt("userid")); if (victim != g_pLocalPlayer->entity_idx) { - // This is only ranged damage and crit boost does not count towards it either - if (shot_weapon_mode != weapon_melee && !re::CTFPlayerShared::IsCritBoosted(re::CTFPlayerShared::GetPlayerShared(RAW_ENT(LOCAL_E)))) + // This is only ranged damage + if (shot_weapon_mode != weapon_melee) { // General damage counter int damage = event->GetInt("damageamount"); if (damage > player_status_list[victim].health) damage = player_status_list[victim].health; - // Crit damage counter - if (event->GetBool("crit")) - crit_damage += damage; - - // Mini crit case - if (event->GetBool("minicrit")) + // Crit handling + if (CE_BAD(LOCAL_E) || CE_BAD(LOCAL_W) || !re::CTFPlayerShared::IsCritBoosted(re::CTFPlayerShared::GetPlayerShared(RAW_ENT(LOCAL_E)))) { - if (!player_status_list[victim].was_jarated && !player_status_list[victim].was_markedfordeath) + // Crit damage counter + if (event->GetBool("crit")) crit_damage += damage; + + // Mini crit case + if (event->GetBool("minicrit")) + { + if (!player_status_list[victim].was_jarated && !player_status_list[victim].was_markedfordeath) + crit_damage += damage; + } } cached_damage += damage; } @@ -686,5 +712,7 @@ static InitRoutine init([]() { EC::Register(EC::Draw, Draw, "crit_draw"); EC::Register(EC::LevelShutdown, LevelShutdown, "crit_lvlshutdown"); g_IGameEventManager->AddListener(&listener, false); + EC::Register( + EC::Shutdown, []() { g_IGameEventManager->RemoveListener(&listener); }, "crit_shutdown"); }); } // namespace criticals diff --git a/src/nospread.cpp b/src/nospread.cpp index 6e3cf0cc..d19d940b 100644 --- a/src/nospread.cpp +++ b/src/nospread.cpp @@ -4,6 +4,7 @@ */ #include "common.hpp" +#include "crits.hpp" namespace hacks::tf2::nospread { @@ -20,8 +21,18 @@ void CreateMove() // Credits to https://www.unknowncheats.me/forum/team-fortress-2-a/139094-projectile-nospread.html // Set up Random Seed - RandomSeed(MD5_PseudoRandom(current_user_cmd->command_number) & 0x7FFFFFFF); - SharedRandomInt(MD5_PseudoRandom(current_user_cmd->command_number) & 0x7FFFFFFF, "SelectWeightedSequence", 0, 0, 0); + int cmd_num = current_user_cmd->command_number; + // Crithack uses different things + if (criticals::isEnabled() && g_pLocalPlayer->weapon_mode != weapon_melee && !criticals::old_mode && criticals::crit_cmds.size()) + { + int array_index = criticals::current_index; + if (array_index >= criticals::crit_cmds.size()) + array_index = 0; + // Adjust for nospread + cmd_num = criticals::crit_cmds[array_index]; + } + RandomSeed(MD5_PseudoRandom(cmd_num) & 0x7FFFFFFF); + SharedRandomInt(MD5_PseudoRandom(cmd_num) & 0x7FFFFFFF, "SelectWeightedSequence", 0, 0, 0); for (int i = 0; i < 6; ++i) RandomFloat();