diff --git a/Source/Contents/EffectResourceSwitcher.cpp b/Source/Contents/EffectResourceSwitcher.cpp index cf5dea61..7edaa7b0 100644 --- a/Source/Contents/EffectResourceSwitcher.cpp +++ b/Source/Contents/EffectResourceSwitcher.cpp @@ -13,6 +13,10 @@ template <> CEZ2STREffectMgr* Singleton::s_instance = nullptr; +// OFFSET: 0x005A1B70 +EffectResourceSwitcher::EffectResourceSwitcher() : CEffect(-1), active(0), effect(nullptr), spawnPosition{0.0f, 0.0f, 0.0f} { +} + // OFFSET: 0x005A2090 // FUNCTION: fn_03082 void EffectResourceSwitcher::RetireEffects() { diff --git a/Source/Contents/EffectResourceSwitcher.h b/Source/Contents/EffectResourceSwitcher.h index eb123166..a5dfc8af 100644 --- a/Source/Contents/EffectResourceSwitcher.h +++ b/Source/Contents/EffectResourceSwitcher.h @@ -13,7 +13,9 @@ struct EZ2STREffectInfo { /* 0000 */ int id; /* 0004 */ std::string name; - /* 001C */ int unknown_001C[3]; + /* 001C */ float offsetX; + /* 0020 */ float offsetY; + /* 0024 */ int unknown_0024; /* 0028 */ std::string unknown_0028; /* 0040 */ int unknown_0040[2]; }; @@ -59,6 +61,8 @@ public: /* 00E0 */ std::string sourceName; /* 00F8 */ std::string targetName; + EffectResourceSwitcher(); + // INLINED ~EffectResourceSwitcher() override { this->RetireEffects(); diff --git a/Source/Contents/Effects/CharacterParticleBundle.cpp b/Source/Contents/Effects/CharacterParticleBundle.cpp new file mode 100644 index 00000000..c071412d --- /dev/null +++ b/Source/Contents/Effects/CharacterParticleBundle.cpp @@ -0,0 +1,153 @@ +#include "Contents/Effects/CharacterParticleBundle.h" + +#include "Client/Mode/CGameMode.h" +#include "Client/Mode/ModeMgr.h" +#include "Contents/Camera/Camera.h" +#include "Contents/EffectResourceSwitcher.h" +#include "Contents/Effects/Particle.h" +#include "Utility/Cipher/XorBytes.h" +#include "Utility/Math/AffineMatrix.h" +#include "Utility/Math/RadialGrid.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace { + template + class EncryptedName { + public: + explicit EncryptedName(const std::uint8_t (&source)[Length]) : m_encrypted(true) { + for (std::uint64_t index = 0; index < Length; ++index) { + this->m_text[index] = source[index]; + } + } + + ~EncryptedName() { + for (std::uint64_t index = 0; index < Length; ++index) { + this->m_text[index] = 0; + } + } + + const char* Text() { + if (this->m_encrypted) { + utility::XorBytes(this->m_text, Length, Key); + this->m_encrypted = false; + } + + return reinterpret_cast(this->m_text); + } + + private: + std::uint8_t m_text[Length]; + bool m_encrypted; + }; + + // GLOBAL: gl_24870 + std::unordered_map> g_clawMarkRings; +} + +// OFFSET: 0x005A2E50 +CharacterParticleBundle::CharacterParticleBundle() : CEffect(-1), startTime(0), unknown_00D8(0), particles() { +} + +// OFFSET: 0x005A31F0 +CharacterParticleBundle::~CharacterParticleBundle() { +} + +// OFFSET: 0x005A3360 +void CChopChopClawMarks::Slot36(CEZ2STRParticle* particle) { + if (particle) { + const float* view = static_cast(g_modeMgr.GetGameMode())->camera->frame.view.values; + const float* inverse = static_cast(g_modeMgr.GetGameMode())->camera->frame.inverse.values; + const float x = this->position[0]; + const float y = this->position[1]; + const float z = this->position[2]; + const float viewX = view[0] * x + view[3] * y + view[6] * z + view[9] + this->offsetX + particle->unknown_00D0; + const float viewY = view[1] * x + view[4] * y + view[7] * z + view[10] - this->offsetY + particle->unknown_00D4; + const float viewZ = view[2] * x + view[5] * y + view[8] * z + view[11] + particle->unknown_00D8; + particle->position.x = viewY * inverse[3] + viewX * inverse[0] + viewZ * inverse[6] + inverse[9]; + particle->position.y = viewX * inverse[1] + viewY * inverse[4] + viewZ * inverse[7] + inverse[10]; + particle->position.z = viewX * inverse[2] + viewY * inverse[5] + viewZ * inverse[8] + inverse[11]; + } +} + +// OFFSET: 0x005A3A10 +const std::vector& CChopChopClawMarks::GetRing(int radius) { + const auto found = g_clawMarkRings.find(radius); + if (found != g_clawMarkRings.end()) { + return found->second; + } + + const std::vector outer = GenerateRadialGrid(RadialGridPoint{0.0f, 0.0f}, radius); + const std::vector inner = GenerateRadialGrid(RadialGridPoint{0.0f, 1.0f}, 1); + std::vector ring; + for (const RadialGridPoint& point : outer) { + const auto match = std::find_if(inner.begin(), inner.end(), [&point](const RadialGridPoint& other) { + return point.x == other.x && point.y == other.y; + }); + if (match == inner.end()) { + ring.push_back(point); + } + } + + g_clawMarkRings[radius] = std::move(ring); + return g_clawMarkRings[radius]; +} + +// OFFSET: 0x005A3C70 +void CChopChopClawMarks::Slot35() { + const int id = CEZ2STREffectMgr::GetInstance()->EffectId([] { + const std::uint8_t bytes[] = {0xC2, 0x55, 0xF0, 0xA7, 0x3C, 0xEC, 0x4F, 0x36, 0xD1, 0x3D}; + thread_local EncryptedName name(bytes); + return name.Text(); + }()); + if (EZ2STREffectInfo* info = CEZ2STREffectMgr::GetInstance()->FindById(id)) { + this->offsetX = info->offsetX; + this->offsetY = info->offsetY; + } +} + +// OFFSET: 0x005A3E50 +void CharacterParticleBundle::Slot01() { + this->unknown_00D8 = 0; + this->startTime = std::chrono::steady_clock::now().time_since_epoch().count(); + this->Slot35(); +} + +// OFFSET: 0x005A3E90 +bool CChopChopClawMarks::Slot06() { + if (!this->ActorExists()) { + return false; + } + + const std::chrono::nanoseconds elapsed = std::chrono::steady_clock::now().time_since_epoch() - std::chrono::nanoseconds(this->startTime); + return std::chrono::seconds(this->unknown_002C) >= std::chrono::duration_cast(elapsed); +} + +// OFFSET: 0x005A4000 +void CharacterParticleBundle::Slot37(CEZ2STRParticle* particle) { + if (particle) { + particle->Process(0.0f, 0.0f, 0.0f); + } +} + +// OFFSET: 0x005A4030 +// FUNCTION: fn_03141 +void CharacterParticleBundle::Slot04() { + for (CEZ2STRParticle* particle : this->particles) { + this->Slot38(particle); + } +} + +// OFFSET: 0x005A4060 +void CharacterParticleBundle::Slot38(CEZ2STRParticle* particle) { + if (particle) { + particle->DrawScreen(static_cast(g_modeMgr.GetGameMode())->camera->frame.view); + } +} diff --git a/Source/Contents/Effects/CharacterParticleBundle.h b/Source/Contents/Effects/CharacterParticleBundle.h index 2d14fcc7..e427dccb 100644 --- a/Source/Contents/Effects/CharacterParticleBundle.h +++ b/Source/Contents/Effects/CharacterParticleBundle.h @@ -4,6 +4,10 @@ #include "Contents/Effects/Effect.h" #include +#include + +class CEZ2STRParticle; +struct RadialGridPoint; class CharacterParticleBundle : public CEffect { public: @@ -13,18 +17,19 @@ public: void Slot03() override; void Slot04() override; void Close() override; + virtual bool Slot06() = 0; ~CharacterParticleBundle() override; virtual void Slot34() = 0; virtual void Slot35(); - virtual void Slot36(); + virtual void Slot36(CEZ2STRParticle* particle) { + } + virtual void Slot37(CEZ2STRParticle* particle); + virtual void Slot38(CEZ2STRParticle* particle); /* 00CC */ int unknown_00CC; - /* 00D0 */ int unknown_00D0; - /* 00D4 */ int unknown_00D4; + /* 00D0 */ long long startTime; /* 00D8 */ int unknown_00D8; - /* 00DC */ int unknown_00DC; - /* 00E0 */ int unknown_00E0; - /* 00E4 */ int unknown_00E4; + /* 00DC */ std::vector particles; }; class CChopChopClawMarks : public CharacterParticleBundle { @@ -33,15 +38,20 @@ public: ~CChopChopClawMarks() override; void Slot34() override; void Slot35() override; - void Slot36() override; + void Slot36(CEZ2STRParticle* particle) override; + + const std::vector& GetRing(int radius); /* 00E8 */ int unknown_00E8 = 0; /* 00EC */ int unknown_00EC = 0; - /* 00F0 */ int unknown_00F0[2]; + /* 00F0 */ float offsetX; + /* 00F4 */ float offsetY; }; #if defined(_WIN32) && !defined(_WIN64) -static_assert(offsetof(CharacterParticleBundle, unknown_00E4) == 0xE4); +static_assert(offsetof(CharacterParticleBundle, startTime) == 0xD0); +static_assert(offsetof(CharacterParticleBundle, particles) == 0xDC); +static_assert(offsetof(CChopChopClawMarks, offsetY) == 0xF4); static_assert(sizeof(CChopChopClawMarks) == 0xF8); #endif diff --git a/data/compile.json b/data/compile.json index b6e95cba..8dfa1168 100644 --- a/data/compile.json +++ b/data/compile.json @@ -328,6 +328,7 @@ "Source/Contents/Effects/BlastForge.cpp": 4, "Source/Contents/Effects/CaneOfEvilEyeEffect.cpp": 4, "Source/Contents/Effects/ChangeSizeEffect.cpp": 4, + "Source/Contents/Effects/CharacterParticleBundle.cpp": 4, "Source/Contents/Effects/ChargingPierceEffect.cpp": 4, "Source/Contents/Effects/ClimaxEffect.cpp": 4, "Source/Contents/Effects/CloudEffect.cpp": 4,