mirror of
https://github.com/Xeeynamo/sotn-decomp.git
synced 2024-11-23 04:59:41 +00:00
CEN cutscene parser (#1680)
`CutsceneUnk2` uses 8 prims but only 7 are allocated. It looks like at some point the game writes to the address `0x00000000` but I did not confirm it with a PS1 debugger. This is a potential bug. `CutsceneUnk2` signature was also wrong. I had to get rid of `GfxBank` in `src/st/cen/header.c` and I probably need to do the same for the other header files. The code reads chunks of WORDS at the time and a structure would be too large to include `GFX_TERMINATE` in it. CEN is there but not linked because it conflicts with some WRP symbols. I decided to take a much simpler approach compared to what I did with WRP (which needs to be refactored later on). There's a cutscene parser. The asset manager is exporting it to `src/st/cen/cutscene_data.h` if you want to have a look. I know I am still using `config/assets.us.weapon.yaml` and it probably needs to be renamed as `config/assets.us.yaml` later on. I am still deciding.
This commit is contained in:
parent
854683e40c
commit
807375d669
@ -256,6 +256,40 @@ set(SOURCE_FILES_STAGE_SEL
|
||||
src/st/sel/3642C.c
|
||||
)
|
||||
|
||||
set(SOURCE_FILES_STAGE_CEN
|
||||
src/pc/stages/stage_cen.c
|
||||
src/st/cen/header.c
|
||||
src/st/cen/e_laydef.c
|
||||
src/st/cen/e_init.c
|
||||
src/st/cen/rooms.c
|
||||
src/st/cen/e_layout.c
|
||||
src/st/cen/cutscene_data.c
|
||||
src/st/cen/tile_data.c
|
||||
src/st/cen/sprites.c
|
||||
src/st/cen/st_debug.c
|
||||
src/st/cen/e_breakable.c
|
||||
src/st/cen/DB18.c
|
||||
src/st/cen/holyglassescutscene.c
|
||||
src/st/cen/F890.c
|
||||
src/st/cen/st_update.c
|
||||
src/st/cen/collision.c
|
||||
src/st/cen/create_entity.c
|
||||
src/st/cen/e_red_door.c
|
||||
src/st/cen/st_common.c
|
||||
src/st/cen/e_collect.c
|
||||
src/st/cen/blit_char.c
|
||||
src/st/cen/e_misc.c
|
||||
src/st/cen/e_stage_name.c
|
||||
src/st/cen/e_particles.c
|
||||
src/st/cen/e_room_fg.c
|
||||
src/st/cen/popup.c
|
||||
src/st/cen/prim_helpers.c
|
||||
src/st/cen/header.c
|
||||
src/st/cen/create_entity.c
|
||||
src/st/cen/holyglassescutscene.c
|
||||
src/st/cen/e_collect.c
|
||||
)
|
||||
|
||||
set(SOURCE_FILES_STAGE_WRP
|
||||
src/pc/stages/stage_wrp.c
|
||||
src/st/wrp/d_1b8.c
|
||||
|
@ -1,4 +1,13 @@
|
||||
files:
|
||||
- target: disks/us/ST/CEN/CEN.BIN
|
||||
asset_path: assets/st/cen
|
||||
src_path: src/st/cen
|
||||
segments:
|
||||
- start: 0
|
||||
vram: 0x80180000
|
||||
assets:
|
||||
- [0x13F0, cutscene, cutscene_data]
|
||||
- [0x1658, skip]
|
||||
- target: disks/us/BIN/WEAPON0.BIN
|
||||
asset_path: assets/weapon
|
||||
src_path: src/weapon
|
||||
|
@ -54,7 +54,16 @@ segments:
|
||||
- [0x1248, .data, e_room_fg]
|
||||
- [0x12D4, .data, rooms]
|
||||
- [0x1300, .data, e_layout] # layout entries data
|
||||
- [0x13F0, data]
|
||||
- [0x13F0, .data, cutscene_data]
|
||||
- [0x1658, cmp, D_80181658]
|
||||
- [0x199C, cmp, D_8018199C]
|
||||
- [0x3A40, cmp, D_80183A40]
|
||||
- [0x4B70, cmp, D_80184B70]
|
||||
- [0x5830, cmp, D_80185830]
|
||||
- [0x658C, raw, D_8018658C]
|
||||
- [0x678C, raw, D_8018678C]
|
||||
- [0x698C, raw, D_8018698C]
|
||||
- [0x69AC, raw, D_801869AC]
|
||||
- [0x69EC, .data, tile_data] # tile data
|
||||
- [0x81EC, .data, tile_data] # tile definitions
|
||||
- [0xC60C, .data, sprites]
|
||||
|
35
include/cutscene.h
Normal file
35
include/cutscene.h
Normal file
@ -0,0 +1,35 @@
|
||||
#include <game.h>
|
||||
|
||||
typedef enum {
|
||||
CSOP_END_CUTSCENE,
|
||||
CSOP_LINE_BREAK,
|
||||
CSOP_SET_SPEED,
|
||||
CSOP_SET_WAIT,
|
||||
CSOP_SET_PORTRAIT = 5,
|
||||
CSOP_NEXT_DIALOG,
|
||||
CSOP_SET_POS,
|
||||
CSOP_CLOSE_DIALOG,
|
||||
CSOP_PLAY_SOUND,
|
||||
CSOP_WAIT_FOR_SOUND,
|
||||
CSOP_UNK_11,
|
||||
CSOP_WAIT_FOR_FLAG = 16,
|
||||
CSOP_SET_FLAG,
|
||||
CSOP_LOAD_PORTRAIT = 19,
|
||||
CSOP_SCRIPT_UNKNOWN_20,
|
||||
} CutsceneOpcode;
|
||||
|
||||
#define END_CUTSCENE() CSOP_END_CUTSCENE
|
||||
#define LINE_BREAK() CSOP_LINE_BREAK
|
||||
#define SET_SPEED(x) CSOP_SET_SPEED, x
|
||||
#define SET_WAIT(x) CSOP_SET_WAIT, x
|
||||
#define SET_PORTRAIT(clut, side) CSOP_SET_PORTRAIT, clut, !!side
|
||||
#define NEXT_DIALOG() CSOP_NEXT_DIALOG
|
||||
#define SET_POS(x, y) CSOP_SET_POS, x, y
|
||||
#define CLOSE_DIALOG() CSOP_CLOSE_DIALOG
|
||||
#define PLAY_SOUND(x, y) CSOP_PLAY_SOUND, x, y
|
||||
#define WAIT_FOR_SOUND() CSOP_WAIT_FOR_SOUND
|
||||
#define SCRIPT_UNKNOWN_11() CSOP_UNK_11
|
||||
#define WAIT_FOR_FLAG(x) CSOP_WAIT_FOR_FLAG, x
|
||||
#define SET_FLAG(x) CSOP_SET_FLAG, x
|
||||
#define LOAD_PORTRAIT(a, b, c, d, e) CSOP_LOAD_PORTRAIT, a, b, c, d, e
|
||||
#define SCRIPT_UNKNOWN_20(x, y) CSOP_SCRIPT_UNKNOWN_20, x, y
|
@ -7,7 +7,7 @@ extern Dialogue g_Dialogue;
|
||||
|
||||
#include "../../st/cutscene_unk1.h"
|
||||
|
||||
#include "../../st/cutscene_unk2.h"
|
||||
#include "../../st/set_cutscene_script.h"
|
||||
|
||||
#include "../../st/cutscene_unk3.h"
|
||||
|
||||
@ -77,7 +77,7 @@ void EntityMariaCutscene(Entity* self) {
|
||||
DestroyEntity(self);
|
||||
return;
|
||||
}
|
||||
if (CutsceneUnk2(D_us_80181424) & 0xFF) {
|
||||
if (SetCutsceneScript(D_us_80181424) & 0xFF) {
|
||||
self->flags |= FLAG_HAS_PRIMS | FLAG_UNK_2000;
|
||||
g_CutsceneFlags = 0;
|
||||
D_us_8019AF2C = 0;
|
||||
|
@ -1293,8 +1293,8 @@ block_160:
|
||||
void func_8010BF64(Unkstruct_8010BF64* arg0) {
|
||||
if (g_PlayableCharacter == PLAYER_ALUCARD) {
|
||||
u32 unk0C_var = (g_Player.unk0C / 2) & 2;
|
||||
arg0->unk14 = D_800ACED0[4].x - unk0C_var;
|
||||
arg0->unk1C = D_800ACED0[4].y + unk0C_var;
|
||||
arg0->unk14 = D_800ACEE0[0].x - unk0C_var;
|
||||
arg0->unk1C = D_800ACEE0[0].y + unk0C_var;
|
||||
arg0->unk18 = D_800ACED0[1].y - 1;
|
||||
arg0->unk20 = D_800ACEC0[1].y + 1;
|
||||
} else {
|
||||
|
@ -182,6 +182,7 @@ void LoadStageTileset(u8* pTilesetData, size_t len, s32 y) {
|
||||
}
|
||||
|
||||
void InitStageDummy(Overlay* o);
|
||||
void InitStageCEN(Overlay* o);
|
||||
void InitStageWrp(Overlay* o);
|
||||
void InitStageSel(Overlay* o);
|
||||
void InitPlayerArc(const struct FileUseContent* file);
|
||||
|
@ -50,20 +50,33 @@ u8 D_800C4A90[MAX_SIZE_FOR_COMPRESSED_GFX];
|
||||
// list of exposed API
|
||||
void FreePrimitives(s32 index);
|
||||
s32 AllocPrimitives(u8 primType, s32 count);
|
||||
void func_80102CD8(s32 start);
|
||||
void SetSpeedX(s32 speed);
|
||||
Entity* GetFreeEntity(s16 start, s16 end);
|
||||
void GetEquipProperties(s32 handId, Equipment* res, s32 equipId);
|
||||
s32 func_800EA5E4(u32);
|
||||
void LoadGfxAsync(s32 gfxId);
|
||||
void PlaySfx(s16 sfxId);
|
||||
void func_800EA538(s32 arg0);
|
||||
void func_800EA5AC(u16 arg0, u8 arg1, u8 arg2, u8 arg3);
|
||||
void func_801027C4(u32 arg0);
|
||||
void func_800EB758(s16 px, s16 py, Entity* e, u8 flags, POLY_GT4* p, u8 flipX);
|
||||
bool func_80131F68(void);
|
||||
DR_ENV* func_800EDB08(Primitive* prim);
|
||||
u16* func_80106A28(u32 arg0, u16 kind);
|
||||
void func_80118894(Entity* self);
|
||||
Entity* func_80118970(void);
|
||||
s16 func_80118B18(Entity* ent1, Entity* ent2, s16 facingLeft);
|
||||
u32 UpdateUnarmedAnim(s8* frameProps, u16** frames);
|
||||
void PlayAnimation(s8* frameProps, AnimationFrame** frames);
|
||||
void func_80118C28(s32 arg0);
|
||||
void func_8010E168(s32 arg0, s16 arg1);
|
||||
void func_8010DFF0(s32 arg0, s32 arg1);
|
||||
void LoadEquipIcon(s32 equipIcon, s32 palette, s32 index);
|
||||
void AddToInventory(u16 itemId, s32 itemCategory);
|
||||
u32 PlaySfxVolPan(s16 sfxId, s32 sfxVol, u16 sfxPan);
|
||||
u32 CheckEquipmentItemCount(u32 itemId, u32 equipType);
|
||||
void func_8010BF64(Unkstruct_8010BF64* arg0);
|
||||
void func_800F2288(s32 arg0);
|
||||
bool CalcPlayerDamage(DamageParam* damage);
|
||||
void DebugInputWait(const char* msg);
|
||||
@ -98,8 +111,6 @@ static bool InitBlueprintData(struct FileAsString* file);
|
||||
|
||||
s32 func_800EDB58(u8 primType, s32 count);
|
||||
|
||||
void func_801027C4(u32 arg0);
|
||||
|
||||
bool InitGame(void) {
|
||||
if (!InitPlatform()) {
|
||||
return false;
|
||||
@ -110,11 +121,11 @@ bool InitGame(void) {
|
||||
api.FreePrimitives = FreePrimitives;
|
||||
api.AllocPrimitives = AllocPrimitives;
|
||||
api.CheckCollision = CheckCollision;
|
||||
api.func_80102CD8 = NULL;
|
||||
api.func_80102CD8 = func_80102CD8;
|
||||
api.UpdateAnim = UpdateAnim;
|
||||
api.SetSpeedX = NULL;
|
||||
api.GetFreeEntity = NULL;
|
||||
api.GetEquipProperties = NULL;
|
||||
api.SetSpeedX = SetSpeedX;
|
||||
api.GetFreeEntity = GetFreeEntity;
|
||||
api.GetEquipProperties = GetEquipProperties;
|
||||
api.func_800EA5E4 = func_800EA5E4;
|
||||
api.LoadGfxAsync = LoadGfxAsync;
|
||||
api.PlaySfx = PlaySfx;
|
||||
@ -122,18 +133,18 @@ bool InitGame(void) {
|
||||
api.func_800EA538 = func_800EA538;
|
||||
api.g_pfn_800EA5AC = func_800EA5AC;
|
||||
api.func_801027C4 = func_801027C4;
|
||||
api.func_800EB758 = NULL;
|
||||
api.func_800EB758 = func_800EB758;
|
||||
api.CreateEntFactoryFromEntity = CreateEntFactoryFromEntity;
|
||||
api.func_80131F68 = func_80131F68;
|
||||
api.func_800EDB08 = NULL;
|
||||
api.func_800EDB08 = func_800EDB08;
|
||||
api.func_80106A28 = func_80106A28;
|
||||
api.func_80118894 = NULL;
|
||||
api.func_80118894 = func_80118894;
|
||||
api.enemyDefs = g_EnemyDefs;
|
||||
api.func_80118970 = NULL;
|
||||
api.func_80118B18 = NULL;
|
||||
api.UpdateUnarmedAnim = NULL;
|
||||
api.func_80118970 = func_80118970;
|
||||
api.func_80118B18 = func_80118B18;
|
||||
api.UpdateUnarmedAnim = UpdateUnarmedAnim;
|
||||
api.PlayAnimation = PlayAnimation;
|
||||
api.func_80118C28 = NULL;
|
||||
api.func_80118C28 = func_80118C28;
|
||||
api.func_8010E168 = func_8010E168;
|
||||
api.func_8010DFF0 = func_8010DFF0;
|
||||
api.DealDamage = NULL;
|
||||
@ -152,7 +163,7 @@ bool InitGame(void) {
|
||||
api.SetVolumeCommand22_23 = NULL;
|
||||
api.func_800F53A4 = NULL;
|
||||
api.CheckEquipmentItemCount = CheckEquipmentItemCount;
|
||||
api.func_8010BF64 = NULL;
|
||||
api.func_8010BF64 = func_8010BF64;
|
||||
api.func_800F1FC4 = NULL;
|
||||
api.func_800F2288 = func_800F2288;
|
||||
api.func_8011A3AC = func_8011A3AC;
|
||||
|
32
src/pc/stages/stage_cen.c
Normal file
32
src/pc/stages/stage_cen.c
Normal file
@ -0,0 +1,32 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
#include <game.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "stage_loader.h"
|
||||
|
||||
extern Overlay CEN_Overlay;
|
||||
|
||||
u16 D_8018658C[0x80];
|
||||
u16 D_8018678C[0x80];
|
||||
u16 D_8018698C[0x10];
|
||||
u16 D_801869AC[0x20];
|
||||
u8 D_80183A40[4400];
|
||||
u8 D_80184B70[3264];
|
||||
u8 D_80181658[836];
|
||||
u8 D_8018199C[8356];
|
||||
u8 D_80185830[3420];
|
||||
|
||||
void InitStageCEN(Overlay* o) {
|
||||
LoadReset();
|
||||
LOAD_ASSET("assets/st/cen/D_8018658C.bin", D_8018658C);
|
||||
LOAD_ASSET("assets/st/cen/D_8018678C.bin", D_8018678C);
|
||||
LOAD_ASSET("assets/st/cen/D_8018698C.bin", D_8018698C);
|
||||
LOAD_ASSET("assets/st/cen/D_801869AC.bin", D_801869AC);
|
||||
LOAD_ASSET("assets/st/cen/D_80183A40.bin", D_80183A40);
|
||||
LOAD_ASSET("assets/st/cen/D_80184B70.bin", D_80184B70);
|
||||
LOAD_ASSET("assets/st/cen/D_80181658.bin", D_80181658);
|
||||
LOAD_ASSET("assets/st/cen/D_8018199C.bin", D_8018199C);
|
||||
LOAD_ASSET("assets/st/cen/D_80185830.bin", D_80185830);
|
||||
memcpy(o, &CEN_Overlay, sizeof(Overlay));
|
||||
}
|
@ -5,6 +5,8 @@
|
||||
#include "../pc.h"
|
||||
#include <stage.h>
|
||||
|
||||
#define LOAD_ASSET(path, dst) FileReadToBuf(path, dst, 0, sizeof(dst))
|
||||
|
||||
// load a rooms.layers.json file and all its dependencies to the returned
|
||||
// pre-allocated RoomDef array. Returns NULL in case of a failure.
|
||||
RoomDef* LoadRoomsLayers(const char* filePath);
|
||||
|
1
src/st/.gitignore
vendored
1
src/st/.gitignore
vendored
@ -6,3 +6,4 @@ layers.h
|
||||
sprite_banks.h
|
||||
tilemap_*.h
|
||||
tiledef_*.h
|
||||
cutscene_*.h
|
||||
|
@ -56,6 +56,7 @@ extern u16 g_InitializeData0[];
|
||||
extern u16 D_80180428[];
|
||||
extern u16 g_EInitGeneric[];
|
||||
extern u16 g_eInitGeneric2[];
|
||||
extern u16 g_InitializeEntityData0[];
|
||||
extern u16 D_8018047C[]; // EntityElevator
|
||||
|
||||
extern ObjInit g_eBackgroundBlockInit[];
|
||||
@ -72,10 +73,6 @@ extern u16 g_ESoulStealOrbAngles[];
|
||||
extern s16 g_ESoulStealOrbSprt[];
|
||||
extern u8 g_ESoulStealOrbAnim[];
|
||||
extern ObjInit D_8018125C[];
|
||||
|
||||
extern u16 g_InitializeEntityData0[];
|
||||
|
||||
// For EntityHolyGlassesCutscene
|
||||
extern const char D_801813F0[];
|
||||
extern u8 g_CutsceneScript[];
|
||||
|
||||
#endif
|
||||
|
6
src/st/cen/cutscene_data.c
Normal file
6
src/st/cen/cutscene_data.c
Normal file
@ -0,0 +1,6 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
#include <cutscene.h>
|
||||
|
||||
u8 g_CutsceneScript[] = {
|
||||
#include "cutscene_data.h"
|
||||
};
|
@ -2,9 +2,9 @@
|
||||
#include "cen.h"
|
||||
|
||||
extern RoomHeader OVL_EXPORT(rooms)[];
|
||||
extern signed short* spriteBanks[];
|
||||
extern void* Cluts[];
|
||||
extern MyRoomDef rooms_layers[];
|
||||
static signed short* spriteBanks[];
|
||||
static void* Cluts[];
|
||||
static MyRoomDef rooms_layers[];
|
||||
static GfxBank* gfxBanks[];
|
||||
void UpdateStageEntities();
|
||||
|
||||
@ -43,51 +43,36 @@ static void* Cluts[] = {
|
||||
|
||||
static u32 D_8019C704[24];
|
||||
|
||||
static GfxBank D_80180134 = {
|
||||
.kind = GFX_BANK_NONE,
|
||||
.entries =
|
||||
{
|
||||
static u_long* D_80180134[] = {
|
||||
GFX_BANK_NONE,
|
||||
GFX_ENTRY(0, 0, 0, 0, NULL),
|
||||
},
|
||||
GFX_TERMINATE(),
|
||||
};
|
||||
static u_long D_80180134_TERM = GFX_TERMINATE();
|
||||
|
||||
extern u_long* D_80183A40;
|
||||
extern u_long* D_80184B70;
|
||||
|
||||
static GfxBank D_80180148 = {
|
||||
.kind = GFX_BANK_COMPRESSED,
|
||||
.entries =
|
||||
{
|
||||
GFX_ENTRY(0x100, 0x80, 0x80, 0x80, &D_80183A40),
|
||||
GFX_ENTRY(0x100, 0xA0, 0x80, 0x80, &D_80184B70),
|
||||
},
|
||||
extern u8 D_80183A40[];
|
||||
extern u8 D_80184B70[];
|
||||
static u_long* D_80180148[] = {
|
||||
GFX_BANK_COMPRESSED,
|
||||
GFX_ENTRY(0x100, 0x80, 0x80, 0x80, D_80183A40),
|
||||
GFX_ENTRY(0x100, 0xA0, 0x80, 0x80, D_80184B70),
|
||||
GFX_TERMINATE(),
|
||||
};
|
||||
static u_long D_80180148_TERM = GFX_TERMINATE();
|
||||
|
||||
extern u_long* D_80181658;
|
||||
extern u_long* D_8018199C;
|
||||
|
||||
static GfxBank D_80180168 = {
|
||||
.kind = GFX_BANK_COMPRESSED,
|
||||
.entries =
|
||||
{
|
||||
GFX_ENTRY(0x100, 0x0040, 0x0080, 0x0080, &D_80181658),
|
||||
GFX_ENTRY(0x100, 0x60, 0x80, 0x80, &D_8018199C),
|
||||
},
|
||||
extern u8 D_80181658[];
|
||||
extern u8 D_8018199C[];
|
||||
static u_long* D_80180168[] = {
|
||||
GFX_BANK_COMPRESSED,
|
||||
GFX_ENTRY(0x100, 0x40, 0x80, 0x80, D_80181658),
|
||||
GFX_ENTRY(0x100, 0x60, 0x80, 0x80, D_8018199C),
|
||||
GFX_TERMINATE(),
|
||||
};
|
||||
static u_long D_80180168_TERM = GFX_TERMINATE();
|
||||
|
||||
extern u_long* D_80185830;
|
||||
|
||||
static GfxBank D_80180188 = {
|
||||
.kind = GFX_BANK_COMPRESSED,
|
||||
.entries =
|
||||
{
|
||||
GFX_ENTRY(0x100, 0x80, 0x80, 0x80, &D_80185830),
|
||||
},
|
||||
extern u8 D_80185830[];
|
||||
static u_long* D_80180188[] = {
|
||||
GFX_BANK_COMPRESSED,
|
||||
GFX_ENTRY(0x100, 0x80, 0x80, 0x80, D_80185830),
|
||||
GFX_TERMINATE(),
|
||||
};
|
||||
static u_long D_80180188_TERM = GFX_TERMINATE();
|
||||
|
||||
static GfxBank* gfxBanks[] = {
|
||||
&D_80180134, &D_80180148, &D_80180188, &D_80180134, &D_80180134,
|
||||
|
@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
#include "cen.h"
|
||||
#include "game.h"
|
||||
#include <cutscene.h>
|
||||
|
||||
static u8 __unused[0xC00];
|
||||
static s32 D_8019D374;
|
||||
@ -50,7 +50,7 @@ static const char _pad[4] = "";
|
||||
|
||||
#include "../cutscene_unk1.h"
|
||||
|
||||
#include "../cutscene_unk2.h"
|
||||
#include "../set_cutscene_script.h"
|
||||
|
||||
#include "../cutscene_unk3.h"
|
||||
|
||||
@ -124,7 +124,7 @@ void EntityHolyGlassesCutscene(Entity* self) {
|
||||
s16 vCoord;
|
||||
u16 nextChar;
|
||||
s32 nextChar2;
|
||||
s32 bit_shifty;
|
||||
u32 bit_shifty;
|
||||
|
||||
if (self->step != 0) {
|
||||
if ((D_8019D428 != 0) && (D_8019D374 == 0) &&
|
||||
@ -154,7 +154,7 @@ void EntityHolyGlassesCutscene(Entity* self) {
|
||||
DestroyEntity(self);
|
||||
return;
|
||||
}
|
||||
if (CutsceneUnk2(D_801813F0)) {
|
||||
if (SetCutsceneScript(g_CutsceneScript)) {
|
||||
self->flags |= FLAG_HAS_PRIMS | FLAG_UNK_2000;
|
||||
D_8003C704 = 1;
|
||||
g_CutsceneFlags = 0;
|
||||
@ -173,10 +173,10 @@ void EntityHolyGlassesCutscene(Entity* self) {
|
||||
}
|
||||
nextChar = *g_Dialogue.nextCharDialogue++;
|
||||
switch (nextChar) {
|
||||
case 0:
|
||||
case CSOP_END_CUTSCENE:
|
||||
self->step = 7;
|
||||
return;
|
||||
case 1:
|
||||
case CSOP_LINE_BREAK:
|
||||
if (D_8019D374 != 0) {
|
||||
continue;
|
||||
}
|
||||
@ -203,10 +203,10 @@ void EntityHolyGlassesCutscene(Entity* self) {
|
||||
self->step_s = 0;
|
||||
self->step++;
|
||||
return;
|
||||
case 2:
|
||||
case CSOP_SET_SPEED:
|
||||
g_Dialogue.unk17 = *g_Dialogue.nextCharDialogue++;
|
||||
continue;
|
||||
case 3:
|
||||
case CSOP_SET_WAIT:
|
||||
g_Dialogue.nextCharTimer = *g_Dialogue.nextCharDialogue++;
|
||||
if (D_8019D374 != 0) {
|
||||
continue;
|
||||
@ -222,7 +222,7 @@ void EntityHolyGlassesCutscene(Entity* self) {
|
||||
prim = prim->next;
|
||||
}
|
||||
return;
|
||||
case 5:
|
||||
case CSOP_SET_PORTRAIT:
|
||||
if (D_8019D374 != 0) {
|
||||
g_Dialogue.nextCharDialogue += 2;
|
||||
continue;
|
||||
@ -257,7 +257,7 @@ void EntityHolyGlassesCutscene(Entity* self) {
|
||||
g_Dialogue.portraitAnimTimer = 6;
|
||||
self->step = 3;
|
||||
return;
|
||||
case 6:
|
||||
case CSOP_NEXT_DIALOG:
|
||||
if (D_8019D374 != 0) {
|
||||
continue;
|
||||
}
|
||||
@ -270,7 +270,7 @@ void EntityHolyGlassesCutscene(Entity* self) {
|
||||
g_Dialogue.portraitAnimTimer = 6;
|
||||
self->step = 4;
|
||||
return;
|
||||
case 7:
|
||||
case CSOP_SET_POS:
|
||||
if (D_8019D374 != 0) {
|
||||
g_Dialogue.nextCharDialogue++;
|
||||
g_Dialogue.nextCharDialogue++;
|
||||
@ -289,15 +289,14 @@ void EntityHolyGlassesCutscene(Entity* self) {
|
||||
self->step = 5;
|
||||
self->step_s = 0;
|
||||
return;
|
||||
|
||||
case 8:
|
||||
case CSOP_CLOSE_DIALOG:
|
||||
if (D_8019D374 != 0) {
|
||||
continue;
|
||||
}
|
||||
g_Dialogue.portraitAnimTimer = 0x18;
|
||||
self->step = 6;
|
||||
return;
|
||||
case 9:
|
||||
case CSOP_PLAY_SOUND:
|
||||
if (D_8019D374 != 0) {
|
||||
g_Dialogue.nextCharDialogue++;
|
||||
g_Dialogue.nextCharDialogue++;
|
||||
@ -308,7 +307,7 @@ void EntityHolyGlassesCutscene(Entity* self) {
|
||||
nextChar |= *g_Dialogue.nextCharDialogue++;
|
||||
g_api.PlaySfx(nextChar);
|
||||
continue;
|
||||
case 10:
|
||||
case CSOP_WAIT_FOR_SOUND:
|
||||
if (D_8019D374 != 0) {
|
||||
continue;
|
||||
}
|
||||
@ -317,7 +316,7 @@ void EntityHolyGlassesCutscene(Entity* self) {
|
||||
}
|
||||
*g_Dialogue.nextCharDialogue--;
|
||||
return;
|
||||
case 11:
|
||||
case CSOP_UNK_11:
|
||||
if (D_8019D374 != 0) {
|
||||
continue;
|
||||
}
|
||||
@ -358,7 +357,6 @@ void EntityHolyGlassesCutscene(Entity* self) {
|
||||
bit_shifty |= (s32)*g_Dialogue.nextCharDialogue;
|
||||
g_Dialogue.nextCharDialogue = (u8*)bit_shifty + 0x100000;
|
||||
continue;
|
||||
|
||||
case 15:
|
||||
bit_shifty = (s32)*g_Dialogue.nextCharDialogue++;
|
||||
bit_shifty <<= 4;
|
||||
@ -369,8 +367,7 @@ void EntityHolyGlassesCutscene(Entity* self) {
|
||||
bit_shifty |= (s32)*g_Dialogue.nextCharDialogue;
|
||||
g_Dialogue.nextCharDialogue = (u8*)bit_shifty + 0x100000;
|
||||
continue;
|
||||
|
||||
case 16:
|
||||
case CSOP_WAIT_FOR_FLAG:
|
||||
if (!((g_CutsceneFlags >> *g_Dialogue.nextCharDialogue) & 1)) {
|
||||
g_Dialogue.nextCharDialogue--;
|
||||
return;
|
||||
@ -384,7 +381,7 @@ void EntityHolyGlassesCutscene(Entity* self) {
|
||||
case 18:
|
||||
g_Dialogue.unk3C = 0;
|
||||
continue;
|
||||
case 19:
|
||||
case CSOP_LOAD_PORTRAIT:
|
||||
if (D_8019D374 != 0) {
|
||||
g_Dialogue.nextCharDialogue += 5;
|
||||
} else {
|
||||
@ -397,11 +394,11 @@ void EntityHolyGlassesCutscene(Entity* self) {
|
||||
bit_shifty |= (s32)*g_Dialogue.nextCharDialogue++;
|
||||
bit_shifty += 0x100000;
|
||||
nextChar2 = g_Dialogue.nextCharDialogue++[0];
|
||||
LoadTPage((u32*)bit_shifty, 1, 0, D_801805E8[nextChar2],
|
||||
LoadTPage((u_long*)bit_shifty, 1, 0, D_801805E8[nextChar2],
|
||||
0x100, 0x30, 0x48);
|
||||
}
|
||||
continue;
|
||||
case 20:
|
||||
case CSOP_SCRIPT_UNKNOWN_20:
|
||||
nextChar = *g_Dialogue.nextCharDialogue++;
|
||||
nextChar <<= 4;
|
||||
nextChar |= *g_Dialogue.nextCharDialogue++;
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
#include "../cutscene_unk1.h"
|
||||
|
||||
#include "../cutscene_unk2.h"
|
||||
#include "../set_cutscene_script.h"
|
||||
|
||||
#include "../cutscene_unk3.h"
|
||||
|
||||
@ -132,9 +132,9 @@ void EntitySuccubusCutscene(Entity* self) {
|
||||
}
|
||||
}
|
||||
if (self->params) {
|
||||
bit_shifty = CutsceneUnk2(D_80181B65);
|
||||
bit_shifty = SetCutsceneScript(D_80181B65);
|
||||
} else {
|
||||
bit_shifty = CutsceneUnk2(D_801816C8);
|
||||
bit_shifty = SetCutsceneScript(D_801816C8);
|
||||
}
|
||||
if (bit_shifty) {
|
||||
self->flags |= FLAG_HAS_PRIMS | FLAG_UNK_2000;
|
||||
|
@ -12,7 +12,7 @@ void CutsceneUnk1(void) {
|
||||
g_Dialogue.nextLineY = g_Dialogue.startY + 0x14;
|
||||
}
|
||||
|
||||
#include "../cutscene_unk2.h"
|
||||
#include "../set_cutscene_script.h"
|
||||
|
||||
void CutsceneUnk3(s16 yOffset) {
|
||||
RECT rect;
|
||||
@ -98,7 +98,7 @@ void EntityDeathCutscene(Entity* self) {
|
||||
return;
|
||||
}
|
||||
g_Entities[192].params = 0x100;
|
||||
if (CutsceneUnk2(D_80184CE0)) {
|
||||
if (SetCutsceneScript(D_80184CE0)) {
|
||||
self->flags |= FLAG_HAS_PRIMS | FLAG_UNK_2000;
|
||||
g_CutsceneFlags = 0;
|
||||
D_801D7DD4 = 0;
|
||||
|
@ -7,7 +7,7 @@
|
||||
|
||||
#include "../cutscene_unk1.h"
|
||||
|
||||
#include "../cutscene_unk2.h"
|
||||
#include "../set_cutscene_script.h"
|
||||
|
||||
#include "../cutscene_unk3.h"
|
||||
|
||||
@ -63,7 +63,7 @@ void EntityMariaCutscene(Entity* self) {
|
||||
DestroyEntity(self);
|
||||
return;
|
||||
}
|
||||
if (CutsceneUnk2(D_80183B0C)) {
|
||||
if (SetCutsceneScript(D_80183B0C)) {
|
||||
self->flags |= FLAG_HAS_PRIMS | FLAG_UNK_2000;
|
||||
g_CutsceneFlags = 0;
|
||||
D_801CB73C = 0;
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
#include "../cutscene_unk1.h"
|
||||
|
||||
u8 CutsceneUnk2(const char* textDialogue) {
|
||||
u8 SetCutsceneScript(const char* textDialogue) {
|
||||
Primitive* prim;
|
||||
s16 firstPrimIndex;
|
||||
|
||||
@ -160,7 +160,7 @@ void func_801B69F8(Entity* entity) {
|
||||
|
||||
switch (entity->step) {
|
||||
case 0:
|
||||
if (CutsceneUnk2(D_8018B304)) {
|
||||
if (SetCutsceneScript(D_8018B304)) {
|
||||
D_801BC350 = D_801D6B00 = D_801BC3E8 = 0;
|
||||
D_8003C704 = 1;
|
||||
entity->flags |= FLAG_HAS_PRIMS | FLAG_UNK_2000;
|
||||
|
@ -1,15 +1,21 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
u8 CutsceneUnk2(s32 textDialogue) {
|
||||
u8 SetCutsceneScript(const char* script) {
|
||||
Primitive* prim;
|
||||
s16 firstPrimIndex;
|
||||
|
||||
firstPrimIndex = g_api.AllocPrimitives(PRIM_SPRT, 7);
|
||||
firstPrimIndex = g_api.AllocPrimitives(PRIM_SPRT,
|
||||
#if defined(VERSION_PC)
|
||||
8
|
||||
#else
|
||||
7
|
||||
#endif
|
||||
);
|
||||
g_Dialogue.primIndex[2] = firstPrimIndex;
|
||||
if (firstPrimIndex == -1) {
|
||||
g_Dialogue.primIndex[2] = 0;
|
||||
return 0;
|
||||
}
|
||||
g_Dialogue.nextCharDialogue = textDialogue;
|
||||
g_Dialogue.nextCharDialogue = script;
|
||||
g_Dialogue.unk3C = 0;
|
||||
g_Dialogue.primIndex[1] = -1;
|
||||
g_Dialogue.primIndex[0] = -1;
|
||||
@ -36,11 +42,11 @@ u8 CutsceneUnk2(s32 textDialogue) {
|
||||
prim->drawMode = DRAW_HIDE;
|
||||
prim = g_Dialogue.prim[5] = prim->next;
|
||||
|
||||
prim->type = 4;
|
||||
prim->type = PRIM_GT4;
|
||||
prim->drawMode = DRAW_HIDE;
|
||||
|
||||
prim = prim->next;
|
||||
prim->type = 3;
|
||||
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;
|
||||
@ -50,7 +56,7 @@ u8 CutsceneUnk2(s32 textDialogue) {
|
||||
prim->drawMode = DRAW_HIDE;
|
||||
|
||||
prim = prim->next;
|
||||
prim->type = 1;
|
||||
prim->type = PRIM_TILE;
|
||||
prim->x0 = 3;
|
||||
prim->y0 = 0x2F;
|
||||
prim->v0 = 0x4A;
|
@ -9,7 +9,7 @@
|
||||
#include "../cutscene_unk1.h"
|
||||
|
||||
// not an exact duplicate
|
||||
u8 CutsceneUnk2(const char* textDialogue) {
|
||||
u8 SetCutsceneScript(const char* textDialogue) {
|
||||
Primitive* prim;
|
||||
s16 firstPrimIndex;
|
||||
|
||||
@ -117,7 +117,7 @@ void EntityDraculaCutscene(Entity* self) {
|
||||
|
||||
switch (self->step) {
|
||||
case 0:
|
||||
if (CutsceneUnk2(D_801829D8)) {
|
||||
if (SetCutsceneScript(D_801829D8)) {
|
||||
self->flags |= FLAG_HAS_PRIMS;
|
||||
g_CutsceneFlags = 0;
|
||||
D_801C2580 = 0;
|
||||
|
@ -1,3 +1,3 @@
|
||||
module github.com/xeeynamo/sotn-decomp/tools/gfxsotn
|
||||
|
||||
go 1.19
|
||||
go 1.22
|
||||
|
@ -35,6 +35,7 @@ type assetEntry struct {
|
||||
start int
|
||||
end int
|
||||
assetDir string
|
||||
srcDir string
|
||||
name string
|
||||
args []string
|
||||
ramBase psx.Addr
|
||||
@ -72,6 +73,23 @@ var extractHandlers = map[string]func(assetEntry) error{
|
||||
}
|
||||
return os.WriteFile(outPath, content, 0644)
|
||||
},
|
||||
"cutscene": func(e assetEntry) error {
|
||||
if e.start == e.end {
|
||||
return fmt.Errorf("cutscene cannot be 0 bytes")
|
||||
}
|
||||
r := bytes.NewReader(e.data)
|
||||
script, err := parseCutsceneAsC(r, e.ramBase, e.ramBase.Sum(e.start))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
outPath := path.Join(e.srcDir, fmt.Sprintf("%s.h", e.name))
|
||||
dir := filepath.Dir(outPath)
|
||||
if err := os.MkdirAll(dir, 0755); err != nil {
|
||||
fmt.Printf("failed to create directory %s: %v\n", dir, err)
|
||||
return err
|
||||
}
|
||||
return os.WriteFile(outPath, []byte(script), 0644)
|
||||
},
|
||||
}
|
||||
|
||||
var buildHandlers = map[string]func(assetBuildEntry) error{
|
||||
@ -105,11 +123,11 @@ func parseArgs(entry []string) (offset int64, kind string, args []string, err er
|
||||
func readConfig(path string) (*assetConfig, error) {
|
||||
yamlFile, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Error reading YAML file: %v", err)
|
||||
return nil, fmt.Errorf("error reading YAML file: %v", err)
|
||||
}
|
||||
var data assetConfig
|
||||
if err = yaml.Unmarshal(yamlFile, &data); err != nil {
|
||||
return nil, fmt.Errorf("Error unmarshalling YAML file: %v", err)
|
||||
return nil, fmt.Errorf("error unmarshalling YAML file: %v", err)
|
||||
}
|
||||
return &data, nil
|
||||
}
|
||||
@ -118,6 +136,7 @@ func enqueueExtractAssetEntry(
|
||||
eg *errgroup.Group,
|
||||
handler func(assetEntry) error,
|
||||
assetDir string,
|
||||
srcDir string,
|
||||
name string,
|
||||
data []byte,
|
||||
start int,
|
||||
@ -130,6 +149,7 @@ func enqueueExtractAssetEntry(
|
||||
start: start,
|
||||
end: end,
|
||||
assetDir: assetDir,
|
||||
srcDir: srcDir,
|
||||
ramBase: ramBase,
|
||||
name: name,
|
||||
args: args,
|
||||
@ -174,7 +194,7 @@ func extractAssetFile(file assetFileEntry) error {
|
||||
}
|
||||
start := int(off) - segment.Start
|
||||
end := start + size
|
||||
enqueueExtractAssetEntry(&eg, handler, file.AssetDir, name, data[segment.Start:], start, end, args, segment.Vram)
|
||||
enqueueExtractAssetEntry(&eg, handler, file.AssetDir, file.SourceDir, name, data[segment.Start:], start, end, args, segment.Vram)
|
||||
}
|
||||
off = off2
|
||||
kind = kind2
|
||||
|
85
tools/sotn-assets/cutscene.go
Normal file
85
tools/sotn-assets/cutscene.go
Normal file
@ -0,0 +1,85 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/xeeynamo/sotn-decomp/tools/sotn-assets/psx"
|
||||
"io"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func readCutscene(r io.ReadSeeker, baseAddr, addr psx.Addr) ([]string, error) {
|
||||
if err := addr.MoveFile(r, baseAddr); err != nil {
|
||||
return []string{}, fmt.Errorf("unable to read cutscene: %w", err)
|
||||
}
|
||||
|
||||
read1 := func(r io.ReadSeeker) byte {
|
||||
b := make([]byte, 1)
|
||||
_, _ = r.Read(b)
|
||||
return b[0]
|
||||
}
|
||||
script := make([]string, 0)
|
||||
loop := true
|
||||
for loop {
|
||||
op := read1(r)
|
||||
switch op {
|
||||
case 0:
|
||||
script = append(script, "END_CUTSCENE()")
|
||||
script = append(script, "0xFF")
|
||||
script = append(script, "0xFF")
|
||||
loop = false
|
||||
case 1:
|
||||
script = append(script, "LINE_BREAK()")
|
||||
case 2:
|
||||
script = append(script, fmt.Sprintf("SET_SPEED(%d)", read1(r)))
|
||||
case 3:
|
||||
script = append(script, fmt.Sprintf("SET_WAIT(%d)", read1(r)))
|
||||
case 4:
|
||||
script = append(script, "HIDE_DIALOG()")
|
||||
case 5:
|
||||
script = append(script, fmt.Sprintf("SET_PORTRAIT(%d, %d)", read1(r), read1(r)))
|
||||
case 6:
|
||||
script = append(script, "NEXT_DIALOG()")
|
||||
case 7:
|
||||
script = append(script, fmt.Sprintf("SET_POS(%d, %d)", read1(r), read1(r)))
|
||||
case 8:
|
||||
script = append(script, "CLOSE_DIALOG()")
|
||||
case 9:
|
||||
script = append(script, fmt.Sprintf("PLAY_SOUND(0x%02X, 0x%02X)", read1(r), read1(r)))
|
||||
case 10:
|
||||
script = append(script, "WAIT_FOR_SOUND()")
|
||||
case 11:
|
||||
script = append(script, "SCRIPT_UNKNOWN_11()")
|
||||
case 13:
|
||||
script = append(script, "SCRIPT_UNKNOWN_13()")
|
||||
case 16:
|
||||
script = append(script, fmt.Sprintf("WAIT_FOR_FLAG(%d)", read1(r)))
|
||||
case 17:
|
||||
script = append(script, fmt.Sprintf("SET_FLAG(%d)", read1(r)))
|
||||
case 18:
|
||||
script = append(script, "SCRIPT_UNKOWN_18()")
|
||||
case 19:
|
||||
script = append(script, fmt.Sprintf(
|
||||
"LOAD_PORTRAIT(0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X)",
|
||||
read1(r), read1(r), read1(r), read1(r), read1(r)))
|
||||
case 20:
|
||||
script = append(script, fmt.Sprintf("SCRIPT_UNKNOWN_20(0x%02X, 0x%02X)", read1(r), read1(r)))
|
||||
case 0x27:
|
||||
script = append(script, "'\\''")
|
||||
default:
|
||||
if op >= 0x20 && op <= 0x7e {
|
||||
script = append(script, fmt.Sprintf("'%s'", string([]byte{op})))
|
||||
} else {
|
||||
return script, fmt.Errorf("unknown op 0x%02X", op)
|
||||
}
|
||||
}
|
||||
}
|
||||
return script, nil
|
||||
}
|
||||
|
||||
func parseCutsceneAsC(r io.ReadSeeker, baseAddr, addr psx.Addr) (string, error) {
|
||||
script, err := readCutscene(r, baseAddr, addr)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return strings.ReplaceAll(strings.Join(script, ",\n"), "',\n'", "','"), nil
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
module github.com/xeeynamo/sotn-decomp/tools/sotn-assets
|
||||
|
||||
go 1.21
|
||||
go 1.22
|
||||
|
||||
require (
|
||||
golang.org/x/sync v0.7.0 // indirect
|
||||
|
@ -1,3 +1,3 @@
|
||||
module github.com/xeeynamo/sotn-decomp/tools/sotn-disk
|
||||
|
||||
go 1.19
|
||||
go 1.22
|
||||
|
Loading…
Reference in New Issue
Block a user