Decompile ST0 func_801ABBBC (#1041)

First function of my new effort to make progress in ST0.

There's a fun bug in case 5 where they forgot to increment their prim.

This required the creation of a new variety of Primitive, since there's
strong evidence of an `f32` at offset 0x20. For now it's
draculaPrimitive, but maybe we'll find more uses of it in the future.

I think those are the main highlights. No pressure to merge this one
quickly, I'm expecting progress on ST0 to be slow.
This commit is contained in:
bismurphy 2024-02-06 18:01:05 -05:00 committed by GitHub
parent 6011e02320
commit fc78c026e5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 365 additions and 5 deletions

View File

@ -49,7 +49,7 @@ segments:
- [0x27ACC, .rodata, 2A8DC] # EntitySecretStairs
- [0x27AE0, .rodata, 2B0C8] # EntityStageTitleFadeout
- [0x27B00, .rodata, 2B0C8] # EntityStageTitleCard
- [0x27B18, rodata]
- [0x27B18, .rodata, 2B0C8] # func_801ABBBC
- [0x27B40, .rodata, 2C564] # EntityDracula
- [0x27B7C, rodata]
- [0x27BFC, rodata]

View File

@ -278,10 +278,16 @@ typedef struct {
} ET_GurkhaSword;
typedef struct ET_Dracula {
/* 0x7C */ char pad_7C[0x10];
/* 0x7C */ char pad_7C[4];
/* 0x80 */ struct draculaPrimitive* unk80;
/* 0x84 */ struct draculaPrimitive* unk84;
/* 0x88 */ char pad_88[4];
/* 0x8C */ s16 unk8C;
/* 0x8E */ char pad_8E[0x2];
/* 0x90 */ char pad_90[0x4];
/* 0x90 */ u8 unk90;
/* 0x91 */ char pad91;
/* 0x92 */ u8 unk92;
/* 0x93 */ char pad93;
/* 0x94 */ u8 unk94;
/* 0x95 */ char pad_95[0x3];
/* 0x98 */ s16 unk98;

View File

@ -33,6 +33,7 @@ typedef enum {
PRIM_SPRT,
PRIM_ENV,
PRIM_TILE_ALT = PRIM_TILE | 0x10,
PRIM_LINE_G2_ALT = PRIM_LINE_G2 | 0x10,
PRIM_G4_ALT = PRIM_G4 | 0x10
} PrimitiveType;

View File

@ -103,4 +103,40 @@ typedef struct {
/* 0x2C */ f32 preciseY;
/* 0x30 */ s16 timer;
/* 0x32 */ u16 drawMode;
} PrimLineG2;
} PrimLineG2;
typedef struct {
struct primitive* next;
/* 0x04 */ u8 r0;
/* 0x05 */ u8 g0;
/* 0x06 */ u8 b0;
/* 0x07 */ u8 type;
/* 0x08 */ s16 x0;
/* 0x0A */ s16 y0;
/* 0x0C */ u8 u0;
/* 0x0D */ u8 v0;
/* 0x0E */ u16 clut;
/* 0x10 */ u8 r1;
/* 0x11 */ u8 g1;
/* 0x12 */ u8 b1;
/* 0x13 */ u8 p1;
/* 0x14 */ s16 x1;
/* 0x16 */ s16 y1;
/* 0x18 */ u8 u1;
/* 0x19 */ u8 v1;
/* 0x1A */ u16 tpage;
/* 0x1C */ u8 r2;
/* 0x1D */ u8 g2;
/* 0x1E */ u8 b2;
/* 0x1F */ u8 p2;
/* 0x20 */ f32 y1_f32;
/* 0x24 */ s16 unk24;
/* 0x26 */ u16 priority;
/* 0x28 */ u8 r3;
/* 0x29 */ u8 g3;
/* 0x2A */ u8 b3;
/* 0x2B */ u8 p3;
/* 0x2C */ f32 y1_f32_velocity;
/* 0x30 */ s16 unk30;
/* 0x32 */ u16 drawMode;
} draculaPrimitive;

View File

@ -381,7 +381,324 @@ void EntityStageTitleCard(Entity* self) {
}
}
INCLUDE_ASM("st/st0/nonmatchings/2B0C8", func_801ABBBC);
// Helper function for EntityDracula
u32 func_801ABBBC(s32 step, Entity* dracula) {
draculaPrimitive* prim;
s32 randVar;
s32 randVar2;
s32 colorLimit;
s32 var_a1;
s32 var_a2;
s32 var_a3;
s32 i;
s32 var_t0;
s32 fake_a2;
s32 color;
u8* redPtr;
u8* greenPtr;
u8 constFF;
switch (step) {
case 0:
prim = dracula->ext.dracula.prim;
dracula->ext.dracula.unk80 = prim;
for (i = 0; i < 16; i++) {
prim->type = PRIM_LINE_G2_ALT;
if (i == 15) {
prim->type = PRIM_LINE_G2;
}
if (i & 1) {
prim->x0 = prim->x1 = dracula->posX.i.hi + i / 2;
} else {
prim->x0 = prim->x1 = dracula->posX.i.hi - i / 2;
}
prim->y0 = prim->y1 = 0;
prim->r0 = prim->g0 = prim->b0 = 0x70;
prim->r1 = prim->g1 = prim->b1 = 0;
randVar = Random();
prim->r2 = (((randVar & 1) * 0x10) + 0x10);
prim->g2 = (((randVar * 8) & 0x10) + 0x10);
prim->b2 = (((randVar * 4) & 0x10) + 0x10);
prim->priority = dracula->zPriority + 2;
prim->drawMode = 0x33;
if (i == 0) {
prim->drawMode = DRAW_HIDE;
}
prim = prim->next;
}
step++;
dracula->ext.dracula.unk90 = 1;
dracula->ext.dracula.unk92 = 0;
dracula->ext.dracula.unk8C = 0;
break;
case 1:
if (dracula->ext.dracula.unk8C++ >= 3) {
dracula->ext.dracula.unk90 += 2;
if (dracula->ext.dracula.unk90 >= 16) {
dracula->ext.dracula.unk90 = 16;
}
dracula->ext.dracula.unk8C = 0;
}
prim = dracula->ext.dracula.unk80;
i = 0;
for (i = 0; i < dracula->ext.dracula.unk90; i++) {
prim->y1 += 0x30;
if (dracula->ext.dracula.unkA1 != 0) {
if (prim->y1 >= 171) {
prim->y1 = 171;
}
} else if (prim->y1 >= 203) {
prim->y1 = 203;
}
// Iterate through r1, g1, and b1.
for (redPtr = &prim->r1, var_a1 = 0; var_a1 < 3; redPtr++,
var_a1++) {
color = *redPtr;
if (color < 0xFF) {
// This ends up offsetting to r2, g2, and b2
color += redPtr[0xC];
if (color > 0xFF) {
color = 0xFF;
}
}
*redPtr = color;
}
prim = prim->next;
}
if (dracula->ext.dracula.unk92++ >= 25) {
dracula->ext.dracula.unk92 = 0;
step++;
}
break;
case 2:
prim = dracula->ext.dracula.unk80;
for (i = 0; i < 16; i++) {
prim = prim->next;
}
dracula->ext.dracula.unk84 = prim;
for (i = 0; i < 48; i++) {
prim->type = PRIM_LINE_G2_ALT;
if (i == 47) {
prim->type = PRIM_LINE_G2;
}
prim->r0 = prim->g0 = prim->b0 = 0x70;
prim->r1 = prim->g1 = prim->b1 = 0x20;
randVar2 = Random();
prim->r2 = (((randVar2 & 1) * 4) + 4);
prim->g2 = (((randVar2 * 2) & 4) + 4);
prim->b2 = ((randVar2 & 4) + 4);
if (i & 1) {
prim->x0 = prim->x1 = dracula->posX.i.hi + i / 2;
} else {
prim->x0 = prim->x1 = dracula->posX.i.hi - i / 2;
}
if (dracula->ext.dracula.unkA1 != 0) {
prim->y0 = prim->y1 = 171;
if (i >= 0x22) {
prim->y0 = prim->y1 = -0x20;
}
} else {
prim->y0 = prim->y1 = 203;
}
prim->y1_f32.i.lo = 0;
prim->y1_f32.i.hi = prim->y1;
// FAKE variable reuse
color = (i >> 1);
prim->y1_f32_velocity.val =
((color * color * color) << 8) + 0x80000;
prim->priority = dracula->zPriority + 2;
prim->drawMode = 0x33;
if (i == 0) {
prim->drawMode = DRAW_HIDE;
}
prim = prim->next;
}
step++;
dracula->ext.dracula.unk8C = 0;
g_api.PlaySfx(0x636);
break;
case 3:
prim = dracula->ext.dracula.unk84;
if (dracula->ext.dracula.unkA1 != 0) {
var_a1 = 0x22;
} else {
var_a1 = 0x30;
}
for (i = 0; i < var_a1; prim = prim->next) {
prim->y1_f32.i.hi = prim->y1;
prim->y1_f32.val -= prim->y1_f32_velocity.val;
prim->y1 = prim->y1_f32.i.hi;
i++;
if (prim->y1 < 0) {
prim->y1 = 0U;
}
}
if (++dracula->ext.dracula.unk8C < 9) {
prim = dracula->ext.dracula.unk80;
for (i = 0; i < 16 - (dracula->ext.dracula.unk8C * 2); i++) {
prim = prim->next;
}
for (; i < 16; i++) {
prim->drawMode = DRAW_HIDE;
prim = prim->next;
}
}
prim = dracula->ext.dracula.unk84;
for (i = 0, constFF = 0xFF, colorLimit = 0xFF; i < 48; i++) {
color = prim->r0;
color += 4;
prim->r0 = (color > colorLimit ? colorLimit : color);
colorLimit -= 2;
if (prim->r0 >= 0xFF) {
prim->r0 = constFF;
step = 4;
}
prim->b0 = prim->g0 = prim->r0;
prim = prim->next;
}
var_a2 = 0xFF;
prim = dracula->ext.dracula.unk84;
for (i = 0; i < 48; i++) {
redPtr = &prim->r1;
for (var_a1 = 0; var_a1 < 3; var_a1 += 1) {
color = *redPtr;
color += redPtr[0xC];
if (var_a2 < color) {
color = var_a2;
}
*redPtr = color;
redPtr++;
}
prim = prim->next;
var_a2 -= 2;
}
break;
case 4:
var_t0 = 1;
prim = dracula->ext.dracula.unk84;
for (i = 0, var_a3 = 0xFF; i < 48; i++) {
for (redPtr = &prim->r1, var_a1 = 0, var_a2 = var_a3; var_a1 < 3;
redPtr++, var_a1++) {
color = *redPtr;
color += 0x18;
if (var_a2 < color) {
color = var_a2;
} else {
var_t0 = 0;
}
*redPtr = color;
}
prim = prim->next;
var_a3 -= 2;
}
if (var_t0 != 0) {
step = 5;
}
break;
case 5:
prim = dracula->ext.dracula.unk80;
// @bug: They forgot to do prim = prim->next in this loop!
for (i = 0; i < 16; i++) {
prim->drawMode = DRAW_HIDE;
}
prim = dracula->ext.dracula.unk80;
prim->type = PRIM_TILE;
prim->r0 = prim->g0 = prim->b0 = 0;
prim->y0 = 0;
if (dracula->ext.dracula.unkA1 != 0) {
prim->x0 = dracula->posX.i.hi - 17;
prim->u0 = 0x22;
prim->v0 = 0xAC;
} else {
prim->x0 = dracula->posX.i.hi - 24;
prim->u0 = 0x30;
prim->v0 = 0xCC;
}
step++;
prim->priority = dracula->zPriority + 1;
prim->drawMode = 0x53;
dracula->ext.dracula.unk8C = 0;
break;
case 6:
var_t0 = 1;
prim = dracula->ext.dracula.unk84;
for (i = 0; i < 48; i++) {
redPtr = &prim->r0;
var_a1 = 0;
greenPtr = &prim->g0;
for (; var_a1 < 2;) {
color = *redPtr;
color -= 10;
if (color < 0) {
color = 0;
} else {
var_t0 = 0;
}
var_a1++;
greenPtr[0] = greenPtr[1] = color;
greenPtr += 0xC;
*redPtr = color;
redPtr += 0xC;
}
prim = prim->next;
}
prim = dracula->ext.dracula.unk80;
prim->r0 += 7;
if (prim->r0 > 0xE0) {
prim->r0 = 0xE0;
} else {
var_t0 = 0;
}
prim->g0 = prim->b0 = prim->r0;
if (var_t0 != 0) {
prim = dracula->ext.dracula.unk84;
for (i = 0; i < 48; i++) {
prim->drawMode = DRAW_HIDE;
prim = prim->next;
}
step++;
dracula->drawFlags = DRAW_HIDE;
dracula->unk6C = 0;
dracula->ext.dracula.unkA0 = 1;
}
break;
case 7:
prim = dracula->ext.dracula.unk80;
color = prim->r0;
color -= 16;
if (color < 0) {
color = 0;
}
prim->g0 = prim->b0 = prim->r0 = color;
if (prim->r0 < 16) {
prim->drawMode = DRAW_HIDE;
step++;
}
break;
case 8:
dracula->unk6C += 10;
if (dracula->unk6C >= 0x80U) {
step++;
dracula->unk6C = 0x80U;
dracula->drawFlags = 0;
}
break;
case 9:
prim = dracula->ext.dracula.prim;
while (prim != NULL) {
prim->drawMode = DRAW_HIDE;
prim = prim->next;
}
step = 0xFF;
if (dracula->ext.dracula.unkA1 != 0) {
dracula->ext.dracula.unkA1 = 0U;
}
break;
}
return step;
}
s32 func_801AC458(s16 arg0) {
s32 ret = arg0;