Decompile no0 EntityBreakable and extract data (#1776)

PSX: https://decomp.me/scratch/ouTpd
PSP: https://decomp.me/scratch/pZMLg

Code is super similar to
af89c6247c/src/st/e_breakable.h (L15)
and other implementations like
af89c6247c/src/st/mad/D8C8.c (L169)

But sound effects seem to differ amongst most - not sure if there's a
really clean way to de-duplicate this with a shared header so I'm just
copying into a new function for now.
This commit is contained in:
Josh Schreuder 2024-10-12 03:41:06 +11:00 committed by GitHub
parent d36616f401
commit 67a6f1cf72
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 183 additions and 114 deletions

View File

@ -42,6 +42,8 @@ segments:
- [0x778, data, e_laydef]
- [0x91C, data, e_init]
- [0xC8C, data]
- [0xF04, .data, e_breakable]
- [0xFC0, data]
- [0x113C, .data, st_update] # UNK_Invincibility0 data
- [0x1168, .data, collision]
- [0x1528, .data, e_red_door]
@ -51,7 +53,7 @@ segments:
- [0x184C, .data, e_collect]
- [0x1B3C, .data, e_misc]
- [0x1C14, data]
- [0x41368, .rodata, first_c_file]
- [0x41368, .rodata, 41F98]
- [0x4137C, .rodata, e_red_door]
- [0x41394, .rodata, e_collect]
- [0x4141C, .rodata, e_misc]
@ -60,6 +62,8 @@ segments:
- [0x414EC, .rodata, unk_4F4A8]
- [0x4184C, .rodata, prim_helpers]
- [0x41854, c, first_c_file]
- [0x41E48, c, e_breakable]
- [0x41F98, c, 41F98]
- [0x43788, c, st_update]
- [0x43BBC, c, collision]
- [0x45378, c, create_entity]

View File

@ -1,6 +1,7 @@
g_pStObjLayoutHorizontal = 0x80180778;
g_pStObjLayoutVertical = 0x8018084C;
NO0_EntityUpdates = 0x80180920;
g_eBreakableInit = 0x80180A64;
g_InitializeData0 = 0x80180A70;
g_InitializeEntityData0 = 0x80180A7C;
g_EInitGeneric = 0x80180A94;
@ -13,6 +14,11 @@ D_80180C70 = 0x80180C08;
D_80180C88 = 0x80180C38;
D_80180CA0 = 0x80180C50;
g_eRedDoorTiles = 0x80180C5C;
g_eBreakableAnimations = 0x80180F58;
g_eBreakableHitboxes = 0x80180F7C;
g_eBreakableExplosionTypes = 0x80180F88;
g_eBreakableanimSets = 0x80180F94;
g_eBreakableDrawModes = 0x80180FA8;
g_HeartDropArray = 0x80181100;
UNK_Invincibility0 = 0x8018113C;
g_testCollEnemyLookup = 0x80181168;
@ -56,6 +62,7 @@ sprites_nz0_3 = 0x801BEBB0;
g_UnkPrimHelperRot = 0x801C184C;
PlayerIsWithinHitbox = 0x801C1968;
func_801B0AA4 = 0x801C19EC;
EntityBreakable = 0x801C1E48;
EntityWargExplosionPuffOpaque = 0x801C33F4;
Random = 0x801C3788;
Update = 0x801C37B8;

View File

@ -18,7 +18,12 @@ void EntityBreakable(Entity* entity) {
AnimateEntity(g_eBreakableAnimations[breakableType], entity);
if (entity->hitParams) { // If the candle is destroyed
Entity* entityDropItem;
#if defined(STAGE_IS_NO0)
breakableType == 1 ? g_api_PlaySfx(SFX_GLASS_BREAK_C)
: g_api_PlaySfx(SFX_CANDLE_HIT_WHOOSH_A);
#else
g_api.PlaySfx(SFX_BREAKABLE_HIT);
#endif
entityDropItem = AllocEntity(&g_Entities[224], &g_Entities[256]);
if (entityDropItem != NULL) {
CreateEntityFromCurrentEntity(E_EXPLOSION, entityDropItem);

113
src/st/no0/41F98.c Normal file
View File

@ -0,0 +1,113 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
#include "no0.h"
s16 func_us_801C1F98(Primitive* prim, s16 arg1) {
s16 ret = arg1;
s16 temp_v0;
prim->x2 = arg1;
prim->x0 = arg1;
ret += 0x20;
prim->drawMode = DRAW_UNK02;
prim->v0 = prim->v1 = 0x50;
prim->v2 = prim->v3 = 0x60;
prim->y0 = prim->y1 = 0x2C;
prim->y2 = prim->y3 = 0x3C;
prim->u0 = prim->u2 = 2;
if (ret > 0xB0) {
temp_v0 = 0xB2 - arg1;
prim->u1 = prim->u3 = temp_v0;
ret = 0;
prim->x1 = prim->x3 = 0xB0;
} else {
prim->u1 = prim->u3 = 0x22;
prim->x1 = prim->x3 = ret;
}
return ret;
}
s16 func_us_801C2044(Primitive* prim, s16 offset) {
prim->drawMode = DRAW_UNK02;
prim->u0 = prim->u2 = 0x50;
prim->u1 = prim->u3 = 0x60;
prim->x0 = prim->x2 = g_CurrentEntity->posX.i.hi - 8;
prim->x1 = prim->x3 = g_CurrentEntity->posX.i.hi + 8;
prim->v2 = prim->v3 = 0x26;
prim->y2 = prim->y3 = offset;
offset -= 0x20;
if (offset < 0x44) {
offset = 0x44 - offset;
prim->v0 = prim->v1 = offset + 6;
prim->y0 = prim->y1 = 0x44;
prim = prim->next;
prim->drawMode = DRAW_UNK02;
prim->v0 = prim->v1 = 0x50;
prim->v2 = prim->v3 = 0x60;
prim->y0 = prim->y1 = 0x2C;
prim->y2 = prim->y3 = 0x3C;
prim->u0 = prim->u2 = 0x22 - offset;
prim->u1 = prim->u3 = 0x22;
prim->x0 = prim->x2 = g_CurrentEntity->posX.i.hi;
prim->x1 = prim->x3 = g_CurrentEntity->posX.i.hi + offset;
} else {
prim->v0 = prim->v1 = 6;
prim->y0 = prim->y1 = offset;
}
return offset;
}
INCLUDE_ASM("st/no0/nonmatchings/41F98", func_us_801C2184);
extern u16 D_us_80180B60[];
void func_us_801C26B8(Entity* self) {
Entity* entity = &self[self->params];
s32 step = self->step;
switch (self->step) {
case 0:
InitializeEntity(D_us_80180B60);
if (self->params & 16) {
self->animCurFrame = self->params & 15;
self->zPriority = 0x6A;
self->step = 2;
return;
}
self->animCurFrame = 0;
break;
case 1:
self->posX.i.hi = entity->posX.i.hi;
if (self->params == step) {
self->posY.i.hi = entity->posY.i.hi + 35;
self->ext.generic.unk80.modeS8.unk0 =
GetPlayerCollisionWith(self, 12, 8, 4);
} else {
self->posY.i.hi = entity->posY.i.hi - 24;
self->ext.generic.unk80.modeS8.unk0 =
GetPlayerCollisionWith(self, 12, 8, 6);
}
break;
}
}
INCLUDE_ASM("st/no0/nonmatchings/41F98", func_us_801C27A4);
INCLUDE_ASM("st/no0/nonmatchings/41F98", func_us_801C2A34);
INCLUDE_ASM("st/no0/nonmatchings/41F98", func_us_801C2B24);
INCLUDE_ASM("st/no0/nonmatchings/41F98", func_us_801C2CD8);
INCLUDE_ASM("st/no0/nonmatchings/41F98", func_us_801C2E7C);
void func_us_801C3308(Entity* self) {
g_CastleFlags[CASTLE_FLAG_1] = 1;
DestroyEntity(self);
}
INCLUDE_ASM("st/no0/nonmatchings/41F98", func_us_801C3334);
INCLUDE_ASM("st/no0/nonmatchings/41F98", EntityWargExplosionPuffOpaque);

53
src/st/no0/e_breakable.c Normal file
View File

@ -0,0 +1,53 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
#include "no0.h"
static u8 anim_1[] = {4, 1, 4, 2, 0, 0, 0, 0};
static u8 anim_2[] = {4, 7, 4, 8, 4, 9, 0, 0};
static u8 anim_3[] = {4, 29, 4, 30, 4, 31, 0, 0};
static u8 anim_4[] = {4, 1, 4, 2, 0, 0, 0, 0};
static u8 anim_5[] = {4, 1, 4, 2, 0, 0, 0, 0};
static u8 anim_6[] = {4, 1, 4, 2, 0, 0, 0, 0};
static u8 anim_7[] = {4, 1, 4, 2, 0, 0, 0, 0};
static u8 anim_8[] = {4, 1, 4, 2, 0, 0, 0, 0, 4, 1, 4, 2, 0, 0, 0, 0};
static u8 anim_9[] = {4, 12, 4, 13, 4, 14, 4, 15, 4, 16, 0, 0};
// This has 9 animations? Other stages only seem to have 8.
static u8* g_eBreakableAnimations[] = {
anim_1, anim_2, anim_3, anim_4, anim_5, anim_6, anim_7, anim_8, anim_9};
static u8 g_eBreakableHitboxes[] = {8, 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0};
// TODO: Check if PSP is in the BSS section like it is on other stages
static u8 g_eBreakableExplosionTypes[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
static u16 g_eBreakableanimSets[] = {
ANIMSET_DRA(3), ANIMSET_OVL(1),
ANIMSET_OVL(1), ANIMSET_DRA(3),
ANIMSET_DRA(3), ANIMSET_DRA(3),
ANIMSET_DRA(3), ANIMSET_DRA(3),
ANIMSET_OVL(1), 0};
static u8 g_eBreakableDrawModes[] = {
DRAW_TPAGE | DRAW_TPAGE2 | DRAW_UNK_40,
DRAW_TPAGE | DRAW_TPAGE2,
DRAW_TPAGE | DRAW_TPAGE2,
DRAW_TPAGE | DRAW_TPAGE2,
DRAW_TPAGE | DRAW_TPAGE2,
DRAW_TPAGE | DRAW_TPAGE2,
DRAW_TPAGE | DRAW_TPAGE2,
DRAW_TPAGE | DRAW_TPAGE2,
DRAW_TPAGE | DRAW_TPAGE2,
DRAW_DEFAULT,
DRAW_DEFAULT,
DRAW_DEFAULT,
DRAW_DEFAULT,
DRAW_DEFAULT,
DRAW_DEFAULT,
DRAW_DEFAULT,
DRAW_DEFAULT,
DRAW_DEFAULT,
DRAW_DEFAULT,
DRAW_DEFAULT,
DRAW_DEFAULT,
DRAW_DEFAULT,
DRAW_DEFAULT,
DRAW_DEFAULT};
#include "../e_breakable.h";

View File

@ -144,116 +144,3 @@ void func_801B0AA4(Entity* self) {
}
}
}
INCLUDE_ASM("st/no0/nonmatchings/first_c_file", func_us_801C1E48);
s16 func_us_801C1F98(Primitive* prim, s16 arg1) {
s16 ret = arg1;
s16 temp_v0;
prim->x2 = arg1;
prim->x0 = arg1;
ret += 0x20;
prim->drawMode = DRAW_UNK02;
prim->v0 = prim->v1 = 0x50;
prim->v2 = prim->v3 = 0x60;
prim->y0 = prim->y1 = 0x2C;
prim->y2 = prim->y3 = 0x3C;
prim->u0 = prim->u2 = 2;
if (ret > 0xB0) {
temp_v0 = 0xB2 - arg1;
prim->u1 = prim->u3 = temp_v0;
ret = 0;
prim->x1 = prim->x3 = 0xB0;
} else {
prim->u1 = prim->u3 = 0x22;
prim->x1 = prim->x3 = ret;
}
return ret;
}
s16 func_us_801C2044(Primitive* prim, s16 offset) {
prim->drawMode = DRAW_UNK02;
prim->u0 = prim->u2 = 0x50;
prim->u1 = prim->u3 = 0x60;
prim->x0 = prim->x2 = g_CurrentEntity->posX.i.hi - 8;
prim->x1 = prim->x3 = g_CurrentEntity->posX.i.hi + 8;
prim->v2 = prim->v3 = 0x26;
prim->y2 = prim->y3 = offset;
offset -= 0x20;
if (offset < 0x44) {
offset = 0x44 - offset;
prim->v0 = prim->v1 = offset + 6;
prim->y0 = prim->y1 = 0x44;
prim = prim->next;
prim->drawMode = DRAW_UNK02;
prim->v0 = prim->v1 = 0x50;
prim->v2 = prim->v3 = 0x60;
prim->y0 = prim->y1 = 0x2C;
prim->y2 = prim->y3 = 0x3C;
prim->u0 = prim->u2 = 0x22 - offset;
prim->u1 = prim->u3 = 0x22;
prim->x0 = prim->x2 = g_CurrentEntity->posX.i.hi;
prim->x1 = prim->x3 = g_CurrentEntity->posX.i.hi + offset;
} else {
prim->v0 = prim->v1 = 6;
prim->y0 = prim->y1 = offset;
}
return offset;
}
INCLUDE_ASM("st/no0/nonmatchings/first_c_file", func_us_801C2184);
extern u16 D_us_80180B60[];
void func_us_801C26B8(Entity* self) {
Entity* entity = &self[self->params];
s32 step = self->step;
switch (self->step) {
case 0:
InitializeEntity(D_us_80180B60);
if (self->params & 16) {
self->animCurFrame = self->params & 15;
self->zPriority = 0x6A;
self->step = 2;
return;
}
self->animCurFrame = 0;
break;
case 1:
self->posX.i.hi = entity->posX.i.hi;
if (self->params == step) {
self->posY.i.hi = entity->posY.i.hi + 35;
self->ext.generic.unk80.modeS8.unk0 =
GetPlayerCollisionWith(self, 12, 8, 4);
} else {
self->posY.i.hi = entity->posY.i.hi - 24;
self->ext.generic.unk80.modeS8.unk0 =
GetPlayerCollisionWith(self, 12, 8, 6);
}
break;
}
}
INCLUDE_ASM("st/no0/nonmatchings/first_c_file", func_us_801C27A4);
INCLUDE_ASM("st/no0/nonmatchings/first_c_file", func_us_801C2A34);
INCLUDE_ASM("st/no0/nonmatchings/first_c_file", func_us_801C2B24);
INCLUDE_ASM("st/no0/nonmatchings/first_c_file", func_us_801C2CD8);
INCLUDE_ASM("st/no0/nonmatchings/first_c_file", func_us_801C2E7C);
void func_us_801C3308(Entity* self) {
g_CastleFlags[CASTLE_FLAG_1] = 1;
DestroyEntity(self);
}
INCLUDE_ASM("st/no0/nonmatchings/first_c_file", func_us_801C3334);
INCLUDE_ASM("st/no0/nonmatchings/first_c_file", EntityWargExplosionPuffOpaque);