From 43dc27c05f238efcdd93f71119f629669a6bb65e Mon Sep 17 00:00:00 2001 From: TotallyNotElite <1yourexperiment@protonmail.com> Date: Mon, 11 May 2020 22:20:58 +0200 Subject: [PATCH] Do some crits.cpp refactoring --- src/crits.cpp | 294 ++++++++++++++++++++++----------------- src/hooks/GetUserCmd.cpp | 2 +- 2 files changed, 169 insertions(+), 127 deletions(-) diff --git a/src/crits.cpp b/src/crits.cpp index 1de312a9..2479125d 100644 --- a/src/crits.cpp +++ b/src/crits.cpp @@ -102,15 +102,6 @@ static void simulateNormalShot(IClientEntity *wep, float flDamage) info.restore_data(wep); } -// This is just a convenient wrapper which will most likely be inlined -static bool canWeaponWithdraw(IClientEntity *wep) -{ - // Check - if (!isAllowedToWithdrawFromBucket(wep, added_per_shot)) - return false; - return true; -} - // Calculate shots until crit static int shotsUntilCrit(IClientEntity *wep) { @@ -245,8 +236,6 @@ static bool randomCritEnabled() } // These are used when we want to force a crit regardless of states (e.g. for delayed weapons like sticky launchers) -static int force_ticks = 0; -static int prevent_ticks = 0; bool force_crit_this_tick = false; // Is the hack enabled? @@ -255,23 +244,103 @@ bool isEnabled() // No crits without random crits if (!randomCritEnabled()) return false; - // Check if - // - forced crits - // - melee enabled and holding melee - // - master switch enabled and not using a melee + (button check) - if (force_ticks || ((melee && g_pLocalPlayer->weapon_mode == weapon_melee) || (enabled && g_pLocalPlayer->weapon_mode != weapon_melee && (!crit_key || crit_key.isKeyDown())))) + // Melee overrides the enabled switch + if (melee || enabled) + return true; + // If none of these conditions pass, crithack is NOT on + return false; +} + +bool shouldMeleeCrit() +{ + if (!melee || g_pLocalPlayer->weapon_mode != weapon_melee) + return false; + namespace bt = hacks::shared::backtrack; + if (bt::isBacktrackEnabled) + { + int target = bt::iBestTarget; + // Valid backtrack target + if (target > 1) + { + // Closest tick for melee + int besttick = bt::BestTick; + // Out of range, don't crit + if (bt::headPositions[target][besttick].entorigin.DistTo(LOCAL_E->m_vecOrigin()) >= re::C_TFWeaponBaseMelee::GetSwingRange(RAW_ENT(LOCAL_W)) + 150.0f) + { + return false; + } + } + else + { + return false; + } + } + // Normal check, get closest entity and check distance + else + { + auto ent = getClosestEntity(LOCAL_E->m_vecOrigin()); + if (!ent || ent->m_flDistance() >= re::C_TFWeaponBaseMelee::GetSwingRange(RAW_ENT(LOCAL_W)) + 150.0f) + { + return false; + } + } + return true; +} + +// Check some basic conditions +bool shouldCrit() +{ + // Melee mode with melee out and in range? + if (shouldMeleeCrit()) + return true; + // Crit key + enabled, for melee, the crit key MUST be set + if (enabled && ((g_pLocalPlayer->weapon_mode != weapon_melee && !crit_key) || crit_key.isKeyDown())) + return true; + // Force crits on sticky launcher + /*if (force_ticks) + { + if (LOCAL_W->m_iClassID() == CL_CLASS(CTFPipebombLauncher)) + return true; + else + force_ticks = 0; + }*/ + // Tick is supposed to be forced because of something external to crithack + if (force_crit_this_tick) return true; return false; } -// Should we Prevent crits? -bool preventCrits() + +// BeggarsCanWeaponCrit +static bool can_beggars_crit = false; +static bool attacked_last_tick = false; + +bool canWeaponCrit(bool canShootCheck = true) { - // Can't randomly crit - if (!randomCritEnabled()) + // Is weapon elligible for crits? + IClientEntity *weapon = RAW_ENT(LOCAL_W); + if (!re::C_TFWeaponBase::IsBaseCombatWeapon(weapon)) return false; - if (g_pLocalPlayer->weapon_mode == weapon_melee || (force_no_crit && crit_key && !crit_key.isKeyDown())) - return true; - return false; + if (!re::C_TFWeaponBase::AreRandomCritsEnabled(weapon) || !added_per_shot) + return false; + if (!re::C_TFWeaponBase::CanFireCriticalShot(weapon, false, nullptr)) + return false; + if (!added_per_shot) + return false; + if (!getCritCap(weapon)) + return false; + + // Misc checks + if (!isAllowedToWithdrawFromBucket(weapon, added_per_shot)) + return false; + if (canShootCheck && !CanShoot() && !isRapidFire(weapon)) + return false; + if (CE_INT(LOCAL_W, netvar.iItemDefinitionIndex) == 730 && !can_beggars_crit) + return false; + // Check if we have done enough damage to crit + auto crit_mult_info = critMultInfo(weapon); + if (crit_mult_info.first > crit_mult_info.second && g_pLocalPlayer->weapon_mode != weapon_melee) + return false; + return true; } // We cycle between the crit cmds so we want to store where we are currently at @@ -306,27 +375,11 @@ bool prevent_crit() // Main function that forces a crit void force_crit() { - // Crithack should not run - if (!isEnabled() && !force_crit_this_tick && !preventCrits()) - return; - // Can't crit - if (!added_per_shot) - return; - - // Reset force ticks - if (force_ticks && LOCAL_W->m_iClassID() != CL_CLASS(CTFPipebombLauncher)) - force_ticks = 0; // New mode stuff (well when not using melee nor using pipe launcher) if (g_pLocalPlayer->weapon_mode != weapon_melee && LOCAL_W->m_iClassID() != CL_CLASS(CTFPipebombLauncher)) { - // Force to not crit - if (!force_crit_this_tick && crit_key && !crit_key.isKeyDown()) - { - // Prevent Crit - prevent_crit(); - } // We have valid crit command numbers - else if (crit_cmds.size()) + if (crit_cmds.size()) { if (current_index >= crit_cmds.size()) current_index = 0; @@ -338,67 +391,30 @@ void force_crit() } } // We can just force to nearest crit for melee, and sticky launchers apparently - else if ((g_pLocalPlayer->weapon_mode == weapon_melee && (melee || force_crit_this_tick)) || (LOCAL_W->m_iClassID() == CL_CLASS(CTFPipebombLauncher) && (force_crit_this_tick || enabled))) + else { int next_crit = nextCritTick(); if (next_crit != -1) { if (LOCAL_W->m_iClassID() == CL_CLASS(CTFPipebombLauncher)) { - if (!force_ticks && isEnabled()) + /*if (!force_ticks && isEnabled()) force_ticks = 3; if (force_ticks) - force_ticks--; - // Prevent crits - if (!force_crit_this_tick && !prevent_ticks && !force_ticks && preventCrits()) - prevent_ticks = 3; + force_ticks--;*/ + /*// Prevent crits + prevent_ticks = 3; if (prevent_ticks) { prevent_crit(); prevent_ticks--; return; - } - } - // Code for handling when to not crit with melee weapons - else if (force_no_crit && !force_crit_this_tick) - { - if (hacks::shared::backtrack::isBacktrackEnabled) - { - int target = hacks::shared::backtrack::iBestTarget; - // Valid backtrack target - if (target > 1) - { - // Closest tick for melee - int besttick = hacks::shared::backtrack::BestTick; - // Out of range, don't crit - if (hacks::shared::backtrack::headPositions[target][besttick].entorigin.DistTo(LOCAL_E->m_vecOrigin()) >= re::C_TFWeaponBaseMelee::GetSwingRange(RAW_ENT(LOCAL_W)) + 150.0f) - { - prevent_crit(); - return; - } - } - else - { - prevent_crit(); - return; - } - } - // Normal check, get closest entity and check distance - else - { - auto ent = getClosestEntity(LOCAL_E->m_vecOrigin()); - if (!ent || ent->m_flDistance() >= re::C_TFWeaponBaseMelee::GetSwingRange(RAW_ENT(LOCAL_W)) + 150.0f) - { - prevent_crit(); - return; - } - } + }*/ } current_late_user_cmd->command_number = next_crit; current_late_user_cmd->random_seed = MD5_PseudoRandom(next_crit) & 0x7FFFFFFF; } } - force_crit_this_tick = false; } // Update the magic crit commands numbers @@ -411,11 +427,7 @@ void force_crit() static void updateCmds() { - if (CE_BAD(LOCAL_E)) - return; auto weapon = RAW_ENT(LOCAL_W); - if (CE_BAD(LOCAL_W)) - return; static int last_weapon; // Current command number @@ -549,10 +561,6 @@ void fixBucket(IClientEntity *weapon, CUserCmd *cmd) info.restore_data(weapon); } -// Beggars -static bool should_crit_beggars = false; -static bool attacked_last_tick = false; - // Damage this round void CreateMove() { @@ -575,50 +583,80 @@ void CreateMove() } } - if (!enabled && !melee && !draw && !draw_meter) + // Basic checks + if (!isEnabled()) + return; + // This is not a tick that will actually matter + if (!current_late_user_cmd->command_number) return; if (CE_BAD(LOCAL_E) || CE_BAD(LOCAL_W)) return; // Update magic crit commands updateCmds(); - if (!enabled && !force_crit_this_tick && !melee) - return; - if (!force_ticks && !force_crit_this_tick && (!(melee && g_pLocalPlayer->weapon_mode == weapon_melee) && !force_no_crit && crit_key && !crit_key.isKeyDown())) - return; - if (!current_late_user_cmd->command_number) - return; - - // Is weapon elligible for crits? - IClientEntity *weapon = RAW_ENT(LOCAL_W); - if (!re::C_TFWeaponBase::IsBaseCombatWeapon(weapon)) - return; - if (!re::C_TFWeaponBase::AreRandomCritsEnabled(weapon) || !added_per_shot) - return; - 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; + if (!can_beggars_crit) + can_beggars_crit = !(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)) + attacked_last_tick = current_late_user_cmd->buttons & IN_ATTACK; + if (!CE_INT(LOCAL_W, netvar.m_iClip1) && CE_INT(LOCAL_W, netvar.iReloadMode) == 0) { // Reset - should_crit_beggars = false; + can_beggars_crit = false; } } - // Should we run crit logic? - if ((force_no_crit && isAllowedToWithdrawFromBucket(RAW_ENT(LOCAL_W), added_per_shot)) || force_ticks || should_crit_beggars || ((CanShoot() || isRapidFire(RAW_ENT(LOCAL_W))) && current_late_user_cmd->buttons & IN_ATTACK)) + else + can_beggars_crit = false; + + // No point in forcing/preventing crits if we can't even crit + if (!canWeaponCrit()) + return; + + // Not in attack? Do nothing, unless using the beggars/Sticky launcher + if (!(current_late_user_cmd->buttons & IN_ATTACK)) { - // Can we crit? - if (canWeaponWithdraw(RAW_ENT(LOCAL_W))) - force_crit(); + if (LOCAL_W->m_iClassID() == CL_CLASS(CTFPipebombLauncher)) + { + float chargebegin = *((float *) ((uintptr_t) RAW_ENT(LOCAL_W) + 3152)); + float chargetime = g_GlobalVars->curtime - chargebegin; + + static bool currently_charging_pipe = false; + + // Sticky started charging + if (chargetime < 6.0f && chargetime) + currently_charging_pipe = true; + + // Sticky was released + if (!(current_user_cmd->buttons & IN_ATTACK) && currently_charging_pipe) + { + currently_charging_pipe = false; + } + else + return; + } + else if (!can_beggars_crit) + return; } + + // Should we even try to crit this tick? + if (shouldCrit()) + { + force_crit(); + } + // Ok, we shouldn't crit for whatever reason, lets prevent crits + else if (force_no_crit) + { + // if (prevent_ticks >= 1) + // prevent_ticks--; + prevent_crit(); + // if (LOCAL_W->m_iClassID() == CL_CLASS(CTFPipebombLauncher) && current_late_user_cmd->buttons & IN_ATTACK) + // prevent_ticks = 3; + } + force_crit_this_tick = false; } // Storage @@ -675,6 +713,8 @@ static Timer update_shots{}; void Draw() { + if (!isEnabled()) + return; if (!draw && !draw_meter) return; if (!g_IEngine->GetNetChannelInfo()) @@ -688,7 +728,7 @@ void Draw() // fixObservedCritchance(wep); // Used by multiple things - bool can_crit = canWeaponWithdraw(wep); + bool can_crit = canWeaponCrit(false); if (bucket != last_bucket || wep->entindex() != last_wep || update_shots.test_and_set(500)) { @@ -708,8 +748,13 @@ void Draw() if (draw) { // Display for when crithack is active - if (isEnabled() && last_crit_tick != -1) - AddCritString("Forcing Crits!", colors::red); + if (shouldCrit()) + { + if (can_crit) + AddCritString("Forcing Crits!", colors::red); + else + AddCritString("Weapon can currently not crit!", colors::red); + } // Weapon can't randomly crit if (!re::C_TFWeaponBase::CanFireCriticalShot(RAW_ENT(LOCAL_W), false, nullptr) || !added_per_shot) @@ -748,10 +793,10 @@ void Draw() { rgba_t bucket_color = colors::FromRGBA8(0x53, 0xbc, 0x31, 255); // Forcing crits, change crit bucket color to a nice azure blue - if (isEnabled()) + if (shouldCrit()) bucket_color = colors::FromRGBA8(0x34, 0xeb, 0xae, 255); // Color everything red - if ((crit_mult_info.first > crit_mult_info.second && g_pLocalPlayer->weapon_mode != weapon_melee) || !can_crit) + if (!can_crit) bucket_color = colors::red; // Get the percentage the bucket will take up @@ -800,10 +845,7 @@ void Draw() { if (!isRapidFire(wep)) { - if (shots_until_crit != 1) - bar_string = std::to_string(shots_until_crit) + " Shots until Crit!"; - else - bar_string = std::to_string(shots_until_crit) + " Shot until Crit!"; + bar_string = std::to_string(shots_until_crit) + " Shots until Crit!"; } else bar_string = "Crit multiplier: " + std::to_string(getWithdrawMult(wep)); diff --git a/src/hooks/GetUserCmd.cpp b/src/hooks/GetUserCmd.cpp index 58fe3dc5..375b213c 100644 --- a/src/hooks/GetUserCmd.cpp +++ b/src/hooks/GetUserCmd.cpp @@ -11,7 +11,7 @@ namespace hooked_methods DEFINE_HOOKED_METHOD(GetUserCmd, CUserCmd *, IInput *this_, int sequence_number) { // We need to overwrite this if crithack is on - if (criticals::enabled || criticals::melee) + if (criticals::isEnabled()) return &GetCmds(this_)[sequence_number % VERIFIED_CMD_SIZE]; else return original::GetUserCmd(this_, sequence_number);