Guía: Adaptación RenderLinkObject (Matrices Armaduras +15) de S6 a S3 - Source Mu - Mu Server Files
 

Guía: Adaptación RenderLinkObject (Matrices Armaduras +15) de S6 a S3

Publicado por Dakosmu, Mar 12, 2026, 12:40 AM

Tema anterior - Siguiente tema

0 Miembros y 1 Visitante están viendo este tema.

Dakosmu

Guía: Adaptación RenderLinkObject (Matrices Armaduras +15) de S6 a S3

Hola comunidad, estoy trabajando en una adaptación visual para mi servidor Season 3 (Main 1.04x).

Estoy portando el código de RenderLinkObject (original de fuentes S6) para que las Armaduras +15 tengan los efectos visuales correctos (Magic + Shiny) alineados a los huesos del personaje.

Lo que ya tengo hecho
Ya adapté toda la lógica matemática del archivo original. Tengo las Matrices de Transformación y los ángulos para cada parte del set (Casco, Botas, Guantes, etc.), de modo que el brillo no salga "chueco" o en el piso.

Aquí una parte del código que ya adapté a mi clase ArmorEffect:

// Código adaptado de S6 para S3 // Lógica de Matrices para posicionar el efecto en el hueso correcto switch (Type) { case MODEL_15GRADE_ARMOR_OBJ_ARMLEFT:

Vector(0.f, -90.f, 0.f, Angle);
       
AngleMatrix(Angle, Matrix);
       
// Offsets exactos para que el brillo quede en el hombro
       
Matrix[0][3] = 30.f;
       
Matrix[1][3] = 0.f;
       
Matrix[2][3] = 20.f;
       
break;
   
// ... resto de los casos (Head, Boots, etc) ...
}

El Problema
El código original de S6 usa una función RenderLinkObject con 12 argumentos. En mi Main Season 3, la función equivalente (RenderPartObjectBody o similar) usa 9 argumentos y no pasa el puntero CHARACTER* explícitamente.

Lo que necesito
Necesito ayuda para ubicar el Offset correcto de la función que renderiza las partes del cuerpo en un Main Season 3 (Protocolo KOR/JPN 1.04x).

  • Dato: Mi GetItemColor está en 0x0052870B.
  • Sé que la función que busco llama a GetItemColor internamente.

Si alguien tiene el offset o sabe cómo adaptar el Hook para que tome estas matrices en S3, agradecería mucho la ayuda. Estoy dispuesto a liberar el código completo de la clase ArmorEffect con las matemáticas corregidas una vez funcione.

Código de Carga de Modelos y Lógica de Renderizado

LoadItemModel(MODEL_15GRADE_ARMOR_OBJ_ARMLEFT, "Item\", "class15_armleft"); LoadItemModel(MODEL_15GRADE_ARMOR_OBJ_ARMRIGHT, "Item\", "class15_armright"); LoadItemModel(MODEL_15GRADE_ARMOR_OBJ_BODYLEFT, "Item\", "class15_bodyleft"); LoadItemModel(MODEL_15GRADE_ARMOR_OBJ_BODYRIGHT, "Item\", "class15_bodyright"); LoadItemModel(MODEL_15GRADE_ARMOR_OBJ_BOOTLEFT, "Item\", "class15_bootleft"); LoadItemModel(MODEL_15GRADE_ARMOR_OBJ_BOOTRIGHT, "Item\", "class15_bootright"); LoadItemModel(MODEL_15GRADE_ARMOR_OBJ_HEAD, "Item\", "class15_head"); LoadItemModel(MODEL_15GRADE_ARMOR_OBJ_PANTLEFT, "Item\", "class15_pantleft"); LoadItemModel(MODEL_15GRADE_ARMOR_OBJ_PANTRIGHT, "\Item\", "class15_pantright");

LoadItemTexture(MODEL_15GRADE_ARMOR_OBJ_ARMLEFT, "Item\"); LoadItemTexture(MODEL_15GRADE_ARMOR_OBJ_ARMRIGHT, "Item\"); LoadItemTexture(MODEL_15GRADE_ARMOR_OBJ_BODYLEFT, "Item\"); LoadItemTexture(MODEL_15GRADE_ARMOR_OBJ_BODYRIGHT, "Item\"); LoadItemTexture(MODEL_15GRADE_ARMOR_OBJ_BOOTLEFT, "Item\"); LoadItemTexture(MODEL_15GRADE_ARMOR_OBJ_BOOTRIGHT, "Item\"); LoadItemTexture(MODEL_15GRADE_ARMOR_OBJ_HEAD, "Item\"); LoadItemTexture(MODEL_15GRADE_ARMOR_OBJ_PANTLEFT, "Item\"); LoadItemTexture(MODEL_15GRADE_ARMOR_OBJ_PANTRIGHT, "Item\");

// ============================================================ // SECCIÓN 1: Verificación de tipo de armadura en RenderLinkObject // ============================================================ void RenderLinkObject(float x, float y, float z, CHARACTER* c, PART_t* f, int Type, int Level, int Option1, bool Link, bool Translate, int RenderType, bool bRightHandItem) { // ... código anterior omitido ...

// Configuración de matriz de transformación para piezas de armadura grado 15
if (Type == MODEL_15GRADE_ARMOR_OBJ_ARMLEFT || Type == MODEL_15GRADE_ARMOR_OBJ_ARMRIGHT ||
    Type == MODEL_15GRADE_ARMOR_OBJ_BODYLEFT || Type == MODEL_15GRADE_ARMOR_OBJ_BODYRIGHT ||
    Type == MODEL_15GRADE_ARMOR_OBJ_BOOTLEFT || Type == MODEL_15GRADE_ARMOR_OBJ_BOOTRIGHT ||
    Type == MODEL_15GRADE_ARMOR_OBJ_HEAD || Type == MODEL_15GRADE_ARMOR_OBJ_PANTLEFT ||
    Type == MODEL_15GRADE_ARMOR_OBJ_PANTRIGHT)
{
    switch (Type)
    {
    case MODEL_15GRADE_ARMOR_OBJ_ARMLEFT:
    {
        Vector(0.f, -90.f, 0.f, Angle);
        AngleMatrix(Angle, Matrix);
        Matrix[0][3] = 30.f;
        Matrix[1][3] = 0.f;
        Matrix[2][3] = 20.f;
    }break;
   
    case MODEL_15GRADE_ARMOR_OBJ_ARMRIGHT:
    {
        Vector(0.f, -90.f, 0.f, Angle);
        AngleMatrix(Angle, Matrix);
        Matrix[0][3] = 30.f;
        Matrix[1][3] = 0.f;
        Matrix[2][3] = -20.f;
    }break;
   
    case MODEL_15GRADE_ARMOR_OBJ_BODYLEFT:
    {
        Vector(0.f, -90.f, 0.f, Angle);
        AngleMatrix(Angle, Matrix);
        Matrix[0][3] = 5.f;
        Matrix[1][3] = -20.f;
        Matrix[2][3] = 0.f;
    }break;
   
    case MODEL_15GRADE_ARMOR_OBJ_BODYRIGHT:
    {
        Vector(0.f, -90.f, 0.f, Angle);
        AngleMatrix(Angle, Matrix);
        Matrix[0][3] = 5.f;
        Matrix[1][3] = -20.f;
        Matrix[2][3] = 0.f;
    }break;
   
    case MODEL_15GRADE_ARMOR_OBJ_BOOTLEFT:
    {
        Vector(0.f, 90.f, 180.f, Angle);
        AngleMatrix(Angle, Matrix);
        Matrix[0][3] = 20.f;
        Matrix[1][3] = 15.f;
        Matrix[2][3] = -10.f;
    }break;
   
    case MODEL_15GRADE_ARMOR_OBJ_BOOTRIGHT:
    {
        Vector(0.f, 90.f, 180.f, Angle);
        AngleMatrix(Angle, Matrix);
        Matrix[0][3] = 20.f;
        Matrix[1][3] = 15.f;
        Matrix[2][3] = 10.f;
    }break;
   
    case MODEL_15GRADE_ARMOR_OBJ_HEAD:
    {
        Vector(180.f, -90.f, 0.f, Angle); // y, x, z
        AngleMatrix(Angle, Matrix);
        Matrix[0][3] = 28.f; // y
        Matrix[1][3] = 20.f; // x
        Matrix[2][3] = 0.f;
    }break;
   
    case MODEL_15GRADE_ARMOR_OBJ_PANTLEFT:
    {
        Vector(0.f, 90.f, 180.f, Angle);
        AngleMatrix(Angle, Matrix);
        Matrix[0][3] = 25.f;
        Matrix[1][3] = 5.f;
        Matrix[2][3] = -5.f;
    }break;
   
    case MODEL_15GRADE_ARMOR_OBJ_PANTRIGHT:
    {
        Vector(0.f, 90.f, 180.f, Angle);
        AngleMatrix(Angle, Matrix);
        Matrix[0][3] = 25.f;
        Matrix[1][3] = 5.f;
        Matrix[2][3] = 5.f;
    }break;
    }
}

// ... resto del código omitido ...
}

// ============================================================ // SECCIÓN 2: Renderizado del cuerpo en RenderPartObjectBody // ============================================================ void RenderPartObjectBody(BMD* b, OBJECT* o, int Type, float Alpha, int RenderType) { // ... código anterior omitido ...

if (o->Type == MODEL_15GRADE_ARMOR_OBJ_ARMLEFT ||
    o->Type == MODEL_15GRADE_ARMOR_OBJ_ARMRIGHT ||
    o->Type == MODEL_15GRADE_ARMOR_OBJ_BODYLEFT ||
    o->Type == MODEL_15GRADE_ARMOR_OBJ_BODYRIGHT ||
    o->Type == MODEL_15GRADE_ARMOR_OBJ_BOOTLEFT ||
    o->Type == MODEL_15GRADE_ARMOR_OBJ_BOOTRIGHT ||
    o->Type == MODEL_15GRADE_ARMOR_OBJ_HEAD ||
    o->Type == MODEL_15GRADE_ARMOR_OBJ_PANTLEFT ||
    o->Type == MODEL_15GRADE_ARMOR_OBJ_PANTRIGHT)
{
    float fLight, texCoordU;

    // Primer pase: Renderizado con brillo variable
    fLight = 0.8f - absf(sinf(WorldTime * 0.0018f) * 0.5f);
    b->RenderMesh(0, RENDER_TEXTURE | RENDER_BRIGHT, o->Alpha, 0, fLight - 0.1f, o->BlendMeshTexCoordU, o->BlendMeshTexCoordV);
   
    // Segundo pase: Efecto de textura animada
    texCoordU = absf(sinf(WorldTime * 0.0005f));
    b->RenderMesh(0, RENDER_TEXTURE | RENDER_BRIGHT, o->Alpha, 0, fLight - 0.3f, texCoordU, o->BlendMeshTexCoordV, BITMAP_RGB_MIX);
   
    // Tercer pase: Efecto cromado
    b->RenderMesh(0, RENDER_TEXTURE | RENDER_CHROME4, o->Alpha, 0, o->BlendMeshLight, o->BlendMeshTexCoordU, o->BlendMeshTexCoordV);
}
}

// ============================================================ // SECCIÓN 3: Renderizado de efectos de armadura en NextGradeObjectRender // ============================================================ void NextGradeObjectRender(CHARACTER* c) { // ... código anterior omitido ...

int bornIndex[2]{}; // left, right
int gradeType[2]{}; // left, right
BMD* b = &Models[c->Object.Type];
PART_t* w;
vec3_t vPos, vLight;
float fLight2;
int Level;

// Iterar sobre todas las partes del cuerpo
for (int k = 0; k < MAX_BODYPART; k++)
{
    w = &c->BodyPart[k];
    Level = w->Level;

    if (k == 0) continue; // Saltar primera parte
    if (Level < 15 || w->Type == -1) continue; // Solo grado 15+

    // Asignar índices de huesos y tipos según la parte del cuerpo
    switch (k)
    {
    case 1: // Cabeza
    {
        bornIndex[0] = 20;
        bornIndex[1] = -1;
        gradeType[0] = MODEL_15GRADE_ARMOR_OBJ_HEAD;
        gradeType[1] = -1;
    }break;
   
    case 2: // Cuerpo
    {
        bornIndex[0] = 35;
        bornIndex[1] = 26;
        gradeType[0] = MODEL_15GRADE_ARMOR_OBJ_BODYLEFT;
        gradeType[1] = MODEL_15GRADE_ARMOR_OBJ_BODYRIGHT;
    }break;
   
    case 3: // Pantalones
    {
        bornIndex[0] = 3;
        bornIndex[1] = 10;
        gradeType[0] = MODEL_15GRADE_ARMOR_OBJ_PANTLEFT;
        gradeType[1] = MODEL_15GRADE_ARMOR_OBJ_PANTRIGHT;
    }break;
   
    case 4: // Brazos
    {
        bornIndex[0] = 36;
        bornIndex[1] = 27;
        gradeType[0] = MODEL_15GRADE_ARMOR_OBJ_ARMLEFT;
        gradeType[1] = MODEL_15GRADE_ARMOR_OBJ_ARMRIGHT;
    }break;
   
    case 5: // Botas
    {
        bornIndex[0] = 4;
        bornIndex[1] = 11;
        gradeType[0] = MODEL_15GRADE_ARMOR_OBJ_BOOTLEFT;
        gradeType[1] = MODEL_15GRADE_ARMOR_OBJ_BOOTRIGHT;
    }break;
   
    default:
        bornIndex[0] = -1;
        bornIndex[1] = -1;
        gradeType[0] = -1;
        gradeType[1] = -1;
        break;
    }

    OBJECT* o = &c->Object;

    // Renderizar efectos para cada lado (izquierdo/derecho)
    for (int m = 0; m < 2; m++)
    {
        if (gradeType[m] == -1) continue;

        switch (Level)
        {
        case 15: // Efectos para armadura +15
        {
            // Vincular al hueso correspondiente
            w->LinkBone = bornIndex[m];
           
            // Renderizar objeto vinculado
            RenderLinkObject(0.f, 0.f, 0.f, c, w, gradeType[m], 0, 0, true, true);

            // Obtener posición transformada
            b->TransformByBoneMatrix(vPos, BoneTransform[0], o->Position);

            // Efecto mágico pulsante azul
            fLight2 = absf(sinf(WorldTime * 0.01f));
            Vector(0.2f * fLight2, 0.4f * fLight2, 1.0f * fLight2, vLight);
            CreateSprite(BITMAP_MAGIC, vPos, 0.12f, vLight, o);

            // Efecto brillante azul
            Vector(0.4f, 0.7f, 1.0f, vLight);
            CreateSprite(BITMAP_SHINY + 5, vPos, 0.4f, vLight, o);

            // Efecto de luz pin azul rotado
            Vector(0.1f, 0.3f, 1.0f, vLight);
            CreateSprite(BITMAP_PIN_LIGHT, vPos, 0.6f, vLight, o, 90.0f);
        }break;
        }
    }
}
}
Bon Dia

🡱 🡳
Real Time Web Analytics