diff --git a/src/Components/Loader.cpp b/src/Components/Loader.cpp index 3e4cce46..a514b5dd 100644 --- a/src/Components/Loader.cpp +++ b/src/Components/Loader.cpp @@ -72,6 +72,7 @@ #include "Modules/Window.hpp" #include "Modules/BotLib/lPrecomp.hpp" +#include "Modules/ViewModelFxSetup.hpp" namespace Components { @@ -180,6 +181,7 @@ namespace Components Register(new GSC::GSC()); Register(new BotLib::lPrecomp()); + Register(new ViewModelFxSetup::Setup()); Pregame = false; } diff --git a/src/Components/Loader.hpp b/src/Components/Loader.hpp index be8b9c59..10855da1 100644 --- a/src/Components/Loader.hpp +++ b/src/Components/Loader.hpp @@ -68,3 +68,4 @@ namespace Components #include "Modules/Rumble.hpp" #include "Modules/GSC/GSC.hpp" +#include "Modules/ViewModelFxSetup.hpp" diff --git a/src/Components/Modules/ViewModelFx.cpp b/src/Components/Modules/ViewModelFx.cpp new file mode 100644 index 00000000..637ce30b --- /dev/null +++ b/src/Components/Modules/ViewModelFx.cpp @@ -0,0 +1,98 @@ +#include +#include "Components/Modules/GSC/Script.hpp" +#include "Components/Modules/GSC/ScriptExtension.hpp" +#include "Components/Modules/Weapon.hpp" +#include "Components/Modules/ViewModelFxSetup.hpp" + +namespace Components::ViewModelFxSetup +{ + static char cg_weaponsArray[32 * Weapon::WEAPON_LIMIT]; + + void Add_GSC_Functions() + { + // 3arc function for iw game + GSC::Script::AddFunction("PlayViewmodelFX", [] + { + if (Game::Scr_GetNumParam() != 2) + { + Game::Scr_Error("PlayViewmodelFX() called with wrong params.\n"); + return; + } + + const char* fxName = Game::Scr_GetString(0); // FX name string + Game::scr_string_t tagName = Game::Scr_GetConstString(1); // Bone/tag + + Game::FxEffectDef* fx = Game::DB_FindXAssetHeader(Game::ASSET_TYPE_FX, fxName).fx; + if (!fx) + { + Game::Scr_Error(Utils::String::VA("PlayViewmodelFX(): FX '%s' not found", fxName)); + return; + } + + int clientNum = 0; // local player + const Game::DObj* dobj = Game::Com_GetClientDObj(clientNum, 0); + if (!dobj) + { + Game::Scr_Error("PlayViewmodelFX(): Could not get DObj for local player"); + return; + } + + unsigned char boneIdx = 0; + if (!Game::DObjGetBoneIndex(reinterpret_cast(dobj), tagName, &boneIdx)) + { + Game::Scr_Error(Utils::String::VA( + "PlayViewmodelFX(): clientNum '%d' does not have bone '%s'", + clientNum, + Game::SL_ConvertToString(tagName) + )); + return; + } + + int dobjHandle = dobj->entnum; + Game::CG_PlayBoltedEffect(0, fx, dobjHandle, tagName); + }); + + GSC::Script::AddFunction("PVMFX_BOTH", [] + { + if (Game::Scr_GetNumParam() != 2) + { + Game::Scr_Error("PVMFX_BOTH() called with wrong params. Expected 2.\n"); + return; + } + + const char* fxName = Game::Scr_GetString(0); // FX name string + Game::scr_string_t tagName = Game::Scr_GetConstString(1); // Bone/tag + + Game::FxEffectDef* fx = Game::DB_FindXAssetHeader(Game::ASSET_TYPE_FX, fxName).fx; + if (!fx) + { + Game::Scr_Error(Utils::String::VA("PVMFX_BOTH(): FX '%s' not found", fxName)); + return; + } + + for (int hand = 0; hand <= 1; ++hand) + { + int fpDObjHandle = Game::CG_WeaponDObjHandle(hand); + if (fpDObjHandle) + { + Game::CG_PlayBoltedEffect(0, fx, fpDObjHandle, tagName); + + Game::CG_StopBoltedEffect(0, 0, fpDObjHandle, tagName); + } + } + + int clientNum = 0; + const Game::DObj* tpDObj = Game::Com_GetClientDObj(clientNum, 0); + if (tpDObj) + { + Game::CG_PlayBoltedEffect(0, fx, tpDObj->entnum, tagName); + + Game::CG_StopBoltedEffect(0, 0, tpDObj->entnum, tagName); + } + }); + + Setup::Setup() + { + Add_GSC_Functions(); + } +} diff --git a/src/Components/Modules/ViewModelFxSetup.hpp b/src/Components/Modules/ViewModelFxSetup.hpp new file mode 100644 index 00000000..0d3571ef --- /dev/null +++ b/src/Components/Modules/ViewModelFxSetup.hpp @@ -0,0 +1,10 @@ +#pragma once + +namespace Components::ViewModelFxSetup +{ + class Setup : public Component + { + public: + Setup(); + }; +} diff --git a/src/Game/Functions.cpp b/src/Game/Functions.cpp index c74b8691..20049983 100644 --- a/src/Game/Functions.cpp +++ b/src/Game/Functions.cpp @@ -415,6 +415,12 @@ namespace Game const char* logFileName = reinterpret_cast(0x730130); + DObjGetBoneIndex_t DObjGetBoneIndex = reinterpret_cast(0x504F20); + Com_GetClientDObj_t Com_GetClientDObj = reinterpret_cast(0x41FF50); + CG_WeaponDObjHandle_t CG_WeaponDObjHandle = reinterpret_cast(0x41DB70); + CG_StopBoltedEffect_t CG_StopBoltedEffect = reinterpret_cast(0x44C230); + + const char* TableLookup(StringTable* stringtable, int row, int column) { if (!stringtable || !stringtable->values || row >= stringtable->rowCount || column >= stringtable->columnCount) return ""; diff --git a/src/Game/Functions.hpp b/src/Game/Functions.hpp index 6222cd15..91089046 100644 --- a/src/Game/Functions.hpp +++ b/src/Game/Functions.hpp @@ -48,6 +48,18 @@ namespace Game typedef const DObj*(*CG_GetBoneIndex_t)(int localClientNum, unsigned int boneName, char* boneIndex); extern CG_GetBoneIndex_t CG_GetBoneIndex; + typedef int(__cdecl* DObjGetBoneIndex_t)(int a1, int a2, unsigned char* a3); + extern DObjGetBoneIndex_t DObjGetBoneIndex; + + typedef DObj* (__cdecl* Com_GetClientDObj_t)(int handle, int localClientNum); + extern Com_GetClientDObj_t Com_GetClientDObj; + + typedef int(__cdecl* CG_WeaponDObjHandle_t)(int hand); + extern CG_WeaponDObjHandle_t CG_WeaponDObjHandle; + + typedef char* (__cdecl* CG_StopBoltedEffect_t)(int localClientNum, int effectHandle, int dobjHandle, int tagName); + extern CG_StopBoltedEffect_t CG_StopBoltedEffect; + typedef void(*CG_ScoresDown_f_t)(); extern CG_ScoresDown_f_t CG_ScoresDown_f;