diff --git a/include/crits.hpp b/include/crits.hpp index 7ebeaf82..4d5d159c 100644 --- a/include/crits.hpp +++ b/include/crits.hpp @@ -26,6 +26,20 @@ struct crithack_saved_state { extern bool weapon_can_crit_last; +extern CatVar crit_hack_next; +extern CatVar crit_info; +extern CatVar crit_hack; +extern CatVar crit_melee; +extern CatVar crit_suppress; + +namespace criticals +{ + +void unfuck_bucket(); +bool force_crit(); + +} + bool CritKeyDown(); bool AllowAttacking(); bool RandomCrits(); diff --git a/include/hacks/Misc.hpp b/include/hacks/Misc.hpp index d32b1c46..bb6af9a7 100644 --- a/include/hacks/Misc.hpp +++ b/include/hacks/Misc.hpp @@ -17,17 +17,9 @@ void CreateMove(); void DrawText(); #endif -extern IClientEntity* found_crit_weapon; -extern int found_crit_number; extern int last_number; - -extern CatVar crit_hack_next; extern CatVar debug_info; extern CatVar flashlight_spam; -extern CatVar crit_info; // TODO separate -extern CatVar crit_hack; -extern CatVar crit_melee; -extern CatVar crit_suppress; extern CatVar anti_afk; extern CatVar tauntslide; extern CatCommand name; diff --git a/include/interfaces.hpp b/include/interfaces.hpp index 7f4874f9..937ebf92 100644 --- a/include/interfaces.hpp +++ b/include/interfaces.hpp @@ -51,6 +51,7 @@ class CBaseClientState; class CHud; class IGameEventManager; class TFGCClientSystem; +class CGameRules; extern TFGCClientSystem* g_TFGCClientSystem; extern CHud* g_CHUD; @@ -82,6 +83,7 @@ extern IVRenderView* g_IVRenderView; extern IMoveHelperServer* g_IMoveHelperServer; extern CBaseClientState* g_IBaseClientState; extern IGameEventManager* g_IGameEventManager; +extern CGameRules *g_pGameRules; void CreateInterfaces(); diff --git a/include/reclasses/C_BaseCombatWeapon.hpp b/include/reclasses/C_BaseCombatWeapon.hpp index 95b886fe..d2ef127d 100644 --- a/include/reclasses/C_BaseCombatWeapon.hpp +++ b/include/reclasses/C_BaseCombatWeapon.hpp @@ -7,7 +7,7 @@ #pragma once -class C_BaseCombatWeapon +class C_BaseCombatWeapon: public C_BaseEntity { public: inline static bool IsBaseCombatWeapon(IClientEntity *self) diff --git a/include/reclasses/C_BaseEntity.hpp b/include/reclasses/C_BaseEntity.hpp new file mode 100644 index 00000000..3aec4f3b --- /dev/null +++ b/include/reclasses/C_BaseEntity.hpp @@ -0,0 +1,20 @@ +/* + * C_BaseEntity.hpp + * + * Created on: Nov 23, 2017 + * Author: nullifiedcat + */ + +#pragma once + +class C_BaseEntity +{ +public: + inline static bool IsPlayer(IClientEntity *self) + { + typedef bool(*fn_t)(IClientEntity *); + return vfunc(self, offsets::PlatformOffset(184, offsets::undefined, 184), 0)(self); + } +}; + + diff --git a/include/reclasses/C_TFWeaponBase.hpp b/include/reclasses/C_TFWeaponBase.hpp index c11ba1ce..28e63072 100644 --- a/include/reclasses/C_TFWeaponBase.hpp +++ b/include/reclasses/C_TFWeaponBase.hpp @@ -25,6 +25,63 @@ public: typedef bool(*fn_t)(IClientEntity *); return vfunc(self, offsets::PlatformOffset(317, offsets::undefined, 317), 0)(self); } + inline static bool AreRandomCritsEnabled(IClientEntity *self) + { + typedef bool(*fn_t)(IClientEntity *); + return vfunc(self, offsets::PlatformOffset(466, offsets::undefined, 466), 0)(self); + } + inline static bool CalcIsAttackCriticalHelper(IClientEntity *self) + { + typedef bool(*fn_t)(IClientEntity *); + return vfunc(self, offsets::PlatformOffset(460, offsets::undefined, 460), 0)(self); + } + inline static bool CalcIsAttackCriticalHelperNoCrits(IClientEntity *self) + { + typedef bool(*fn_t)(IClientEntity *); + return vfunc(self, offsets::PlatformOffset(461, offsets::undefined, 461), 0)(self); + } + inline static int CalcIsAttackCritical(IClientEntity *self) + { + IClientEntity *owner = GetOwnerViaInterface(self); + if (owner) + { + if (IsPlayer(owner)) + { + // Always run calculations + // Never write anything into entity, at least from here. + + // if (g_GlobalVars->framecount != *(int *)(self + 2872)) + { + // *(int *)(self + 2872) = g_GlobalVars->framecount; + // *(char *)(self + 2839) = 0; + + if (g_pGameRules->critmode == 5 || + g_pGameRules->winning_team == NET_INT(owner, netvar.iTeamNum)) + { + // *(char *)(self + 2838) = 1; + return 1; + } + else + { + if (AreRandomCritsEnabled(self)) + { + return CalcIsAttackCriticalHelper(self); + } + else + { + return CalcIsAttackCriticalHelperNoCrits(self); + } + } + } + } + } + + return 0; + } + inline static float& crit_bucket_(IClientEntity *self) + { + return *(float *)(unsigned(self) + 2616u); + } }; diff --git a/include/reclasses/C_TFWeaponBaseGun.hpp b/include/reclasses/C_TFWeaponBaseGun.hpp index 437bb46a..56076394 100644 --- a/include/reclasses/C_TFWeaponBaseGun.hpp +++ b/include/reclasses/C_TFWeaponBaseGun.hpp @@ -7,7 +7,7 @@ #pragma once -class C_TFWeaponBaseGun : public C_TFWeaponBase +class C_TFWeaponBaseGun: public C_TFWeaponBase { public: inline static float GetProjectileSpeed(IClientEntity *self) diff --git a/include/reclasses/reclasses.hpp b/include/reclasses/reclasses.hpp index 5879241d..14140341 100644 --- a/include/reclasses/reclasses.hpp +++ b/include/reclasses/reclasses.hpp @@ -12,6 +12,7 @@ namespace re { +#include "C_BaseEntity.hpp" #include "C_BaseCombatWeapon.hpp" #include "C_TFWeaponBase.hpp" #include "C_TFWeaponBaseMelee.hpp" diff --git a/include/sdk.hpp b/include/sdk.hpp index 87338b97..9c64b393 100644 --- a/include/sdk.hpp +++ b/include/sdk.hpp @@ -64,5 +64,6 @@ #include "sdk/iinput.h" #include "sdk/igamemovement.h" #include "sdk/HUD.h" +#include "sdk/CGameRules.h" #endif /* SDK_HPP_ */ diff --git a/include/sdk/CGameRules.h b/include/sdk/CGameRules.h new file mode 100644 index 00000000..47120b0b --- /dev/null +++ b/include/sdk/CGameRules.h @@ -0,0 +1,19 @@ +/* + * CGameRules.h + * + * Created on: Nov 23, 2017 + * Author: nullifiedcat + */ + +#pragma once + +class CGameRules +{ +public: + int unknown_pad_0[12]; + int critmode; + int unknown_pad_1[1]; + int winning_team; +}; + + diff --git a/src/crits.cpp b/src/crits.cpp index 5e13d6c4..b2976487 100644 --- a/src/crits.cpp +++ b/src/crits.cpp @@ -8,12 +8,80 @@ #include "common.hpp" #include +CatVar crit_hack_next(CV_SWITCH, "crit_hack_next", "0", "Next crit info"); +CatVar crit_info(CV_SWITCH, "crit_info", "0", "Show crit info"); // TODO separate +CatVar crit_hack(CV_KEY, "crit_hack", "0", "Crit Key"); +CatVar crit_melee(CV_SWITCH, "crit_melee", "0", "Melee crits"); +CatVar crit_suppress(CV_SWITCH, "crit_suppress", "0", "Disable random crits", "Can help saving crit bucket for forced crits"); CatVar experimental_crit_hack(CV_KEY, "crit_hack_experimental", "0", "Unstable Crit Hack", "Experimental crit hack, use this **OR** old crit hack, do not use both!\nNEEDS NEXT CRIT INFO TO BE ACTIVE!"); std::unordered_map command_number_mod {}; int* g_PredictionRandomSeed = nullptr; +namespace criticals +{ + +int find_next_random_crit_for_weapon(IClientEntity *weapon) +{ + int tries = 0, + number = g_pUserCmd->command_number, + found = 0, + seed, + seed_md5; + + crithack_saved_state state; + state.Save(weapon); + + while (!found && tries < 4096) + { + seed_md5 = MD5_PseudoRandom(number) & 0x7FFFFFFF; + *g_PredictionRandomSeed = seed_md5; + seed = seed_md5 ^ (LOCAL_E->m_IDX | (LOCAL_W->m_IDX << 8)); + found = re::C_TFWeaponBase::CalcIsAttackCritical(weapon); + if (found) + break; + ++tries; + ++number; + } + + state.Load(weapon); + if (found) + return number; + return 0; +} + +void unfuck_bucket(IClientEntity *weapon) +{ + static bool changed; + static float last_bucket; + static int last_weapon; + + if (g_pUserCmd->command_number) + changed = false; + + float& bucket = re::C_TFWeaponBase::crit_bucket_(weapon); + + if (bucket != last_bucket) + { + if (changed && weapon->entindex() == last_weapon) + { + bucket = last_bucket; + } + changed = true; + } + last_weapon = weapon->entindex(); + last_bucket = bucket; +} + +bool force_crit() +{ + + return false; +} + +} + bool CritKeyDown() { return g_IInputSystem->IsButtonDown(static_cast((int)hacks::shared::misc::crit_hack));// || g_IInputSystem->IsButtonDown(static_cast((int)experimental_crit_hack)); } diff --git a/src/hacks/Misc.cpp b/src/hacks/Misc.cpp index 51435a5c..e8e58265 100644 --- a/src/hacks/Misc.cpp +++ b/src/hacks/Misc.cpp @@ -33,12 +33,6 @@ CatEnum spycrab_mode_enum({"DISABLED", "FORCE CRAB", "FORCE NON-CRAB"}); CatVar spycrab_mode(spycrab_mode_enum, "spycrab", "0", "Spycrab", "Defines spycrab taunting mode"); CatVar tauntslide(CV_SWITCH, "tauntslide", "0", "TF2C tauntslide", "Allows moving and shooting while taunting"); CatVar tauntslide_tf2(CV_SWITCH, "tauntslide_tf2", "0", "Tauntslide", "Allows free movement while taunting with movable taunts\nOnly works in tf2"); -// Crithack -CatVar crit_hack_next(CV_SWITCH, "crit_hack_next", "0", "Next crit info"); -CatVar crit_info(CV_SWITCH, "crit_info", "0", "Show crit info"); // TODO separate -CatVar crit_hack(CV_KEY, "crit_hack", "0", "Crit Key"); -CatVar crit_melee(CV_SWITCH, "crit_melee", "0", "Melee crits"); -CatVar crit_suppress(CV_SWITCH, "crit_suppress", "0", "Disable random crits", "Can help saving crit bucket for forced crits"); void* C_TFPlayer__ShouldDraw_original = nullptr; @@ -53,8 +47,6 @@ bool C_TFPlayer__ShouldDraw_hook(IClientEntity* thisptr) { } } -IClientEntity* found_crit_weapon = nullptr; -int found_crit_number = 0; int last_number = 0; // SUPER SECRET CODE DONOT STEEL @@ -184,26 +176,6 @@ void CreateMove() { PROF_SECTION(CM_misc_crit_hack_apply); if (!AllowAttacking()) g_pUserCmd->buttons &= ~IN_ATTACK; }*/ - /* - if (WeaponCanCrit()) { - PROF_SECTION(CM_misc_crit_hack_bucket_fixing); - weapon = RAW_ENT(LOCAL_W); - float& bucket = *(float*)((uintptr_t)(weapon) + 2612); - if (g_pUserCmd->command_number) { - changed = false; - } - if (bucket != last_bucket) { - if (changed && weapon == last_weapon) { - bucket = last_bucket; - } else { - //logging::Info("db: %.2f", g_pUserCmd->command_number, bucket - last_bucket); - } - changed = true; - } - last_weapon = weapon; - last_bucket = bucket; - } - */ // Spycrab stuff // TODO FIXME this should be moved out of here if (no_taunt_ticks && CE_GOOD(LOCAL_E)) { diff --git a/src/interfaces.cpp b/src/interfaces.cpp index cc014b94..fc03ac4d 100644 --- a/src/interfaces.cpp +++ b/src/interfaces.cpp @@ -49,6 +49,7 @@ CBaseClientState* g_IBaseClientState = nullptr; IGameEventManager* g_IGameEventManager = nullptr; TFGCClientSystem* g_TFGCClientSystem = nullptr; CHud* g_CHUD = nullptr; +CGameRules *g_pGameRules = nullptr; template T* BruteforceInterface(std::string name, sharedobj::SharedObject& object, int start = 0) { @@ -117,6 +118,9 @@ void CreateInterfaces() { IF_GAME (IsTF2()) { uintptr_t sig = gSignatures.GetClientSignature("A3 ? ? ? ? C3 8D 74 26 00 B8 FF FF FF FF 5D A3 ? ? ? ? C3"); g_PredictionRandomSeed = *reinterpret_cast(sig + (uintptr_t)1); + + uintptr_t g_pGameRules_sig = gSignatures.GetClientSignature("C7 03 ? ? ? ? 89 1D ? ? ? ? 83 C4 14 5B 5D C3"); + g_pGameRules = *reinterpret_cast(g_pGameRules_sig + 8); } IF_GAME (IsTF2()) { /*