Decompile ST0 EntityCutscenePhotograph (#1833)

Well. Oh my god. This function is finally done. It was brutal. I feel
like the status bar face of the Doom Guy when he's at 1 HP.

Anyway, it's decompiled! What a wild function. ST0 is coming to an end
just as the other stages did before it. GTE continues to be a monster,
but it's done.
This commit is contained in:
bismurphy 2024-10-27 16:02:05 -04:00 committed by GitHub
parent d243ab82d9
commit d97142f0f7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 491 additions and 18 deletions

View File

@ -89,7 +89,7 @@ segments:
- [0x27C8C, .rodata, e_collect]
- [0x27CAC, .rodata, e_collect] # EntityEquipItemDrop
- [0x27CC4, .rodata, e_misc]
- [0x27CFC, rodata]
- [0x27CFC, .rodata, 39EA8] # EntityCutscenePhotograph
- [0x27D30, .rodata, 3C5C0] # "d_step" string
- [0x27D3C, .rodata, prim_helpers]
- [0x27D44, .rodata, 3D8F0]

View File

@ -1930,6 +1930,15 @@ typedef struct {
/* 0xA6 */ s16 unkA6;
} ET_801BC5C0;
typedef struct {
/* 0x7C */ struct Primitive* prim;
/* 0x80 */ s16 rotationTimer;
/* 0x82 */ s16 : 16;
/* 0x84 */ s32 : 32;
/* 0x84 */ s32 : 32;
/* 0x8C */ s16 cameraDistance;
} ET_CutscenePhotograph;
// ====== RIC ENTITIES ======
// ==========================
@ -2099,6 +2108,7 @@ typedef union { // offset=0x7C
ET_RicMaria ricMaria;
ET_BatEnemy batEnemy;
ET_801BC5C0 et_801BC5C0;
ET_CutscenePhotograph cutscenePhoto;
} Ext;
#define SYNC_FIELD(struct1, struct2, field) \

View File

@ -24,20 +24,6 @@
typedef long Event;
typedef enum {
PRIM_NONE,
PRIM_TILE,
PRIM_LINE_G2,
PRIM_G4,
PRIM_GT4,
PRIM_GT3,
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;
typedef struct Vertex {
/* 0x0 */ u8 r;
/* 0x1 */ u8 g;

View File

@ -27,6 +27,20 @@ typedef enum {
// PGREY(prim, 0) = 255
#define PGREY(p, n) p->r##n = p->g##n = p->b##n
typedef enum {
PRIM_NONE,
PRIM_TILE,
PRIM_LINE_G2,
PRIM_G4,
PRIM_GT4,
PRIM_GT3,
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;
typedef struct Primitive {
/* 0x00 */ struct Primitive* next;
#if defined(VERSION_PC) || defined(VERSION_PSP)

View File

@ -367,7 +367,7 @@ void EntityDraculaFinalForm(Entity* self) {
g_api.PlaySfx(0x856);
temp_s2 = AllocEntity(&g_Entities[160], &g_Entities[192]);
if (temp_s2 != NULL) {
CreateEntityFromEntity(E_DRACULA_UNK2F, self, temp_s2);
CreateEntityFromEntity(E_DRACULA_UNK2E, self, temp_s2);
if (self->facingLeft != 0) {
temp_s2->posX.i.hi += 40;
} else {

View File

@ -36,7 +36,470 @@ INCLUDE_ASM("st/st0/nonmatchings/39EA8", EntityClouds);
INCLUDE_ASM("st/st0/nonmatchings/39EA8", EntityClockTower3D);
INCLUDE_ASM("st/st0/nonmatchings/39EA8", EntityCutscenePhotograph);
extern u8 D_80182438[3];
extern SVECTOR D_8018243C;
extern SVECTOR D_80182444;
extern SVECTOR D_8018244C;
extern SVECTOR D_80182454;
extern s16 D_8018245C[];
void EntityCutscenePhotograph(Entity* self) {
RECT clipRect;
DRAWENV drawEnv;
SVECTOR rotVector;
VECTOR transVector;
MATRIX m;
s32 newEntX;
s32 newEntY;
s32 primIndex;
s16* newEntXY;
s32 dualFlag; // Used in color limit system, and as facing left
s32 i;
DR_ENV* dr_env;
Entity* otherEnt;
Primitive* prim;
// These 5 variables are not used in PSP.
u8* colorPtr;
u8* comparePtr;
s32 j;
s32 newColor;
s32 limit;
g_Player.D_80072EFC = 4;
g_Player.padSim = 0;
D_8003C8B8 = 0;
switch (self->step) {
case 0:
InitializeEntity(D_801805D4);
primIndex = g_api.AllocPrimitives(PRIM_GT4, 8);
if (primIndex == -1) {
self->step = 0;
return;
}
self->flags |= FLAG_HAS_PRIMS;
self->primIndex = primIndex;
prim = &g_PrimBuf[primIndex];
self->ext.cutscenePhoto.prim = prim;
while (prim != NULL) {
prim->drawMode = DRAW_HIDE;
prim = prim->next;
}
case 1:
prim = self->ext.cutscenePhoto.prim;
drawEnv = g_CurrentBuffer->draw;
if (drawEnv.ofs[0] == 0) {
prim->tpage = 0x100;
} else {
prim->tpage = 0x104;
}
prim->u0 = prim->u2 = 0;
prim->u1 = prim->u3 = 0xFF;
prim->v0 = prim->v1 = 12;
prim->v2 = prim->v3 = 12 + 0xE0;
prim->x0 = prim->x2 = 0;
prim->x1 = prim->x3 = 0xFF;
prim->y0 = prim->y1 = 12;
prim->y2 = prim->y3 = 12 + 0xE0;
prim->r0 = prim->g0 = prim->b0 = 0x80;
LOW(prim->r1) = LOW(prim->r0);
LOW(prim->r2) = LOW(prim->r0);
LOW(prim->r3) = LOW(prim->r0);
prim->priority = 0x1F8;
prim->drawMode = DRAW_UNK_400 | DRAW_COLORS;
prim = prim->next;
self->step++;
// Fallthrough!
case 2:
prim = self->ext.cutscenePhoto.prim;
drawEnv = g_CurrentBuffer->draw;
if (drawEnv.ofs[0] == 0) {
prim->tpage = 0x100;
} else {
prim->tpage = 0x104;
}
dualFlag = 1;
comparePtr = &D_80182438[0];
colorPtr = &prim->r0;
// Iterate through prim r0, r1, r2, r3
// Colors are spaced 12 bytes apart.
for (i = 0; i < 4; i++, colorPtr += 12) {
// Iterate through r, g, b
for (j = 0; j < 3; j++) {
newColor = colorPtr[j];
newColor--;
if (newColor < comparePtr[j]) {
newColor = comparePtr[j];
} else {
dualFlag = 0;
}
colorPtr[j] = newColor;
}
}
if (dualFlag == 0) {
return;
}
self->step++;
return;
case 3:
prim = self->ext.cutscenePhoto.prim;
prim = prim->next;
drawEnv = g_CurrentBuffer->draw;
if (drawEnv.ofs[0] == 0) {
prim->tpage = 0x100;
} else {
prim->tpage = 0x104;
}
prim->type = PRIM_GT4;
prim->u0 = prim->u2 = 6;
prim->u1 = prim->u3 = 0xF9;
prim->v0 = prim->v1 = 18;
prim->v2 = prim->v3 = 18 + 0xD4;
prim->x0 = prim->x2 = 6;
prim->x1 = prim->x3 = 0xF9;
prim->y0 = prim->y1 = 18;
prim->y2 = prim->y3 = 18 + 0xD4;
prim->priority = 0x1FB;
prim->drawMode = DRAW_DEFAULT;
prim = prim->next;
dr_env = g_api.func_800EDB08(prim);
if (dr_env == NULL) {
SetStep(12);
return;
}
prim->type = PRIM_ENV;
drawEnv.isbg = 1;
drawEnv.r0 = 0x70;
drawEnv.g0 = 0x70;
drawEnv.b0 = 0x60;
drawEnv.dtd = 0;
clipRect.x = 0;
clipRect.y = 0x100;
clipRect.w = 0x100;
clipRect.h = 0x100;
drawEnv.clip = clipRect;
drawEnv.ofs[0] = 0;
drawEnv.ofs[1] = 0x100;
SetDrawEnv(dr_env, &drawEnv);
prim->priority = 0x1FA;
prim->drawMode = DRAW_DEFAULT;
prim = prim->next;
dr_env = g_api.func_800EDB08(prim);
if (dr_env == NULL) {
SetStep(12);
return;
}
prim->type = PRIM_ENV;
prim->priority = 0x1FC;
prim->drawMode = DRAW_UNK_800;
prim = prim->next;
prim->type = PRIM_G4;
prim->x0 = prim->x2 = 0;
prim->x1 = prim->x3 = 0x100;
prim->y0 = prim->y1 = 0;
prim->y2 = prim->y3 = 0x100;
prim->r0 = prim->g0 = prim->b0 = 8;
LOW(prim->r1) = LOW(prim->r0);
LOW(prim->r2) = LOW(prim->r0);
LOW(prim->r3) = LOW(prim->r0);
prim->priority = 0x1F9;
prim->drawMode = DRAW_TPAGE2 | DRAW_TPAGE | DRAW_TRANSP;
self->step++;
break;
case 4:
prim = self->ext.cutscenePhoto.prim;
prim = prim->next;
prim->drawMode = DRAW_HIDE;
prim = prim->next;
for (i = 0; i < 2; i++) {
dr_env = (DR_ENV*)LOW(prim->r1);
dr_env->tag = 0;
prim->type = PRIM_GT4;
prim = prim->next;
}
prim->drawMode = DRAW_HIDE;
// useless line due to the following line!
prim = prim->next;
prim = self->ext.cutscenePhoto.prim;
prim->tpage = 0x110;
prim->u0 = prim->u2 = 0;
prim->u1 = prim->u3 = 0xFF;
prim->v0 = prim->v1 = 12;
prim->v2 = prim->v3 = 12 + 0xE0;
prim->x0 = prim->x2 = 0;
prim->x1 = prim->x3 = 0xFF;
prim->y0 = prim->y1 = 12;
prim->y2 = prim->y3 = 12 + 0xE0;
prim->r0 = prim->g0 = prim->b0 = 0x80;
LOW(prim->r1) = LOW(prim->r0);
LOW(prim->r2) = LOW(prim->r0);
LOW(prim->r3) = LOW(prim->r0);
prim->priority = 0x1F9;
prim->drawMode = DRAW_DEFAULT;
for (otherEnt = &g_Entities[1], i = 1; i < 256; i++, otherEnt++) {
if (otherEnt != self) {
DestroyEntity(otherEnt);
}
}
PLAYER.animSet = 0;
D_8003C744 = 5;
g_GpuBuffers[0].draw.clip.y = 0;
g_GpuBuffers[0].draw.clip.h = 0xF0;
g_GpuBuffers[1].draw.clip.y = 0;
g_GpuBuffers[1].draw.clip.h = 0xF0;
self->rotZ = 0;
self->rotX = 0x100;
self->ext.cutscenePhoto.cameraDistance = 0;
self->ext.cutscenePhoto.rotationTimer = 0x20;
g_api.PlaySfx(SFX_EXPLODE_A);
self->step++;
/* fallthrough */
case 5:
g_GpuBuffers[0].draw.r0 = 0;
g_GpuBuffers[0].draw.g0 = 0;
g_GpuBuffers[0].draw.b0 = 0;
g_GpuBuffers[1].draw.r0 = 0;
g_GpuBuffers[1].draw.g0 = 0;
g_GpuBuffers[1].draw.b0 = 0;
prim = self->ext.cutscenePhoto.prim;
SetGeomScreen(0x400);
SetGeomOffset(0x80, 0x80);
rotVector.vx = 0;
rotVector.vy = 0;
rotVector.vz = self->rotZ;
RotMatrix(&rotVector, &m);
SetRotMatrix(&m);
transVector.vx = 0;
transVector.vy = 0;
transVector.vz = 0x400;
transVector.vz += self->ext.cutscenePhoto.cameraDistance;
TransMatrix(&m, &transVector);
SetTransMatrix(&m);
gte_ldv3(&D_8018243C, &D_80182444, &D_8018244C);
gte_rtpt();
gte_stsxy3_gt3(prim);
gte_ldv0(&D_80182454);
gte_rtps();
gte_stsxy(&prim->x3);
if (!self->ext.cutscenePhoto.rotationTimer) {
self->rotZ += 2;
self->ext.cutscenePhoto.cameraDistance += 8;
} else {
self->ext.cutscenePhoto.rotationTimer--;
}
if (self->ext.cutscenePhoto.cameraDistance <= 0x600) {
return;
}
self->step++;
return;
case 6:
prim = self->ext.cutscenePhoto.prim;
prim = prim->next;
drawEnv = g_CurrentBuffer->draw;
if (drawEnv.ofs[0] == 0) {
prim->tpage = 0x100;
} else {
prim->tpage = 0x104;
}
prim->type = PRIM_GT4;
prim->u0 = prim->u2 = 0;
prim->u1 = prim->u3 = 0xFF;
prim->v0 = prim->v1 = 12;
prim->v2 = prim->v3 = 12 + 0xE0;
prim->x0 = prim->x2 = 0;
prim->x1 = prim->x3 = 0xFF;
prim->y0 = prim->y1 = 12;
prim->y2 = prim->y3 = 12 + 0xE0;
prim->priority = 0x1FB;
prim->drawMode = DRAW_DEFAULT;
prim = prim->next;
dr_env = g_api.func_800EDB08(prim);
if (dr_env == NULL) {
SetStep(12);
return;
}
prim->type = PRIM_ENV;
drawEnv.isbg = 1;
drawEnv.r0 = 8;
drawEnv.g0 = 8;
drawEnv.b0 = 8;
drawEnv.dtd = 1;
clipRect.x = 0;
clipRect.y = 0x100;
clipRect.w = 0x100;
clipRect.h = 0x100;
drawEnv.clip = clipRect;
drawEnv.ofs[0] = 0;
drawEnv.ofs[1] = 0x100;
SetDrawEnv(dr_env, &drawEnv);
prim->priority = 0x1FA;
prim->drawMode = DRAW_DEFAULT;
prim = prim->next;
dr_env = g_api.func_800EDB08(prim);
if (dr_env == NULL) {
SetStep(12);
return;
}
prim->type = PRIM_ENV;
prim->priority = 0x1FD;
prim->drawMode = DRAW_UNK_800;
prim = prim->next;
prim->type = PRIM_TILE;
prim->x0 = 0;
prim->y0 = 0;
prim->u0 = 0xFF;
prim->v0 = 0xFF;
prim->r0 = prim->g0 = prim->b0 = 8;
prim->priority = 0x1FC;
prim->drawMode = DRAW_TPAGE2 | DRAW_TPAGE | DRAW_TRANSP;
self->step++;
return;
case 7:
prim = self->ext.cutscenePhoto.prim;
prim->tpage = 0x110;
prim->u0 = prim->x0;
prim->u1 = prim->x1;
prim->u2 = prim->x2;
prim->u3 = prim->x3;
prim->v0 = prim->y0;
prim->v1 = prim->y1;
prim->v2 = prim->y2;
prim->v3 = prim->y3;
prim->priority = 0x1FE;
prim->drawMode = DRAW_DEFAULT;
prim = prim->next;
prim->drawMode = DRAW_HIDE;
prim = prim->next;
prim->type = PRIM_ENV;
dr_env = (DR_ENV*)LOW(prim->r1);
drawEnv = g_CurrentBuffer->draw;
drawEnv.isbg = 0;
drawEnv.dtd = 0;
clipRect.x = 0;
clipRect.y = 0x100;
clipRect.w = 0x100;
clipRect.h = 0x100;
drawEnv.clip = clipRect;
drawEnv.ofs[0] = 0;
drawEnv.ofs[1] = 0x100;
SetDrawEnv(dr_env, &drawEnv);
prim->priority = 0x1FA;
prim->drawMode = DRAW_DEFAULT;
prim = prim->next;
prim = prim->next;
prim->type = PRIM_TILE;
prim->x0 = 0x40;
prim->y0 = 0x40;
prim->u0 = 0x80;
prim->v0 = 0x80;
prim->r0 = prim->g0 = prim->b0 = 0;
prim->priority = 0x1FC;
prim->drawMode = DRAW_UNK_40 | DRAW_TPAGE | DRAW_TRANSP;
self->animFrameIdx = 0;
g_api.PlaySfx(NA_SE_CS_BURNING_PHOTOGRAPH);
self->step++;
/* fallthrough */
case 8:
if (self->animFrameDuration) {
self->animFrameDuration--;
return;
}
self->animFrameDuration = 4;
// Ugh, this should have been a 2D array.
newEntXY = &D_8018245C[0];
newEntXY += self->animFrameIdx * 2;
self->animFrameIdx++;
if (newEntXY[0] == -1) {
self->step++;
return;
}
newEntX = newEntXY[0];
newEntY = newEntXY[1];
if (self->animFrameIdx & 1) {
dualFlag = 0;
} else {
dualFlag = 1;
}
otherEnt = AllocEntity(self, (Entity*)&g_EvHwCardEnd);
if (otherEnt != NULL) {
CreateEntityFromCurrentEntity(E_ID_2D, otherEnt);
otherEnt->posX.i.hi = newEntX;
otherEnt->posY.i.hi = newEntY;
otherEnt->facingLeft = dualFlag;
otherEnt->params = 0;
}
otherEnt = AllocEntity(self, (Entity*)&g_EvHwCardEnd);
if (otherEnt != NULL) {
CreateEntityFromCurrentEntity(E_ID_2D, otherEnt);
otherEnt->posX.i.hi = newEntX;
otherEnt->posY.i.hi = newEntY + 0xC;
otherEnt->facingLeft = dualFlag;
otherEnt->params = 1;
}
break;
case 9:
prim = self->ext.cutscenePhoto.prim;
prim = prim->next;
prim->type = PRIM_G4;
prim->x0 = prim->x2 = 0;
prim->x1 = prim->x3 = 0x100;
prim->y0 = prim->y1 = 0;
prim->y2 = prim->y3 = 0x100;
prim->r0 = prim->g0 = prim->b0 = 0;
LOW(prim->r1) = LOW(prim->r0);
LOW(prim->r2) = LOW(prim->r0);
LOW(prim->r3) = LOW(prim->r0);
prim->priority = 0x1FF;
prim->drawMode = DRAW_TPAGE2 | DRAW_TPAGE | DRAW_TRANSP;
self->step++;
return;
case 10:
prim = self->ext.cutscenePhoto.prim;
prim = prim->next;
prim->r0 += 8;
if (prim->r0 > 0xF0) {
self->step++;
}
prim->g0 = prim->b0 = prim->r0;
LOW(prim->r1) = LOW(prim->r0);
LOW(prim->r2) = LOW(prim->r0);
LOW(prim->r3) = LOW(prim->r0);
return;
case 11:
case 12:
g_GameEngineStep = Engine_10;
g_MenuStep = 0;
break;
}
}
void EntityCutscenePhotographFire(Entity* entity) {
switch (entity->step) {

View File

@ -41,8 +41,8 @@ typedef enum EntityIDs {
E_SECRET_STAIRS,
E_DRACULA_UNK2B = 0x2B,
E_DRACULA_UNK2C,
E_ID_2D,
E_DRACULA_UNK2E,
E_DRACULA_UNK2F
} EntityIDs;
void CreateEntityFromEntity(u16 entityId, Entity* source, Entity* entity);