From 36c1b3ac4056d5309b61dedb3c5b6331e87efdbb Mon Sep 17 00:00:00 2001 From: ragnarok-clanker Date: Thu, 29 Oct 2026 19:49:51 +0000 Subject: [PATCH] Decompile fn_19799 (CEffectPrim::PrimFieldFireflies) Batch #2889 by ragnarok-clanker: 0 byte-identical, 1 confirmed by peer review. - fn_19799 CEffectPrim::PrimFieldFireflies: logic confirmed by peer review Peer-reviewed-by: meitogi, willerthal, youko Accepted without human review: peers confirmed the logic ("same" ahead by at least 3, with 70% of the votes). --- Source/Contents/Effects/EffectPrim.h | 1 + .../Effects/EffectPrimitiveMotion.cpp | 156 ++++++++++++++++++ 2 files changed, 157 insertions(+) diff --git a/Source/Contents/Effects/EffectPrim.h b/Source/Contents/Effects/EffectPrim.h index d3a39481..c9b6e2d2 100644 --- a/Source/Contents/Effects/EffectPrim.h +++ b/Source/Contents/Effects/EffectPrim.h @@ -70,6 +70,7 @@ struct CEffectPrim : CRenderObject { bool PrimDriftingRings(); bool PrimSpiralFade(); bool Prim3DSlotParticle(); + bool PrimFieldFireflies(); void Render2DCircle(); void RenderGroundFog(matrix& wtm); void RenderCrossPlanes(matrix& wtm); diff --git a/Source/Contents/Effects/EffectPrimitiveMotion.cpp b/Source/Contents/Effects/EffectPrimitiveMotion.cpp index 68bb8234..2736392e 100644 --- a/Source/Contents/Effects/EffectPrimitiveMotion.cpp +++ b/Source/Contents/Effects/EffectPrimitiveMotion.cpp @@ -26,6 +26,7 @@ #include #include #include +#include namespace { // INLINED @@ -5624,3 +5625,158 @@ bool CEffectPrim::Prim3DSlotParticle() { this->ShiftSegment(); return this->AnimMotion(); } + +// OFFSET: 0x00BBC080 +// FUNCTION: fn_19799 +bool CEffectPrim::PrimFieldFireflies() { + FaceCamera(this->state.slots); + this->render.position = this->state.master->render.position; + + for (int index = 0; index < 4; ++index) { + EffectPrimitiveSlot& slot = this->state.slots[index]; + + if (slot.life != 1) { + continue; + } + + const float kind = slot.height[7]; + if (kind < 99.0f) { + const int process = ++slot.process; + + if (slot.flag1[2] == 23 && process % 14 == 0) { + char frame = ++slot.flag1[0]; + if (frame > 5) { + frame = 0; + } + slot.flag1[0] = frame; + } + + if (kind == 0.0f) { + if (process < 80 && slot.height[6] > this->render.position.y) { + slot.alphaB += 2; + } + } else if (kind == 2.0f) { + if (process < 80) { + slot.alphaB += 2; + } + } else if (kind == 3.0f) { + if (process < 170) { + ++slot.alphaB; + } + } else if (kind == 5.0f) { + if (process < 80) { + slot.alphaB += 2; + } + } else if (kind == 11.0f || kind == 12.0f || kind == 13.0f || kind == 14.0f) { + if (process < 70) { + ++slot.alphaB; + } + } else if (process < 80) { + slot.alphaB += 3; + } + + if (process > slot.rotStart && --slot.alphaB <= 0) { + slot.process = 0; + slot.alphaB = 0; + + const float respawn = slot.height[7]; + if (respawn == 0.0f) { + if (this->render.position.y > slot.height[6]) { + slot.process = 300; + } + slot.vecBNow.x = static_cast(Random(300) - 150); + slot.vecBNow.z = static_cast(Random(300) - 150); + } else if (respawn == 2.0f || respawn == 5.0f) { + slot.vecBNow.x = static_cast(Random(300) - 150); + slot.vecBNow.z = static_cast(Random(300) - 150); + } else if (respawn == 3.0f) { + slot.vecBNow.x = static_cast(Random(300) - 150); + slot.vecBNow.z = static_cast(Random(300) - 150); + const auto& grid = static_cast(g_modeMgr.GetGameMode())->scene->terrain->Grid(); + const int sink = Random(5); + slot.vecBNow.y = grid.Height(this->render.position.x + slot.vecBNow.x, this->render.position.z + slot.vecBNow.z) - 20.0f - static_cast(sink); + } else { + slot.vecBNow.x = static_cast(Random(200) + 25); + slot.vecBNow.z = static_cast(Random(200) + 25); + if (std::string(static_cast(g_modeMgr.GetGameMode())->mapName) == "ecl_fild01.rsw") { + slot.vecBNow.x = static_cast(Random(400) + 25); + slot.vecBNow.z = static_cast(Random(400) + 25); + } + if (Random(2) == 0) { + slot.vecBNow.x *= -1.0f; + } + if (Random(2) == 0) { + slot.vecBNow.z *= -1.0f; + } + } + + slot.vecBNow.x = this->render.position.x + slot.vecBNow.x; + slot.vecBNow.z = this->render.position.z + slot.vecBNow.z; + } + + for (int pair = 0; pair < 2; ++pair) { + float& current = slot.height[2 * pair]; + float& target = slot.height[2 * pair + 1]; + int next; + if (target <= current) { + current -= 1.0f; + if (current < 0.0f) { + current = 0.0f; + } + if (target < current) { + continue; + } + const int range = static_cast(current); + int pick = 0; + if (range != 0) { + const int value = std::rand() % range; + pick = value >= 0 ? value : 0; + } + next = 359 - pick; + } else { + current += 1.0f; + if (current > 359.0f) { + current = 359.0f; + } + if (current <= target) { + continue; + } + const int range = static_cast(current); + next = 0; + if (range != 0) { + const int value = std::rand() % range; + next = value >= 0 ? value : 0; + } + } + target = static_cast(next); + } + + const float motion = slot.height[7]; + const float driftX = g_sinTable[static_cast(slot.height[0])]; + if (motion == 3.0f) { + slot.vecBNow.x += driftX * 0.015f; + slot.vecBNow.z += g_sinTable[static_cast(slot.height[2])] * 0.015f; + } else if (motion == 4.0f) { + if (driftX <= 0.0f) { + slot.vecBNow.x -= driftX * 0.2f; + } else { + slot.vecBNow.x += driftX * 0.2f; + } + slot.vecBNow.z += g_sinTable[static_cast(slot.height[2])] * 0.05f; + } else if (motion == 5.0f) { + slot.vecBNow.x += driftX * 0.035f; + slot.vecBNow.z += g_sinTable[static_cast(slot.height[2])] * 0.035f; + } else { + slot.vecBNow.x += driftX * 0.05f; + slot.vecBNow.z += g_sinTable[static_cast(slot.height[2])] * 0.05f; + } + } + + slot.height[8] += 1.0f; + if (slot.height[8] >= 360.0f) { + slot.height[8] -= 360.0f; + } + } + + return true; +}