-
Автор темы
- #1
Preview:
Note: code can be optimized a lot, also those addresses for latest CS:S, regard it as anti-paste .
C++:
namespace Fireworks
{
static enum class Step_t
{
Whistle, Explosion, Clap, Erase
};
static struct Firework
{
Step_t m_nStep;
Vector m_vecPos;
float m_flNextStepTime;
};
static void* pSimple;
static void* pMaterial;
constexpr auto WhistleTime = 2.f;
constexpr auto ExplosionTime = 0.1f;
static std::vector<Firework> gFireworks;
using DispatchEffect_Type = void(*)(const char*, const CEffectData&);
using CSimpleEmitter_Create_Type = void* (__cdecl*)(void*, const char*);
using AddParticle_Type = SimpleParticle * (__thiscall*)(void*, int, void*, const Vector&);
void OnStartup() noexcept // Take FX_Tesla as ref
{
reinterpret_cast<CSimpleEmitter_Create_Type >(ClientModule + 0x1644C0)(&pSimple, "FX_ElectricSpark 1");
if (!pSimple)
return;
void* __fastcall Hooked_GetPMaterial(void* pThis, void* EDX, const char* MaterialName);
pMaterial = reinterpret_cast<void* (__thiscall*)(void*, const char*)>(&Hooked_GetPMaterial)(pSimple, "effects/spark");
}
void OnMapEnd() noexcept
{
gFireworks.clear();
}
void Create(const Vector& Positaion) noexcept
{
gFireworks.emplace_back(Step_t::Whistle, Positaion, 0.f);
}
void Whistle(CBaseEntity* pLocal, Firework& gpFirework) noexcept
{
const auto& MyOrigin = pLocal->GetAbsOrigin();
SimpleParticle* pParticle = reinterpret_cast<AddParticle_Type>(ClientModule + 0x164230)(pSimple, sizeof(SimpleParticle), pMaterial, MyOrigin);
if (!pParticle)
return;
auto vecVelocity = (gpFirework.m_vecPos - MyOrigin) / WhistleTime;
pParticle->m_flLifetime = 0.0f;
pParticle->m_flDieTime = WhistleTime;
pParticle->m_vecVelocity = vecVelocity;
pParticle->m_uchColor[0] = 255;
pParticle->m_uchColor[1] = 255;
pParticle->m_uchColor[2] = 255;
pParticle->m_uchStartSize = 20;
pParticle->m_uchEndSize = 20;
pParticle->m_uchStartAlpha = 255;
pParticle->m_uchEndAlpha = 255;
pParticle->m_flRoll = 0;
pParticle->m_flRollDelta = 45;
Surface->PlaySound("Fireworks\\Whistle.wav");
gpFirework.m_nStep = Step_t::Explosion;
gpFirework.m_flNextStepTime = Globals->curtime + WhistleTime;
}
void Explosion(Firework& gpFirework) noexcept
{
CEffectData data;
if (Globals->curtime <= gpFirework.m_flNextStepTime)
return;
data.m_fFlags = 6;
data.m_vNormal.Init(-1.f, 1.f, -2.f);
data.m_flScale = 2.f;
data.m_nColor = 3;
data.m_nEntIndex = -1;
data.m_vAngles.Zero();
data.m_vOrigin = gpFirework.m_vecPos;
gpFirework.m_nStep = Step_t::Clap;
gpFirework.m_flNextStepTime = Globals->curtime + ExplosionTime;
reinterpret_cast<DispatchEffect_Type>(DispatchEffectA)("Explosion", data);
}
void Clap(CBaseEntity* pLocal, Firework& gpFirework) noexcept
{
Vector Angles, RIGHT;
if (Globals->curtime <= gpFirework.m_flNextStepTime)
return;
Vector DELTA = pLocal->GetAbsOrigin() - gpFirework.m_vecPos;
Math::VectorAngles(DELTA, Angles);
if (!pSimple || !pMaterial)
return;
for (auto a = 0; a < 3; a++) { // increases strength
for (auto c = 0; c < 360; c++) {
Angles.z = c;
constexpr float flMaxSpeed = 20.f;
Color color = Color::Rainbow();
Math::AngleVectors(Angles, NULL, &RIGHT, NULL);
auto vecVelocity = RIGHT * RandomFloat(1.f, flMaxSpeed) * flMaxSpeed;
SimpleParticle* pParticle = reinterpret_cast<AddParticle_Type>(ClientModule + 0x164230)(pSimple, sizeof(SimpleParticle), pMaterial, gpFirework.m_vecPos);
if (!pParticle)
continue;
pParticle->m_flLifetime = 0.0f;
pParticle->m_flDieTime = 2.f;
pParticle->m_vecVelocity = vecVelocity;
pParticle->m_uchColor[0] = color.a();
pParticle->m_uchColor[1] = color.g();
pParticle->m_uchColor[2] = color.b();
pParticle->m_uchStartSize = RandomFloat(5, 25);
pParticle->m_uchEndSize = pParticle->m_uchStartSize - 2;
pParticle->m_uchStartAlpha = 255;
pParticle->m_uchEndAlpha = 10;
pParticle->m_flRoll = RandomFloat(5, 360);
pParticle->m_flRollDelta = 0;
}
}
gpFirework.m_nStep = Step_t::Erase;
Surface->PlaySound("Fireworks\\Clap.wav");
}
void Process(CBaseEntity* pLocal) noexcept
{
for (auto i = 0; i < gFireworks.size(); i++)
{
auto& gpFirework = gFireworks[i];
switch (gpFirework.m_nStep)
{
case Step_t::Whistle:
Whistle(pLocal, gpFirework);
break;
case Step_t::Explosion:
Explosion(gpFirework);
break;
case Step_t::Clap:
Clap(pLocal, gpFirework);
break;
default:
gFireworks.erase(gFireworks.begin() + i);
break;
}
}
}
}
C++:
namespace Fireworks
{
void OnStartup() noexcept;
void OnMapEnd() noexcept;
void Process(CBaseEntity* pLocal) noexcept;
void Create(const Vector& Positaion) noexcept;
}
C++:
struct Particle
{
Particle *m_pPrev, *m_pNext;
// Which sub texture this particle uses (so we can get at the tcoord mins and maxs).
void*m_pSubTexture;
// If m_Pos isn't used to store the world position, then implement IParticleEffect::GetParticlePosition()
Vector m_Pos; // Position of the particle in world space
};
class SimpleParticle : public Particle
{
public:
SimpleParticle() : m_iFlags(0) {}
// AddSimpleParticle automatically initializes these fields.
Vector m_vecVelocity;
float m_flRoll;
float m_flDieTime; // How long it lives for.
float m_flLifetime; // How long it has been alive for so far.
unsigned char m_uchColor[3];
unsigned char m_uchStartAlpha;
unsigned char m_uchEndAlpha;
unsigned char m_uchStartSize;
unsigned char m_uchEndSize;
unsigned char m_iFlags; // See SimpleParticleFlag_t above
float m_flRollDelta;
};
Note: code can be optimized a lot