Skip to content

Commit

Permalink
Decompile more ST0 cutscene (#2075)
Browse files Browse the repository at this point in the history
The `Dialogue` struct is 4 bytes shorter on PSP. It's hard to tell which
field is different without decompiling `ST0_EntityCutscene`. But I
re-adjusted the offsets based on what I think the struct is shorter. The
`g_Dialogue.prim[5]` is infact missing on PSP.

Data is imported using `CH(x)` instead of `_S(X)`. This is because
`sotn-str` cannot yet be integrated on the build-chain on PSP. A longer
discussion about it happened here:
https://discord.com/channels/1079389589950705684/1079395311350452255/1309620547696595015

Some functions were far too different to be ported to the shared
headers.
  • Loading branch information
Xeeynamo authored Jan 15, 2025
1 parent fbab1e6 commit 17e6aa4
Show file tree
Hide file tree
Showing 11 changed files with 198 additions and 42 deletions.
2 changes: 2 additions & 0 deletions config/splat.pspeu.stst0.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ segments:
- [0x1B268, data, header]
- [0x1B538, data, e_init]
- [0x1B700, data]
- [0x1C500, .data, st0_psp/cutscene]
- [0x1C8C8, data]
- [0x41B88, .data, st0/2A218] # EntityCutscene
- [0x41BF0, .data, st0/e_lock_camera]
- [0x41C08, .data, st0/e_red_door]
Expand Down
14 changes: 13 additions & 1 deletion config/symbols.pspeu.stst0.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ SetTitleDisplayBuffer = 0x09237BC0;
func_801B0414 = 0x09237CB8;
PrologueScroll = 0x09237D10;
DrawCutsceneActorName = 0x09238BF8;
CutsceneUnk3 = 0x09238F10;
CutsceneUnk4 = 0x09238F90;
CutsceneUnk1 = 0x09239060;
SetCutsceneScript = 0x092390C0;
SetCutsceneEnd = 0x092392D0;
CutsceneRun = 0x09239308;
ST0_EntityCutscene = 0x092396A0;
EntitySecretButton = 0x0923B5D8;
EntitySecretStairsCeiling = 0x0923B950;
Expand Down Expand Up @@ -131,6 +137,11 @@ g_EInitDraculaMegaFireball = 0x09252D40;
g_EInitDraculaRainAttack = 0x09252D50;
g_EInitSecretStairs = 0x09252D60;
ST0_RedDoorTiles = 0x09252D70;
D_80180784 = 0x09253E88;
D_8018078C = 0x09253E90;
D_80180790 = 0x09253E98;
D_80180794 = 0x09253EA0;
D_80180798 = 0x09253EA8;
g_Rooms = 0x09257350;
ST0_BackgroundBlockInit = 0x092791F0;
g_ESoulStealOrbAngles = 0x092792D0;
Expand All @@ -151,7 +162,8 @@ explode_lifetime = 0x09279610;
g_eDamageDisplayClut = 0x09279978;
eRoomForegroundInit = 0x092799B0;
D_80180908 = 0x09279DA0;
g_Dialogue = 0x0927BA58;
g_Dialogue = 0x0927BA58; // size = 0x44
g_CutsceneFlags = 0x0927BAA8;
D_801BEE0C = 0x0927BAB0;
D_801BEE08 = 0x0927BAB8;
D_801BEE04 = 0x0927BAC0;
Expand Down
1 change: 0 additions & 1 deletion config/symbols.pspeu.txt
Original file line number Diff line number Diff line change
Expand Up @@ -102,5 +102,4 @@ g_GpuBuffers = 0x091FC4E8;
g_CastleFlags = 0x09234730;
g_IsCutsceneDone = 0x0927BA98;
g_SkipCutscene = 0x0927BAA0;
g_CutsceneFlags = 0x0927BAA8;
DestroyEntity = 0x092EE938;
18 changes: 12 additions & 6 deletions include/game.h
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,8 @@ typedef enum {
// font. e.g. _S("I am a Symphony of the Night encoded string")
#define _S(x) (x)
#endif
// same as above, but it processes a single character from CPP
#define CH(x) ((x) - 0x20)

#define DEMO_KEY_LEN 3
#define DEMO_MAX_LEN 0x2000
Expand Down Expand Up @@ -1499,13 +1501,17 @@ typedef struct {
/* 0x14 */ u16 clutIndex; // CLUT index
/* 0x16 */ u8 nextCharTimer; // timer to next character
/* 0x17 */ u8 unk17; // unknown
// Of course, offsets beyond here won't be right in ST0_WEIRD_DIALOGUE.
// Of course, offsets beyond here won't be right in ST0_WEIRD_DIALOGUE.
#if defined(VERSION_PSP)
/* 0x18 */ Primitive* prim[5]; // for dialogue graphics rendering
#else
/* 0x18 */ Primitive* prim[6]; // for dialogue graphics rendering
/* 0x30 */ s32 primIndex[3]; // primIndices: unk, actorName, unk
/* 0x3C */ u16 unk3C; // maybe it is a begin flag?
/* 0x3E */ u16 timer; // global timer
/* 0x40 */ u8* scriptEnd; // pointer to the end of the script
} Dialogue; // size = 0x44
#endif
/* 0x30 */ s32 primIndex[3]; // primIndices: unk, actorName, unk
/* 0x3C */ u16 unk3C; // maybe it is a begin flag?
/* 0x3E */ u16 timer; // global timer
/* 0x40 */ u8* scriptEnd; // pointer to the end of the script
} Dialogue; // size = 0x44

// Used for the damageKind of DamageParam
typedef enum {
Expand Down
2 changes: 0 additions & 2 deletions src/dra/menu.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@ typedef struct {
/* 0x0A */ s16 padding;
} MenuContextInit; // size = 0x1C

#define CH(x) ((x) - 0x20)

#if defined(VERSION_US)
#define ShowText(str, id) func_800F99B8(str, id, 0);
#elif defined(VERSION_HD)
Expand Down
5 changes: 2 additions & 3 deletions src/st/cutscene_unk1.h
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
static void CutsceneUnk1(void) {
g_Dialogue.nextLineX = 2;
g_Dialogue.nextCharX = 2;
g_Dialogue.nextLineY = g_Dialogue.startY + 0x14;
g_Dialogue.nextCharX = g_Dialogue.nextLineX = 2;
g_Dialogue.nextCharY = 0;
g_Dialogue.unk12 = 0;
g_Dialogue.nextCharTimer = 0;
g_Dialogue.unk17 = 8;
g_Dialogue.nextLineY = g_Dialogue.startY + 0x14;
}
9 changes: 7 additions & 2 deletions src/st/cutscene_unk3.h
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
#if defined(VERSION_PSP)
extern void* D_pspeu_0927B6A8;
#endif
static void CutsceneUnk3(s16 arg0) {
RECT rect;

rect.x = 0;
rect.y = (arg0 * 12) + 384;
rect.w = 64;
rect.x = 0;
rect.h = 12;
ClearImage(&rect, 0, 0, 0);
#if defined(VERSION_PSP)
func_890A3C0(&D_pspeu_0927B6A8, 0, 0x380);
#endif
}
5 changes: 2 additions & 3 deletions src/st/cutscene_unk4.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,8 @@ static void CutsceneUnk4(void) {
prim->clut = g_Dialogue.clutIndex;
prim->y0 = g_Dialogue.nextLineY;
prim->u0 = 0;
prim->x0 = g_Dialogue.startX;
prim->x0 = prim->x0 + 4;
prim->v0 = g_Dialogue.nextCharY * 0xC - 0x80;
prim->x0 = g_Dialogue.startX + 4;
prim->v0 = g_Dialogue.nextCharY * 0xC + 0x80;
prim->u1 = 0xC0;
prim->v1 = 0xC;
prim->priority = 0x1FF;
Expand Down
5 changes: 5 additions & 0 deletions src/st/set_cutscene_end.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
// SPDX-License-Identifier: AGPL-3.0-or-later

static void SetCutsceneEnd(u8* ptr) {
#if !defined(VERSION_PSP)
g_Dialogue.scriptEnd = ptr + 0x100000;
#else
g_Dialogue.scriptEnd = ptr;
#endif
g_Dialogue.timer = 0;
g_Dialogue.unk3C = 1;
}
1 change: 0 additions & 1 deletion src/st/st0/cutscene.c
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,6 @@ static u8 SetCutsceneScript(u8* script) {
}

#include "../cutscene_unk3.h"

#include "../cutscene_unk4.h"

static const char* actor_names[] = {_S("Richter"), _S("Dracula")};
Expand Down
178 changes: 155 additions & 23 deletions src/st/st0_psp/cutscene.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,87 @@
#include <cutscene.h>

extern Dialogue g_Dialogue;
extern u8 D_pspeu_09253C08[];
extern u8 D_pspeu_09253DE0[];
extern u8 D_pspeu_09253CA0[];
extern u8 D_pspeu_09253E78[];
extern u8 D_pspeu_09253D48[];
extern u8 D_pspeu_09253B80[];
extern u8 D_pspeu_09253D58[];
extern u8 D_pspeu_09253C18[];
extern u8 D_pspeu_09253DF0[];
extern u8 D_pspeu_09253CB0[];
// clang-format off
static u16 actor_names_en[] = {
CH('R'), CH('i'), CH('c'), CH('h'), CH('t'), CH('e'), CH('r'),
CH('D'), CH('r'), CH('a'), CH('c'), CH('u'), CH('l'), CH('a'),
CH('D'), CH('e'), CH('a'), CH('t'), CH('h'),
CH('A'), CH('l'), CH('u'), CH('c'), CH('a'), CH('r'), CH('d'),
CH('M'), CH('a'), CH('r'), CH('i'), CH('a'),
CH('L'), CH('i'), CH('b'), CH('r'), CH('a'), CH('r'), CH('i'), CH('a'), CH('n'),
CH('L'), CH('i'), CH('s'), CH('a'),
CH('S'), CH('u'), CH('c'), CH('c'), CH('u'), CH('b'), CH('u'), CH('s'),
CH('F'), CH('e'), CH('r'), CH('r'), CH('y'), CH('m'), CH('a'), CH('n'),
CH('S'), CH('h'), CH('a'), CH('f'), CH('t')};
static u8 actor_name_len_en[] = {7, 7, 5, 7, 5, 9, 4, 8, 8, 5};

static u16 actor_names_sp[] = {
CH('R'), CH('i'), CH('c'), CH('h'), CH('t'), CH('e'), CH('r'),
CH('D'), CH('r'), CH('a'), CH('c'), CH('u'), CH('l'), CH('a'),
CH('D'), CH('e'), CH('a'), CH('t'), CH('h'),
CH('A'), CH('l'), CH('u'), CH('c'), CH('a'), CH('r'), CH('d'),
CH('M'), CH('a'), CH('r'), CH('i'), CH('a'),
CH('B'), CH('i'), CH('b'), CH('l'), CH('i'), CH('o'), CH('t'), CH('e'), CH('c'), CH('a'), CH('r'), CH('i'), CH('o'),
CH('L'), CH('i'), CH('s'), CH('a'),
CH('S'), 0xAC, CH('c'), CH('u'), CH('b'), CH('o'),
CH('B'), CH('a'), CH('r'), CH('q'), CH('u'), CH('e'), CH('r'), CH('o'),
CH('S'), CH('h'), CH('a'), CH('f'), CH('t')};
static u8 actor_name_len_sp[] = {7, 7, 5, 7, 5, 13, 4, 6, 8, 5};

static u16 actor_names_it[] = {
CH('R'), CH('i'), CH('c'), CH('h'), CH('t'), CH('e'), CH('r'),
CH('D'), CH('r'), CH('a'), CH('c'), CH('u'), CH('l'), CH('a'),
CH('D'), CH('e'), CH('a'), CH('t'), CH('h'),
CH('A'), CH('l'), CH('u'), CH('c'), CH('a'), CH('r'), CH('d'),
CH('M'), CH('a'), CH('r'), CH('i'), CH('a'),
CH('B'), CH('i'), CH('b'), CH('l'), CH('i'), CH('o'), CH('t'), CH('e'), CH('c'), CH('a'), CH('r'), CH('i'), CH('o'),
CH('L'), CH('i'), CH('s'), CH('a'),
CH('S'), CH('u'), CH('c'), CH('c'), CH('u'), CH('b'), CH('u'), CH('s'),
CH('T'), CH('r'), CH('a'), CH('g'), CH('h'), CH('e'), CH('t'), CH('t'), CH('a'), CH('t'), CH('o'), CH('r'), CH('e'),
CH('S'), CH('h'), CH('a'), CH('f'), CH('t')};
static u8 actor_name_len_it[] = {7, 7, 5, 7, 5, 13, 4, 8, 13, 5};

static u16 actor_names_fr[] = {
CH('R'), CH('i'), CH('c'), CH('h'), CH('t'), CH('e'), CH('r'),
CH('D'), CH('r'), CH('a'), CH('c'), CH('u'), CH('l'), CH('a'),
CH('D'), CH('e'), CH('a'), CH('t'), CH('h'),
CH('A'), CH('l'), CH('u'), CH('c'), CH('a'), CH('r'), CH('d'),
CH('M'), CH('a'), CH('r'), CH('i'), CH('a'),
CH('B'), CH('i'), CH('b'), CH('l'), CH('i'), CH('o'), CH('t'), CH('h'), 0xA0, CH('c'), CH('a'), CH('i'), CH('r'), CH('e'),
CH('L'), CH('i'), CH('s'), CH('a'),
CH('S'), CH('u'), CH('c'), CH('c'), CH('u'), CH('b'), CH('e'),
CH('P'), CH('a'), CH('s'), CH('s'), CH('e'), CH('u'), CH('r'),
CH('S'), CH('h'), CH('a'), CH('f'), CH('t')};
static u8 actor_name_len_fr[] = {7, 7, 5, 7, 5, 14, 4, 7, 7, 5};

static u16 actor_names_ge[] = {
CH('R'), CH('i'), CH('c'), CH('h'), CH('t'), CH('e'), CH('r'),
CH('D'), CH('r'), CH('a'), CH('c'), CH('u'), CH('l'), CH('a'),
CH('D'), CH('e'), CH('a'), CH('t'), CH('h'),
CH('A'), CH('l'), CH('u'), CH('c'), CH('a'), CH('r'), CH('d'),
CH('M'), CH('a'), CH('r'), CH('i'), CH('a'),
CH('B'), CH('i'), CH('b'), CH('l'), CH('i'), CH('o'), CH('t'), CH('h'), CH('e'), CH('k'), CH('a'), CH('r'),
CH('L'), CH('i'), CH('s'), CH('a'),
CH('S'), CH('u'), CH('k'), CH('k'), CH('u'), CH('b'), CH('u'), CH('s'),
CH('F'), 0x9D, CH('h'), CH('r'), CH('m'), CH('a'), CH('n'), CH('n'),
CH('S'), CH('h'), CH('a'), CH('f'), CH('t')};
static u8 actor_name_len_ge[] = {7, 7, 5, 7, 5, 12, 4, 8, 8, 5};
// clang-format on

static u8 D_80180784[] = {0, 64, 0, 0};
static u8 D_80180788[] = {0, 0, 0, 0};
static u16 D_8018078C[] = {0x230, 0x248};
static u16 D_80180790[] = {0, 32};
static u16 D_80180794[] = {0x1A1, 0x1A1};
static s16 D_80180798[] = {
0x8, 0x13, 0x11, 0x31, 0x4F, 0x26, 0x36, 0x1D, 0x1B, 0x33, 0x2C, 0x21,
0x19, 0xA, 0x33, 0x1F, 0x48, 0x2F, 0x13, 0x19, 0x4D, 0x4B, 0x17, 0x1D,
0x12, 0x2, 0x1B, 0x2A, 0x50, 0x45, 0x32, 0xD, 0x2A, 0x4D, 0x6, 0x27,
0x7, 0x48, 0x2F, 0x1B, 0x36, 0x22, 0x39, 0x14, 0x39, 0x1D, 0xA, 0x35,
0x10, 0x1B, 0x3D, 0x17, 0x2E, 0xB, 0x49, 0x42, 0x3D, 0x2A, 0x1, 0xC,
0x1B, 0x34, 0x41, 0x35, 0x8, 0xE, 0x4D, 0x11, 0x34, 0x41, 0x29, 0x48};
s32 D_pspeu_09253F38[] = {0x100, 0};
s32 D_pspeu_09253F40[] = {0x100, 0};

void DrawCutsceneActorName(u16 actorIndex, Entity* self, u16* actorNames,
u8* arg3, s32* arg4, s32 nActors) {
Expand All @@ -28,8 +99,8 @@ void DrawCutsceneActorName(u16 actorIndex, Entity* self, u16* actorNames,

// Create a certain amount of sprites based on the actor name's letter count
actorNameLength =
(u8*)GetLang(D_pspeu_09253C08, D_pspeu_09253DE0, D_pspeu_09253CA0,
D_pspeu_09253E78, D_pspeu_09253D48);
(u8*)GetLang(actor_name_len_en, actor_name_len_fr, actor_name_len_sp,
actor_name_len_ge, actor_name_len_it);
ch = actorNameLength[arg3[actorIndex]];
primIndex = g_api.AllocPrimitives(PRIM_SPRT, ch);
if (primIndex == -1) {
Expand All @@ -39,23 +110,23 @@ void DrawCutsceneActorName(u16 actorIndex, Entity* self, u16* actorNames,

// Pre-calculate primitives that renders the actor's name
x = 0x38;
g_Dialogue.primIndex[0] = primIndex;
g_Dialogue.primIndex[1] = primIndex;
prim = &g_PrimBuf[primIndex];
len = actorNameLength;
actorNameStartIndex = 0;
for (i = 0; i < arg3[actorIndex]; i++) {
actorNameStartIndex += actorNameLength[i];
}
actorNames =
(u16*)GetLang(D_pspeu_09253B80, D_pspeu_09253D58, D_pspeu_09253C18,
D_pspeu_09253DF0, D_pspeu_09253CB0);
actorNames = (u16*)GetLang(
(u8*)actor_names_en, (u8*)actor_names_fr, (u8*)actor_names_sp,
(u8*)actor_names_ge, (u8*)actor_names_it);
actorName = (u16*)(actorNames + actorNameStartIndex);
while (prim) {
prim->type = PRIM_SPRT;
prim->tpage = 0x1E;
prim->clut = 0x196;
ch = *actorName++;
prim->u0 = (s8)((ch & 0x0F) * FONT_W);
prim->u0 = (s8)((ch & 0xF) * FONT_W);
prim->v0 = (s8)((ch & 0xF0) >> 1);
prim->u1 = prim->v1 = FONT_W;
prim->priority = 0x1FF;
Expand Down Expand Up @@ -84,16 +155,77 @@ void DrawCutsceneActorName(u16 actorIndex, Entity* self, u16* actorNames,
}
}

INCLUDE_ASM("st/st0_psp/psp/st0_psp/cutscene", func_pspeu_09238F10);
#include "../cutscene_unk3.h"
#include "../cutscene_unk4.h"

static void CutsceneUnk1(void) {
g_Dialogue.nextLineY = g_Dialogue.startY + 0x14;
g_Dialogue.nextCharX = g_Dialogue.nextLineX = 0;
g_Dialogue.nextCharY = 0;
g_Dialogue.unk12 = 0;
g_Dialogue.nextCharTimer = 0;
g_Dialogue.unk17 = 2;
}

static u8 SetCutsceneScript(u8* script) {
Primitive* prim;
g_Dialogue.primIndex[2] = g_api.AllocPrimitives(PRIM_SPRT, 7);
if (g_Dialogue.primIndex[2] != -1) {
g_Dialogue.scriptCur = script;
g_Dialogue.unk3C = 0;
g_Dialogue.primIndex[1] = -1;
g_Dialogue.primIndex[0] = -1;
CutsceneUnk1();

prim = &g_PrimBuf[g_Dialogue.primIndex[2]];
g_Dialogue.prim[0] = prim;
prim->drawMode = DRAW_HIDE;
prim = prim->next;

g_Dialogue.prim[1] = prim;
prim->drawMode = DRAW_HIDE;
prim = prim->next;

g_Dialogue.prim[2] = prim;
prim->drawMode = DRAW_HIDE;
prim = prim->next;

g_Dialogue.prim[3] = prim;
prim->drawMode = DRAW_HIDE;
prim = prim->next;

INCLUDE_ASM("st/st0_psp/psp/st0_psp/cutscene", func_pspeu_09238F90);
g_Dialogue.prim[4] = prim;
prim->type = PRIM_GT4;
prim->drawMode = DRAW_HIDE;
prim = prim->next;

INCLUDE_ASM("st/st0_psp/psp/st0_psp/cutscene", func_pspeu_09239060);
prim->type = PRIM_G4;
prim->r0 = prim->r1 = prim->r2 = prim->r3 = 0xFF;
prim->g0 = prim->g1 = prim->g2 = prim->g3 = 0;
prim->b0 = prim->b1 = prim->b2 = prim->b3 = 0;
prim->x0 = prim->x2 = 4;
prim->x1 = prim->x3 = 0xF8;
prim->priority = 0x1FD;
prim->drawMode = DRAW_HIDE;
prim = prim->next;

INCLUDE_ASM("st/st0_psp/psp/st0_psp/cutscene", func_pspeu_092390C0);
prim->type = PRIM_TILE;
prim->r0 = prim->g0 = prim->b0 = 0xFF;
prim->x0 = 3;
prim->y0 = 0x2F;
prim->v0 = 0x4A;
prim->priority = 0x1FC;
prim->drawMode = DRAW_HIDE;
return 1;
}
g_Dialogue.primIndex[2] = 0;
return 0;
}

INCLUDE_ASM("st/st0_psp/psp/st0_psp/cutscene", func_pspeu_092392D0);
#include "../set_cutscene_end.h"

INCLUDE_ASM("st/st0_psp/psp/st0_psp/cutscene", func_pspeu_09239308);
extern PfnEntityUpdate OVL_EXPORT(EntityUpdates)[];
#define PfnEntityUpdates OVL_EXPORT(EntityUpdates)
#include "../cutscene_run.h"

INCLUDE_ASM("st/st0_psp/psp/st0_psp/cutscene", ST0_EntityCutscene);

0 comments on commit 17e6aa4

Please sign in to comment.