#include "Contents/AttachedEffect.h" #include "Contents/EffectActor.h" #include "Contents/PartyMemberEffects.h" #include "Contents/RagEffectInitialization.h" #include "Script/LuaScript.h" #include "Utility/AffineMatrix.h" namespace { // OFFSET: 0x00CADD60 // FUNCTION: fn_21069 AttachedEffect* CreatePartyEffect(EffectActor& actor, PartyEffectMode& mode) { mode.lastEffectId = 160; auto* effect = new AttachedEffect(mode.resources, mode.names); bool force = false; mode.effectScript.Call("IsForceRenderEffect", "d>b", 160, &force); effect->state.forceRender = force; // Even zero offsets pass through the original angle table and arithmetic. const float sine = ClientSine(0); const float cosine = ClientCosine(0); const float x = 0.0f * cosine - 0.0f * sine; const float z = 0.0f * cosine + 0.0f * sine; InitializeRagEffect( effect->state, effect->render, &actor, actor.render, 160, x, 0, z, mode.options, mode.resources ); mode.objects.push_back(effect); actor.state.effects.push_back(&effect->state); return effect; } } // OFFSET: 0x00DD70B0 // FUNCTION: fn_23283 bool PartyMemberEffects::Enabled() const { const auto* mode = this->activeMode; return mode && (mode->playerOption48 != 0 || mode->playerOption54 != 0); } // OFFSET: 0x00DD70B0 // FUNCTION: fn_23283 // First account-id match, no deduplication or new effect on the existing-roster-member return path. void PartyMemberEffects::EnsurePartyEffect(std::uint32_t accountId) { PartyEffectMode& mode = *this->activeMode; // Actor lookup scans the mode's actor list in order. for (EffectActor* actor : mode.actors) { if (actor->render.accountId == accountId) { if (!actor->state.Attachments().HasId(160)) { CreatePartyEffect(*actor, mode); } return; } } }