diff --git a/AMBuilder b/AMBuilder index 35b70d50..f4cd4810 100644 --- a/AMBuilder +++ b/AMBuilder @@ -14,7 +14,7 @@ sourceFiles = [ 'src/common.cpp', 'src/sizeof.cpp', 'src/extension.cpp', - 'src/client.cpp', + 'src/factory.cpp', 'src/gameconf.cpp', 'src/library.cpp', 'src/disasm/disasm.cpp', @@ -45,6 +45,8 @@ sourceFiles = [ 'src/stub/objects.cpp', 'src/stub/econ.cpp', 'src/stub/cdebugoverlay.cpp', + 'src/stub/particles.cpp', + 'src/stub/igamesystem.cpp', 'src/link/link.cpp', 'src/link/nextbot1.cpp', 'src/link/nextbot2.cpp', @@ -91,6 +93,7 @@ sourceFiles = [ 'src/mod/robot/ticklish.cpp', 'src/mod/sniper/charge_uncap.cpp', 'src/mod/sniper/head_uncap.cpp', + 'src/mod/sound/tele_activate.cpp', 'src/mod/util/console_recv.cpp', 'src/mod/util/console_send.cpp', 'src/mod/util/listenserverhost.cpp', @@ -102,6 +105,7 @@ sourceFiles = [ 'src/mod/visualize/explosive_headshot.cpp', 'src/mod/visualize/minigun_deflect.cpp', 'src/mod/visualize/taunt_attacks.cpp', + 'src/mod/visualize/jar_radius.cpp', ] ############### diff --git a/PackageScript b/PackageScript index 0a5b6b26..1e5feea2 100644 --- a/PackageScript +++ b/PackageScript @@ -14,6 +14,7 @@ folder_list = [ 'addons/sourcemod/gamedata/sigsegv', # 'addons/sourcemod/configs', 'custom/sigsegv/resource', + 'custom/sigsegv/scripts', ] # Create the distribution folder hierarchy. @@ -86,6 +87,13 @@ CopyFiles('resource', 'custom/sigsegv/resource', ] ) +# Script files +CopyFiles('scripts', 'custom/sigsegv/scripts', + [ + 'sigsegv_sound_overrides.txt', + ] +) + # Copy binaries. for cxx_task in Extension.extensions: src = os.path.join('..', cxx_task.binary.path) diff --git a/gamedata/sigsegv/misc.txt b/gamedata/sigsegv/misc.txt index 4690a131..6f399856 100644 --- a/gamedata/sigsegv/misc.txt +++ b/gamedata/sigsegv/misc.txt @@ -495,6 +495,85 @@ type "sym" sym "_ZN11CBaseEntity6RemoveEv" } + + "UTIL_EntitiesInSphere" + { + type "sym" + sym "_Z21UTIL_EntitiesInSphereRK6VectorfP20CFlaggedEntitiesEnum" + } + "CTFProjectile_Jar::Explode" + { + type "sym" + sym "_ZN17CTFProjectile_Jar7ExplodeEP10CGameTracei" + } + "CBaseProjectile::GetProjectileType" + { + type "sym" + sym "_ZNK15CBaseProjectile17GetProjectileTypeEv" + } + "CTFWeaponBaseGrenadeProj::GetWeaponID" + { + type "sym" + sym "_ZNK24CTFWeaponBaseGrenadeProj11GetWeaponIDEv" + } + + "DispatchParticleEffect [overload 1]" + { + type "sym" + sym "_Z22DispatchParticleEffectPKc20ParticleAttachment_tP11CBaseEntityS0_b" + } + "DispatchParticleEffect [overload 2]" + { + type "sym" + sym "_Z22DispatchParticleEffectPKc20ParticleAttachment_tP11CBaseEntityib" + } + "DispatchParticleEffect [overload 3]" + { + type "sym" + sym "_Z22DispatchParticleEffectPKc6Vector6QAngleP11CBaseEntity" + } + "DispatchParticleEffect [overload 4]" + { + type "sym" + sym "_Z22DispatchParticleEffectPKc6VectorS1_6QAngleP11CBaseEntity" + } + "DispatchParticleEffect [overload 5]" + { + type "sym" + sym "_Z22DispatchParticleEffecti6VectorS_6QAngleP11CBaseEntity" + } + "DispatchParticleEffect [overload 6]" + { + type "sym" + sym "_Z22DispatchParticleEffectPKc20ParticleAttachment_tP11CBaseEntityS0_6VectorS4_bb" + } + "DispatchParticleEffect [overload 7]" + { + type "sym" + sym "_Z22DispatchParticleEffectPKc6Vector6QAngleS1_S1_bP11CBaseEntityi" + } + "StopParticleEffects" + { + type "sym" + sym "_Z19StopParticleEffectsP11CBaseEntity" + } + + "CBaseEntity::EmitSound" + { + type "sym" + sym "_ZN11CBaseEntity9EmitSoundEPKcfPf" + } + + "IGameSystem::Add" + { + type "sym" + sym "_ZN11IGameSystem3AddEPS_" + } + "IGameSystem::Remove" + { + type "sym" + sym "_ZN11IGameSystem6RemoveEPS_" + } } } } diff --git a/gamedata/sigsegv/tfplayer.txt b/gamedata/sigsegv/tfplayer.txt index 70b73c4a..6ec66d91 100644 --- a/gamedata/sigsegv/tfplayer.txt +++ b/gamedata/sigsegv/tfplayer.txt @@ -122,6 +122,16 @@ type "sym" sym "_ZN15CTFPlayerShared10StunPlayerEffiP9CTFPlayer" } + "CTFPlayerShared::OnConditionAdded" + { + type "sym" + sym "_ZN15CTFPlayerShared16OnConditionAddedE7ETFCond" + } + "CTFPlayerShared::OnConditionRemoved" + { + type "sym" + sym "_ZN15CTFPlayerShared18OnConditionRemovedE7ETFCond" + } "CTFPlayerSharedUtils::GetEconItemViewByLoadoutSlot" { diff --git a/scripts/sigsegv_sound_overrides.txt b/scripts/sigsegv_sound_overrides.txt new file mode 100644 index 00000000..7d47e40e --- /dev/null +++ b/scripts/sigsegv_sound_overrides.txt @@ -0,0 +1,8 @@ +"MVM.Robot_Teleporter_Activate" +{ + "channel" "CHAN_STATIC" + "volume" "1" + "pitch" "100" + "soundlevel" "SNDLVL_150dB" + "wave" ")mvm/mvm_tele_activate.wav" +} diff --git a/src/common.h b/src/common.h index c121c49b..4457ce31 100644 --- a/src/common.h +++ b/src/common.h @@ -18,12 +18,14 @@ class ICvar; class ISpatialPartition; class IEngineTrace; class IStaticPropMgrServer; -class IVDebugOverlay; class IGameEventManager2; +class IEngineSound; +class IVDebugOverlay; +class ISoundEmitterSystemBase; +class IMaterialSystem; class CGlobalVars; class CBaseEntityList; class IBaseClientDLL; -class IMaterialSystem; namespace SourcePawn { class ISourcePawnEngine; } @@ -38,13 +40,17 @@ extern ISpatialPartition *partition; extern IEngineTrace *enginetrace; extern IStaticPropMgrServer *staticpropmgr; extern IGameEventManager2 *gameeventmanager; +extern IEngineSound *enginesound; extern IVDebugOverlay *debugoverlay; +extern ISoundEmitterSystemBase *soundemitterbase; + +extern IMaterialSystem *g_pMaterialSystem; + extern CGlobalVars *gpGlobals; extern CBaseEntityList *g_pEntityList; extern IBaseClientDLL *clientdll; -extern IMaterialSystem *g_pMaterialSystem; extern SourcePawn::ISourcePawnEngine *g_pSourcePawn; extern SourceMod::IExtensionManager *smexts; @@ -155,6 +161,10 @@ extern SourceMod::IExtensionManager *smexts; #include #include #include +#include +#include +#include +#include #define DECLARE_PREDICTABLE() #include diff --git a/src/extension.cpp b/src/extension.cpp index 33994814..035542ba 100644 --- a/src/extension.cpp +++ b/src/extension.cpp @@ -8,7 +8,7 @@ #include "prop.h" #include "util/rtti.h" #include "disasm/disasm.h" -#include "client.h" +#include "factory.h" CExtSigsegv g_Ext; @@ -20,13 +20,17 @@ ISpatialPartition *partition = nullptr; IEngineTrace *enginetrace = nullptr; IStaticPropMgrServer *staticpropmgr = nullptr; IGameEventManager2 *gameeventmanager = nullptr; +IEngineSound *enginesound = nullptr; IVDebugOverlay *debugoverlay = nullptr; +ISoundEmitterSystemBase *soundemitterbase = nullptr; + +IMaterialSystem *g_pMaterialSystem = nullptr; + CGlobalVars *gpGlobals = nullptr; CBaseEntityList *g_pEntityList = nullptr; IBaseClientDLL *clientdll = nullptr; -IMaterialSystem *g_pMaterialSystem = nullptr; SourcePawn::ISourcePawnEngine *g_pSourcePawn = nullptr; SourceMod::IExtensionManager *smexts = nullptr; @@ -54,7 +58,11 @@ bool CExtSigsegv::SDK_OnLoad(char *error, size_t maxlen, bool late) // sharesys->AddDependency(myself, "sdktools.ext", true, true); // SM_GET_IFACE(SDKTOOLS, g_pSDKTools); - gameeventmanager->LoadEventsFromFile("resource/sigsegv_events.res"); + if (gameeventmanager != nullptr) { + gameeventmanager->LoadEventsFromFile("resource/sigsegv_events.res"); + } + + this->LoadSoundOverrides(); g_pEntityList = reinterpret_cast(gamehelpers->GetGlobalEntityList()); @@ -73,7 +81,9 @@ bool CExtSigsegv::SDK_OnLoad(char *error, size_t maxlen, bool late) Prop::PreloadAll(); - CModManager::LoadAllMods(); + g_ModManager.Load(); + + IGameSystem::Add(this); return true; @@ -84,7 +94,9 @@ bool CExtSigsegv::SDK_OnLoad(char *error, size_t maxlen, bool late) void CExtSigsegv::SDK_OnUnload() { - CModManager::UnloadAllMods(); + IGameSystem::Remove(this); + + g_ModManager.Unload(); LibMgr::Unload(); @@ -121,15 +133,23 @@ bool CExtSigsegv::SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlen, b GET_V_IFACE_CURRENT(GetEngineFactory, enginetrace, IEngineTrace, INTERFACEVERSION_ENGINETRACE_SERVER); GET_V_IFACE_CURRENT(GetEngineFactory, staticpropmgr, IStaticPropMgrServer, INTERFACEVERSION_STATICPROPMGR_SERVER); GET_V_IFACE_CURRENT(GetEngineFactory, gameeventmanager, IGameEventManager2, INTERFACEVERSION_GAMEEVENTSMANAGER2); + GET_V_IFACE_CURRENT(GetEngineFactory, enginesound, IEngineSound, IENGINESOUND_SERVER_INTERFACE_VERSION); //GET_V_IFACE_CURRENT(GetEngineFactory, debugoverlay, IVDebugOverlay, VDEBUG_OVERLAY_INTERFACE_VERSION); debugoverlay = (IVDebugOverlay *)ismm->VInterfaceMatch(ismm->GetEngineFactory(), VDEBUG_OVERLAY_INTERFACE_VERSION, 0); - if (IsClient()) { - clientdll = (IBaseClientDLL *)ismm->VInterfaceMatch(GetClientFactory(), CLIENT_DLL_INTERFACE_VERSION, 0); + if (GetSoundEmitterSystemFactory() != nullptr) { + soundemitterbase = (ISoundEmitterSystemBase *)ismm->VInterfaceMatch(GetSoundEmitterSystemFactory(), SOUNDEMITTERSYSTEM_INTERFACE_VERSION, 0); + } + + if (GetMaterialSystemFactory() != nullptr) { g_pMaterialSystem = (IMaterialSystem *)ismm->VInterfaceMatch(GetMaterialSystemFactory(), MATERIAL_SYSTEM_INTERFACE_VERSION, 0); } + if (GetClientFactory() != nullptr) { + clientdll = (IBaseClientDLL *)ismm->VInterfaceMatch(GetClientFactory(), CLIENT_DLL_INTERFACE_VERSION, 0); + } + gpGlobals = ismm->GetCGlobals(); LibMgr::SetPtr(Library::SERVER, (void *)ismm->GetServerFactory(false)); @@ -153,6 +173,47 @@ bool CExtSigsegv::RegisterConCommandBase(ConCommandBase *pCommand) } +void CExtSigsegv::LevelInitPreEntity() +{ + this->LoadSoundOverrides(); + + g_ModManager.LevelInitPreEntity(); +} + +void CExtSigsegv::LevelInitPostEntity() +{ + g_ModManager.LevelInitPostEntity(); +} + +void CExtSigsegv::LevelShutdownPreEntity() +{ + g_ModManager.LevelShutdownPreEntity(); +} + +void CExtSigsegv::LevelShutdownPostEntity() +{ + g_ModManager.LevelShutdownPostEntity(); +} + +void CExtSigsegv::FrameUpdatePreEntityThink() +{ + g_ModManager.FrameUpdatePreEntityThink(); +} + +void CExtSigsegv::FrameUpdatePostEntityThink() +{ + g_ModManager.FrameUpdatePostEntityThink(); +} + + +void CExtSigsegv::LoadSoundOverrides() +{ + if (soundemitterbase != nullptr) { + soundemitterbase->AddSoundOverrides("scripts/sigsegv_sound_overrides.txt", true); + } +} + + void CExtSigsegv::EnableColorSpew() { #if defined POSIX diff --git a/src/extension.h b/src/extension.h index c2953069..3dce364d 100644 --- a/src/extension.h +++ b/src/extension.h @@ -6,27 +6,40 @@ #define maxlength maxlen -class CExtSigsegv : public SDKExtension, public IConCommandBaseAccessor +class CExtSigsegv : + public SDKExtension, + public IMetamodListener, + public IConCommandBaseAccessor, + public CBaseGameSystemPerFrame { public: - virtual bool SDK_OnLoad(char *error, size_t maxlen, bool late); - virtual void SDK_OnUnload(); - virtual void SDK_OnAllLoaded(); -// virtual void SDK_OnPauseChange(bool paused); - virtual bool QueryRunning(char *error, size_t maxlen); + virtual bool SDK_OnLoad(char *error, size_t maxlen, bool late) override; + virtual void SDK_OnUnload() override; + virtual void SDK_OnAllLoaded() override; +// virtual void SDK_OnPauseChange(bool paused) override; + virtual bool QueryRunning(char *error, size_t maxlen) override; #if defined SMEXT_CONF_METAMOD - virtual bool SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlen, bool late); - virtual bool SDK_OnMetamodUnload(char *error, size_t maxlen); -// virtual bool SDK_OnMetamodPauseChange(bool paused, char *error, size_t maxlen); + virtual bool SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlen, bool late) override; + virtual bool SDK_OnMetamodUnload(char *error, size_t maxlen) override; +// virtual bool SDK_OnMetamodPauseChange(bool paused, char *error, size_t maxlen) override; #endif bool RegisterConCommandBase(ConCommandBase *pCommand); +private: + virtual void LevelInitPreEntity() override; + virtual void LevelInitPostEntity() override; + virtual void LevelShutdownPreEntity() override; + virtual void LevelShutdownPostEntity() override; + virtual void FrameUpdatePreEntityThink() override; + virtual void FrameUpdatePostEntityThink() override; + + void LoadSoundOverrides(); + void EnableColorSpew(); void DisableColorSpew(); -private: SpewOutputFunc_t m_pSpewOutputBackup = nullptr; }; extern CExtSigsegv g_Ext; diff --git a/src/client.cpp b/src/factory.cpp similarity index 69% rename from src/client.cpp rename to src/factory.cpp index db8dc2c0..a8b01895 100644 --- a/src/client.cpp +++ b/src/factory.cpp @@ -1,20 +1,27 @@ -#include "client.h" +#include "factory.h" -#undef DLL_EXT_STRING - #if defined _WINDOWS -#define DLL_EXT_STRING ".dll" +#define DLL_EXT_STRINGS { ".dll" } #elif defined _LINUX -#define DLL_EXT_STRING ".so" +#define DLL_EXT_STRINGS { ".so", "_srv.so" } #elif defined _OSX -#define DLL_EXT_STRING ".dylib" +#define DLL_EXT_STRINGS { ".dylib" } #endif -bool IsClient() +CreateInterfaceFn GetFactory_NoExt(const char *name) { - return (GetClientFactory() != nullptr); + char buf[1024]; + + for (auto ext : DLL_EXT_STRINGS) { + snprintf(buf, sizeof(buf), "%s%s", name, ext); + + auto fn = Sys_GetFactory(buf); + if (fn != nullptr) return fn; + } + + return nullptr; } @@ -24,7 +31,31 @@ CreateInterfaceFn GetClientFactory() static CreateInterfaceFn factory = nullptr; if (!init) { - factory = Sys_GetFactory("client" DLL_EXT_STRING); + factory = GetFactory_NoExt("client"); + + if (factory == nullptr) { + Warning("GetClientFactory: factory is nullptr\n"); + } + + init = true; + } + + return factory; +} + + +CreateInterfaceFn GetSoundEmitterSystemFactory() +{ + static bool init = false; + static CreateInterfaceFn factory = nullptr; + + if (!init) { + factory = GetFactory_NoExt("soundemittersystem"); + + if (factory == nullptr) { + Warning("GetSoundEmitterSystemFactory: factory is nullptr\n"); + } + init = true; } @@ -38,7 +69,12 @@ CreateInterfaceFn GetMaterialSystemFactory() static CreateInterfaceFn factory = nullptr; if (!init) { - factory = Sys_GetFactory("materialsystem" DLL_EXT_STRING); + factory = GetFactory_NoExt("materialsystem"); + + if (factory == nullptr) { + Warning("GetMaterialSystemFactory: factory is nullptr\n"); + } + init = true; } diff --git a/src/factory.h b/src/factory.h new file mode 100644 index 00000000..7c463ede --- /dev/null +++ b/src/factory.h @@ -0,0 +1,10 @@ +#ifndef _INCLUDE_SIGSEGV_FACTORY_H_ +#define _INCLUDE_SIGSEGV_FACTORY_H_ + + +CreateInterfaceFn GetClientFactory(); +CreateInterfaceFn GetSoundEmitterSystemFactory(); +CreateInterfaceFn GetMaterialSystemFactory(); + + +#endif diff --git a/src/mem/detour.cpp b/src/mem/detour.cpp index 99da9324..7c5ec2ea 100644 --- a/src/mem/detour.cpp +++ b/src/mem/detour.cpp @@ -631,7 +631,7 @@ void CDetouredFunc::FuncPost() } -thread_local std::vector CDetouredFunc::s_SaveEIP; +/*thread_local*/ std::vector CDetouredFunc::s_SaveEIP; void CDetouredFunc::WrapperPre(void *func_ptr, uint32_t *eip) diff --git a/src/mem/detour.h b/src/mem/detour.h index 308918bd..00db964a 100644 --- a/src/mem/detour.h +++ b/src/mem/detour.h @@ -156,7 +156,10 @@ class CDetouredFunc static void WrapperPre(void *func_ptr, uint32_t *eip); static void WrapperPost(void *func_ptr, uint32_t *eip); - static thread_local std::vector s_SaveEIP; + /* TODO: should be thread_local, but our statically linked libstdc++ thinks + * it has recent glibc, and it may not, which breaks + * __cxa_thread_atexit_impl */ + static /*thread_local*/ std::vector s_SaveEIP; static std::map s_FuncMap; }; diff --git a/src/mod.cpp b/src/mod.cpp index f7804c8d..9f48e960 100644 --- a/src/mod.cpp +++ b/src/mod.cpp @@ -1,18 +1,187 @@ #include "mod.h" -void CModManager::LoadAllMods() +bool IHasPatches::LoadPatches() +{ + bool ok = true; + + for (auto patch : this->m_Patches) { + if (patch->Init()) { + if (patch->Check()) { + DevMsg("IHasPatches::LoadPatches: \"%s\" OK\n", this->GetName()); + } else { + DevMsg("IHasPatches::LoadPatches: \"%s\" FAIL in Check\n", this->GetName()); + ok = false; + } + } else { + DevMsg("IHasPatches::LoadPatches: \"%s\" FAIL in Init\n", this->GetName()); + ok = false; + } + } + + return ok; +} + +void IHasPatches::UnloadPatches() +{ + for (auto patch : this->m_Patches) { + patch->UnApply(); + delete patch; + } + + this->m_Patches.clear(); +} + + +void IHasPatches::AddPatch(IPatch *patch) +{ + DevMsg("IHasPatches::AddPatch: \"%s\" \"%s\" off:[0x%05x~0x%05x] len:0x%05x\n", this->GetName(), + patch->GetFuncName(), patch->GetFuncOffMin(), patch->GetFuncOffMax(), patch->GetLength()); + + assert(this->CanAddPatches()); + + this->m_Patches.push_back(patch); +} + + +void IHasPatches::ToggleAllPatches(bool enable) +{ + if (!this->CanTogglePatches()) return; + + DevMsg("IHasPatches::ToggleAllPatches: \"%s\" %s\n", this->GetName(), + (enable ? "ON" : "OFF")); + + for (auto patch : this->m_Patches) { + if (enable) { + patch->Apply(); + } else { + patch->UnApply(); + } + } +} + + +bool IHasDetours::LoadDetours() +{ + bool ok = true; + + for (auto& pair : this->m_Detours) { + const char *name = pair.first; + IDetour *detour = pair.second; + + if (!detour->IsLoaded()) { + if (detour->Load()) { + DevMsg("IHasDetours::LoadDetours: \"%s\" \"%s\" OK\n", this->GetName(), name); + } else { + DevMsg("IHasDetours::LoadDetours: \"%s\" \"%s\" FAIL\n", this->GetName(), name); + ok = false; + } + } + } + + return ok; +} + +void IHasDetours::UnloadDetours() +{ + for (auto& pair : this->m_Detours) { + IDetour *detour = pair.second; + + if (detour->IsLoaded()) { + detour->Unload(); + } + + delete detour; + } + + this->m_Detours.clear(); +} + + +void IHasDetours::AddDetour(IDetour *detour) +{ + const char *name = detour->GetName(); + + DevMsg("IHasDetours::AddDetour: \"%s\" \"%s\"\n", this->GetName(), name); + + assert(this->CanAddDetours()); + assert(this->m_Detours.find(name) == this->m_Detours.end()); + + this->m_Detours[name] = detour; +} + + +void IHasDetours::ToggleDetour(const char *name, bool enable) +{ + if (!this->CanToggleDetours()) return; + + DevMsg("IHasDetours::ToggleDetour: \"%s\" \"%s\" %s\n", this->GetName(), name, + (enable ? "ON" : "OFF")); + + this->m_Detours.at(name)->Toggle(enable); +} + + +void IHasDetours::ToggleAllDetours(bool enable) +{ + if (!this->CanToggleDetours()) return; + + DevMsg("IHasDetours::ToggleAllDetours: \"%s\" %s\n", this->GetName(), + (enable ? "ON" : "OFF")); + + for (auto& pair : this->m_Detours) { + IDetour *detour = pair.second; + detour->Toggle(enable); + } +} + + +void IMod::InvokeLoad() +{ + DevMsg("IMod::InvokeLoad: \"%s\"\n", this->GetName()); + + bool ok_patch = this->LoadPatches(); + bool ok_detour = this->LoadDetours(); + + if (!ok_patch || !ok_detour) { + this->m_bFailed = true; + return; + } + + bool ok_load = this->OnLoad(); + if (ok_load) { + this->m_bLoaded = true; + } else { + this->m_bFailed = true; + } +} + +void IMod::InvokeUnload() +{ + DevMsg("IMod::InvokeUnload: \"%s\"\n", this->GetName()); + + this->OnUnload(); + + this->UnloadDetours(); + this->UnloadPatches(); +} + + +CModManager g_ModManager; + + +void CModManager::Load() { - DevMsg("CModManager::LoadAllMods\n"); + DevMsg("CModManager::Load\n"); for (auto mod : AutoList::List()) { mod->InvokeLoad(); } } -void CModManager::UnloadAllMods() +void CModManager::Unload() { - DevMsg("CModManager::UnloadAllMods\n"); + DevMsg("CModManager::Unload\n"); for (auto mod : AutoList::List()) { mod->InvokeUnload(); @@ -161,163 +330,3 @@ void CModManager::CC_ListMods(const CCommand& cmd) ConColorMsg(info.c_d_active, "%-*s\n", 2 + l_d_active, info.d_active.c_str()); } } - - -bool IHasPatches::LoadPatches() -{ - bool ok = true; - - for (auto patch : this->m_Patches) { - if (patch->Init()) { - if (patch->Check()) { - DevMsg("IHasPatches::LoadPatches: \"%s\" OK\n", this->GetName()); - } else { - DevMsg("IHasPatches::LoadPatches: \"%s\" FAIL in Check\n", this->GetName()); - ok = false; - } - } else { - DevMsg("IHasPatches::LoadPatches: \"%s\" FAIL in Init\n", this->GetName()); - ok = false; - } - } - - return ok; -} - -void IHasPatches::UnloadPatches() -{ - for (auto patch : this->m_Patches) { - patch->UnApply(); - delete patch; - } - - this->m_Patches.clear(); -} - - -void IHasPatches::AddPatch(IPatch *patch) -{ - DevMsg("IHasPatches::AddPatch: \"%s\" \"%s\" off:[0x%05x~0x%05x] len:0x%05x\n", this->GetName(), - patch->GetFuncName(), patch->GetFuncOffMin(), patch->GetFuncOffMax(), patch->GetLength()); - - assert(this->CanAddPatches()); - - this->m_Patches.push_back(patch); -} - - -void IHasPatches::ToggleAllPatches(bool enable) -{ - if (!this->CanTogglePatches()) return; - - DevMsg("IHasPatches::ToggleAllPatches: \"%s\" %s\n", this->GetName(), - (enable ? "ON" : "OFF")); - - for (auto patch : this->m_Patches) { - if (enable) { - patch->Apply(); - } else { - patch->UnApply(); - } - } -} - - -bool IHasDetours::LoadDetours() -{ - bool ok = true; - - for (auto& pair : this->m_Detours) { - const char *name = pair.first; - IDetour *detour = pair.second; - - if (detour->Load()) { - DevMsg("IHasDetours::LoadDetours: \"%s\" \"%s\" OK\n", this->GetName(), name); - } else { - DevMsg("IHasDetours::LoadDetours: \"%s\" \"%s\" FAIL\n", this->GetName(), name); - ok = false; - } - } - - return ok; -} - -void IHasDetours::UnloadDetours() -{ - for (auto& pair : this->m_Detours) { - IDetour *detour = pair.second; - detour->Unload(); - delete detour; - } - - this->m_Detours.clear(); -} - - -void IHasDetours::AddDetour(IDetour *detour) -{ - const char *name = detour->GetName(); - - DevMsg("IHasDetours::AddDetour: \"%s\" \"%s\"\n", this->GetName(), name); - - assert(this->CanAddDetours()); - assert(this->m_Detours.find(name) == this->m_Detours.end()); - - this->m_Detours[name] = detour; -} - - -void IHasDetours::ToggleDetour(const char *name, bool enable) -{ - if (!this->CanToggleDetours()) return; - - DevMsg("IHasDetours::ToggleDetour: \"%s\" \"%s\" %s\n", this->GetName(), name, - (enable ? "ON" : "OFF")); - - this->m_Detours.at(name)->Toggle(enable); -} - - -void IHasDetours::ToggleAllDetours(bool enable) -{ - if (!this->CanToggleDetours()) return; - - DevMsg("IHasDetours::ToggleAllDetours: \"%s\" %s\n", this->GetName(), - (enable ? "ON" : "OFF")); - - for (auto& pair : this->m_Detours) { - IDetour *detour = pair.second; - detour->Toggle(enable); - } -} - - -void IMod::InvokeLoad() -{ - DevMsg("IMod::InvokeLoad: \"%s\"\n", this->GetName()); - - bool ok_patch = this->LoadPatches(); - bool ok_detour = this->LoadDetours(); - - if (!ok_patch || !ok_detour) { - this->m_bFailed = true; - return; - } - - bool ok_load = this->OnLoad(); - if (ok_load) { - this->m_bLoaded = true; - } else { - this->m_bFailed = true; - } -} - -void IMod::InvokeUnload() -{ - DevMsg("IMod::InvokeUnload: \"%s\"\n", this->GetName()); - - this->OnUnload(); - - this->UnloadDetours(); - this->UnloadPatches(); -} diff --git a/src/mod.h b/src/mod.h index d391e0ae..e81f07ad 100644 --- a/src/mod.h +++ b/src/mod.h @@ -6,16 +6,6 @@ #include "mem/detour.h" -class CModManager -{ -public: - static void LoadAllMods(); - static void UnloadAllMods(); - - static void CC_ListMods(const CCommand& cmd); -}; - - class IHasPatches { public: @@ -113,6 +103,25 @@ class IMod : public AutoList, public IHasPatches, public IHasDetours }; +class CModManager : public CBaseGameSystemPerFrame +{ +public: + void Load(); + void Unload(); + + /* TODO: pass these events on to all loaded IMods */ + virtual void LevelInitPreEntity() override {} + virtual void LevelInitPostEntity() override {} + virtual void LevelShutdownPreEntity() override {} + virtual void LevelShutdownPostEntity() override {} + virtual void FrameUpdatePreEntityThink() override {} + virtual void FrameUpdatePostEntityThink() override {} + + static void CC_ListMods(const CCommand& cmd); +}; +extern CModManager g_ModManager; + + #define MOD_ADD_DETOUR_MEMBER(detour, addr) \ this->AddDetour(new CDetour(addr, addr, GET_MEMBER_CALLBACK(detour), GET_MEMBER_INNERPTR(detour))) #define MOD_ADD_DETOUR_STATIC(detour, addr) \ diff --git a/src/mod/cond/reprogrammed.cpp b/src/mod/cond/reprogrammed.cpp index a8d1913a..f5bb538a 100644 --- a/src/mod/cond/reprogrammed.cpp +++ b/src/mod/cond/reprogrammed.cpp @@ -7,13 +7,25 @@ namespace Mod_Cond_Reprogrammed { void OnAddReprogrammed(CTFPlayer *player) { + DevMsg("OnAddReprogrammed(#%d \"%s\")\n", ENTINDEX(player), player->GetPlayerName()); + player->m_Shared->StunPlayer(5.0f, 0.65f, TF_STUNFLAG_NOSOUNDOREFFECT | TF_STUNFLAG_SLOWDOWN, nullptr); player->ForceChangeTeam(TF_TEAM_RED, false); + + /* this used to be in CTFPlayerShared::OnAddReprogrammed on the client + * side, but we now have to do it from the server side */ + DispatchParticleEffect("sapper_sentry1_fx", PATTACH_POINT_FOLLOW, player, "head"); } void OnRemoveReprogrammed(CTFPlayer *player) { + DevMsg("OnRemoveReprogrammed(#%d \"%s\")\n", ENTINDEX(player), player->GetPlayerName()); + player->ForceChangeTeam(TF_TEAM_BLUE, false); + + /* this is far from ideal; we can only remove ALL particle effects from + * the server side */ + StopParticleEffects(player); } diff --git a/src/mod/sound/tele_activate.cpp b/src/mod/sound/tele_activate.cpp new file mode 100644 index 00000000..a3be32d0 --- /dev/null +++ b/src/mod/sound/tele_activate.cpp @@ -0,0 +1,45 @@ +#include "mod.h" +#include "stub/entities.h" + + +namespace Mod_Sound_Tele_Activate +{ + DETOUR_DECL_MEMBER(void, CTFBotHintEngineerNest_HintTeleporterThink) + { + auto hint = reinterpret_cast(this); + + bool active_pre = hint->m_bHasActiveTeleporter; + DETOUR_MEMBER_CALL(CTFBotHintEngineerNest_HintTeleporterThink)(); + bool active_post = hint->m_bHasActiveTeleporter; + + if (!active_pre && active_post) { + enginesound->PrecacheSound(")mvm/mvm_tele_activate.wav", true); + // DevMsg("Teleporter going active!\n"); + hint->EmitSound("MVM.Robot_Teleporter_Activate"); + } + } + + + class CMod : public IMod + { + public: + CMod() : IMod("Sound:Tele_Activate") + { + MOD_ADD_DETOUR_MEMBER(CTFBotHintEngineerNest_HintTeleporterThink, "CTFBotHintEngineerNest::HintTeleporterThink"); + } + + void SetEnabled(bool enable) + { + this->ToggleAllDetours(enable); + } + }; + CMod s_Mod; + + + ConVar cvar_enable("sig_sound_tele_activate", "0", FCVAR_NOTIFY, + "Mod: enable the engiebot teleporter activation sound effect", + [](IConVar *pConVar, const char *pOldValue, float flOldValue) { + ConVarRef var(pConVar); + s_Mod.SetEnabled(var.GetBool()); + }); +} diff --git a/src/mod/visualize/jar_radius.cpp b/src/mod/visualize/jar_radius.cpp new file mode 100644 index 00000000..070f9957 --- /dev/null +++ b/src/mod/visualize/jar_radius.cpp @@ -0,0 +1,193 @@ +#include "mod.h" +#include "util/scope.h" +#include "stub/projectiles.h" +#include "stub/tf_shareddefs.h" +#include "stub/misc.h" +#include "stub/tfplayer.h" + + +namespace Mod_Visualize_Jar_Radius +{ + [[gnu::format(printf, 1, 2)]] + void ServerCommand(const char *format, ...) + { + char buf[4096]; + + va_list va; + va_start(va, format); + vsnprintf(buf, sizeof(buf), format, va); + va_end(va); + + engine->ServerCommand(buf); + engine->ServerExecute(); + } + + + void AddPuppetBot(const char *team, const char *playerclass, const char *name) + { + ServerCommand("bot -team %s -class %s -name %s\n", team, playerclass, name); + } + + void TeleportBot(const char *name, const Vector& origin, const QAngle& angles) + { + ServerCommand("bot_teleport %s %f %f %f %f %f %f\n", name, + origin.x, origin.y, origin.z, + angles.x, angles.y, angles.x); + + // constexpr int damage = -1000000; + // ServerCommand("bot_hurt -name %s -damage %d\n", name, damage); + } + + + constexpr int num_bots = 30; + + + CON_COMMAND(sig_visualize_jar_radius_addbots, "") + { + ServerCommand("bot_kick all\n"); + + for (int i = 0; i < num_bots; ++i) { + AddPuppetBot("blu", "pyro", CFmtStrN<64>("Bot%d", i + 1)); + } + } + + CON_COMMAND(sig_visualize_jar_radius_movebots, "") + { + constexpr float x = 0.0f; + float y = 0.0f; + constexpr float z = -50.0f; + + constexpr float ax = 0.0f; + constexpr float ay = 0.0f; + constexpr float az = 0.0f; + + for (int i = 0; i < num_bots; ++i) { + constexpr float spacing = 100.0f; + + float xi = RemapValClamped(i / 5, 0, 5, -2.5f * spacing, 2.5f * spacing); + float yi = RemapValClamped(i % 5, 0, 4, -2.0f * spacing, 2.0f * spacing); + + Vector origin(xi, yi, z); + QAngle angles(ax, ay, az); + + TeleportBot(CFmtStrN<64>("Bot%d", i + 1), origin, angles); + } + } + + + ConVar cvar_duration_sphere("sig_visualize_jar_radius_duration_sphere", "3.00", FCVAR_NOTIFY, + "Visualization: duration for the sphere overlay"); + ConVar cvar_duration_player("sig_visualize_jar_radius_duration_player", "10.00", FCVAR_NOTIFY, + "Visualization: duration for the player damage overlay"); + ConVar cvar_clear("sig_visualize_jar_radius_clear", "1", FCVAR_NOTIFY, + "Visualization: clear overlays each time?"); + + + bool is_jarate = false; + bool is_milk = false; + DETOUR_DECL_MEMBER(void, CTFProjectile_Jar_Explode, CGameTrace *trace, int i1) + { + auto jar = reinterpret_cast(this); + + switch (jar->GetWeaponID()) { + case TF_WEAPON_GRENADE_JAR: + is_jarate = true; + DevMsg("weapon ID: GRENADE_JAR\n"); + break; + case TF_WEAPON_GRENADE_JAR_MILK: + is_milk = true; + DevMsg("weapon ID: GRENADE_JAR_MILK\n"); + break; + default: + DevMsg("weapon ID: %02x\n", jar->GetWeaponID()); + break; + } + + DETOUR_MEMBER_CALL(CTFProjectile_Jar_Explode)(trace, i1); + + is_jarate = false; + is_milk = false; + } + + DETOUR_DECL_STATIC(int, UTIL_EntitiesInSphere, const Vector& center, float radius, CFlaggedEntitiesEnum *pEnum) + { + DevMsg("radius: %.1f\n", radius); + + if (cvar_clear.GetBool()) { + NDebugOverlay::Clear(); + } + + DevMsg("sphere\n"); + if (is_jarate) { + DevMsg("sphere: is_jarate\n"); + NDebugOverlay::Sphere(center, vec3_angle, radius, 0xff, 0xff, 0x00, 0x20, false, cvar_duration_sphere.GetFloat()); + } + if (is_milk) { + DevMsg("sphere: is_milk\n"); + NDebugOverlay::Sphere(center, vec3_angle, radius, 0xff, 0xff, 0xff, 0x20, false, cvar_duration_sphere.GetFloat()); + } + + return DETOUR_STATIC_CALL(UTIL_EntitiesInSphere)(center, radius, pEnum); + } + + + DETOUR_DECL_MEMBER(void, CTFPlayerShared_AddCond, ETFCond cond, float duration, CTFPlayer *provider) + { + DevMsg("addcond\n"); + + if (is_jarate && cond == TF_COND_URINE) { + DevMsg("addcond URINE\n"); + + auto shared = reinterpret_cast(this); + CTFPlayer *player = shared->GetOuter(); + + NDebugOverlay::EntityBounds(player, 0xff, 0xff, 0x00, 0x20, cvar_duration_player.GetFloat()); + + // NDebugOverlay::EntityText(ENTINDEX(player), 0, player->GetPlayerName(), cvar_duration_player.GetFloat(), 0xff, 0xff, 0xff, 0xff); + NDebugOverlay::EntityText(ENTINDEX(player), 1, "JARATED", cvar_duration_player.GetFloat(), 0xff, 0xff, 0xff, 0xff); + NDebugOverlay::EntityText(ENTINDEX(player), 2, CFmtStrN<64>("%.1f sec", duration), cvar_duration_player.GetFloat(), 0xff, 0xff, 0xff, 0xff); + } + + if (is_milk && cond == TF_COND_MAD_MILK) { + DevMsg("addcond MAD_MILK\n"); + + auto shared = reinterpret_cast(this); + CTFPlayer *player = shared->GetOuter(); + + NDebugOverlay::EntityBounds(player, 0xff, 0xff, 0xff, 0x20, cvar_duration_player.GetFloat()); + + // NDebugOverlay::EntityText(ENTINDEX(player), 0, player->GetPlayerName(), cvar_duration_player.GetFloat(), 0xff, 0xff, 0xff, 0xff); + NDebugOverlay::EntityText(ENTINDEX(player), 1, "MILKED", cvar_duration_player.GetFloat(), 0xff, 0xff, 0xff, 0xff); + NDebugOverlay::EntityText(ENTINDEX(player), 2, CFmtStrN<64>("%.1f sec", duration), cvar_duration_player.GetFloat(), 0xff, 0xff, 0xff, 0xff); + } + + DETOUR_MEMBER_CALL(CTFPlayerShared_AddCond)(cond, duration, provider); + } + + + class CMod : public IMod + { + public: + CMod() : IMod("Visualize:Jar_Radius") + { + MOD_ADD_DETOUR_MEMBER(CTFProjectile_Jar_Explode, "CTFProjectile_Jar::Explode"); + MOD_ADD_DETOUR_STATIC(UTIL_EntitiesInSphere, "UTIL_EntitiesInSphere"); + + MOD_ADD_DETOUR_MEMBER(CTFPlayerShared_AddCond, "CTFPlayerShared::AddCond"); + } + + void SetEnabled(bool enable) + { + this->ToggleAllDetours(enable); + } + }; + CMod s_Mod; + + + ConVar cvar_enable("sig_visualize_jar_radius", "0", FCVAR_NOTIFY, + "Visualization: jar radius", + [](IConVar *pConVar, const char *pOldValue, float flOldValue) { + ConVarRef var(pConVar); + s_Mod.SetEnabled(var.GetBool()); + }); +} diff --git a/src/stub/baseentity.cpp b/src/stub/baseentity.cpp index 31b4fc64..78a39e50 100644 --- a/src/stub/baseentity.cpp +++ b/src/stub/baseentity.cpp @@ -18,16 +18,17 @@ IMPL_SENDPROP(char, CBaseEntity, m_lifeState, CBasePlayer); IMPL_SENDPROP(CHandle, CBaseEntity, m_hGroundEntity, CBasePlayer); IMPL_SENDPROP(CHandle, CBaseEntity, m_hOwnerEntity, CBaseEntity); -MemberFuncThunk CBaseEntity::ft_Remove ("CBaseEntity::Remove"); -MemberFuncThunk CBaseEntity::ft_CalcAbsolutePosition("CBaseEntity::CalcAbsolutePosition"); -MemberFuncThunk CBaseEntity::ft_ClassMatches( "CBaseEntity::ClassMatches"); -MemberFuncThunk CBaseEntity::ft_SetAbsOrigin( "CBaseEntity::SetAbsOrigin"); -MemberFuncThunk CBaseEntity::ft_SetAbsAngles( "CBaseEntity::SetAbsAngles"); - -MemberVFuncThunk CBaseEntity::vt_EyePosition( TypeName(), "CBaseEntity::EyePosition"); -MemberVFuncThunk CBaseEntity::vt_EyeAngles( TypeName(), "CBaseEntity::EyeAngles"); +MemberFuncThunk CBaseEntity::ft_Remove ("CBaseEntity::Remove"); +MemberFuncThunk CBaseEntity::ft_CalcAbsolutePosition("CBaseEntity::CalcAbsolutePosition"); +MemberFuncThunk CBaseEntity::ft_ClassMatches ("CBaseEntity::ClassMatches"); +MemberFuncThunk CBaseEntity::ft_SetAbsOrigin ("CBaseEntity::SetAbsOrigin"); +MemberFuncThunk CBaseEntity::ft_SetAbsAngles ("CBaseEntity::SetAbsAngles"); +MemberFuncThunk CBaseEntity::ft_EmitSound ("CBaseEntity::EmitSound"); + +MemberVFuncThunk CBaseEntity::vt_EyePosition (TypeName(), "CBaseEntity::EyePosition"); +MemberVFuncThunk CBaseEntity::vt_EyeAngles (TypeName(), "CBaseEntity::EyeAngles"); MemberVFuncThunk CBaseEntity::vt_SetOwnerEntity(TypeName(), "CBaseEntity::SetOwnerEntity"); -MemberVFuncThunk CBaseEntity::vt_Spawn( TypeName(), "CBaseEntity::Spawn"); +MemberVFuncThunk CBaseEntity::vt_Spawn (TypeName(), "CBaseEntity::Spawn"); bool CBaseEntity::IsPlayer() const diff --git a/src/stub/baseentity.h b/src/stub/baseentity.h index 2d554f53..38081662 100644 --- a/src/stub/baseentity.h +++ b/src/stub/baseentity.h @@ -34,15 +34,16 @@ class CBaseEntity CBaseEntity *GetOwnerEntity() const { return this->m_hOwnerEntity; } /* thunk */ - void Remove() { ft_Remove (this); } - void CalcAbsolutePosition() { ft_CalcAbsolutePosition(this); } - bool ClassMatches(const char *pszClassOrWildcard) { return ft_ClassMatches (this, pszClassOrWildcard); } - void SetAbsOrigin(const Vector& absOrigin) { ft_SetAbsOrigin (this, absOrigin); } - void SetAbsAngles(const QAngle& absAngles) { ft_SetAbsAngles (this, absAngles); } - Vector EyePosition() { return vt_EyePosition (this); } - const QAngle& EyeAngles() { return vt_EyeAngles (this); } - void SetOwnerEntity(CBaseEntity *pOwner) { vt_SetOwnerEntity (this, pOwner); } - void Spawn() { vt_Spawn (this); } + void Remove() { ft_Remove (this); } + void CalcAbsolutePosition() { ft_CalcAbsolutePosition(this); } + bool ClassMatches(const char *pszClassOrWildcard) { return ft_ClassMatches (this, pszClassOrWildcard); } + void SetAbsOrigin(const Vector& absOrigin) { ft_SetAbsOrigin (this, absOrigin); } + void SetAbsAngles(const QAngle& absAngles) { ft_SetAbsAngles (this, absAngles); } + void EmitSound(const char *soundname, float soundtime = 0.0f, float *duration = nullptr) { ft_EmitSound (this, soundname, soundtime, duration); } + Vector EyePosition() { return vt_EyePosition (this); } + const QAngle& EyeAngles() { return vt_EyeAngles (this); } + void SetOwnerEntity(CBaseEntity *pOwner) { vt_SetOwnerEntity (this, pOwner); } + void Spawn() { vt_Spawn (this); } /* hack */ bool IsPlayer() const; @@ -68,11 +69,12 @@ class CBaseEntity DECL_SENDPROP(CHandle, m_hGroundEntity); DECL_SENDPROP(CHandle, m_hOwnerEntity); - static MemberFuncThunk ft_Remove; - static MemberFuncThunk ft_CalcAbsolutePosition; - static MemberFuncThunk ft_ClassMatches; - static MemberFuncThunk ft_SetAbsOrigin; - static MemberFuncThunk ft_SetAbsAngles; + static MemberFuncThunk ft_Remove; + static MemberFuncThunk ft_CalcAbsolutePosition; + static MemberFuncThunk ft_ClassMatches; + static MemberFuncThunk ft_SetAbsOrigin; + static MemberFuncThunk ft_SetAbsAngles; + static MemberFuncThunk ft_EmitSound; static MemberVFuncThunk vt_EyePosition; static MemberVFuncThunk vt_EyeAngles; diff --git a/src/stub/igamesystem.cpp b/src/stub/igamesystem.cpp new file mode 100644 index 00000000..c49a2fb1 --- /dev/null +++ b/src/stub/igamesystem.cpp @@ -0,0 +1,46 @@ +//#include "stub/igamesystem.h" +#include "link/link.h" + + +CAutoGameSystem::CAutoGameSystem(const char *name) : + m_pszName(name) +{ + Add(this); +} + +CAutoGameSystemPerFrame::CAutoGameSystemPerFrame(const char *name) : + m_pszName(name) +{ + Add(this); +} + + +IGameSystem::~IGameSystem() +{ +// Remove(this); +} + +IGameSystemPerFrame::~IGameSystemPerFrame() +{ +// Remove(this); +} + + +static StaticFuncThunk ft_IGameSystem_Add("IGameSystem::Add"); +void IGameSystem::Add(IGameSystem *pSys) +{ + ft_IGameSystem_Add(pSys); +} + +static StaticFuncThunk ft_IGameSystem_Remove("IGameSystem::Remove"); +void IGameSystem::Remove(IGameSystem *pSys) +{ + ft_IGameSystem_Remove(pSys); +} + +// NOT IMPLEMENTED +// void IGameSystem::RemoveAll(IGameSystem *pSys) + + +// NOT IMPLEMENTED +// const char *IGameSystem::MapName() diff --git a/src/stub/particles.cpp b/src/stub/particles.cpp new file mode 100644 index 00000000..61d45979 --- /dev/null +++ b/src/stub/particles.cpp @@ -0,0 +1,51 @@ +//#include "stub/particles.h" +#include "link/link.h" + + +static StaticFuncThunk ft_DispatchParticleEffect1("DispatchParticleEffect [overload 1]"); +void DispatchParticleEffect(const char *pszParticleName, ParticleAttachment_t iAttachType, CBaseEntity *pEntity, const char *pszAttachmentName, bool bResetAllParticlesOnEntity) +{ + ft_DispatchParticleEffect1(pszParticleName, iAttachType, pEntity, pszAttachmentName, bResetAllParticlesOnEntity); +} + +static StaticFuncThunk ft_DispatchParticleEffect2("DispatchParticleEffect [overload 2]"); +void DispatchParticleEffect(const char *pszParticleName, ParticleAttachment_t iAttachType, CBaseEntity *pEntity, int iAttachmentPoint, bool bResetAllParticlesOnEntity) +{ + ft_DispatchParticleEffect2(pszParticleName, iAttachType, pEntity, iAttachmentPoint, bResetAllParticlesOnEntity); +} + +static StaticFuncThunk ft_DispatchParticleEffect3("DispatchParticleEffect [overload 3]"); +void DispatchParticleEffect(const char *pszParticleName, Vector vecOrigin, QAngle vecAngles, CBaseEntity *pEntity) +{ + ft_DispatchParticleEffect3(pszParticleName, vecOrigin, vecAngles, pEntity); +} + +static StaticFuncThunk ft_DispatchParticleEffect4("DispatchParticleEffect [overload 4]"); +void DispatchParticleEffect(const char *pszParticleName, Vector vecOrigin, Vector vecStart, QAngle vecAngles, CBaseEntity *pEntity) +{ + ft_DispatchParticleEffect4(pszParticleName, vecOrigin, vecStart, vecAngles, pEntity); +} + +static StaticFuncThunk ft_DispatchParticleEffect5("DispatchParticleEffect [overload 5]"); +void DispatchParticleEffect(int iEffectIndex, Vector vecOrigin, Vector vecStart, QAngle vecAngles, CBaseEntity *pEntity) +{ + ft_DispatchParticleEffect5(iEffectIndex, vecOrigin, vecStart, vecAngles, pEntity); +} + +static StaticFuncThunk ft_DispatchParticleEffect6("DispatchParticleEffect [overload 6]"); +void DispatchParticleEffect(const char *pszParticleName, ParticleAttachment_t iAttachType, CBaseEntity *pEntity, const char *pszAttachmentName, Vector vecColor1, Vector vecColor2, bool bUseColors, bool bResetAllParticlesOnEntity) +{ + ft_DispatchParticleEffect6(pszParticleName, iAttachType, pEntity, pszAttachmentName, vecColor1, vecColor2, bUseColors, bResetAllParticlesOnEntity); +} + +static StaticFuncThunk ft_DispatchParticleEffect7("DispatchParticleEffect [overload 7]"); +void DispatchParticleEffect(const char *pszParticleName, Vector vecOrigin, QAngle vecAngles, Vector vecColor1, Vector vecColor2, bool bUseColors, CBaseEntity *pEntity, ParticleAttachment_t iAttachType) +{ + ft_DispatchParticleEffect7(pszParticleName, vecOrigin, vecAngles, vecColor1, vecColor2, bUseColors, pEntity, iAttachType); +} + +static StaticFuncThunk ft_StopParticleEffects("StopParticleEffects"); +void StopParticleEffects(CBaseEntity *pEntity) +{ + ft_StopParticleEffects(pEntity); +} diff --git a/src/stub/projectiles.cpp b/src/stub/projectiles.cpp index 50a8e342..70a1cc30 100644 --- a/src/stub/projectiles.cpp +++ b/src/stub/projectiles.cpp @@ -1,7 +1,12 @@ #include "stub/projectiles.h" +MemberVFuncThunk CBaseProjectile::vt_GetProjectileType(TypeName(), "CBaseProjectile::GetProjectileType"); + + IMPL_SENDPROP(bool, CTFWeaponBaseGrenadeProj, m_bCritical, CTFWeaponBaseGrenadeProj); +MemberVFuncThunk CTFWeaponBaseGrenadeProj::vt_GetWeaponID(TypeName(), "CTFWeaponBaseGrenadeProj::GetWeaponID"); + GlobalThunk> IBaseProjectileAutoList::m_IBaseProjectileAutoListAutoList("IBaseProjectileAutoList::m_IBaseProjectileAutoListAutoList"); diff --git a/src/stub/projectiles.h b/src/stub/projectiles.h index 01ea5b3b..8507444f 100644 --- a/src/stub/projectiles.h +++ b/src/stub/projectiles.h @@ -6,7 +6,14 @@ #include "stub/baseanimating.h" -class CBaseProjectile : public CBaseAnimating {}; +class CBaseProjectile : public CBaseAnimating +{ +public: + int GetProjectileType() const { return vt_GetProjectileType(this); } + +private: + static MemberVFuncThunk vt_GetProjectileType; +}; class CBaseGrenade : public CBaseProjectile {}; class CThrownGrenade : public CBaseGrenade {}; @@ -33,7 +40,12 @@ class CTFProjectile_GrapplingHook : public CTFProjectile_Arrow {}; class CTFWeaponBaseGrenadeProj : public CBaseGrenade { public: + int GetWeaponID() const { return vt_GetWeaponID(this); } + DECL_SENDPROP(bool, m_bCritical); + +private: + static MemberVFuncThunk vt_GetWeaponID; }; class CTFGrenadePipebombProjectile : public CTFWeaponBaseGrenadeProj {}; diff --git a/src/stub/tf_shareddefs.h b/src/stub/tf_shareddefs.h index c9fbc053..72ae8103 100644 --- a/src/stub/tf_shareddefs.h +++ b/src/stub/tf_shareddefs.h @@ -233,6 +233,41 @@ enum TF_STUNFLAGS_BIGBONK = TF_STUNFLAG_CHEERSOUND | TF_STUNFLAG_BONKSTUCK, }; +enum +{ + TF_PROJECTILE_NONE, + TF_PROJECTILE_BULLET, + TF_PROJECTILE_ROCKET, + TF_PROJECTILE_PIPEBOMB, + TF_PROJECTILE_PIPEBOMB_REMOTE, + TF_PROJECTILE_SYRINGE, + TF_PROJECTILE_FLARE, + TF_PROJECTILE_JAR, + TF_PROJECTILE_ARROW, + TF_PROJECTILE_FLAME_ROCKET, + TF_PROJECTILE_JAR_MILK, + TF_PROJECTILE_HEALING_BOLT, + TF_PROJECTILE_ENERGY_BALL, + TF_PROJECTILE_ENERGY_RING, + TF_PROJECTILE_PIPE_REMOTE_PRACTICE, + TF_PROJECTILE_CLEAVER, + TF_PROJECTILE_STICKY_BALL, + TF_PROJECTILE_CANNONBALL, + TF_PROJECTILE_BUILDING_REPAIR_BOLT, + TF_PROJECTILE_FESTIVE_ARROW, + TF_PROJECTILE_THROWABLE, + TF_PROJECTILE_SPELLFIREBALL, + TF_PROJECTILE_FESTIVE_URINE, + TF_PROJECTILE_FESTIVE_HEALING_BOLT, + TF_PROJECTILE_BREADMONSTER_JARATE, + TF_PROJECTILE_BREADMONSTER_MADMILK, + TF_PROJECTILE_GRAPPLINGHOOK, + TF_PROJECTILE_SENTRY_ROCKET, + TF_PROJECTILE_BREAD_MONSTER, + + TF_NUM_PROJECTILES, +}; + /* I invented this function, because this particular idiom comes up frequently; * I can't seem to actually find it anywhere in the 2013 SDK or the 2007 leak, diff --git a/src/stub/tfbot.h b/src/stub/tfbot.h index 17bebbcb..621acc39 100644 --- a/src/stub/tfbot.h +++ b/src/stub/tfbot.h @@ -216,12 +216,12 @@ class CTFBot : public NextBotPlayer static MemberFuncThunk ft_IsLineOfFireClear_ent; static MemberFuncThunk ft_IsLineOfFireClear_vec_vec; static MemberFuncThunk ft_IsLineOfFireClear_vec_ent; - static MemberFuncThunk< CTFBot *, SuspectedSpyInfo_t *, CTFPlayer *> ft_IsSuspectedSpy; - static MemberFuncThunk< CTFBot *, void, CTFPlayer *> ft_SuspectSpy; - static MemberFuncThunk< CTFBot *, void, CTFPlayer *> ft_StopSuspectingSpy; - static MemberFuncThunk ft_IsKnownSpy; - static MemberFuncThunk< CTFBot *, void, CTFPlayer *> ft_RealizeSpy; - static MemberFuncThunk< CTFBot *, void, CTFPlayer *> ft_ForgetSpy; + static MemberFuncThunk< CTFBot *, SuspectedSpyInfo_t *, CTFPlayer * > ft_IsSuspectedSpy; + static MemberFuncThunk< CTFBot *, void, CTFPlayer * > ft_SuspectSpy; + static MemberFuncThunk< CTFBot *, void, CTFPlayer * > ft_StopSuspectingSpy; + static MemberFuncThunk ft_IsKnownSpy; + static MemberFuncThunk< CTFBot *, void, CTFPlayer * > ft_RealizeSpy; + static MemberFuncThunk< CTFBot *, void, CTFPlayer * > ft_ForgetSpy; static std::map, ExtendedAttr> s_ExtAttrs; }; @@ -229,7 +229,12 @@ class CTFBot : public NextBotPlayer inline CTFBot *ToTFBot(CBaseEntity *pEntity) { - /* not actually correct but close enough */ + if (pEntity == nullptr) return nullptr; + if (!pEntity->IsPlayer()) return nullptr; + + /* not actually correct, but to do this the "right" way we'd need to do an + * rtti_cast to CBasePlayer before we can call IsBotOfType, and then we'd + * need to do another rtti_cast after that... may as well just do this */ return rtti_cast(pEntity); } diff --git a/src/stub/tfplayer.h b/src/stub/tfplayer.h index 16d44066..b0c872a5 100644 --- a/src/stub/tfplayer.h +++ b/src/stub/tfplayer.h @@ -303,13 +303,25 @@ inline void CTFPlayerShared::NetworkStateChanged(void *pVar) { this->GetOuter()- inline CBasePlayer *ToBasePlayer(CBaseEntity *pEntity) { - /* not actually correct but close enough */ + if (pEntity == nullptr) return nullptr; + if (!pEntity->IsPlayer()) return nullptr; + return rtti_cast(pEntity); } +inline CBaseMultiplayerPlayer *ToBaseMultiplayerPlayer(CBaseEntity *pEntity) +{ + if (pEntity == nullptr) return nullptr; + if (!pEntity->IsPlayer()) return nullptr; + + return rtti_cast(pEntity); +} + inline CTFPlayer *ToTFPlayer(CBaseEntity *pEntity) { - /* not actually correct but close enough */ + if (pEntity == nullptr) return nullptr; + if (!pEntity->IsPlayer()) return nullptr; + return rtti_cast(pEntity); }