From 0aa64c3622ce94cfd90d877262ac2bfa0a8e712a Mon Sep 17 00:00:00 2001 From: ragnarok-clanker Date: Thu, 29 Oct 2026 14:39:20 +0000 Subject: [PATCH] Decompile 15 functions in Source/Contents/Effects/EffectPrimitiveRendering.cpp, Source/Contents/Effects/EffectPrim.h Batch #2150 by ragnarok-clanker: 0 byte-identical, 15 confirmed by peer review. - fn_19894 CEffectPrim::RenderHalfSphere: logic confirmed by peer review - fn_19895 CEffectPrim::RenderHermode: logic confirmed by peer review - fn_19896 CEffectPrim::RenderHitLine3: logic confirmed by peer review - fn_19897 CEffectPrim::RenderHitLine: logic confirmed by peer review - fn_19902 CEffectPrim::RenderMagnum2: logic confirmed by peer review - fn_19905 CEffectPrim::RenderPeongUp: logic confirmed by peer review - fn_19908 CEffectPrim::RenderRainbow: logic confirmed by peer review - fn_19909 CEffectPrim::RenderRectUp2: logic confirmed by peer review - fn_19910 CEffectPrim::RenderRectUp: logic confirmed by peer review - fn_19911 CEffectPrim::RenderSMA2: logic confirmed by peer review - fn_19915 CEffectPrim::RenderSaintWing: logic confirmed by peer review - fn_19916 CEffectPrim::RenderSlash1: logic confirmed by peer review - fn_19918 CEffectPrim::RenderSoulLink: logic confirmed by peer review - fn_19919 CEffectPrim::RenderSoulParticle: logic confirmed by peer review - fn_19920 CEffectPrim::RenderSphereWind: logic confirmed by peer review Reviewed-by: ragnarok-clanker --- Source/Contents/Effects/EffectPrim.h | 15 + .../Effects/EffectPrimitiveRendering.cpp | 1043 +++++++++++++++++ 2 files changed, 1058 insertions(+) diff --git a/Source/Contents/Effects/EffectPrim.h b/Source/Contents/Effects/EffectPrim.h index 45591aef1..41be66475 100644 --- a/Source/Contents/Effects/EffectPrim.h +++ b/Source/Contents/Effects/EffectPrim.h @@ -79,6 +79,21 @@ struct CEffectPrim : CRenderObject { void RenderTeiRect(int* rpCnt, short alpha, vector3d vec1, vector3d vec2, vector3d vec3, vector3d vec4, matrix& wtm, short pw, char tn, char f1, unsigned char r, unsigned char g, unsigned char b, float ty1, float ty2, float tx, float tx2, char extra); void RenderTeiRect(int* rpCnt, int texPart, short alphaB, short alphaT, vector3d vec1, vector3d vec2, vector3d vec3, vector3d vec4, matrix& wtm, char pw); void RenderTeiRect(int* rpCnt, int texPart, short alphaB, short alphaT, vector3d vec1, vector3d vec2, vector3d vec3, vector3d vec4, matrix& wtm, char pw, unsigned char r, unsigned char g, unsigned char b); + void RenderHalfSphere(matrix& wtm); + void RenderHermode(matrix& wtm); + void RenderHitLine3(matrix& wtm); + void RenderHitLine(matrix& wtm); + void RenderMagnum2(matrix& wtm); + void RenderPeongUp(matrix& wtm); + void RenderRainbow(matrix& wtm); + void RenderRectUp2(matrix& wtm); + void RenderRectUp(matrix& wtm); + void RenderSMA2(matrix& wtm); + void RenderSaintWing(matrix& wtm); + void RenderSlash1(matrix& wtm); + void RenderSoulLink(matrix& wtm); + void RenderSoulParticle(matrix& wtm); + void RenderSphereWind(matrix& wtm); /* 0138 */ EffectPrimitiveState state; }; diff --git a/Source/Contents/Effects/EffectPrimitiveRendering.cpp b/Source/Contents/Effects/EffectPrimitiveRendering.cpp index 7a3b63609..0b317ba81 100644 --- a/Source/Contents/Effects/EffectPrimitiveRendering.cpp +++ b/Source/Contents/Effects/EffectPrimitiveRendering.cpp @@ -11,6 +11,12 @@ #include "Render/Renderer.h" #include "Render/TextureQuad.h" #include "Utility/Math/AffineMatrix.h" +#include "Client/Mode/CGameMode.h" +#include "Client/Mode/ModeMgr.h" +#include "Client/Session.h" +#include "Contents/Actors/Pc.h" +#include "Contents/Camera/Camera.h" +#include "Contents/World/World.h" // OFFSET: 0x00BCD960 // FUNCTION: fn_19865 @@ -579,3 +585,1040 @@ void CEffectPrim::RenderTeiRect( } } } + +// OFFSET: 0x00BDAC40 +// FUNCTION: fn_19894 +void CEffectPrim::RenderHalfSphere(matrix& wtm) { + vector3d vec1{}; + vector3d vec3{}; + int rpCnt = 0; + + for (int ec = 0; ec < 4; ++ec) { + const EffectPrimitiveSlot& slot = this->state.slots[ec]; + + if (slot.life != 1) { + continue; + } + + const int step = slot.fullDisplayAngle / 10; + + for (int angle2 = 0; angle2 < 180; angle2 += 18) { + for (int count = 0; count <= slot.fullDisplayAngle; count += step) { + int angle = slot.rotStart + count; + + if (angle >= 360) { + angle -= 360; + } + + if (slot.fullDisplayAngle == 360 && count == 360) { + angle = slot.rotStart; + } + + const float cs1 = g_cosTable[angle]; + const float sn1 = g_sinTable[angle]; + const float dist = slot.distance; + + float ring = g_sinTable[angle2] * dist; + const vector3d vec2{cs1 * ring + slot.vecTNow.x, g_cosTable[angle2] * dist - slot.maxHeight, sn1 * ring + slot.vecTNow.z}; + ring = g_sinTable[angle2 + 18] * dist; + const vector3d vec4{cs1 * ring + slot.vecTNow.x, g_cosTable[angle2 + 18] * dist - slot.maxHeight, sn1 * ring + slot.vecTNow.z}; + + if (count > 0) { + this->RenderTeiRect(&rpCnt, slot.alphaB, vec1, vec2, vec4, vec3, wtm, 1, 0, 0, 250, 250, 255, 0.0f, 1.0f, 0.0f, 1.0f, 0); + } + + vec1 = vec2; + vec3 = vec4; + } + } + } +} + +// OFFSET: 0x00BDAEF0 +// FUNCTION: fn_19895 +void CEffectPrim::RenderHermode(matrix& wtm) { + int rpCnt = 0; + + for (int ec = 0; ec < 4; ++ec) { + EffectPrimitiveSlot& slot = this->state.slots[ec]; + + if (slot.life != 1) { + continue; + } + + int angle = slot.rotStart; + const float snA = g_sinTable[angle] * 2.0f; + const float rx = slot.distance * 0.1f * (g_sinTable[slot.riseAngle] + 1.0f); + const double radius = slot.distance * 0.8 + rx; + const float y = slot.height[0] + snA; + + slot.vecBPre = {static_cast(g_cosTable[angle] * radius), y, static_cast(g_sinTable[angle] * radius)}; + angle += angle >= 270 ? -270 : 90; + slot.vecBNow = {static_cast(g_cosTable[angle] * radius), y, static_cast(g_sinTable[angle] * radius)}; + angle += angle + 90 >= 360 ? -270 : 90; + slot.vecTNow = {static_cast(g_cosTable[angle] * radius), y, static_cast(g_sinTable[angle] * radius)}; + angle += angle + 90 >= 360 ? -270 : 90; + slot.vecTPre = {static_cast(g_cosTable[angle] * radius), y, static_cast(g_sinTable[angle] * radius)}; + + vector3d vec1 = slot.vecBPre; + vec1.y -= slot.distance; + vector3d vec2 = slot.vecBNow; + vec2.y -= slot.distance; + vector3d vec3 = slot.vecTPre; + vec3.y -= slot.distance; + vector3d vec4 = slot.vecTNow; + vec4.y -= slot.distance; + + const unsigned char shade = static_cast(slot.flag1[0]); + this->RenderTeiRect(&rpCnt, slot.alphaB, slot.vecBPre, slot.vecBNow, slot.vecTNow, slot.vecTPre, wtm, 0, 0, 0, shade, shade, 250, 0.0f, 1.0f, 0.0f, 1.0f, 0); + this->RenderTeiRect(&rpCnt, slot.alphaB, slot.vecBPre, slot.vecBNow, vec2, vec1, wtm, 0, 0, 0, shade, shade, 220, 0.0f, 1.0f, 0.0f, 1.0f, 0); + this->RenderTeiRect(&rpCnt, slot.alphaB, slot.vecBNow, slot.vecTNow, vec4, vec2, wtm, 0, 0, 0, shade, shade, 190, 0.0f, 1.0f, 0.0f, 1.0f, 0); + this->RenderTeiRect(&rpCnt, slot.alphaB, slot.vecTNow, slot.vecTPre, vec3, vec4, wtm, 0, 0, 0, shade, shade, 130, 0.0f, 1.0f, 0.0f, 1.0f, 0); + this->RenderTeiRect(&rpCnt, slot.alphaB, slot.vecTPre, slot.vecBPre, vec1, vec3, wtm, 0, 0, 0, shade, shade, 160, 0.0f, 1.0f, 0.0f, 1.0f, 0); + this->RenderTeiRect(&rpCnt, slot.alphaB, vec1, vec2, vec4, vec3, wtm, 0, 0, 0, shade, shade, 250, 0.0f, 1.0f, 0.0f, 1.0f, 0); + } +} + +// OFFSET: 0x00BDB530 +// FUNCTION: fn_19896 +void CEffectPrim::RenderHitLine3(matrix& wtm) { + vector3d vec1{}; + vector3d vec3{}; + int rpCnt = 0; + + for (int ec = 0; ec < 4; ++ec) { + const EffectPrimitiveSlot& slot = this->state.slots[ec]; + + if (slot.life != 1 || slot.alphaB <= 0 || slot.process <= 0) { + continue; + } + + for (int j = 0; static_cast(j) < slot.vecTNow.y; ++j) { + float speed = 0.0f; + + if (slot.height[j] > 0.0f) { + speed += slot.height[j] / 90.0f * slot.distance; + } + + vector3d vecA{ + speed * g_cosTable[slot.riseAngle], -slot.distance * g_sinTable[static_cast(slot.height[j])] * slot.vecTNow.x, + speed * g_sinTable[slot.riseAngle] + }; + + speed = 0.0f; + + if (slot.height[j + 1] > 0.0f) { + speed += slot.height[j + 1] / 90.0f * slot.distance; + } + + vector3d vecB{ + speed * g_cosTable[slot.riseAngle], -slot.distance * g_sinTable[static_cast(slot.height[j + 1])] * slot.vecTNow.x, + speed * g_sinTable[slot.riseAngle] + }; + + std::int16_t angle; + Get_Angle(vecA.x - vecB.x, vecA.z - vecB.z, &angle); + vecA.x += slot.vecBNow.x; + vecA.y += slot.vecBNow.y; + vecA.z += slot.vecBNow.z; + vecB.x += slot.vecBNow.x; + vecB.y += slot.vecBNow.y; + vecB.z += slot.vecBNow.z; + angle += 90; + + if (angle >= 360) { + angle -= 360; + } + + for (int i = 0; i <= 3; ++i) { + const float radius = slot.maxHeight; + const float tx = radius * g_cosTable[i * 120]; + const float ry = radius * g_sinTable[i * 120] - 5.0f; + const float rx = tx * g_cosTable[angle]; + const float rz = tx * g_sinTable[angle]; + const vector3d vec2{vecA.x + rx, vecA.y + ry, vecA.z + rz}; + const vector3d vec4{vecB.x + rx, vecB.y + ry, vecB.z + rz}; + + if (i > 0) { + const int alpha = slot.alphaB - j * 10; + + if (alpha > 0) { + if (slot.alphaT == 0) { + this->RenderTeiRect(&rpCnt, alpha, vec2, vec4, vec3, vec1, wtm, 0, 0, 1, 255, 200, 150 - (5 - j) * 30, 0.0f, 1.0f, 0.0f, 1.0f, 0); + } else if (slot.alphaT == 1) { + this->RenderTeiRect(&rpCnt, alpha, vec2, vec4, vec3, vec1, wtm, 0, 0, 1, 120 - (5 - j) * 22, 120 - (5 - j) * 22, 255, 0.0f, 1.0f, 0.0f, 1.0f, 0); + } else if (slot.alphaT == 2) { + this->RenderTeiRect(&rpCnt, alpha, vec2, vec4, vec3, vec1, wtm, 0, 0, 1, 255, 200, 150 - (3 - j) * 50, 0.0f, 1.0f, 0.0f, 1.0f, 0); + } else if (slot.alphaT >= 3) { + const unsigned char grey = static_cast(255 - (5 - j) * 30); + this->RenderTeiRect(&rpCnt, alpha, vec2, vec4, vec3, vec1, wtm, 0, 0, 1, grey, grey, grey, 0.0f, 1.0f, 0.0f, 1.0f, 0); + } + } + } + + vec1 = vec2; + vec3 = vec4; + } + + if (slot.alphaT >= 3) { + for (int i = 0; i <= 3; ++i) { + const float radius = slot.maxHeight * 4.0f; + const float tx = radius * g_cosTable[i * 120]; + const float ry = radius * g_sinTable[i * 120] - 5.0f; + const float rx = tx * g_cosTable[angle]; + const float rz = tx * g_sinTable[angle]; + const vector3d vec2{vecA.x + rx, vecA.y + ry, vecA.z + rz}; + const vector3d vec4{vecB.x + rx, vecB.y + ry, vecB.z + rz}; + + if (i > 0) { + const int alpha = static_cast(static_cast(slot.alphaB - j * 10) * 0.5f); + + if (alpha > 0 && slot.alphaT == 3) { + this->RenderTeiRect(&rpCnt, alpha, vec2, vec4, vec3, vec1, wtm, 0, 0, 1, 0, 0, 255, 0.0f, 1.0f, 0.0f, 1.0f, 0); + } + } + + vec1 = vec2; + vec3 = vec4; + } + } + } + } +} + +// OFFSET: 0x00BDBC50 +// FUNCTION: fn_19897 +void CEffectPrim::RenderHitLine(matrix& wtm) { + vector3d vec1{}; + vector3d vec3{}; + int rpCnt = 0; + + for (int ec = 0; ec < 4; ++ec) { + const EffectPrimitiveSlot& slot = this->state.slots[ec]; + + if (slot.life != 1 || slot.alphaB <= 0 || slot.process <= 0) { + continue; + } + + for (int j = 0; j < 20; ++j) { + float speed = 0.0f; + float radius = 1.0f; + + for (int i = 0; i < slot.flag1[j]; ++i) { + speed += slot.distance * 2.0f * radius; + radius *= 0.7f; + } + + if (slot.height[j] > 0.0f) { + speed += slot.distance * radius * (slot.height[j] / 90.0f); + } + + radius = 1.0f; + + for (int i = 0; i < slot.flag1[j]; ++i) { + radius *= 0.7f; + } + + vector3d vecA{ + speed * g_cosTable[slot.riseAngle], -slot.distance * g_sinTable[static_cast(slot.height[j])] * 1.5f * radius, + speed * g_sinTable[slot.riseAngle] + }; + + speed = 0.0f; + radius = 1.0f; + + for (int i = 0; i < slot.flag1[j + 1]; ++i) { + speed += slot.distance * 2.0f * radius; + radius *= 0.7f; + } + + if (slot.height[j + 1] > 0.0f) { + speed += slot.distance * radius * (slot.height[j + 1] / 90.0f); + } + + radius = 1.0f; + + for (int i = 0; i < slot.flag1[j + 1]; ++i) { + radius *= 0.7f; + } + + vector3d vecB{ + speed * g_cosTable[slot.riseAngle], -slot.distance * g_sinTable[static_cast(slot.height[j + 1])] * 1.5f * radius, + speed * g_sinTable[slot.riseAngle] + }; + + std::int16_t angle; + Get_Angle(vecA.x - vecB.x, vecA.z - vecB.z, &angle); + vecA.x += slot.vecBNow.x; + vecA.y += slot.vecBNow.y; + vecA.z += slot.vecBNow.z; + vecB.x += slot.vecBNow.x; + vecB.y += slot.vecBNow.y; + vecB.z += slot.vecBNow.z; + angle = static_cast((angle + 90) % 360); + + for (int i = 0; i <= 3; ++i) { + const float tx = slot.maxHeight * g_cosTable[i * 120]; + const float ry = slot.maxHeight * g_sinTable[i * 120]; + const float rx = tx * g_cosTable[angle]; + const float rz = tx * g_sinTable[angle]; + const vector3d vec2{vecA.x + rx, vecA.y + ry, vecA.z + rz}; + const vector3d vec4{vecB.x + rx, vecB.y + ry, vecB.z + rz}; + + if (i > 0) { + const int alpha = slot.alphaB - j * 5; + + if (alpha > 0) { + if (slot.alphaT == 2) { + const unsigned char shade = static_cast(200 - (20 - j) * 7); + this->RenderTeiRect(&rpCnt, alpha, vec1, vec2, vec4, vec3, wtm, 0, 0, 1, 255, shade, shade, 0.0f, 1.0f, 0.0f, 1.0f, 0); + } else if (slot.alphaT == 8) { + const unsigned char shade = static_cast(150 - (20 - j) * 7); + this->RenderTeiRect(&rpCnt, alpha, vec1, vec2, vec4, vec3, wtm, 0, 0, 1, shade, shade, 255, 0.0f, 1.0f, 0.0f, 1.0f, 0); + } else { + this->RenderTeiRect(&rpCnt, alpha, vec1, vec2, vec4, vec3, wtm, 0, 0, 1, 255, 200, 150 - (20 - j) * 7, 0.0f, 1.0f, 0.0f, 1.0f, 0); + } + } + } + + vec1 = vec2; + vec3 = vec4; + } + } + } +} + +// OFFSET: 0x00BDD980 +// FUNCTION: fn_19902 +void CEffectPrim::RenderMagnum2(matrix& wtm) { + int rpCnt = 0; + + for (int ec = 0; ec < 4; ++ec) { + EffectPrimitiveSlot& slot = this->state.slots[ec]; + + if (rpCnt >= 256 || slot.life != 1) { + continue; + } + + const int step = slot.fullDisplayAngle / 20; + int order = 0; + + for (int count = 0; count <= slot.fullDisplayAngle; count += step) { + int angle = slot.rotStart + count; + + if (angle >= 360) { + angle -= 360; + } + + if (slot.fullDisplayAngle == 360 && order == 20) { + angle = slot.rotStart; + } + + const float cs1 = g_cosTable[angle]; + const float sn1 = g_sinTable[angle]; + slot.vecBNow.x = cs1 * slot.distance; + slot.vecBNow.y = -3.0f; + slot.vecBNow.z = sn1 * slot.distance; + + const float rx = g_cosTable[slot.riseAngle] * slot.maxHeight; + const float ry = g_sinTable[slot.riseAngle] * slot.maxHeight; + slot.vecTNow.x = cs1 * rx + slot.vecBNow.x; + slot.vecTNow.y = -(ry + 3.0f); + slot.vecTNow.z = sn1 * rx + slot.vecBNow.z; + + if (order > 0 && slot.alphaB > 0) { + this->RenderTeiRect(&rpCnt, order - 1, slot.alphaB, slot.alphaB, slot.vecBPre, slot.vecBNow, slot.vecTNow, slot.vecTPre, wtm, 0); + } + + ++order; + + if (order >= 21) { + order = 20; + } + + slot.vecBPre = slot.vecBNow; + slot.vecTPre = slot.vecTNow; + } + } +} + +// OFFSET: 0x00BDE720 +// FUNCTION: fn_19905 +void CEffectPrim::RenderPeongUp(matrix& wtm) { + int rpCnt = 0; + + for (int ec = 0; ec < 4; ++ec) { + const EffectPrimitiveSlot& slot = this->state.slots[ec]; + + if (slot.life != 1) { + continue; + } + + const float rx = slot.distance; + vector3d vec1{g_cosTable[45] * rx, 0.0f, g_sinTable[45] * rx}; + vector3d vec2{g_cosTable[135] * rx, 0.0f, g_sinTable[135] * rx}; + vector3d vec3{g_cosTable[225] * rx, 0.0f, g_sinTable[225] * rx}; + vector3d vec4{g_cosTable[315] * rx, 0.0f, g_sinTable[315] * rx}; + this->Tei_TowardScreen(vec1, vec2, vec3, vec4, this->state.slots[0].alphaT, this->state.slots[1].alphaT); + + const vector3d& base = slot.vecBPre; + vec1 = {vec1.x + base.x, vec1.y + base.y, vec1.z + base.z}; + vec2 = {vec2.x + base.x, vec2.y + base.y, vec2.z + base.z}; + vec3 = {vec3.x + base.x, vec3.y + base.y, vec3.z + base.z}; + vec4 = {vec4.x + base.x, vec4.y + base.y, vec4.z + base.z}; + + if (vec1.y <= 0.0f) { + if (slot.flag1[0] == 2) { + this->RenderTeiRect(&rpCnt, slot.alphaB, vec1, vec2, vec3, vec4, wtm, 0, 0, 0, 105, 105, 225, 0.0f, 1.0f, 0.0f, 1.0f, 0); + } else if (slot.flag1[0] == 3) { + this->RenderTeiRect(&rpCnt, slot.alphaB, vec1, vec2, vec3, vec4, wtm, 0, 0, 0, 55, 55, 55, 0.0f, 1.0f, 0.0f, 1.0f, 0); + } else { + this->RenderTeiRect(&rpCnt, slot.alphaB, vec1, vec2, vec3, vec4, wtm, 0, 0, 0, 255, 255, 255, 0.0f, 1.0f, 0.0f, 1.0f, 0); + } + } + } +} + +// OFFSET: 0x00BDF0A0 +// FUNCTION: fn_19908 +void CEffectPrim::RenderRainbow(matrix& wtm) { + int rpCnt = 0; + + for (int ec = 0; ec < 4; ++ec) { + const EffectPrimitiveSlot& slot = this->state.slots[ec]; + + if (slot.life != 1 || slot.alphaB <= 0) { + continue; + } + + const int step = slot.fullDisplayAngle / 20; + + for (int rcolor = 0; rcolor < 7; ++rcolor) { + int order = 0; + const float inner = static_cast(1.0 - rcolor * 0.05f); + const float outer = static_cast(1.0 - (rcolor + 1) * 0.05f); + + for (int count = 0; count <= slot.fullDisplayAngle; count += step) { + int angle = slot.rotStart + count; + + if (angle >= 360) { + angle -= 360; + } + + const float cs = g_cosTable[slot.riseAngle]; + const float sn = g_sinTable[slot.riseAngle]; + const float x1 = g_cosTable[angle] * slot.distance; + const float y1 = g_sinTable[angle] * slot.distance; + const vector3d vec1{cs * (x1 * inner), y1 * inner * 2.0f, sn * (x1 * inner)}; + const vector3d vec4{cs * (x1 * outer), y1 * outer * 2.0f, sn * (x1 * outer)}; + + int next = angle + step; + + if (next >= 360) { + next -= 360; + } + + const float x2 = g_cosTable[next] * slot.distance; + const float y2 = g_sinTable[next] * slot.distance; + const vector3d vec2{cs * (x2 * inner), y2 * inner * 2.0f, sn * (x2 * inner)}; + const vector3d vec3{cs * (x2 * outer), y2 * outer * 2.0f, sn * (x2 * outer)}; + + unsigned char red; + unsigned char green; + unsigned char blue; + + switch (rcolor) { + case 0: + red = 255; + green = 0; + blue = 0; + break; + case 1: + red = 255; + green = 126; + blue = 0; + break; + case 2: + red = 255; + green = 255; + blue = 0; + break; + case 3: + red = 0; + green = 255; + blue = 0; + break; + case 4: + red = 0; + green = 0; + blue = 255; + break; + case 5: + red = 115; + green = 50; + blue = 200; + break; + case 6: + red = 255; + green = 0; + blue = 255; + break; + } + + this->RenderTeiRect(&rpCnt, order, slot.alphaB, slot.alphaB, vec2, vec3, vec4, vec1, wtm, 0, red, green, blue); + + ++order; + + if (order >= 21) { + order = 20; + } + } + } + } +} + +// OFFSET: 0x00BDF440 +// FUNCTION: fn_19909 +void CEffectPrim::RenderRectUp2(matrix& wtm) { + int rpCnt = 0; + + for (int ec = 0; ec < 2; ++ec) { + EffectPrimitiveSlot& slot = this->state.slots[ec]; + + if (slot.life != 1 || slot.alphaB <= 0) { + continue; + } + + const bool distant = 10.0f <= slot.distance; + const unsigned char r = distant ? 100 : 200; + const unsigned char g = distant ? 100 : 250; + const unsigned char b = distant ? 250 : 200; + + slot.vecBPre = {slot.height[0], -1.0f, slot.height[1]}; + slot.vecBNow = {slot.height[0], -1.0f, -slot.height[1]}; + slot.vecTNow = {-slot.height[0], -1.0f, -slot.height[1]}; + slot.vecTPre = {-slot.height[0], -1.0f, slot.height[1]}; + + const float y = -1.0f - slot.height[2]; + const vector3d vec1{slot.vecBPre.x, y, slot.vecBPre.z}; + const vector3d vec2{slot.vecBNow.x, y, slot.vecBNow.z}; + const vector3d vec3{slot.vecTPre.x, y, slot.vecTPre.z}; + const vector3d vec4{slot.vecTNow.x, y, slot.vecTNow.z}; + + this->RenderTeiRect(&rpCnt, slot.alphaB, slot.vecBPre, slot.vecBNow, vec2, vec1, wtm, 0, 0, 0, r, g, b, 0.0f, 1.0f, 0.0f, 1.0f, 0); + this->RenderTeiRect(&rpCnt, slot.alphaB, slot.vecBNow, slot.vecTNow, vec4, vec2, wtm, 0, 0, 0, r, g, b, 0.0f, 1.0f, 0.0f, 1.0f, 0); + this->RenderTeiRect(&rpCnt, slot.alphaB, slot.vecTNow, slot.vecTPre, vec3, vec4, wtm, 0, 0, 0, r, g, b, 0.0f, 1.0f, 0.0f, 1.0f, 0); + this->RenderTeiRect(&rpCnt, slot.alphaB, slot.vecTPre, slot.vecBPre, vec1, vec3, wtm, 0, 0, 0, r, g, b, 0.0f, 1.0f, 0.0f, 1.0f, 0); + } + + for (int ec = 2; ec < 4; ++ec) { + EffectPrimitiveSlot& slot = this->state.slots[ec]; + float left = 0.0f; + + if (slot.life != 1 || slot.alphaB <= 0) { + continue; + } + + const bool distant = 10.0f <= slot.distance; + const unsigned char r = distant ? 50 : 150; + const unsigned char g = distant ? 50 : 250; + const unsigned char b = distant ? 250 : 150; + const float w = slot.height[0]; + const float h = slot.height[1]; + const float dist = slot.distance; + + slot.vecBPre = {w, -1.0f, h}; + slot.vecBNow = {w, -1.0f, -h}; + slot.vecTNow = {-w, -1.0f, -h}; + slot.vecTPre = {-w, -1.0f, h}; + + if (dist < w * 2.0f) { + slot.vecBPre.z = h - dist; + slot.vecBNow.z = slot.vecBPre.z - slot.height[3]; + + if (slot.vecBNow.z < -h) { + left = -h - slot.vecBNow.z; + slot.vecBNow.z = -h; + slot.vecTNow.x = slot.vecBNow.x - left; + } + } else if (dist < w * 4.0f) { + slot.vecBNow.x = w - (dist - w * 2.0f); + slot.vecTNow.x = slot.vecBNow.x - slot.height[3]; + + if (slot.vecTNow.x < -w) { + left = -w - slot.vecTNow.x; + slot.vecTNow.x = -w; + slot.vecTPre.z = slot.vecTNow.z + left; + } + } else if (dist < w * 6.0f) { + slot.vecTNow.z = dist - w * 4.0f - h; + slot.vecTPre.z = slot.vecTNow.z + slot.height[3]; + + if (slot.vecTPre.z > h) { + left = slot.vecTPre.z - h; + slot.vecTPre.z = h; + slot.vecBPre.x = slot.vecTPre.x + left; + } + } else { + slot.vecTPre.x = dist - w * 6.0f - w; + slot.vecBPre.x = slot.vecTPre.x + slot.height[3]; + + if (slot.vecBPre.x > w) { + left = slot.vecBPre.x - w; + slot.vecBPre.x = w; + slot.vecBNow.z = slot.vecBPre.z - left; + } + } + + const float y = -1.0f - slot.height[2]; + const vector3d vec1{slot.vecBPre.x, y, slot.vecBPre.z}; + const vector3d vec2{slot.vecBNow.x, y, slot.vecBNow.z}; + const vector3d vec3{slot.vecTPre.x, y, slot.vecTPre.z}; + const vector3d vec4{slot.vecTNow.x, y, slot.vecTNow.z}; + + if (dist < w * 2.0f) { + this->RenderTeiRect(&rpCnt, slot.alphaB, slot.vecBPre, slot.vecBNow, vec2, vec1, wtm, 0, 0, 0, r, g, b, 0.0f, 1.0f, 0.0f, 1.0f, 0); + + if (left > 0.0f) { + this->RenderTeiRect(&rpCnt, slot.alphaB, slot.vecBNow, slot.vecTNow, vec4, vec2, wtm, 0, 0, 0, r, g, b, 0.0f, 1.0f, 0.0f, 1.0f, 0); + } + } else if (dist < w * 4.0f) { + this->RenderTeiRect(&rpCnt, slot.alphaB, slot.vecBNow, slot.vecTNow, vec4, vec2, wtm, 0, 0, 0, r, g, b, 0.0f, 1.0f, 0.0f, 1.0f, 0); + + if (left > 0.0f) { + this->RenderTeiRect(&rpCnt, slot.alphaB, slot.vecTNow, slot.vecTPre, vec3, vec4, wtm, 0, 0, 0, r, g, b, 0.0f, 1.0f, 0.0f, 1.0f, 0); + } + } else if (dist < w * 6.0f) { + this->RenderTeiRect(&rpCnt, slot.alphaB, slot.vecTNow, slot.vecTPre, vec3, vec4, wtm, 0, 0, 0, r, g, b, 0.0f, 1.0f, 0.0f, 1.0f, 0); + + if (left > 0.0f) { + this->RenderTeiRect(&rpCnt, slot.alphaB, slot.vecTPre, slot.vecBPre, vec1, vec3, wtm, 0, 0, 0, r, g, b, 0.0f, 1.0f, 0.0f, 1.0f, 0); + } + } else { + this->RenderTeiRect(&rpCnt, slot.alphaB, slot.vecTPre, slot.vecBPre, vec1, vec3, wtm, 0, 0, 0, r, g, b, 0.0f, 1.0f, 0.0f, 1.0f, 0); + + if (left > 0.0f) { + this->RenderTeiRect(&rpCnt, slot.alphaB, slot.vecBPre, slot.vecBNow, vec2, vec1, wtm, 0, 0, 0, r, g, b, 0.0f, 1.0f, 0.0f, 1.0f, 0); + } + } + } +} + +// OFFSET: 0x00BE0010 +// FUNCTION: fn_19910 +void CEffectPrim::RenderRectUp(matrix& wtm) { + int rpCnt = 0; + unsigned char r; + unsigned char g; + unsigned char b; + short p; + + for (int ec = 0; ec < 4; ++ec) { + EffectPrimitiveSlot& slot = this->state.slots[ec]; + + if (slot.life != 1 || slot.alphaB <= 0) { + continue; + } + + const float cs1 = g_cosTable[slot.rotStart]; + const float sn1 = g_sinTable[slot.rotStart]; + float rx = slot.height[0]; + float rz = slot.height[1]; + slot.vecBPre = {cs1 * rx - sn1 * rz, -1.0f, sn1 * rx + cs1 * rz}; + rz = -slot.height[1]; + slot.vecBNow = {cs1 * rx - sn1 * rz, -1.0f, sn1 * rx + cs1 * rz}; + rx = -slot.height[0]; + slot.vecTNow = {cs1 * rx - sn1 * rz, -1.0f, sn1 * rx + cs1 * rz}; + rz = slot.height[1]; + slot.vecTPre = {cs1 * rx - sn1 * rz, -1.0f, sn1 * rx + cs1 * rz}; + + const float y = -1.0f - slot.height[2]; + const vector3d vec1{slot.vecBPre.x, y, slot.vecBPre.z}; + const vector3d vec2{slot.vecBNow.x, y, slot.vecBNow.z}; + const vector3d vec3{slot.vecTPre.x, y, slot.vecTPre.z}; + const vector3d vec4{slot.vecTNow.x, y, slot.vecTNow.z}; + + if (slot.height[3] == 0.0f) { + r = 255; + g = 255; + b = 255; + p = 0; + } else if (slot.height[3] == 1.0f) { + r = 235; + g = 255; + b = 235; + p = 1; + } else if (slot.height[3] == 2.0f) { + r = 80; + g = 80; + b = 80; + p = 1; + } else if (slot.height[3] == 4.0f) { + r = 255; + g = 255; + b = static_cast(static_cast(slot.height[4] + 0.0f + slot.height[5])); + p = 1; + } + + this->RenderTeiRect(&rpCnt, slot.alphaB, slot.vecBPre, slot.vecBNow, vec2, vec1, wtm, p, 0, 0, r, g, b, 0.0f, 1.0f, 0.0f, 1.0f, 0); + this->RenderTeiRect(&rpCnt, slot.alphaB, slot.vecBNow, slot.vecTNow, vec4, vec2, wtm, p, 0, 0, r, g, b, 0.0f, 1.0f, 0.0f, 1.0f, 0); + this->RenderTeiRect(&rpCnt, slot.alphaB, slot.vecTNow, slot.vecTPre, vec3, vec4, wtm, p, 0, 0, r, g, b, 0.0f, 1.0f, 0.0f, 1.0f, 0); + this->RenderTeiRect(&rpCnt, slot.alphaB, slot.vecTPre, slot.vecBPre, vec1, vec3, wtm, p, 0, 0, r, g, b, 0.0f, 1.0f, 0.0f, 1.0f, 0); + + if (slot.height[3] == 2.0f) { + int alpha = slot.alphaB * 2; + + if (alpha > 255) { + alpha = 255; + } + + this->RenderTeiRect(&rpCnt, static_cast(alpha), slot.vecBPre, slot.vecTNow, vec4, vec1, wtm, p, 0, 0, r, g, b, 0.0f, 1.0f, 0.0f, 1.0f, 0); + this->RenderTeiRect(&rpCnt, static_cast(alpha), slot.vecBNow, slot.vecTPre, vec3, vec2, wtm, p, 0, 0, r, g, b, 0.0f, 1.0f, 0.0f, 1.0f, 0); + } + } +} + +// OFFSET: 0x00BE0680 +// FUNCTION: fn_19911 +void CEffectPrim::RenderSMA2(matrix& wtm) { + vector3d vec1{}; + vector3d vec3{}; + int rpCnt = 0; + + for (int ec = 0; ec < 4; ++ec) { + const EffectPrimitiveSlot& slot = this->state.slots[ec]; + + if (slot.life != 1) { + continue; + } + + const int step = slot.fullDisplayAngle / 20; + int order = 0; + + for (int count = 0; count <= slot.fullDisplayAngle; count += step) { + int angle = (slot.rotStart + count) % 360; + + if (slot.fullDisplayAngle == 360 && order == 20) { + angle = slot.rotStart; + } + + const float cs1 = g_cosTable[angle]; + const float sn1 = g_sinTable[angle]; + const float rx = g_cosTable[slot.riseAngle] * slot.height[order]; + const float ry = g_sinTable[slot.riseAngle] * slot.height[order]; + const vector3d& delta = this->state.offset; + const vector3d vec2{cs1 * slot.distance + delta.x, delta.y + 0.0f, sn1 * slot.distance + delta.z}; + const vector3d vec4{cs1 * rx + cs1 * slot.distance + delta.x, delta.y - ry, sn1 * rx + sn1 * slot.distance + delta.z}; + + if (order > 0) { + const float tx1 = static_cast(order - 1) / 21.0f; + const float tx2 = static_cast(order) / 21.0f; + + if (slot.alphaT == 99) { + this->RenderTeiRect(&rpCnt, slot.alphaB, vec1, vec2, vec4, vec3, wtm, 99, 0, 1, 70, 70, 70, 0.0f, 1.0f, tx1, tx2, 0); + } else { + this->RenderTeiRect(&rpCnt, slot.alphaB, vec1, vec2, vec4, vec3, wtm, 0, 0, 1, 90, 90, 255, 0.0f, 1.0f, tx1, tx2, 0); + } + } + + ++order; + + if (order >= 21) { + order = 20; + } + + vec1 = vec2; + vec3 = vec4; + } + } +} + +// OFFSET: 0x00BE1150 +// FUNCTION: fn_19915 +void CEffectPrim::RenderSaintWing(matrix& wtm) { + int rpCnt = 0; + + for (int ec = 0; ec < 4; ++ec) { + EffectPrimitiveSlot& slot = this->state.slots[ec]; + + if (slot.life != 1) { + continue; + } + + for (int i = 0; i < 10; ++i) { + const float rx = slot.distance; + int angle = slot.rotStart - 65; + + if (angle >= 360) { + angle -= 360; + } + + if (angle < 0) { + angle += 360; + } + + const vector3d vec1{rx * g_cosTable[angle], slot.height[0], rx * g_sinTable[angle]}; + int angle2 = slot.rotStart + 65; + + if (angle2 >= 360) { + angle2 -= 360; + } + + if (angle2 < 0) { + angle2 += 360; + } + + const vector3d vec4{rx * g_cosTable[angle2], slot.height[0], rx * g_sinTable[angle2]}; + const float rz = i < 5 ? slot.maxHeight : slot.maxHeight + (0.5f * g_sinTable[slot.riseAngle] + 0.5f); + + angle = slot.rotStart; + + if (angle >= 360) { + angle -= 360; + } + + if (angle < 0) { + angle += 360; + } + + const float sn1 = g_sinTable[angle]; + const float cs1 = g_cosTable[angle]; + const int add = i < 5 ? (i - i % 5) * 9 + i % 5 * 3 + slot.fullDisplayAngle : (i - i % 5) * 9 + i % 5 * 3; + const float lx = g_cosTable[add] * rz; + const float ly = g_sinTable[add] * rz; + + slot.vecBNow.z = sn1 * lx; + slot.vecBNow.x = cs1 * lx; + const vector3d vec2{vec1.x + slot.vecBNow.x, vec1.y - ly, vec1.z + slot.vecBNow.z}; + const vector3d vec3{vec4.x + slot.vecBNow.x, vec4.y - ly, vec4.z + slot.vecBNow.z}; + + if (ec == 1) { + if (i % 5 < 4) { + int alpha = slot.alphaB; + + for (int b = 3; b >= i % 5; --b) { + alpha = static_cast(static_cast(alpha) * 0.7f); + } + + this->RenderTeiRect(&rpCnt, static_cast(alpha), vec1, vec2, vec3, vec4, wtm, 0, 0, 0, 105, 105, 255, 0.0f, 1.0f, 0.0f, 1.0f, 0); + } else { + this->RenderTeiRect(&rpCnt, slot.alphaB, vec1, vec2, vec3, vec4, wtm, 1, 0, 0, 205, 205, 255, 0.0f, 1.0f, 0.0f, 1.0f, 0); + } + } else if (ec == 0) { + if (i % 5 < 4) { + int alpha = slot.alphaB; + + for (int b = 3; b >= i % 5; --b) { + alpha = static_cast(static_cast(alpha) * 0.7f); + } + + this->RenderTeiRect(&rpCnt, static_cast(alpha), vec4, vec3, vec2, vec1, wtm, 0, 0, 0, 105, 105, 255, 0.0f, 1.0f, 0.0f, 1.0f, 0); + } else { + this->RenderTeiRect(&rpCnt, slot.alphaB, vec4, vec3, vec2, vec1, wtm, 1, 0, 0, 205, 205, 255, 0.0f, 1.0f, 0.0f, 1.0f, 0); + } + } + } + } +} + +// OFFSET: 0x00BE1820 +// FUNCTION: fn_19916 +void CEffectPrim::RenderSlash1(matrix& wtm) { + int rpCnt = 0; + + for (int ec = 0; ec < 4; ++ec) { + const EffectPrimitiveSlot& slot = this->state.slots[ec]; + + if (slot.life != 1 || slot.alphaB <= 0) { + continue; + } + + for (int i = 0; i <= 2; ++i) { + int angle = slot.rotStart - 1 + i; + + if (angle < 0) { + angle += 360; + } else if (angle >= 360) { + angle -= 360; + } + + const float cs1 = g_cosTable[angle]; + const float sn1 = g_sinTable[angle]; + float rx = slot.height[0]; + const vector3d vec1{cs1 * rx, -0.0f, sn1 * rx}; + const vector3d vec2{vec1.x, i == 1 ? vec1.y - slot.maxHeight * 0.2f : vec1.y - slot.maxHeight * 0.1f, vec1.z}; + rx = slot.height[0] + slot.distance; + const vector3d vec3{cs1 * rx, -0.0f, sn1 * rx}; + const vector3d vec4{vec3.x, i == 1 ? vec3.y - slot.maxHeight : vec3.y - slot.maxHeight * 0.4f, vec3.z}; + const int alpha = i == 1 ? slot.alphaB : slot.alphaB / 3; + + this->RenderTeiRect(&rpCnt, static_cast(alpha), vec1, vec3, vec4, vec2, wtm, 0, 0, 0, 255, 255, 255, 0.0f, 1.0f, 0.0f, 1.0f, 0); + } + } +} + +// OFFSET: 0x00BE1D70 +// FUNCTION: fn_19918 +void CEffectPrim::RenderSoulLink(matrix& wtm) { + int rpCnt = 0; + + for (int ec = 0; ec < 4; ++ec) { + const EffectPrimitiveSlot& slot = this->state.slots[ec]; + + if (slot.life != 1) { + continue; + } + + const float rx = slot.distance; + vector3d vec1{g_cosTable[45] * rx, 0.0f, g_sinTable[45] * rx}; + vector3d vec2{g_cosTable[135] * rx, 0.0f, g_sinTable[135] * rx}; + vector3d vec3{g_cosTable[225] * rx, 0.0f, g_sinTable[225] * rx}; + vector3d vec4{g_cosTable[315] * rx, 0.0f, g_sinTable[315] * rx}; + const std::int16_t rot0 = this->state.slots[0].alphaT; + this->Tei_TowardScreen(vec1, vec2, vec3, vec4, rot0, this->state.slots[1].alphaT); + + const float length = slot.vecBPre.x; + const vector3d vecA{length * g_cosTable[rot0], slot.vecBPre.y, length * g_sinTable[rot0]}; + vec1 = {vec1.x + vecA.x, vec1.y + vecA.y, vec1.z + vecA.z}; + vec2 = {vec2.x + vecA.x, vec2.y + vecA.y, vec2.z + vecA.z}; + vec3 = {vec3.x + vecA.x, vec3.y + vecA.y, vec3.z + vecA.z}; + vec4 = {vec4.x + vecA.x, vec4.y + vecA.y, vec4.z + vecA.z}; + const int alpha = static_cast(slot.height[13]); + + if (vec1.y > 0.0f) { + continue; + } + + if (slot.process < 180) { + CGameMode* gameMode = static_cast(g_modeMgr.GetGameMode()); + CRagEffect* effect = nullptr; + + if (static_cast(g_session.m_aid) == slot.height[10]) { + effect = gameMode->scene->player->LaunchEffect(506, vector3d{0.0f, 0.0f, 0.0f}, 0.0f); + } else if (auto* actor = static_cast(gameMode->scene->GetGameActorByAID(static_cast(slot.height[10])))) { + effect = actor->LaunchEffect(506, vector3d{0.0f, 0.0f, 0.0f}, 0.0f); + } + + if (effect) { + vector3d position = vecA; + effect->SendMsg(nullptr, 14, 0, reinterpret_cast(&position), 0, 0, 0, 0); + } + } + + this->RenderTeiRect(&rpCnt, static_cast(alpha), vec1, vec2, vec3, vec4, wtm, 0, 0, 0, 125, 125, 255, 0.0f, 1.0f, 0.0f, 1.0f, 0); + } +} + +// INLINED +static __forceinline void RenderSoulParticleQuad( + CEffectPrim& prim, int* rpCnt, const EffectPrimitiveSlot& slot, const vector3d* corners, const vector3d& base, float countValue, unsigned char extraShade, matrix& wtm +) { + int count = static_cast(countValue); + + if (count < 0) { + count = 0; + } + + const vector3d vec1{corners[0].x + base.x, corners[0].y + base.y, corners[0].z + base.z}; + const vector3d vec2{corners[1].x + base.x, corners[1].y + base.y, corners[1].z + base.z}; + const vector3d vec3{corners[2].x + base.x, corners[2].y + base.y, corners[2].z + base.z}; + const vector3d vec4{corners[3].x + base.x, corners[3].y + base.y, corners[3].z + base.z}; + + if (vec1.y > 0.0f) { + return; + } + + const short alpha = static_cast(count); + + if (slot.height[15] == 0.0f) { + prim.RenderTeiRect(rpCnt, alpha, vec1, vec2, vec3, vec4, wtm, 0, 0, 0, 80, 80, 255, 0.0f, 1.0f, 0.0f, 1.0f, 0); + } else if (slot.height[15] == 1.0f) { + prim.RenderTeiRect(rpCnt, alpha, vec1, vec2, vec3, vec4, wtm, 0, 0, 0, 255, 200, 200, 0.0f, 1.0f, 0.0f, 1.0f, 0); + } else if (slot.height[15] == 2.0f) { + prim.RenderTeiRect(rpCnt, alpha, vec1, vec2, vec3, vec4, wtm, 0, 0, 0, 255, 160, 160, 0.0f, 1.0f, 0.0f, 1.0f, 0); + } else if (slot.height[15] == 3.0f) { + prim.RenderTeiRect(rpCnt, alpha, vec1, vec2, vec3, vec4, wtm, 0, 0, 0, 255, 120, 120, 0.0f, 1.0f, 0.0f, 1.0f, 0); + } else if (slot.height[15] == 4.0f) { + prim.RenderTeiRect(rpCnt, alpha, vec1, vec2, vec3, vec4, wtm, 0, 0, 0, extraShade, extraShade, 255, 0.0f, 1.0f, 0.0f, 1.0f, 0); + } +} + +// OFFSET: 0x00BE2190 +// FUNCTION: fn_19919 +void CEffectPrim::RenderSoulParticle(matrix& wtm) { + int rpCnt = 0; + + for (int ec = 0; ec < 4; ++ec) { + const EffectPrimitiveSlot& slot = this->state.slots[ec]; + + if (slot.life != 1) { + continue; + } + + const float rx = slot.distance; + vector3d corners[4] = { + {g_cosTable[45] * rx, 0.0f, g_sinTable[45] * rx}, + {g_cosTable[135] * rx, 0.0f, g_sinTable[135] * rx}, + {g_cosTable[225] * rx, 0.0f, g_sinTable[225] * rx}, + {g_cosTable[315] * rx, 0.0f, g_sinTable[315] * rx}, + }; + this->Tei_TowardScreen(corners[0], corners[1], corners[2], corners[3], this->state.slots[0].alphaT, this->state.slots[1].alphaT); + + RenderSoulParticleQuad(*this, &rpCnt, slot, corners, slot.vecBPre, slot.height[12], 40, wtm); + RenderSoulParticleQuad(*this, &rpCnt, slot, corners, slot.vecBNow, slot.height[13], 10, wtm); + RenderSoulParticleQuad(*this, &rpCnt, slot, corners, slot.vecTPre, slot.height[14], 70, wtm); + } +} + +// OFFSET: 0x00BE2B10 +// FUNCTION: fn_19920 +void CEffectPrim::RenderSphereWind(matrix& wtm) { + vector3d vec1{}; + vector3d vec3{}; + int rpCnt = 0; + + for (int ec = 0; ec < 4; ++ec) { + const EffectPrimitiveSlot& slot = this->state.slots[ec]; + + if (slot.life != 1) { + continue; + } + + const int step = slot.fullDisplayAngle / 20; + int order = 0; + + for (int count = 0; count <= slot.fullDisplayAngle; count += step) { + int angle = slot.rotStart + count; + + if (angle >= 360) { + angle -= 360; + } else if (angle < 0) { + angle += 360; + } + + if (slot.fullDisplayAngle == 360 && order == 20) { + angle = slot.rotStart; + } + + const float cs1 = g_cosTable[angle]; + const float sn1 = g_sinTable[angle]; + const vector3d vecM{cs1 * (g_cosTable[slot.riseAngle] * slot.distance), cs1 * (g_sinTable[slot.riseAngle] * slot.distance), sn1 * slot.distance}; + const vector3d vecA{-(slot.maxHeight * g_sinTable[slot.riseAngle]), slot.maxHeight * g_cosTable[slot.riseAngle], 0.0f}; + const vector3d vec2{vecM.x + vecA.x, vecM.y + vecA.y + slot.height[0], vecM.z + vecA.z}; + const vector3d vec4{vecM.x - vecA.x, vecM.y - vecA.y + slot.height[0], vecM.z - vecA.z}; + + if (order > 0) { + this->RenderTeiRect(&rpCnt, order - 1, slot.alphaB, slot.alphaB, vec1, vec2, vec4, vec3, wtm, 0); + } + + ++order; + + if (order >= 21) { + order = 20; + } + + vec1 = vec2; + vec3 = vec4; + } + } +}