From 577eaa3d691cd2ef775726a8b3753056435c0ec5 Mon Sep 17 00:00:00 2001
From: Viceroy <97338859+Viceroyy@users.noreply.github.com>
Date: Thu, 8 Aug 2024 18:57:31 +0300
Subject: [PATCH] Added particle effect changers, Added WIP Streamer mode
---
Fusion/Fusion.vcxproj | 6 +
Fusion/Fusion.vcxproj.filters | 6 +
.../Aimbot/AimbotHitscan/AimbotHitscan.cpp | 2 +
Fusion/src/Features/ImGui/Menu/Menu.cpp | 10 +-
Fusion/src/Features/Visuals/ESP/ESP.cpp | 17 ++-
.../Visuals/SpectatorList/SpectatorList.cpp | 13 +-
.../CAttributeManager_AttribHookValue.cpp | 29 +++++
Fusion/src/Hooks/CBaseHudChat_ChatPrintf.cpp | 23 ++++
...entScoreBoardDialog_UpdatePlayerAvatar.cpp | 12 ++
Fusion/src/Hooks/CCvar_ConsoleColorPrintf.cpp | 18 +++
Fusion/src/Hooks/CParticleProperty_Create.cpp | 122 ++++++++++++++++++
.../Hooks/C_PlayerResource_GetPlayerName.cpp | 26 ++++
Fusion/src/Hooks/Panel_PaintTraverse.cpp | 18 +++
Fusion/src/Hooks/S_StartSound.cpp | 2 +
Fusion/src/Hooks/TF_IsHolidayActive.cpp | 28 ++++
Fusion/src/SDK/SDK.cpp | 22 ++++
Fusion/src/SDK/SDK.h | 2 +
Fusion/src/SDK/Vars.h | 9 ++
18 files changed, 362 insertions(+), 3 deletions(-)
create mode 100644 Fusion/src/Hooks/CAttributeManager_AttribHookValue.cpp
create mode 100644 Fusion/src/Hooks/CClientScoreBoardDialog_UpdatePlayerAvatar.cpp
create mode 100644 Fusion/src/Hooks/CCvar_ConsoleColorPrintf.cpp
create mode 100644 Fusion/src/Hooks/CParticleProperty_Create.cpp
create mode 100644 Fusion/src/Hooks/C_PlayerResource_GetPlayerName.cpp
create mode 100644 Fusion/src/Hooks/Panel_PaintTraverse.cpp
create mode 100644 Fusion/src/Hooks/TF_IsHolidayActive.cpp
diff --git a/Fusion/Fusion.vcxproj b/Fusion/Fusion.vcxproj
index 73fe39d..26a90fc 100644
--- a/Fusion/Fusion.vcxproj
+++ b/Fusion/Fusion.vcxproj
@@ -272,6 +272,7 @@
+
@@ -284,6 +285,8 @@
+
+
@@ -303,6 +306,7 @@
+
@@ -324,6 +328,7 @@
+
@@ -341,6 +346,7 @@
+
diff --git a/Fusion/Fusion.vcxproj.filters b/Fusion/Fusion.vcxproj.filters
index da75840..d0f5a2b 100644
--- a/Fusion/Fusion.vcxproj.filters
+++ b/Fusion/Fusion.vcxproj.filters
@@ -163,6 +163,12 @@
+
+
+
+
+
+
diff --git a/Fusion/src/Features/Aimbot/AimbotHitscan/AimbotHitscan.cpp b/Fusion/src/Features/Aimbot/AimbotHitscan/AimbotHitscan.cpp
index a3c85ea..affbcac 100644
--- a/Fusion/src/Features/Aimbot/AimbotHitscan/AimbotHitscan.cpp
+++ b/Fusion/src/Features/Aimbot/AimbotHitscan/AimbotHitscan.cpp
@@ -704,10 +704,12 @@ void CAimbotHitscan::Run(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CUserCmd* pC
switch (nWeaponID)
{
case TF_WEAPON_MINIGUN:
+ {
pCmd->buttons |= IN_ATTACK2;
if (pWeapon->As()->m_iWeaponState() != AC_STATE_FIRING && pWeapon->As()->m_iWeaponState() != AC_STATE_SPINNING)
return;
break;
+ }
case TF_WEAPON_SNIPERRIFLE:
case TF_WEAPON_SNIPERRIFLE_DECAP:
{
diff --git a/Fusion/src/Features/ImGui/Menu/Menu.cpp b/Fusion/src/Features/ImGui/Menu/Menu.cpp
index 05f368c..94d0bbc 100644
--- a/Fusion/src/Features/ImGui/Menu/Menu.cpp
+++ b/Fusion/src/Features/ImGui/Menu/Menu.cpp
@@ -625,6 +625,7 @@ void CMenu::MenuVisuals()
FToggle("Clean screenshots", Vars::Visuals::UI::CleanScreenshots, FToggle_Middle);
FToggle("Sniper sightlines", Vars::Visuals::UI::SniperSightlines);
FToggle("Pickup timers", Vars::Visuals::UI::PickupTimers, FToggle_Middle);
+ FToggle("Streamer mode (WIP)", Vars::Visuals::UI::StreamerMode);
} EndSection();
if (Section("Viewmodel"))
{
@@ -667,6 +668,13 @@ void CMenu::MenuVisuals()
FToggle("MEDIC: Show injured teammates", Vars::Visuals::Other::ShowInjuredTeammatesWhenMedic);
FToggle("Low graphics", Vars::Visuals::Other::ThePS2Inator);
} EndSection();
+ if (Section("Particles"))
+ {
+ FDropdown("Medigun beam", Vars::Visuals::Particle::MedigunBeamEffect, { "Off", "Dispenser heal", "PASS Time", "Bombonomicon spell", "White", "Uber" }, {}, FDropdown_Left);
+ FDropdown("Medigun charge", Vars::Visuals::Particle::MedigunChargeEffect, { "Off", "Fireball spell", "Spellbound", "Electrocuted", "Cloud 9", "Electrostatic", "Knifestorm", "Frostbite", "Haunted Phantasm Jr.", "Time Warp", "Stormy 13th Hour", "Terror-Watt", "Sunbeams", "Sunbeams new", "Disco beams", "Pumpkin" }, {}, FDropdown_Right);
+ FDropdown("Rocket trail", Vars::Visuals::Particle::RocketTrailEffect, { "Off", "Crit", "Bubbles", "Halloween", "Airstrike", "Monoculus", "Cow Mangler", "Cow Mangler charged" }, {}, FDropdown_Left);
+ FToggle("Rainbow footsteps", Vars::Visuals::Particle::RainbowFootstepEffect);
+ } EndSection();
if (Section("Bullet"))
{
FColorPicker("Bullet tracer color", Vars::Colors::BulletTracer);
@@ -738,7 +746,7 @@ void CMenu::MenuVisuals()
} EndSection();
if (Section("World"))
{
- FSDropdown("World texture", Vars::Visuals::World::WorldTexture, { "Default", "Dev", "Camo", "Black", "White", "Flat" }, FSDropdown_Custom);
+ FSDropdown("World texture", Vars::Visuals::World::WorldTexture, { "Default", "Dev", "Camo", "Black", "White" }, FSDropdown_Custom);
FDropdown("Modulations", Vars::Visuals::World::Modulations, { "World", "Sky", "Prop", "Particle", "Fog" }, {}, FDropdown_Left | FDropdown_Multi);
static std::vector skyNames = {
"Off", "sky_tf2_04", "sky_upward", "sky_dustbowl_01", "sky_goldrush_01", "sky_granary_01", "sky_well_01", "sky_gravel_01", "sky_badlands_01",
diff --git a/Fusion/src/Features/Visuals/ESP/ESP.cpp b/Fusion/src/Features/Visuals/ESP/ESP.cpp
index 1d05b5e..e1320eb 100644
--- a/Fusion/src/Features/Visuals/ESP/ESP.cpp
+++ b/Fusion/src/Features/Visuals/ESP/ESP.cpp
@@ -156,7 +156,22 @@ void CESP::DrawPlayers(CTFPlayer* pLocal)
if (Vars::ESP::Player.Value & 1 << 0)
{
tOffset += fFontName.m_nTall + 2;
- H::Draw.String(fFontName, middle, y - tOffset, Vars::Menu::Theme::Active.Value, ALIGN_TOP, SDK::ConvertUtf8ToWide(pi.name).data());
+ if (Vars::Visuals::UI::StreamerMode.Value)
+ {
+ const char* name;
+ if (nIndex == I::EngineClient->GetLocalPlayer())
+ name = "You";
+ else if (H::Entities.IsFriend(nIndex))
+ name = "Friend";
+ else if (pPlayer->m_iTeamNum() != pLocal->m_iTeamNum())
+ name = "Enemy";
+ else if (pPlayer->m_iTeamNum() == pLocal->m_iTeamNum())
+ name = "Teammate";
+
+ H::Draw.String(fFontName, middle, y - tOffset, Vars::Menu::Theme::Active.Value, ALIGN_TOP, name);
+ }
+ else
+ H::Draw.String(fFontName, middle, y - tOffset, Vars::Menu::Theme::Active.Value, ALIGN_TOP, SDK::ConvertUtf8ToWide(pi.name).data());
}
if (Vars::ESP::Player.Value & 1 << 12)
diff --git a/Fusion/src/Features/Visuals/SpectatorList/SpectatorList.cpp b/Fusion/src/Features/Visuals/SpectatorList/SpectatorList.cpp
index 0b6d571..1102d54 100644
--- a/Fusion/src/Features/Visuals/SpectatorList/SpectatorList.cpp
+++ b/Fusion/src/Features/Visuals/SpectatorList/SpectatorList.cpp
@@ -38,8 +38,19 @@ bool CSpectatorList::GetSpectators(CTFPlayer* pLocal)
PlayerInfo_t pi{};
if (I::EngineClient->GetPlayerInfo(pPlayer->entindex(), &pi))
{
+ std::wstring name = SDK::ConvertUtf8ToWide(pi.name);
+ if (Vars::Visuals::UI::StreamerMode.Value)
+ {
+ if (H::Entities.IsFriend(pPlayer->entindex()))
+ name = L"Friend";
+ else if (pPlayer->m_iTeamNum() != pLocal->m_iTeamNum())
+ name = L"Enemy";
+ else if (pPlayer->m_iTeamNum() == pLocal->m_iTeamNum())
+ name = L"Teammate";
+ }
+
Spectators.push_back({
- SDK::ConvertUtf8ToWide(pi.name), szMode, respawnIn, respawnTimeIncreased, H::Entities.IsFriend(pPlayer->entindex()),
+ name, szMode, respawnIn, respawnTimeIncreased, H::Entities.IsFriend(pPlayer->entindex()),
pPlayer->m_iTeamNum(), pPlayer->entindex()
});
}
diff --git a/Fusion/src/Hooks/CAttributeManager_AttribHookValue.cpp b/Fusion/src/Hooks/CAttributeManager_AttribHookValue.cpp
new file mode 100644
index 0000000..a4d2b7d
--- /dev/null
+++ b/Fusion/src/Hooks/CAttributeManager_AttribHookValue.cpp
@@ -0,0 +1,29 @@
+#include "../SDK/SDK.h"
+
+// Credits to Mad?
+
+MAKE_SIGNATURE(CAttributeManager_AttribHookValue, "client.dll", "4C 8B DC 49 89 5B ? 49 89 6B ? 49 89 73 ? 57 41 54 41 55 41 56 41 57 48 83 EC ? 48 8B 3D ? ? ? ? 4C 8D 35", 0x0);
+MAKE_SIGNATURE(FireEvent_AttribHookValue_Call, "client.dll", "E8 ? ? ? ? 8B F8 83 BE", 0x5);
+
+MAKE_HOOK(CAttributeManager_AttribHookValue, S::CAttributeManager_AttribHookValue(), int, __fastcall,
+ int baseVal, const char* str, void* pEnt, void* buffer, bool isGlobalConstStr)
+{
+ if (!Vars::Visuals::Particle::RainbowFootstepEffect.Value || I::EngineClient->IsTakingScreenshot() && Vars::Visuals::UI::CleanScreenshots.Value)
+ return CALL_ORIGINAL(baseVal, str, pEnt, buffer, isGlobalConstStr);
+
+ static const auto dwDesired = S::FireEvent_AttribHookValue_Call();
+ const auto dwRetAddr = std::uintptr_t(_ReturnAddress());
+
+ if (dwRetAddr == dwDesired)
+ {
+ static constexpr int HashedFootstepType = FNV1A::HashConst("halloween_footstep_type");
+ auto Hashed = FNV1A::Hash(str);
+ if (Hashed == HashedFootstepType)
+ {
+ Color_t Color = SDK::Rainbow();
+ return std::stoul(std::format("0x{:02X}{:02X}{:02X}", Color.r, Color.g, Color.b), nullptr, 16);
+ }
+ }
+
+ return CALL_ORIGINAL(baseVal, str, pEnt, buffer, isGlobalConstStr);
+}
\ No newline at end of file
diff --git a/Fusion/src/Hooks/CBaseHudChat_ChatPrintf.cpp b/Fusion/src/Hooks/CBaseHudChat_ChatPrintf.cpp
index b121d62..632ab60 100644
--- a/Fusion/src/Hooks/CBaseHudChat_ChatPrintf.cpp
+++ b/Fusion/src/Hooks/CBaseHudChat_ChatPrintf.cpp
@@ -2,6 +2,9 @@
#include "../Features/Players/PlayerUtils.h"
+std::string ColorRed = { '\x7', 'F', 'F', '3', 'F', '3', 'F' };
+std::string ColorBlue = { '\x7', '9', '9', 'C', 'C', 'F', 'F' };
+
MAKE_HOOK(CBaseHudChat_ChatPrintf, U::Memory.GetVFunc(I::ClientModeShared->m_pChatElement, 19), void, __fastcall,
void* ecx, int iPlayerIndex, int iFilter, const char* fmt, ...)
{
@@ -51,5 +54,25 @@ MAKE_HOOK(CBaseHudChat_ChatPrintf, U::Memory.GetVFunc(I::ClientModeShared->m_pCh
}
}
+ CTFPlayer* pEntity = I::ClientEntityList->GetClientEntity(iPlayerIndex)->As();
+ auto pLocal = H::Entities.GetLocal();
+ if (Vars::Visuals::UI::StreamerMode.Value && pEntity && pLocal)
+ {
+ std::string changedname;
+ if (iPlayerIndex == I::EngineClient->GetLocalPlayer())
+ changedname = "You";
+ else if (H::Entities.IsFriend(iPlayerIndex))
+ changedname = "Friend";
+ else if (pEntity->m_iTeamNum() != pLocal->m_iTeamNum())
+ changedname = "Enemy";
+ else if (pEntity->m_iTeamNum() == pLocal->m_iTeamNum())
+ changedname = "Teammate";
+
+ std::string newname = pEntity->IsAlive() ? (changedname + "\x1") : changedname;
+ std::string finalname = (pEntity->m_iTeamNum() == TF_TEAM_RED ? ColorRed : ColorBlue) + newname;
+ std::string finalmessage = (pEntity->IsAlive() ? "" : "\x1*DEAD* ") + finalname;
+ finalMsg = finalMsg.replace(0, finalMsg.find(name) + name.length(), finalmessage.c_str());
+ }
+
CALL_ORIGINAL(ecx, iPlayerIndex, iFilter, "%s", finalMsg.c_str());
}
\ No newline at end of file
diff --git a/Fusion/src/Hooks/CClientScoreBoardDialog_UpdatePlayerAvatar.cpp b/Fusion/src/Hooks/CClientScoreBoardDialog_UpdatePlayerAvatar.cpp
new file mode 100644
index 0000000..d79c0ca
--- /dev/null
+++ b/Fusion/src/Hooks/CClientScoreBoardDialog_UpdatePlayerAvatar.cpp
@@ -0,0 +1,12 @@
+#include "../SDK/SDK.h"
+
+MAKE_SIGNATURE(CClientScoreBoardDialog_UpdatePlayerAvatar, "client.dll", "4D 85 C0 0F 84 ? ? ? ? 53 55", 0x0);
+
+MAKE_HOOK(CClientScoreBoardDialog_UpdatePlayerAvatar, S::CClientScoreBoardDialog_UpdatePlayerAvatar(), void, __fastcall,
+ void* ecx, int playerIndex, KeyValues* kv)
+{
+ if (Vars::Visuals::UI::StreamerMode.Value)
+ return; // :trollface:
+
+ CALL_ORIGINAL(ecx, playerIndex, kv);
+}
\ No newline at end of file
diff --git a/Fusion/src/Hooks/CCvar_ConsoleColorPrintf.cpp b/Fusion/src/Hooks/CCvar_ConsoleColorPrintf.cpp
new file mode 100644
index 0000000..0b0c3f6
--- /dev/null
+++ b/Fusion/src/Hooks/CCvar_ConsoleColorPrintf.cpp
@@ -0,0 +1,18 @@
+#include "../SDK/SDK.h"
+
+MAKE_HOOK(CCvar_ConsoleColorPrintf, U::Memory.GetVFunc(I::CVar, 23), void, __fastcall,
+ void* ecx, const Color_t& clr, const char* pFormat, ...)
+{
+ va_list marker;
+ char buffer[4096];
+ va_start(marker, pFormat);
+ vsnprintf_s(buffer, sizeof(buffer), pFormat, marker);
+ va_end(marker);
+
+ char* msg = buffer;
+ if (!*msg) { return; }
+
+ std::string Message = msg;
+
+ return CALL_ORIGINAL(ecx, clr, "%s", Message.c_str());
+}
\ No newline at end of file
diff --git a/Fusion/src/Hooks/CParticleProperty_Create.cpp b/Fusion/src/Hooks/CParticleProperty_Create.cpp
new file mode 100644
index 0000000..53cc896
--- /dev/null
+++ b/Fusion/src/Hooks/CParticleProperty_Create.cpp
@@ -0,0 +1,122 @@
+#include "../SDK/SDK.h"
+
+// Credits to Mad? for the idea and medigun particle changer
+// Credits to yaya for the x86 sigs, rocket trail particle changer and the whole code :trollface:
+
+MAKE_SIGNATURE(CParticleProperty_Create, "client.dll", "48 89 5C 24 ? 48 89 6C 24 ? 48 89 74 24 ? 48 89 7C 24 ? 41 56 48 83 EC ? 48 8B 59 ? 49 8B F1", 0x0);
+
+MAKE_SIGNATURE(UpdateEffectsCall1, "client.dll", "E8 ? ? ? ? 49 8B CC F3 0F 11 74 24", 0x5);
+MAKE_SIGNATURE(UpdateEffectsCall2, "client.dll", "E8 ? ? ? ? 41 8B 14 24 48 8B D8", 0x5);
+MAKE_SIGNATURE(ManageChargeEffectCall, "client.dll", "E8 ? ? ? ? 48 89 86 ? ? ? ? 48 89 BE", 0x5);
+MAKE_SIGNATURE(Rockettrail_UnderwaterCall, "client.dll", "E8 ? ? ? ? 48 8B 5C 24 ? 40 38 B7", 0x5);
+
+MAKE_HOOK(CParticleProperty_Create, S::CParticleProperty_Create(), int, __fastcall,
+ void* ecx, const char* pszParticleName, ParticleAttachment_t iAttachType, const char* pszAttachmentName)
+{
+ if (I::EngineClient->IsTakingScreenshot() && Vars::Visuals::UI::CleanScreenshots.Value)
+ return CALL_ORIGINAL(ecx, pszParticleName, iAttachType, pszAttachmentName);
+
+ if (auto pLocal = H::Entities.GetLocal())
+ {
+ static auto UpdateEffectsCall1 = S::UpdateEffectsCall1();
+ static auto UpdateEffectsCall2 = S::UpdateEffectsCall2();
+ static auto ManageChargeEffectCall = S::ManageChargeEffectCall();
+ static auto Rockettrail_UnderwaterCall = S::Rockettrail_UnderwaterCall();
+
+ const auto dwRetAddr = std::uintptr_t(_ReturnAddress());
+
+ if (dwRetAddr == UpdateEffectsCall1 || dwRetAddr == UpdateEffectsCall2)
+ {
+ switch (Vars::Visuals::Particle::MedigunBeamEffect.Value)
+ {
+ case 0: break;
+ case 1: pszParticleName = pLocal->m_iTeamNum() == TF_TEAM_BLUE ? "dispenser_heal_blue" : "dispenser_heal_red"; break;
+ case 2: pszParticleName = "passtime_beam"; break;
+ case 3: pszParticleName = "bombonomicon_spell_trail"; break;
+ case 4: pszParticleName = "medicgun_beam_machinery_stage3"; break;
+ case 5: pszParticleName = pLocal->m_iTeamNum() == TF_TEAM_BLUE ? "medicgun_beam_blue_invun" : "medicgun_beam_red_invun"; break;
+ }
+ }
+
+ if (dwRetAddr == ManageChargeEffectCall)
+ {
+ switch (Vars::Visuals::Particle::MedigunChargeEffect.Value)
+ {
+ case 0: break;
+ case 1: pszParticleName = pLocal->m_iTeamNum() == TF_TEAM_BLUE ? "spell_fireball_small_trail_blue" : "spell_fireball_small_trail_red"; break;
+ case 2: pszParticleName = "unusual_spellbook_circle_purple"; break;
+ case 3: pszParticleName = pLocal->m_iTeamNum() == TF_TEAM_BLUE ? "electrocuted_blue" : "electrocuted_red"; break;
+ case 4: pszParticleName = "unusual_hearts_bubbling"; break;
+ case 5: pszParticleName = pLocal->m_iTeamNum() == TF_TEAM_BLUE ? "unusual_robot_orbiting_sparks" : "unusual_robot_orbiting_sparks2"; break;
+ case 6: pszParticleName = "unusual_storm_knives_clouds"; break;
+ case 7: pszParticleName = "unusual_eotl_frostbite"; break;
+ case 8: pszParticleName = pLocal->m_iTeamNum() == TF_TEAM_BLUE ? "unusual_souls_green_parent" : "unusual_souls_purple_parent"; break;
+ case 9: pszParticleName = pLocal->m_iTeamNum() == TF_TEAM_BLUE ? "unusual_robot_time_warp" : "unusual_robot_time_warp2"; break;
+ case 10: pszParticleName = "unusual_storm_spooky"; break;
+ case 11: pszParticleName = pLocal->m_iTeamNum() == TF_TEAM_BLUE ? "unusual_zap_green" : "unusual_zap_yellow"; break;
+ case 12: pszParticleName = "superrare_beams1"; break;
+ case 13: pszParticleName = "superrare_beams1_newstyle"; break;
+ case 14: pszParticleName = "utaunt_disco_beams3"; break;
+ case 15: pszParticleName = "ghost_pumpkin"; break;
+ }
+ }
+
+ if (dwRetAddr == Rockettrail_UnderwaterCall)
+ {
+ switch (Vars::Visuals::Particle::RocketTrailEffect.Value)
+ {
+ case 0: break;
+ case 1: pszParticleName = pLocal->m_iTeamNum() == TF_TEAM_BLUE ? "critical_rocket_blue" : "critical_rocket_red"; break;
+ case 2: pszParticleName = "rockettrail_underwater"; break;
+ case 3: pszParticleName = "halloween_rockettrail"; break;
+ case 4: pszParticleName = "rockettrail_airstrike_line"; break;
+ case 5: pszParticleName = "eyeboss_projectile"; break;
+ case 6: pszParticleName = pLocal->m_iTeamNum() == TF_TEAM_BLUE ? "drg_cow_rockettrail_normal_blue" : "drg_cow_rockettrail_normal"; break;
+ case 7: pszParticleName = pLocal->m_iTeamNum() == TF_TEAM_BLUE ? "drg_cow_rockettrail_charged_blue" : "drg_cow_rockettrail_charged"; break;
+ }
+ }
+ }
+
+ return CALL_ORIGINAL(ecx, pszParticleName, iAttachType, pszAttachmentName);
+}
+
+MAKE_SIGNATURE(CParticleProperty_Create2, "client.dll", "44 89 4C 24 ? 44 89 44 24 ? 53", 0x0);
+
+MAKE_SIGNATURE(Rockettrail_AirstrikeCall, "client.dll", "E8 ? ? ? ? 48 8B CF E8 ? ? ? ? 48 8B D8 48 85 C0 0F 84", 0x5);
+MAKE_SIGNATURE(Rockettrail_bUsingCustomCall, "client.dll", "E8 ? ? ? ? EB ? 4C 8D 0D ? ? ? ? 41 B8 ? ? ? ? 48 8D 15", 0x5);
+MAKE_SIGNATURE(Halloween_RockettrailCall, "client.dll", "E8 ? ? ? ? E9 ? ? ? ? 48 85 DB 0F 85", 0x5);
+MAKE_SIGNATURE(CTFProjectile_EnergyBallCall, "client.dll", "E8 ? ? ? ? 48 8B 7C 24 ? 48 89 83", 0x5);
+
+MAKE_HOOK(CParticleProperty_Create2, S::CParticleProperty_Create2(), int, __fastcall,
+ void* ecx, const char* pszParticleName, ParticleAttachment_t iAttachType, int iAttachmentPoint, Vector vecOriginOffset)
+{
+ if (I::EngineClient->IsTakingScreenshot() && Vars::Visuals::UI::CleanScreenshots.Value)
+ return CALL_ORIGINAL(ecx, pszParticleName, iAttachType, iAttachmentPoint, vecOriginOffset);
+
+ if (auto pLocal = H::Entities.GetLocal())
+ {
+ static auto Rockettrail_AirstrikeCall = S::Rockettrail_AirstrikeCall();
+ static auto Rockettrail_bUsingCustomCall = S::Rockettrail_bUsingCustomCall();
+ static auto Halloween_RockettrailCall = S::Halloween_RockettrailCall();
+ static auto CTFProjectile_EnergyBallCall = S::CTFProjectile_EnergyBallCall();
+
+ const auto dwRetAddr = std::uintptr_t(_ReturnAddress());
+
+ if (dwRetAddr == Rockettrail_AirstrikeCall || dwRetAddr == Rockettrail_bUsingCustomCall || dwRetAddr == Halloween_RockettrailCall || dwRetAddr == CTFProjectile_EnergyBallCall)
+ {
+ switch (Vars::Visuals::Particle::RocketTrailEffect.Value)
+ {
+ case 0: break;
+ case 1: pszParticleName = pLocal->m_iTeamNum() == TF_TEAM_BLUE ? "critical_rocket_blue" : "critical_rocket_red"; break;
+ case 2: pszParticleName = "rockettrail_underwater"; break;
+ case 3: pszParticleName = "halloween_rockettrail"; break;
+ case 4: pszParticleName = "rockettrail_airstrike_line"; break;
+ case 5: pszParticleName = "eyeboss_projectile"; break;
+ case 6: pszParticleName = pLocal->m_iTeamNum() == TF_TEAM_BLUE ? "drg_cow_rockettrail_normal_blue" : "drg_cow_rockettrail_normal"; break;
+ case 7: pszParticleName = pLocal->m_iTeamNum() == TF_TEAM_BLUE ? "drg_cow_rockettrail_charged_blue" : "drg_cow_rockettrail_charged"; break;
+ }
+ }
+ }
+
+ return CALL_ORIGINAL(ecx, pszParticleName, iAttachType, iAttachmentPoint, vecOriginOffset);
+}
\ No newline at end of file
diff --git a/Fusion/src/Hooks/C_PlayerResource_GetPlayerName.cpp b/Fusion/src/Hooks/C_PlayerResource_GetPlayerName.cpp
new file mode 100644
index 0000000..9574cbb
--- /dev/null
+++ b/Fusion/src/Hooks/C_PlayerResource_GetPlayerName.cpp
@@ -0,0 +1,26 @@
+#include "../SDK/SDK.h"
+
+MAKE_SIGNATURE(C_PlayerResource_GetPlayerName, "client.dll", "48 89 5C 24 ? 56 48 83 EC ? 48 63 F2", 0x0);
+
+MAKE_HOOK(C_PlayerResource_GetPlayerName, S::C_PlayerResource_GetPlayerName(), const char*, __fastcall,
+ void* ecx, int iIndex)
+{
+ if (!Vars::Visuals::UI::StreamerMode.Value)
+ return CALL_ORIGINAL(ecx, iIndex);
+
+ CTFPlayer* pEntity = I::ClientEntityList->GetClientEntity(iIndex)->As();
+ auto pLocal = H::Entities.GetLocal();
+ if (!pEntity || !pLocal)
+ return CALL_ORIGINAL(ecx, iIndex);
+
+ if (iIndex == I::EngineClient->GetLocalPlayer())
+ return "You";
+ else if (H::Entities.IsFriend(iIndex))
+ return "Friend";
+ else if (pEntity->m_iTeamNum() != pLocal->m_iTeamNum())
+ return "Enemy";
+ else if (pEntity->m_iTeamNum() == pLocal->m_iTeamNum())
+ return "Teammate";
+
+ return CALL_ORIGINAL(ecx, iIndex);
+}
\ No newline at end of file
diff --git a/Fusion/src/Hooks/Panel_PaintTraverse.cpp b/Fusion/src/Hooks/Panel_PaintTraverse.cpp
new file mode 100644
index 0000000..790f192
--- /dev/null
+++ b/Fusion/src/Hooks/Panel_PaintTraverse.cpp
@@ -0,0 +1,18 @@
+// this crashes, why?
+#include "../SDK/SDK.h"
+
+MAKE_HOOK(Panel_PaintTraverse, U::Memory.GetVFunc(I::VGuiPanel, 41), void, __fastcall,
+ void* ecx, unsigned int VGuiPanel, bool forceRepaint, bool allowForce)
+{
+ /*const auto PanelName = I::VGuiPanel->GetName(VGuiPanel);
+
+ constexpr auto SteamFriendsList = FNV1A::HashConst("SteamFriendsList");
+ constexpr auto RankPanel = FNV1A::HashConst("RankPanel");
+ constexpr auto avatar = FNV1A::HashConst("avatar");*/
+
+ if (I::VGuiPanel->GetName(VGuiPanel) == "SteamFriendsList" || I::VGuiPanel->GetName(VGuiPanel) == "RankPanel" || I::VGuiPanel->GetName(VGuiPanel) == "avatar")
+ return;
+
+ SDK::Output("PaintTraverse", I::VGuiPanel->GetName(VGuiPanel));
+ CALL_ORIGINAL(ecx, VGuiPanel, forceRepaint, allowForce);
+}
\ No newline at end of file
diff --git a/Fusion/src/Hooks/S_StartSound.cpp b/Fusion/src/Hooks/S_StartSound.cpp
index 500860e..00aa54d 100644
--- a/Fusion/src/Hooks/S_StartSound.cpp
+++ b/Fusion/src/Hooks/S_StartSound.cpp
@@ -1,5 +1,7 @@
#include "../SDK/SDK.h"
+// Credits to yaya for the sig and general help
+
MAKE_SIGNATURE(S_StartSound, "engine.dll", "40 53 48 83 EC ? 48 83 79 ? ? 48 8B D9 75 ? 33 C0", 0x0);
const static std::vector NOISEMAKER_SOUNDS{ "items\\halloween", "items\\football_manager", "items\\japan_fundraiser", "items\\samurai", "items\\summer", "misc\\happy_birthday_tf", "misc\\jingle_bells" };
diff --git a/Fusion/src/Hooks/TF_IsHolidayActive.cpp b/Fusion/src/Hooks/TF_IsHolidayActive.cpp
new file mode 100644
index 0000000..f8037ea
--- /dev/null
+++ b/Fusion/src/Hooks/TF_IsHolidayActive.cpp
@@ -0,0 +1,28 @@
+#include "../SDK/SDK.h"
+
+// Credits to Myzarfin
+
+enum EHoliday
+{
+ kHoliday_None = 0, // must stay at zero for backwards compatibility
+ kHoliday_TFBirthday,
+ kHoliday_Halloween,
+ kHoliday_Christmas,
+ kHoliday_CommunityUpdate,
+ kHoliday_EOTL,
+ kHoliday_Valentines,
+ kHoliday_MeetThePyro,
+ kHoliday_FullMoon,
+ kHoliday_HalloweenOrFullMoon,
+ kHoliday_HalloweenOrFullMoonOrValentines,
+ kHoliday_AprilFools,
+ kHolidayCount,
+};
+
+MAKE_SIGNATURE(TF_IsHolidayActive, "client.dll", "48 83 EC ? 48 8B 05 ? ? ? ? 44 8B C9", 0x0);
+
+MAKE_HOOK(TF_IsHolidayActive, S::TF_IsHolidayActive(), bool, __fastcall,
+ int eHoliday)
+{
+ return eHoliday == kHoliday_HalloweenOrFullMoon ? true : CALL_ORIGINAL(eHoliday);
+}
\ No newline at end of file
diff --git a/Fusion/src/SDK/SDK.cpp b/Fusion/src/SDK/SDK.cpp
index 3be927f..b5aba36 100644
--- a/Fusion/src/SDK/SDK.cpp
+++ b/Fusion/src/SDK/SDK.cpp
@@ -14,6 +14,28 @@ BOOL CALLBACK TeamFortressWindow(HWND hwnd, LPARAM lParam)
return TRUE;
}
+Color_t SDK::Rainbow()
+{
+ float t = TICKS_TO_TIME(I::GlobalVars->tickcount);
+
+ int r = static_cast(std::round(std::cos(I::GlobalVars->realtime + t + 0.0f) * 127.5f + 127.5f));
+ int g = static_cast(std::round(std::cos(I::GlobalVars->realtime + t + 2.0f) * 127.5f + 127.5f));
+ int b = static_cast(std::round(std::cos(I::GlobalVars->realtime + t + 4.0f) * 127.5f + 127.5f));
+
+ return Color_t{ static_cast(r), static_cast(g), static_cast(b), 255 };
+}
+
+Color_t SDK::RainbowTickOffset(int nTick)
+{
+ float t = TICKS_TO_TIME(nTick);
+
+ int r = static_cast(std::lround(std::cos((I::GlobalVars->realtime * 2.0f) + t + 0.0f) * 127.5f + 127.5f));
+ int g = static_cast(std::lround(std::cos((I::GlobalVars->realtime * 2.0f) + t + 2.0f) * 127.5f + 127.5f));
+ int b = static_cast(std::lround(std::cos((I::GlobalVars->realtime * 2.0f) + t + 4.0f) * 127.5f + 127.5f));
+
+ return Color_t{ static_cast(r), static_cast(g), static_cast(b), 255 };
+}
+
Color_t SDK::WarningColor()
{
return I::GlobalVars->tickcount % 63 < 32 ? Color_t(250, 170, 10, 255) : Color_t(252, 92, 101, 255);
diff --git a/Fusion/src/SDK/SDK.h b/Fusion/src/SDK/SDK.h
index e3baf7a..ddf746a 100644
--- a/Fusion/src/SDK/SDK.h
+++ b/Fusion/src/SDK/SDK.h
@@ -107,6 +107,8 @@ enum DataCenter_t // i'm not sure all of these are actually used for tf2 servers
namespace SDK
{
+ Color_t Rainbow();
+ Color_t RainbowTickOffset(int nTick);
Color_t WarningColor();
void Output(const char* cFunction, const char* cLog, Color_t cColor = { 255, 255, 255, 255 }, bool bConsole = true, bool bChat = false, bool bDebug = false);
diff --git a/Fusion/src/SDK/Vars.h b/Fusion/src/SDK/Vars.h
index 937517a..a01bdae 100644
--- a/Fusion/src/SDK/Vars.h
+++ b/Fusion/src/SDK/Vars.h
@@ -415,6 +415,13 @@ namespace Vars
CVar(ThePS2Inator, false)
SUBNAMESPACE_END(Yes)
+ SUBNAMESPACE_BEGIN(Particle)
+ CVar(MedigunBeamEffect, 0, VISUAL)
+ CVar(MedigunChargeEffect, 0, VISUAL)
+ CVar(RocketTrailEffect, 0, VISUAL)
+ CVar(RainbowFootstepEffect, false, VISUAL)
+ SUBNAMESPACE_END(Particle)
+
SUBNAMESPACE_BEGIN(Removals)
CVar(Scope, false, VISUAL)
CVar(Interpolation, false)
@@ -440,6 +447,7 @@ namespace Vars
CVar(ScoreboardColors, false, VISUAL)
CVar(SniperSightlines, false, VISUAL)
CVar(PickupTimers, false, VISUAL)
+ CVar(StreamerMode, false, VISUAL)
SUBNAMESPACE_END(Viewmodel)
SUBNAMESPACE_BEGIN(Viewmodel)
@@ -716,6 +724,7 @@ namespace Vars
CVar(PropModulation, Color_t(255, 255, 255, 255), VISUAL)
CVar(ParticleModulation, Color_t(255, 255, 255, 255), VISUAL)
CVar(FogModulation, Color_t(255, 255, 255, 255), VISUAL)
+ CVar(FootstepParticle, Color_t(203, 166, 247, 255), VISUAL)
CVar(BulletTracer, Color_t(255, 255, 255, 255), VISUAL)
CVar(PredictionColor, Color_t(255, 255, 255, 255), VISUAL)