diff --git a/Client/game_sa/CFxSA.cpp b/Client/game_sa/CFxSA.cpp index dca7844fdf5..1b91eb0b2fe 100644 --- a/Client/game_sa/CFxSA.cpp +++ b/Client/game_sa/CFxSA.cpp @@ -10,8 +10,16 @@ *****************************************************************************/ #include "StdInc.h" +#include "game/Common.h" +#include "game/RenderWare.h" +#include "CVector2D.h" #include "CFxSA.h" #include "CEntitySA.h" +; +using StoreShadowToBeRendered_t = int(__cdecl*)(eShadowType, struct RwTexture*, const CVector*, float, float, float, float, short, unsigned char, + unsigned char, unsigned char, float, bool, float, class CRealTimeShadow*, bool); +auto StoreShadowToBeRendered = reinterpret_cast(0x707390); +unsigned short& CShadows_ShadowsStoredToBeRendered = *(unsigned short*)0xC403DC; void CFxSA::AddBlood(CVector& vecPosition, CVector& vecDirection, int iCount, float fBrightness) { @@ -239,3 +247,22 @@ void CFxSA::TriggerFootSplash(CVector& vecPosition) call dwFunc } } + +bool CFxSA::IsShadowsLimitReached() +{ + constexpr int shadowsLimit = 48; + return CShadows_ShadowsStoredToBeRendered >= shadowsLimit; +} + +bool CFxSA::AddShadow(eShadowTextureType shadowTextureType, const CVector& vecPosition, const CVector2D& vecOffset1, const CVector2D& vecOffset2, SColor color, eShadowType shadowType, float fZDistance, + bool bDrawOnWater, bool bDrawOnBuildings) +{ + if (IsShadowsLimitReached()) + return false; + + void* textureAddress = *(void**)(SHADOW_BASE_TEXTURE_OFFSET + (int)shadowTextureType * 4); + RwTexture* pRwTexture = reinterpret_cast(textureAddress); + + + return StoreShadowToBeRendered(shadowType, pRwTexture, &vecPosition, vecOffset1.fX, vecOffset1.fY, vecOffset2.fX, vecOffset2.fY, color.A, color.R, color.G, color.B, fZDistance, bDrawOnWater, 1, 0, bDrawOnBuildings); +} diff --git a/Client/game_sa/CFxSA.h b/Client/game_sa/CFxSA.h index 55b56b83f23..ee9428c0a21 100644 --- a/Client/game_sa/CFxSA.h +++ b/Client/game_sa/CFxSA.h @@ -29,6 +29,7 @@ struct RwColor; #define FUNC_CFx_TriggerWaterSplash 0x4a1070 #define FUNC_CFx_TriggerBulletSplash 0x4a10e0 #define FUNC_CFx_TriggerFootSplash 0x4a1150 +constexpr auto SHADOW_BASE_TEXTURE_OFFSET = 0xC403E0; class CFxSAInterface { @@ -49,6 +50,8 @@ class CFxSA : public CFx void AddPunchImpact(CVector& vecPosition, CVector& vecDirection, int); void AddDebris(CVector& vecPosition, RwColor& rwColor, float fScale, int iCount); void AddGlass(CVector& vecPosition, RwColor& rwColor, float fScale, int iCount); + bool AddShadow(eShadowTextureType shadowTextureType, const CVector& vecPosition, const CVector2D& vecOffset1, const CVector2D& vecOffset2, SColor color, + eShadowType shadowType, float fZDistance, bool bDrawOnWater, bool bDrawOnBuildings); void TriggerWaterHydrant(CVector& vecPosition); void TriggerGunshot(CEntity* pEntity, CVector& vecPosition, CVector& vecDirection, bool bIncludeSparks); void TriggerTankFire(CVector& vecPosition, CVector& vecDirection); @@ -56,6 +59,7 @@ class CFxSA : public CFx void TriggerBulletSplash(CVector& vecPosition); void TriggerFootSplash(CVector& vecPosition); + static bool IsShadowsLimitReached(); private: CFxSAInterface* m_pInterface; }; diff --git a/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp b/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp index ffc4466a339..f5be09cbe8c 100644 --- a/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp +++ b/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp @@ -7867,6 +7867,13 @@ bool CStaticFunctionDefinitions::FxAddFootSplash(CVector& vecPosition) return true; } +bool CStaticFunctionDefinitions::FxAddShadow(eShadowTextureType shadowTextureType, const CVector& vecPosition, const CVector2D& vecOffset1, + const CVector2D& vecOffset2, SColor color, eShadowType shadowType, float fZDistance, bool bDrawOnWater, + bool bDrawOnBuildings) +{ + return g_pGame->GetFx()->AddShadow(shadowTextureType, vecPosition, vecOffset1, vecOffset2, color, shadowType, fZDistance, bDrawOnWater, bDrawOnBuildings); +} + CClientEffect* CStaticFunctionDefinitions::CreateEffect(CResource& Resource, const SString& strFxName, const CVector& vecPosition, bool bSoundEnable) { CClientEffect* pFx = m_pManager->GetEffectManager()->Create(strFxName, vecPosition, INVALID_ELEMENT_ID, bSoundEnable); diff --git a/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.h b/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.h index 437e4503f65..a1023e3ead1 100644 --- a/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.h +++ b/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.h @@ -729,6 +729,8 @@ class CStaticFunctionDefinitions static bool FxAddWaterSplash(CVector& vecPosition); static bool FxAddBulletSplash(CVector& vecPosition); static bool FxAddFootSplash(CVector& vecPosition); + static bool FxAddShadow(eShadowTextureType shadowTextureType, const CVector& vecPosition, const CVector2D& vecOffset1, const CVector2D& vecOffset2, + SColor color, eShadowType shadowType, float fZDistance, bool bDrawOnWater, bool bDrawOnBuildings); static CClientEffect* CreateEffect(CResource& Resource, const SString& strFxName, const CVector& vecPosition, bool bSoundEnable); // Sound funcs diff --git a/Client/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.cpp b/Client/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.cpp index ba91b033815..b05e9141f0d 100644 --- a/Client/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.cpp +++ b/Client/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.cpp @@ -824,6 +824,27 @@ ADD_ENUM(_D3DFORMAT::D3DFMT_G32R32F, "g32r32f") ADD_ENUM(_D3DFORMAT::D3DFMT_A32B32G32R32F, "a32b32g32r32f") IMPLEMENT_ENUM_CLASS_END("surface-format") +IMPLEMENT_ENUM_CLASS_BEGIN(eShadowTextureType) +ADD_ENUM(eShadowTextureType::PLANE, "plane") +ADD_ENUM(eShadowTextureType::CAR, "car") +ADD_ENUM(eShadowTextureType::PED, "ped") +ADD_ENUM(eShadowTextureType::HELI, "heli") +ADD_ENUM(eShadowTextureType::BIKE, "bike") +ADD_ENUM(eShadowTextureType::RCBARON, "rcbaron") +ADD_ENUM(eShadowTextureType::EXPLOSION, "explosion") +ADD_ENUM(eShadowTextureType::HEADLIGHT1, "headlight1") +ADD_ENUM(eShadowTextureType::HEADLIGHT2, "headlight2") +ADD_ENUM(eShadowTextureType::BLOOD, "blood") +ADD_ENUM(eShadowTextureType::HANDMAN, "handman") +ADD_ENUM(eShadowTextureType::WINCRACK, "wincrack") +ADD_ENUM(eShadowTextureType::LAMP, "lamp") +IMPLEMENT_ENUM_CLASS_END("shadow-texture-type") + +IMPLEMENT_ENUM_CLASS_BEGIN(eShadowType) +ADD_ENUM(eShadowType::DEFAULT, "default") +ADD_ENUM(eShadowType::ADDITIVE, "additive") +ADD_ENUM(eShadowType::INVCOLOR, "invcolor") +IMPLEMENT_ENUM_CLASS_END("shadow-type") // // CResource from userdata // diff --git a/Client/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.h b/Client/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.h index 5688c78d345..700e89b0d5d 100644 --- a/Client/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.h +++ b/Client/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.h @@ -81,6 +81,8 @@ DECLARE_ENUM_CLASS(eSoundEffectParams::ParamEq); DECLARE_ENUM_CLASS(eSoundEffectParams::Reverb); DECLARE_ENUM_CLASS(eModelIdeFlag); DECLARE_ENUM_CLASS(_D3DFORMAT); +DECLARE_ENUM_CLASS(eShadowTextureType); +DECLARE_ENUM_CLASS(eShadowType); class CRemoteCall; @@ -490,6 +492,14 @@ inline SString GetClassTypeName(eSoundEffectParams::Reverb*) { return "soundeffect-params-reverb"; } +inline SString GetClassTypeName(eShadowTextureType*) +{ + return "shadow-texture-type"; +} +inline SString GetClassTypeName(eShadowType*) +{ + return "shadow-type"; +} inline SString GetClassTypeName(CClientVectorGraphic*) { diff --git a/Client/mods/deathmatch/logic/luadefs/CLuaEffectDefs.cpp b/Client/mods/deathmatch/logic/luadefs/CLuaEffectDefs.cpp index 5b9940a01a2..2e0c78e6863 100644 --- a/Client/mods/deathmatch/logic/luadefs/CLuaEffectDefs.cpp +++ b/Client/mods/deathmatch/logic/luadefs/CLuaEffectDefs.cpp @@ -10,6 +10,27 @@ *****************************************************************************/ #include "StdInc.h" +#include "lua/CLuaFunctionParser.h" + +bool FxAddShadow(eShadowTextureType shadowTextureType, CVector vecPosition, CVector2D vecOffset1, CVector2D vecOffset2, SColor color, eShadowType shadowType, float zDistance, + bool bDrawOnWater, bool bDrawOnBuildings) +{ + if (vecOffset1.Length() > 32) + { + throw std::invalid_argument("First offset can not be longer than 32 units"); + } + else if (vecOffset2.Length() > 32) // bigger and close to limit shadows size can be partially invisible + { + throw std::invalid_argument("Second offset can not be longer than 32 units"); + } + else if (zDistance < 0 || zDistance > 3000) // negative distance not working + { + throw std::invalid_argument("Z Distance must be between 0.0 and 3000.0"); + } + return CStaticFunctionDefinitions::FxAddShadow(shadowTextureType, vecPosition, vecOffset1, vecOffset2, color, shadowType, zDistance, bDrawOnWater, + bDrawOnBuildings); + +} void CLuaEffectDefs::LoadFunctions() { @@ -28,6 +49,7 @@ void CLuaEffectDefs::LoadFunctions() {"fxAddWaterSplash", fxAddWaterSplash}, {"fxAddBulletSplash", fxAddBulletSplash}, {"fxAddFootSplash", fxAddFootSplash}, + {"fxAddShadow", ArgumentParser}, {"createEffect", CreateEffect}, {"setEffectSpeed", SetEffectSpeed}, {"getEffectSpeed", GetEffectSpeed}, diff --git a/Client/sdk/game/CFx.h b/Client/sdk/game/CFx.h index 8b4460357d2..e7214b141a9 100644 --- a/Client/sdk/game/CFx.h +++ b/Client/sdk/game/CFx.h @@ -28,6 +28,8 @@ class CFx virtual void AddPunchImpact(CVector& vecPosition, CVector& vecDirection, int i) = 0; virtual void AddDebris(CVector& vecPosition, RwColor& rwColor, float fScale, int iCount) = 0; virtual void AddGlass(CVector& vecPosition, RwColor& rwColor, float fScale, int iCount) = 0; + virtual bool AddShadow(eShadowTextureType shadowTextureType, const CVector& vecPosition, const CVector2D& vecOffset1, const CVector2D& vecOffset2, SColor color, eShadowType shadowType, + float fZDistance, bool bDrawOnWater, bool bDrawOnBuildings) = 0; virtual void TriggerWaterHydrant(CVector& vecPosition) = 0; virtual void TriggerGunshot(CEntity* pEntity, CVector& vecPosition, CVector& vecDirection, bool bIncludeSparks) = 0; virtual void TriggerTankFire(CVector& vecPosition, CVector& vecDirection) = 0; diff --git a/Client/sdk/game/Common.h b/Client/sdk/game/Common.h index 503f4c9021f..2c2c6e30f5a 100644 --- a/Client/sdk/game/Common.h +++ b/Client/sdk/game/Common.h @@ -1442,6 +1442,32 @@ enum eObjectProperty OBJECT_PROPERTY_MAX, }; +enum class eShadowTextureType +{ + // use only color instead of texture + PLANE = -1, + CAR, + PED, + HELI, + BIKE, + RCBARON, + EXPLOSION, + HEADLIGHT1, + HEADLIGHT2, + BLOOD, + HANDMAN, + WINCRACK, + LAMP, +}; + +enum class eShadowType +{ + NONE, + DEFAULT, + ADDITIVE, + INVCOLOR, +}; + namespace eObjectGroup { enum Modifiable