diff --git a/include/animated_materials.h b/include/animated_materials.h index 01ceaa60e..227752885 100644 --- a/include/animated_materials.h +++ b/include/animated_materials.h @@ -2,6 +2,9 @@ #define ANIMATED_MATERIALS_H #include "ultra64.h" +#include "config.h" + +#if ENABLE_ANIMATED_MATERIALS typedef enum AnimatedMatType { /* 0 */ ANIM_MAT_TYPE_TEX_SCROLL, @@ -82,3 +85,5 @@ void AnimatedMat_DrawAlphaStepOpa(struct PlayState* play, AnimatedMaterial* matA void AnimatedMat_DrawAlphaStepXlu(struct PlayState* play, AnimatedMaterial* matAnim, f32 alphaRatio, u32 step); #endif + +#endif diff --git a/include/config/config_game.h b/include/config/config_game.h index 9be9c08fd..92fd36e3c 100644 --- a/include/config/config_game.h +++ b/include/config/config_game.h @@ -74,4 +74,16 @@ */ #define ENABLE_ANIMATED_MATERIALS true +/** + * Enable New Letterbox (from Majora's Mask) + */ +#define ENABLE_NEW_LETTERBOX true + +/** + * Enable Cutscene Improvements (from Majora's Mask) + * + * This includes actor cutscenes + */ +#define ENABLE_CUTSCENE_IMPROVEMENTS true + #endif diff --git a/include/config/config_safeguards.h b/include/config/config_safeguards.h index cef95c277..e8999fe84 100644 --- a/include/config/config_safeguards.h +++ b/include/config/config_safeguards.h @@ -137,6 +137,14 @@ #define USE_WIDESCREEN (ENABLE_WIDESCREEN && gSaveContext.save.useWidescreen == true) #endif +#if ENABLE_CUTSCENE_IMPROVEMENTS && !ENABLE_NEW_LETTERBOX + #undef ENABLE_NEW_LETTERBOX + #define ENABLE_NEW_LETTERBOX true +#endif + +/***************** + * config_graphics.h + */ //! TODO: implement better Wii VC compatibility #ifdef CONSOLE_WIIVC #undef ENABLE_F3DEX3 diff --git a/include/letterbox.h b/include/letterbox.h index 48d6ea7c1..cf54c2719 100644 --- a/include/letterbox.h +++ b/include/letterbox.h @@ -11,4 +11,25 @@ void Letterbox_Init(void); void Letterbox_Destroy(void); void Letterbox_Update(s32 updateRate); +#if ENABLE_NEW_LETTERBOX + +struct GraphicsContext; + +void ShrinkWindow_Letterbox_SetSizeTarget(s32 target); +s32 ShrinkWindow_Letterbox_GetSizeTarget(void); +void ShrinkWindow_Letterbox_SetSize(s32 size); +s32 ShrinkWindow_Letterbox_GetSize(void); + +void ShrinkWindow_Pillarbox_SetSizeTarget(s32 target); +s32 ShrinkWindow_Pillarbox_GetSizeTarget(void); +void ShrinkWindow_Pillarbox_SetSize(s32 size); +s32 ShrinkWindow_Pillarbox_GetSize(void); + +void ShrinkWindow_Init(void); +void ShrinkWindow_Destroy(void); +void ShrinkWindow_Update(s32 framerateDivisor); +void ShrinkWindow_Draw(struct GraphicsContext* gfxCtx); + +#endif + #endif diff --git a/include/tables/scene_table.h b/include/tables/scene_table.h index 9d9da9128..9efdc4e66 100644 --- a/include/tables/scene_table.h +++ b/include/tables/scene_table.h @@ -124,5 +124,9 @@ #endif #if CAN_INCLUDE_EXAMPLE_SCENE +#if ENABLE_ANIMATED_MATERIALS +/* 0x6C */ DEFINE_SCENE(example_scene, none, SCENE_EXAMPLE, SDC_MAT_ANIM, 0, 0) +#else /* 0x6C */ DEFINE_SCENE(example_scene, none, SCENE_EXAMPLE, SDC_HAUNTED_WASTELAND, 0, 0) #endif +#endif diff --git a/include/z64actor.h b/include/z64actor.h index deac35481..5f3241e72 100644 --- a/include/z64actor.h +++ b/include/z64actor.h @@ -220,6 +220,13 @@ typedef struct ActorShape { // Flag controlling the use of `Actor.sfx`. Do not use directly. See Actor_PlaySfx_FlaggedTimer #define ACTOR_FLAG_SFX_TIMER (1 << 28) +// Actor can update even if Player is currently in one of the `sCategoryFreezeMasks` states. +// Typically an actor will halt while the player is in one of the `sCategoryFreezeMasks` states (depending on category). +// This flag allows a given actor to be an exception. +// +// Note: Not implemented yet. +#define ACTOR_FLAG_FREEZE_EXCEPTION (1 << 29) + #define COLORFILTER_GET_COLORINTENSITY(colorFilterParams) (((colorFilterParams) & 0x1F00) >> 5) #define COLORFILTER_GET_DURATION(colorFilterParams) ((colorFilterParams) & 0xFF) diff --git a/include/z64camera.h b/include/z64camera.h index 41f22aec7..dfa6ad94d 100644 --- a/include/z64camera.h +++ b/include/z64camera.h @@ -205,7 +205,10 @@ typedef enum CameraSettingType { /* 0x3F */ CAM_SET_DIRECTED_YAW, // Does not auto-update yaw, tends to keep the camera pointed at a certain yaw (used by biggoron and final spirit lowering platform) "TEPPEN" /* 0x40 */ CAM_SET_PIVOT_FROM_SIDE, // Fixed side view, allows rotation of camera (eg. Potion Shop, Meadow at fairy grotto) "CIRCLE7" /* 0x41 */ CAM_SET_NORMAL4, - /* 0x42 */ CAM_SET_MAX +#if ENABLE_CUTSCENE_IMPROVEMENTS + /* 0x42 */ CAM_SET_FIXED1, +#endif + /* 0x43 */ CAM_SET_MAX } CameraSettingType; typedef enum CameraModeType { @@ -305,7 +308,10 @@ typedef enum CameraFuncType { /* 0x44 */ CAM_FUNC_SPEC7, /* 0x45 */ CAM_FUNC_SPEC8, /* 0x46 */ CAM_FUNC_SPEC9, - /* 0x47 */ CAM_FUNC_MAX +#if ENABLE_CUTSCENE_IMPROVEMENTS + /* 0x47 */ CAM_FUNC_FIXED1, +#endif + /* 0x48 */ CAM_FUNC_MAX } CameraFuncType; typedef enum CameraDataType { @@ -1733,4 +1739,13 @@ void Camera_SetCameraData(Camera* camera, s16 setDataFlags, void* data0, void* d s32 func_8005B198(void); s16 Camera_SetFinishedFlag(Camera* camera); +s16 Camera_GetBgCamOrActorCsCamSetting(Camera* camera, u32 camDataId); +Vec3s* Camera_GetBgCamOrActorCsCamFuncData(Camera* camera, u32 camDataId); +#if ENABLE_CUTSCENE_IMPROVEMENTS +s16 Camera_ChangeSettingFlags(Camera* camera, s16 setting, s16 flags); +s32 Camera_ChangeSetting(Camera* camera, s16 setting); +s32 Camera_ChangeActorCsCamIndex(Camera* camera, s32 bgCamIndex); +void Camera_800E0348(Camera* camera); +#endif + #endif diff --git a/include/z64cutscene.h b/include/z64cutscene.h index 8e94406ed..381c5c58d 100644 --- a/include/z64cutscene.h +++ b/include/z64cutscene.h @@ -11,7 +11,7 @@ typedef union CutsceneData { s32 i; f32 f; s16 s[2]; - s8 b[4]; + s8 b[4]; } CutsceneData; typedef enum CutsceneState { @@ -198,7 +198,7 @@ typedef enum CutsceneTextType { /* 0x00 */ CS_TEXT_NORMAL, /* 0x01 */ CS_TEXT_CHOICE, /* 0x02 */ CS_TEXT_OCARINA_ACTION, - /* 0x03 */ CS_TEXT_GORON_RUBY, // use `altTextId1` in the ruby cutscene if sapphire is already obtained + /* 0x03 */ CS_TEXT_GORON_RUBY, // use `altTextId1` in the ruby cutscene if sapphire is already obtained /* 0x04 */ CS_TEXT_ZORA_SAPPHIRE // use `altTextId1` in the sapphire cutscene if ruby is already obtained } CutsceneTextType; @@ -240,7 +240,7 @@ typedef enum CutsceneDestination { /* 0x0D */ CS_DEST_ZORAS_FOUNTAIN_FROM_ZORAS_SAPPHIRE, /* 0x0E */ CS_DEST_KOKIRI_FOREST_FROM_KOKIRI_EMERALD, /* 0x0F */ CS_DEST_TEMPLE_OF_TIME_KOKIRI_EMERALD_RESTORED, // unused - /* 0x10 */ CS_DEST_TEMPLE_OF_TIME_GORON_RUBY_RESTORED, // unused + /* 0x10 */ CS_DEST_TEMPLE_OF_TIME_GORON_RUBY_RESTORED, // unused /* 0x11 */ CS_DEST_TEMPLE_OF_TIME_ZORAS_SAPPHIRE_RESTORED, // unused /* 0x12 */ CS_DEST_TEMPLE_OF_TIME_AFTER_LIGHT_MEDALLION, /* 0x13 */ CS_DEST_DEATH_MOUNTAIN_TRAIL, // unused @@ -251,7 +251,7 @@ typedef enum CutsceneDestination { /* 0x18 */ CS_DEST_JABU_JABU, /* 0x19 */ CS_DEST_CHAMBER_OF_SAGES_LIGHT_MEDALLION, /* 0x1A */ CS_DEST_TEMPLE_OF_TIME_KOKIRI_EMERALD_RESTORED_2, // unused - /* 0x1B */ CS_DEST_TEMPLE_OF_TIME_GORON_RUBY_RESTORED_2, // unused + /* 0x1B */ CS_DEST_TEMPLE_OF_TIME_GORON_RUBY_RESTORED_2, // unused /* 0x1C */ CS_DEST_TEMPLE_OF_TIME_ZORAS_SAPPHIRE_RESTORED_2, // unused /* 0x1D */ CS_DEST_CHAMBER_OF_SAGES_FOREST_MEDALLION, /* 0x1E */ CS_DEST_CHAMBER_OF_SAGES_FIRE_MEDALLION, @@ -303,15 +303,15 @@ typedef enum CutsceneDestination { /* 0x4C */ CS_DEST_LON_LON_RANCH_CREDITS_PART_4, /* 0x4D */ CS_DEST_LON_LON_RANCH_CREDITS_PART_5, /* 0x4E */ CS_DEST_LON_LON_RANCH_CREDITS_PART_6, - /* 0x4F */ CS_DEST_LON_LON_RANCH_1, // unused - /* 0x50 */ CS_DEST_LON_LON_RANCH_2, // unused - /* 0x51 */ CS_DEST_LON_LON_RANCH_3, // unused - /* 0x52 */ CS_DEST_LON_LON_RANCH_4, // unused - /* 0x53 */ CS_DEST_LON_LON_RANCH_5, // unused - /* 0x54 */ CS_DEST_LON_LON_RANCH_6, // unused - /* 0x55 */ CS_DEST_LON_LON_RANCH_7, // unused - /* 0x56 */ CS_DEST_LON_LON_RANCH_8, // unused - /* 0x57 */ CS_DEST_LON_LON_RANCH_9, // unused + /* 0x4F */ CS_DEST_LON_LON_RANCH_1, // unused + /* 0x50 */ CS_DEST_LON_LON_RANCH_2, // unused + /* 0x51 */ CS_DEST_LON_LON_RANCH_3, // unused + /* 0x52 */ CS_DEST_LON_LON_RANCH_4, // unused + /* 0x53 */ CS_DEST_LON_LON_RANCH_5, // unused + /* 0x54 */ CS_DEST_LON_LON_RANCH_6, // unused + /* 0x55 */ CS_DEST_LON_LON_RANCH_7, // unused + /* 0x56 */ CS_DEST_LON_LON_RANCH_8, // unused + /* 0x57 */ CS_DEST_LON_LON_RANCH_9, // unused /* 0x58 */ CS_DEST_LON_LON_RANCH_10, // unused /* 0x59 */ CS_DEST_LON_LON_RANCH_11, // unused /* 0x5A */ CS_DEST_LON_LON_RANCH_12, // unused @@ -355,7 +355,6 @@ typedef union CsCmdCam { s32 _words[2]; } CsCmdCam; // size = 0x8 - typedef union CsCmdMisc { struct { /* 0x00 */ u16 type; @@ -421,8 +420,8 @@ typedef union CsCmdTime { /* 0x00 */ u16 unused0; /* 0x02 */ u16 startFrame; /* 0x04 */ u16 endFrame; // unused - /* 0x06 */ u8 hour; - /* 0x07 */ u8 minute; + /* 0x06 */ u8 hour; + /* 0x07 */ u8 minute; }; s32 _words[3]; } CsCmdTime; // size = 0xC @@ -500,22 +499,240 @@ typedef struct CutsceneCameraMove { /* 0x8 */ s16 relativeToPlayer; } CutsceneCameraMove; // size = 0xC +typedef struct CutsceneScriptEntry { + /* 0x0 */ CutsceneData* script; + /* 0x4 */ s16 nextEntrance; + /* 0x6 */ u8 spawn; + /* 0x7 */ u8 spawnFlags; // See `CS_SPAWN_FLAG_` +} CutsceneScriptEntry; // size = 0x8 + +typedef struct CutsceneEntry { + /* 0x0 */ s16 priority; // Lower means higher priority. -1 means it ignores priority + /* 0x2 */ s16 length; + /* 0x4 */ s16 csCamId; // Index of CsCameraEntry to use. Negative indices use sGlobalCamDataSettings. Indices 0 and + // above use CsCameraEntry from a sceneLayer + /* 0x6 */ s16 scriptIndex; + /* 0x8 */ s16 additionalCsId; + /* 0xA */ u8 endSfx; + /* 0xB */ u8 customValue; // 0 - 99: actor-specific custom value. 100+: spawn. 255: none + /* 0xC */ s16 hudVisibility; + /* 0xE */ u8 endCam; + /* 0xF */ u8 letterboxSize; +} CutsceneEntry; // size = 0x10 + +#define CS_SCRIPT_ID_NONE -1 + +typedef enum CutsceneCamId { + // global (see sGlobalCamDataSettings) + /* -66 */ CS_CAM_ID_GLOBAL_NORMAL4 = -67, // CAM_SET_NORMAL4 (set to -CAM_SET_MAX) + /* -65 */ CS_CAM_ID_GLOBAL_PIVOT_FROM_SIDE, // CAM_SET_PIVOT_FROM_SIDE + /* -64 */ CS_CAM_ID_GLOBAL_DIRECTED_YAW, // CAM_SET_DIRECTED_YAW + /* -63 */ CS_CAM_ID_GLOBAL_DUNGEON2, // CAM_SET_DUNGEON2 + /* -62 */ CS_CAM_ID_GLOBAL_JABU_TENTACLE, // CAM_SET_JABU_TENTACLE + /* -61 */ CS_CAM_ID_GLOBAL_CS_C, // CAM_SET_CS_C + /* -60 */ CS_CAM_ID_GLOBAL_FISHING, // CAM_SET_FISHING + /* -59 */ CS_CAM_ID_GLOBAL_NORMAL2, // CAM_SET_NORMAL2 + /* -58 */ CS_CAM_ID_GLOBAL_PIVOT_VERTICAL, // CAM_SET_PIVOT_VERTICAL + /* -57 */ CS_CAM_ID_GLOBAL_TURN_AROUND, // CAM_SET_TURN_AROUND + /* -56 */ CS_CAM_ID_GLOBAL_FIRE_BIRDS_EYE, // CAM_SET_FIRE_BIRDS_EYE + /* -55 */ CS_CAM_ID_GLOBAL_MEADOW_UNUSED, // CAM_SET_MEADOW_UNUSED + /* -54 */ CS_CAM_ID_GLOBAL_MEADOW_BIRDS_EYE, // CAM_SET_MEADOW_BIRDS_EYE + /* -53 */ CS_CAM_ID_GLOBAL_BIG_OCTO, // CAM_SET_BIG_OCTO + /* -52 */ CS_CAM_ID_GLOBAL_FOREST_DEFEAT_POE, // CAM_SET_FOREST_DEFEAT_POE + /* -51 */ CS_CAM_ID_GLOBAL_FOREST_UNUSED, // CAM_SET_FOREST_UNUSED + /* -50 */ CS_CAM_ID_GLOBAL_FIRE_STAIRCASE, // CAM_SET_FIRE_STAIRCASE + /* -49 */ CS_CAM_ID_GLOBAL_ELEVATOR_PLATFORM, // CAM_SET_ELEVATOR_PLATFORM + /* -48 */ CS_CAM_ID_GLOBAL_SCENE_TRANSITION, // CAM_SET_SCENE_TRANSITION + /* -47 */ CS_CAM_ID_GLOBAL_SCENE_UNUSED, // CAM_SET_SCENE_UNUSED + /* -46 */ CS_CAM_ID_GLOBAL_BEAN_LOST_WOODS, // CAM_SET_BEAN_LOST_WOODS + /* -45 */ CS_CAM_ID_GLOBAL_BEAN_GENERIC, // CAM_SET_BEAN_GENERIC + /* -44 */ CS_CAM_ID_GLOBAL_CS_ATTENTION, // CAM_SET_CS_ATTENTION + /* -43 */ CS_CAM_ID_GLOBAL_CS_3, // CAM_SET_CS_3 + /* -42 */ CS_CAM_ID_GLOBAL_ITEM_UNUSED, // CAM_SET_ITEM_UNUSED + /* -41 */ CS_CAM_ID_GLOBAL_SLOW_CHEST_CS, // CAM_SET_SLOW_CHEST_CS + /* -40 */ CS_CAM_ID_GLOBAL_FOREST_BIRDS_EYE, // CAM_SET_FOREST_BIRDS_EYE + /* -39 */ CS_CAM_ID_GLOBAL_CS_TWISTED_HALLWAY, // CAM_SET_CS_TWISTED_HALLWAY + /* -38 */ CS_CAM_ID_GLOBAL_CS_0, // CAM_SET_CS_0 + /* -37 */ CS_CAM_ID_GLOBAL_PIVOT_WATER_SURFACE, // CAM_SET_PIVOT_WATER_SURFACE + /* -36 */ CS_CAM_ID_GLOBAL_PIVOT_CORNER, // CAM_SET_PIVOT_CORNER + /* -35 */ CS_CAM_ID_GLOBAL_FREE2, // CAM_SET_FREE2 + /* -34 */ CS_CAM_ID_GLOBAL_FREE0, // CAM_SET_FREE0 + /* -33 */ CS_CAM_ID_GLOBAL_START1, // CAM_SET_START1 + /* -32 */ CS_CAM_ID_GLOBAL_START0, // CAM_SET_START0 + /* -31 */ CS_CAM_ID_GLOBAL_CRAWLSPACE, // CAM_SET_CRAWLSPACE + /* -30 */ CS_CAM_ID_GLOBAL_DOORC, // CAM_SET_DOORC + /* -29 */ CS_CAM_ID_GLOBAL_DOOR0, // CAM_SET_DOOR0 + /* -28 */ CS_CAM_ID_GLOBAL_PREREND_SIDE_SCROLL, // CAM_SET_PREREND_SIDE_SCROLL + /* -27 */ CS_CAM_ID_GLOBAL_PREREND_PIVOT, // CAM_SET_PREREND_PIVOT + /* -26 */ CS_CAM_ID_GLOBAL_PREREND_FIXED, // CAM_SET_PREREND_FIXED + /* -25 */ CS_CAM_ID_GLOBAL_PIVOT_IN_FRONT, // CAM_SET_PIVOT_IN_FRONT + /* -24 */ CS_CAM_ID_GLOBAL_PIVOT_SHOP_BROWSING, // CAM_SET_PIVOT_SHOP_BROWSING + /* -23 */ CS_CAM_ID_GLOBAL_PIVOT_CRAWLSPACE, // CAM_SET_PIVOT_CRAWLSPACE + /* -22 */ CS_CAM_ID_GLOBAL_CHU_BOWLING, // CAM_SET_CHU_BOWLING + /* -21 */ CS_CAM_ID_GLOBAL_MARKET_BALCONY, // CAM_SET_MARKET_BALCONY + /* -20 */ CS_CAM_ID_GLOBAL_TOWER_UNUSED, // CAM_SET_TOWER_UNUSED + /* -19 */ CS_CAM_ID_GLOBAL_TOWER_CLIMB, // CAM_SET_TOWER_CLIMB + /* -18 */ CS_CAM_ID_GLOBAL_BOSS_GANON, // CAM_SET_BOSS_GANON + /* -17 */ CS_CAM_ID_GLOBAL_BOSS_GANONDORF, // CAM_SET_BOSS_GANONDORF + /* -16 */ CS_CAM_ID_GLOBAL_BOSS_TWINROVA_FLOOR, // CAM_SET_BOSS_TWINROVA_FLOOR + /* -15 */ CS_CAM_ID_GLOBAL_BOSS_TWINROVA_PLATFORM, // CAM_SET_BOSS_TWINROVA_PLATFORM + /* -14 */ CS_CAM_ID_GLOBAL_BOSS_MORPHA, // CAM_SET_BOSS_MORPHA + /* -13 */ CS_CAM_ID_GLOBAL_BOSS_BONGO, // CAM_SET_BOSS_BONGO + /* -12 */ CS_CAM_ID_GLOBAL_BOSS_VOLVAGIA, // CAM_SET_BOSS_VOLVAGIA + /* -11 */ CS_CAM_ID_GLOBAL_BOSS_PHANTOM_GANON, // CAM_SET_BOSS_PHANTOM_GANON + /* -10 */ CS_CAM_ID_GLOBAL_BOSS_BARINADE, // CAM_SET_BOSS_BARINADE + /* -9 */ CS_CAM_ID_GLOBAL_BOSS_DODONGO, // CAM_SET_BOSS_DODONGO + /* -8 */ CS_CAM_ID_GLOBAL_BOSS_GOHMA, // CAM_SET_BOSS_GOHMA + /* -7 */ CS_CAM_ID_GLOBAL_HORSE, // CAM_SET_HORSE + /* -6 */ CS_CAM_ID_GLOBAL_NORMAL3, // CAM_SET_NORMAL3 + /* -5 */ CS_CAM_ID_GLOBAL_DUNGEON1, // CAM_SET_DUNGEON1 + /* -4 */ CS_CAM_ID_GLOBAL_DUNGEON0, // CAM_SET_DUNGEON0 + /* -3 */ CS_CAM_ID_GLOBAL_NORMAL1, // CAM_SET_NORMAL1 + /* -2 */ CS_CAM_ID_GLOBAL_NORMAL0, // CAM_SET_NORMAL0 + /* -1 */ CS_CAM_ID_NONE, + // CamCsId's 0+ are sceneLayer-specific and index `ActorCsCamInfo` +} CutsceneCamId; + +typedef enum CutsceneHudVisibility { + /* -1 */ CS_HUD_VISIBILITY_ALL_ALT = -1, + /* 0 */ CS_HUD_VISIBILITY_NONE, + /* 1 */ CS_HUD_VISIBILITY_ALL, + /* 2 */ CS_HUD_VISIBILITY_A_HEARTS_MAGIC, + /* 3 */ CS_HUD_VISIBILITY_C_HEARTS_MAGIC, + /* 4 */ CS_HUD_VISIBILITY_ALL_NO_MINIMAP, + /* 5 */ CS_HUD_VISIBILITY_A_B_C, + /* 6 */ CS_HUD_VISIBILITY_B_MINIMAP, + /* 7 */ CS_HUD_VISIBILITY_A +} CutsceneHudVisibility; + +typedef enum CutsceneEndSfx { + /* 0 */ CS_END_SFX_NONE, + /* 1 */ CS_END_SFX_TRE_BOX_APPEAR, + /* 2 */ CS_END_SFX_CORRECT_CHIME, + /* 255 */ CS_END_SFX_NONE_ALT = 0xFF +} CutsceneEndSfx; + +typedef enum CutsceneEndCam { + /* 0 */ CS_END_CAM_0, + /* 1 */ CS_END_CAM_1, + /* 2 */ CS_END_CAM_SMOOTH +} CutsceneEndCam; + +typedef enum CutsceneId { + /* -1 */ CS_ID_NONE = -1, + // CsId's 0 - 119 are sceneLayer-specific and index `CutsceneEntry` + /* 0x78 */ CS_ID_GLOBAL_78 = 120, + /* 0x79 */ CS_ID_GLOBAL_79, + /* 0x7A */ CS_ID_GLOBAL_7A, + /* 0x7C */ CS_ID_GLOBAL_TALK, + /* 0x7D */ CS_ID_GLOBAL_DOOR, + /* 0x7F */ CS_ID_GLOBAL_END = 0x7F +} CutsceneId; + +typedef struct { + /* 0x0 */ s16 numEntries; + /* 0x2 */ s16 unk_02; // unused + /* 0x4 */ s16 unk_04; // unused + /* 0x6 */ s16 duration; // total duration +} CsCmdCamSpline; // size = 0x8 + +// Both camAt and camEye +typedef struct { + /* 0x0 */ u8 interpType; // see `CutsceneCamInterpType` + /* 0x1 */ u8 weight; // for certain types of interpTypes, shifts the weight to certain points. Default is 100. + /* 0x2 */ s16 duration; // duration of current point + /* 0x4 */ Vec3s pos; + /* 0xA */ s16 relativeTo; // see `CutsceneCamRelativeTo` +} CsCmdCamPoint; // size = 0xC + +typedef enum CutsceneCamInterpType { + /* 0 */ CS_CAM_INTERP_NONE, // values do not change. + // values 1-3 only uses a single point from the cmd + /* 1 */ CS_CAM_INTERP_SET, // values immediately set to cmd values. + /* 2 */ CS_CAM_INTERP_LINEAR, // Lerp to the target position + /* 3 */ CS_CAM_INTERP_SCALE, // Step to the target position in increments scaled by the remaining distance + // values 4-5 uses multiple points from the cmd + /* 4 */ CS_CAM_INTERP_MP_CUBIC, // cubic multi-point (identical to SM64/OoT) + /* 5 */ CS_CAM_INTERP_MP_QUAD, // quadratic multi-point + // value 6 only uses a single point from the cmd + /* 6 */ CS_CAM_INTERP_GEO, // does VecGeo calculations using fov + /* 7 */ CS_CAM_INTERP_OFF // interpolation is not processed. +} CutsceneCamInterpType; + +typedef enum CutsceneCamRelativeTo { + /* 0 */ CS_CAM_REL_0, + /* 1 */ CS_CAM_REL_1, + /* 2 */ CS_CAM_REL_2, + /* 3 */ CS_CAM_REL_3, + /* 4 */ CS_CAM_REL_4, + /* 5 */ CS_CAM_REL_5 +} CutsceneCamRelativeTo; + +// Roll and Fov Data +typedef struct CsCmdCamMisc { + /* 0x0 */ s16 unused0; // used only in the unused interp function + /* 0x2 */ s16 roll; + /* 0x4 */ s16 fov; + /* 0x6 */ s16 unused1; // unused +} CsCmdCamMisc; // size = 0x8 + +typedef struct CutsceneCameraInterp { + /* 0x00 */ Vec3f curPos; + /* 0x0C */ Vec3f initPos; + /* 0x18 */ f32 initFov; + /* 0x1C */ f32 initRoll; + /* 0x2A */ f32 unk_20; // position adjustment based on fov? + /* 0x24 */ s16 curFrame; + /* 0x26 */ s16 waypoint; + /* 0x28 */ s16 duration; + /* 0x2A */ s16 numEntries; + /* 0x1E */ u8 curPoint; + /* 0x2D */ u8 type; // See `CutsceneCamInterpType` +} CutsceneCameraInterp; // size = 0x30 + +typedef struct CutsceneCamera { + /* 0x00 */ s16 splineIndex; + /* 0x02 */ s16 cmdIndex; + /* 0x04 */ s16 splineNeedsInit; + /* 0x06 */ s16 state; + /* 0x08 */ s16 nextSplineTimer; + /* 0x0A */ s16 updateSplineTimer; + /* 0x0C */ s16 duration; // Duration of the current spline + /* 0x10 */ CutsceneCameraInterp eyeInterp; + /* 0x40 */ CutsceneCameraInterp atInterp; + /* 0x70 */ CsCmdCamPoint* atCmd; + /* 0x74 */ CsCmdCamPoint* eyeCmd; + /* 0x78 */ CsCmdCamMisc* miscCmd; + /* 0x7C */ struct Camera* camera; +} CutsceneCamera; // size = 0x80 + +typedef enum { + /* 0 */ CS_CAM_STATE_UPDATE_ALL, // Update spline and next spline timer + /* 1 */ CS_CAM_STATE_UPDATE_SPLINE, // Update spline, do not advance next spline timer + /* 2 */ CS_CAM_STATE_PAUSE, // No updates + /* 3 */ CS_CAM_STATE_DONE_SPLINE, // Finished the current spline, ready for the next one + /* 999 */ CS_CAM_STATE_DONE = 999 // Finished all the splines. +} CutsceneCameraState; + typedef struct CutsceneContext { - /* 0x00 */ char unk_00[0x4]; + /* 0x00 */ u8 scriptListCount; /* 0x04 */ void* script; /* 0x08 */ u8 state; /* 0x0C */ f32 timer; /* 0x10 */ u16 curFrame; // current frame of the script that is running - /* 0x12 */ u16 unk_12; // set but never used + /* 0x12 */ u16 scriptIndex; /* 0x14 */ s32 subCamId; /* 0x18 */ u16 camEyeSplinePointsAppliedFrame; // stores the frame the cam eye spline points data was last applied on - /* 0x1A */ u8 camAtReady; // cam `at` data is ready to be applied - /* 0x1B */ u8 camEyeReady; // cam `eye` data is ready to be applied + /* 0x1A */ u8 camAtReady; // cam `at` data is ready to be applied + /* 0x1B */ u8 camEyeReady; // cam `eye` data is ready to be applied /* 0x1C */ CutsceneCameraPoint* camAtPoints; /* 0x20 */ CutsceneCameraPoint* camEyePoints; /* 0x24 */ CsCmdActorCue* playerCue; /* 0x28 */ CsCmdActorCue* actorCues[10]; // "npcdemopnt" /* 0x38 */ u16 originalBlurAlpha; +#if ENABLE_CUTSCENE_IMPROVEMENTS + CutsceneScriptEntry* scriptList; +#endif } CutsceneContext; // size = 0x50 typedef union { @@ -541,5 +758,38 @@ void Cutscene_UpdateScripted(struct PlayState* play, CutsceneContext* csCtx); void Cutscene_HandleEntranceTriggers(struct PlayState* play); void Cutscene_HandleConditionalTriggers(struct PlayState* play); void Cutscene_SetScript(struct PlayState* play, void* script); +void Cutscene_StartScripted(struct PlayState* play, u8 scriptIndex); + +#if ENABLE_CUTSCENE_IMPROVEMENTS +struct Camera; +struct Actor; + +void CutsceneManager_Init(struct PlayState* play, CutsceneEntry* cutsceneList, s16 numEntries); +void CutsceneManager_StoreCamera(struct Camera* camera); +void CutsceneManager_ClearWaiting(void); +s16 CutsceneManager_Update(void); +void CutsceneManager_Queue(s16 csId); +s16 CutsceneManager_IsNext(s16 csId); +s16 CutsceneManager_StartWithPlayerCs(s16 csId, struct Actor* actor); +s16 CutsceneManager_StartWithPlayerCsAndSetFlag(s16 csId, struct Actor* actor); +s16 CutsceneManager_Start(s16 csId, struct Actor* actor); +s16 CutsceneManager_Stop(s16 csId); +s16 CutsceneManager_GetCurrentCsId(void); +CutsceneEntry* CutsceneManager_GetCutsceneEntry(s16 csId); +s16 CutsceneManager_GetAdditionalCsId(s16 csId); +s16 CutsceneManager_GetLength(s16 csId); +s16 CutsceneManager_GetCutsceneScriptIndex(s16 csId); +s16 CutsceneManager_GetCutsceneCustomValue(s16 csId); +s16 CutsceneManager_GetCurrentSubCamId(s16 csId); +s16 CutsceneManager_FindEntranceCsId(void); +s32 CutsceneManager_800F22C4(s16 csId, struct Actor* actor); +void CutsceneManager_SetReturnCamera(s16 camId); +s16 CutsceneManager_MarkNextCutscenes(void); + +s32 CutsceneCamera_Init(struct Camera* camera, CutsceneCamera* csCamera); +s32 CutsceneCamera_UpdateSplines(u8* script, CutsceneCamera* csCamera); +void CutsceneCamera_SetState(s16 state); +void CutsceneCamera_Reset(void); +#endif #endif diff --git a/include/z64olib.h b/include/z64olib.h index 1b704b0e6..8c34199a6 100644 --- a/include/z64olib.h +++ b/include/z64olib.h @@ -3,6 +3,19 @@ #include "z64math.h" +// To be used with OLib_Vec3fAdd() +typedef enum { + /* 0 */ OLIB_ADD_COPY, // Copy `b` to dest + /* 1 */ OLIB_ADD_OFFSET, // Add `a` and `b` to dest, and also add the yaw of `a` to the dest + /* 2 */ OLIB_ADD // Add `a` and `b` to dest +} OlibVec3fAdd; + +typedef enum { + /* 0 */ OLIB_DIFF_COPY, // Copy `b` to dest + /* 1 */ OLIB_DIFF_OFFSET, // Sub `a` and `b` to dest, and also subs the yaw of `a` to the dest + /* 2 */ OLIB_DIFF // Sub `a` and `b` to dest +} OlibVec3fDiff; + f32 OLib_Vec3fDist(Vec3f* a, Vec3f* b); f32 OLib_Vec3fDistXZ(Vec3f* a, Vec3f* b); f32 OLib_ClampMinDist(f32 val, f32 min); @@ -14,4 +27,8 @@ VecGeo OLib_Vec3fToVecGeo(Vec3f* vec); VecGeo OLib_Vec3fDiffToVecGeo(Vec3f* a, Vec3f* b); Vec3f OLib_Vec3fDiffRad(Vec3f* a, Vec3f* b); +Vec3f OLib_AddVecGeoToVec3f(Vec3f* a, VecGeo* geo); +void OLib_Vec3fDiff(PosRot* a, Vec3f* b, Vec3f* dest, s16 mode); +void OLib_Vec3fAdd(PosRot* a, Vec3f* b, Vec3f* dest, s16 mode); + #endif diff --git a/include/z64play.h b/include/z64play.h index 6a36fa1ed..c8d7defe7 100644 --- a/include/z64play.h +++ b/include/z64play.h @@ -113,6 +113,9 @@ typedef struct PlayState { #if ENABLE_ANIMATED_MATERIALS AnimatedMaterial* sceneMaterialAnims; #endif +#if ENABLE_CUTSCENE_IMPROVEMENTS + ActorCsCamInfo* actorCsCamList; +#endif } PlayState; // size = 0x12518 #define GET_ACTIVE_CAM(play) ((play)->cameraPtrs[(play)->activeCamId]) @@ -149,6 +152,11 @@ void Play_TriggerVoidOut(PlayState* this); void Play_TriggerRespawn(PlayState* this); int Play_CamIsNotFixed(PlayState* this); +#if ENABLE_CUTSCENE_IMPROVEMENTS +u16 Play_GetActorCsCamSetting(PlayState* this, s32 csCamDataIndex); +Vec3s* Play_GetActorCsCamFuncData(PlayState* this, s32 csCamDataIndex); +#endif + #if DEBUG_FEATURES extern void* gDebugCutsceneScript; #endif diff --git a/include/z64player.h b/include/z64player.h index 19acbeff3..732f02cbc 100644 --- a/include/z64player.h +++ b/include/z64player.h @@ -4,6 +4,7 @@ #include "z64actor.h" #include "alignment.h" #include "face_change.h" +#include "config.h" struct Player; @@ -766,6 +767,12 @@ typedef struct WeaponInfo { #define PLAYER_STATE3_RESTORE_NAYRUS_LOVE (1 << 6) // Set by ocarina effects actors when destroyed to signal Nayru's Love may be restored (see `ACTOROVL_ALLOC_ABSOLUTE`) #define PLAYER_STATE3_FLYING_WITH_HOOKSHOT (1 << 7) // Flying in the air with the hookshot as it pulls Player toward its destination +#if ENABLE_CUTSCENE_IMPROVEMENTS +#define PLAYER_STATE3_CS_HALT (1 << 8) // Prevents updating the actor while a cutscene is playing +#else +#define PLAYER_STATE3_CS_HALT (0) +#endif + #define PLAYER_ALLOC_GI_MIN 0x2880 // title card maximum file size typedef void (*PlayerActionFunc)(struct Player*, struct PlayState*); @@ -862,7 +869,7 @@ typedef struct Player { /* 0x0688 */ Actor* boomerangActor; /* 0x068C */ Actor* naviActor; /* 0x0690 */ s16 naviTextId; - /* 0x0692 */ u8 stateFlags3; + /* 0x0692 */ u32 stateFlags3; /* 0x0693 */ s8 exchangeItemId; /* 0x0694 */ Actor* talkActor; // Actor offering to talk, or currently talking to, depending on context /* 0x0698 */ f32 talkActorDistance; // xz distance away from `talkActor` diff --git a/include/z64save.h b/include/z64save.h index c5eac0027..d36a93cd1 100644 --- a/include/z64save.h +++ b/include/z64save.h @@ -36,6 +36,15 @@ typedef enum HudVisibilityMode { /* 11 */ HUD_VISIBILITY_HEARTS, /* 12 */ HUD_VISIBILITY_A_B_MINIMAP, /* 13 */ HUD_VISIBILITY_HEARTS_MAGIC_FORCE, // See above + /* 14 */ HUD_VISIBILITY_HEARTS_MAGIC_C, + /* 15 */ HUD_VISIBILITY_ALL_NO_MINIMAP, + /* 16 */ HUD_VISIBILITY_A_B_C, + /* 17 */ HUD_VISIBILITY_B_MINIMAP, + /* 18 */ HUD_VISIBILITY_HEARTS_MAGIC_MINIMAP, + /* 19 */ HUD_VISIBILITY_A_HEARTS_MAGIC_MINIMAP, + /* 20 */ HUD_VISIBILITY_B_MAGIC, + /* 21 */ HUD_VISIBILITY_A_B, + /* 22 */ HUD_VISIBILITY_A_B_HEARTS_MAGIC_MINIMAP, /* 50 */ HUD_VISIBILITY_ALL = 50, // Only raises button alphas if not disabled /* 52 */ HUD_VISIBILITY_NOTHING_INSTANT = 52 } HudVisibilityMode; diff --git a/include/z64scene.h b/include/z64scene.h index 7d4744bd6..4f25eea60 100644 --- a/include/z64scene.h +++ b/include/z64scene.h @@ -398,6 +398,26 @@ typedef struct { } SCmdTextureAnimations; // size = 0x8 #endif +#if ENABLE_CUTSCENE_IMPROVEMENTS +typedef struct { + /* 0x0 */ u8 code; + /* 0x1 */ u8 data1; + /* 0x4 */ void* segment; +} SCmdCsCameraList; // size = 0x8 + +typedef struct { + /* 0x0 */ u8 code; + /* 0x1 */ u8 num; + /* 0x4 */ void* segment; +} SCmdCutsceneList; // size = 0x8 + +typedef struct { + /* 0x0 */ s16 setting; // camera setting described by CameraSettingType enum + /* 0x2 */ s16 count; + /* 0x4 */ Vec3s* actorCsCamFuncData; // s16 data grouped in threes +} ActorCsCamInfo; // size = 0x8 +#endif + typedef union SceneCmd { SCmdBase base; SCmdPlayerEntryList playerEntryList; @@ -431,6 +451,10 @@ typedef union SceneCmd { #if ENABLE_ANIMATED_MATERIALS SCmdTextureAnimations textureAnimations; #endif +#if ENABLE_CUTSCENE_IMPROVEMENTS + SCmdCsCameraList actorCsCamList; + SCmdCutsceneList cutsceneList; +#endif } SceneCmd; // size = 0x8 typedef BAD_RETURN(s32) (*SceneCmdHandlerFunc)(struct PlayState*, SceneCmd*); @@ -556,8 +580,10 @@ typedef enum SceneDrawConfig { /* 50 */ SDC_FISHING_POND, /* 51 */ SDC_GANONS_TOWER_COLLAPSE_INTERIOR, /* 52 */ SDC_INSIDE_GANONS_CASTLE_COLLAPSE, +#if ENABLE_ANIMATED_MATERIALS /* 53 */ SDC_MAT_ANIM, /* 54 */ SDC_MAT_ANIM_MANUAL_STEP, +#endif /* 55 */ SDC_MAX } SceneDrawConfig; @@ -610,7 +636,13 @@ typedef enum SceneCommandTypeID { #if ENABLE_F3DEX3 SCENE_CMD_ID_OCC_PLANE_CAND_LIST, #endif +#if ENABLE_ANIMATED_MATERIALS SCENE_CMD_ID_ANIMATED_MATERIAL_LIST, +#endif +#if ENABLE_CUTSCENE_IMPROVEMENTS + SCENE_CMD_ID_ACTOR_CUTSCENE_LIST, + SCENE_CMD_ID_ACTOR_CUTSCENE_CAM_LIST, +#endif /* 0x1A */ SCENE_CMD_ID_MAX } SceneCommandTypeID; @@ -698,8 +730,18 @@ typedef enum SceneCommandTypeID { { SCENE_CMD_ID_OCC_PLANE_CAND_LIST, numPlanes, CMD_PTR(planeList) } #endif +#if ENABLE_ANIMATED_MATERIALS #define SCENE_CMD_ANIMATED_MATERIAL_LIST(matAnimList) \ { SCENE_CMD_ID_ANIMATED_MATERIAL_LIST, 0, CMD_PTR(matAnimList) } +#endif + +#if ENABLE_CUTSCENE_IMPROVEMENTS +#define SCENE_CMD_ACTOR_CUTSCENE_LIST(numEntries, actorCutsceneList) \ + { SCENE_CMD_ID_ACTOR_CUTSCENE_LIST, numEntries, CMD_PTR(actorCutsceneList) } + +#define SCENE_CMD_ACTOR_CUTSCENE_CAM_LIST(numCams, camList) \ + { SCENE_CMD_ID_ACTOR_CUTSCENE_CAM_LIST, numCams, CMD_PTR(camList) } +#endif s32 Scene_ExecuteCommands(struct PlayState* play, SceneCmd* sceneCmd); diff --git a/include/z_lib.h b/include/z_lib.h index 34581da98..a16454293 100644 --- a/include/z_lib.h +++ b/include/z_lib.h @@ -41,4 +41,8 @@ void Sfx_PlaySfxCentered(u16 sfxId); void Sfx_PlaySfxCentered2(u16 sfxId); void Sfx_PlaySfxAtPos(Vec3f* projectedPos, u16 sfxId); +s32 Math_StepToIImpl(s32 start, s32 target, s32 step); +void Math_StepToIGet(s32* pValue, s32 target, s32 step); +s32 Math_StepToI(s32* pValue, s32 target, s32 step); + #endif diff --git a/mod_assets/scenes/example/example_room_0_model.c b/mod_assets/scenes/example/example_room_0_model.c index 5d3950e4f..d9e3a7b75 100644 --- a/mod_assets/scenes/example/example_room_0_model.c +++ b/mod_assets/scenes/example/example_room_0_model.c @@ -1413,6 +1413,9 @@ Gfx mat_example_room_0_dl_wall_layerOpaque[] = { gsDPLoadBlock(7, 0, 0, 511, 512), gsDPSetTile(G_IM_FMT_I, G_IM_SIZ_8b, 4, 0, 0, 0, G_TX_WRAP | G_TX_NOMIRROR, 5, 14, G_TX_WRAP | G_TX_NOMIRROR, 5, 14), gsDPSetTileSize(0, 0, 0, 124, 124), +#if ENABLE_ANIMATED_MATERIALS + gsSPDisplayList(0xA000000), +#endif gsSPEndDisplayList(), }; @@ -1663,6 +1666,9 @@ Gfx mat_example_room_0_dl_water_layerTransparent[] = { gsDPSetTileSize(0, 0, 0, 124, 124), gsDPSetTile(G_IM_FMT_CI, G_IM_SIZ_8b, 4, 0, 1, 0, G_TX_WRAP | G_TX_NOMIRROR, 5, 15, G_TX_WRAP | G_TX_NOMIRROR, 5, 15), gsDPSetTileSize(1, 0, 0, 124, 124), +#if ENABLE_ANIMATED_MATERIALS + gsSPDisplayList(0x8000000), +#endif gsSPDisplayList(0x9000000), gsSPEndDisplayList(), }; diff --git a/mod_assets/scenes/example/example_scene.h b/mod_assets/scenes/example/example_scene.h index ca6b9cb4d..f06d43456 100644 --- a/mod_assets/scenes/example/example_scene.h +++ b/mod_assets/scenes/example/example_scene.h @@ -4,6 +4,7 @@ #include "ultra64.h" #include "macros.h" #include "z64.h" +#include "config.h" extern SceneCmd example_scene_header00[]; @@ -15,6 +16,20 @@ extern ActorEntry example_scene_header00_playerEntryList[]; extern Spawn example_scene_header00_entranceList[]; extern TransitionActorEntry example_scene_header00_transitionActors[]; extern EnvLightSettings example_scene_header00_lightSettings[4]; +#if ENABLE_ANIMATED_MATERIALS +extern AnimatedMatTexScrollParams debug1_scene_header00_AnimatedMaterialTexScrollParams_00[]; +extern AnimatedMatTexScrollParams debug1_scene_header00_AnimatedMaterialTexScrollParams_01[]; +extern F3DPrimColor debug1_scene_header00_AnimatedMaterialColorPrimColor_02[]; +extern F3DEnvColor debug1_scene_header00_AnimatedMaterialColorEnvColor_02[]; +extern u16 debug1_scene_header00_AnimatedMaterialColorKeyFrames_02[]; +extern AnimatedMatColorParams debug1_scene_header00_AnimatedMaterialColorParams_02; +extern AnimatedMaterial debug1_scene_header00_AnimatedMaterial[]; +#endif +#if ENABLE_CUTSCENE_IMPROVEMENTS +extern Vec3s debug1_scene_header00_ActorCutsceneCameraData[]; +extern ActorCsCamInfo debug1_scene_header00_ActorCutsceneCameraInfo[]; +extern CutsceneEntry debug1_scene_header00_ActorCutsceneList[]; +#endif extern SceneCmd example_scene_header01[]; extern ActorEntry example_scene_header01_playerEntryList[]; extern Spawn example_scene_header01_entranceList[]; diff --git a/mod_assets/scenes/example/example_scene_main.c b/mod_assets/scenes/example/example_scene_main.c index aabb783b6..45d59d0e5 100644 --- a/mod_assets/scenes/example/example_scene_main.c +++ b/mod_assets/scenes/example/example_scene_main.c @@ -19,6 +19,13 @@ SceneCmd example_scene_header00[] = { SCENE_CMD_ENTRANCE_LIST(example_scene_header00_entranceList), SCENE_CMD_SPAWN_LIST(7, example_scene_header00_playerEntryList), SCENE_CMD_CUTSCENE_DATA(gExampleCS), +#if ENABLE_ANIMATED_MATERIALS + SCENE_CMD_ANIMATED_MATERIAL_LIST(debug1_scene_header00_AnimatedMaterial), +#endif +#if ENABLE_CUTSCENE_IMPROVEMENTS + SCENE_CMD_ACTOR_CUTSCENE_LIST(2, debug1_scene_header00_ActorCutsceneList), + SCENE_CMD_ACTOR_CUTSCENE_CAM_LIST(2, debug1_scene_header00_ActorCutsceneCameraInfo), +#endif SCENE_CMD_END(), }; @@ -153,6 +160,78 @@ EnvLightSettings example_scene_header00_lightSettings[4] = { }, }; +#if ENABLE_ANIMATED_MATERIALS +AnimatedMatTexScrollParams debug1_scene_header00_AnimatedMaterialTexScrollParams_00[] = { + { 0, -1, 32, 32 }, + { 0, -1, 32, 32 } +}; + +AnimatedMatTexScrollParams debug1_scene_header00_AnimatedMaterialTexScrollParams_01[] = { + { 0, 1, 32, 32 }, + { 0, -1, 32, 32 } +}; + +F3DPrimColor debug1_scene_header00_AnimatedMaterialColorPrimColor_02[] = { + { 255, 255, 255, 255, 128 }, + { 255, 255, 255, 255, 128 }, + { 128, 0, 0, 255, 128 }, + { 255, 255, 255, 255, 128 }, + { 255, 255, 255, 255, 128 } +}; + +F3DEnvColor debug1_scene_header00_AnimatedMaterialColorEnvColor_02[] = { + { 255, 255, 255, 255 }, + { 255, 255, 255, 255 }, + { 255, 255, 255, 255 }, + { 255, 255, 255, 255 }, + { 255, 255, 255, 255 } +}; + +u16 debug1_scene_header00_AnimatedMaterialColorKeyFrames_02[] = { + 0, + 5, + 30, + 55, + 59 +}; + +AnimatedMatColorParams debug1_scene_header00_AnimatedMaterialColorParams_02 = { + 60, + 5, + debug1_scene_header00_AnimatedMaterialColorPrimColor_02, + debug1_scene_header00_AnimatedMaterialColorEnvColor_02, + debug1_scene_header00_AnimatedMaterialColorKeyFrames_02, +}; + +AnimatedMaterial debug1_scene_header00_AnimatedMaterial[] = { + { 1 /* 8 */, 1, debug1_scene_header00_AnimatedMaterialTexScrollParams_00 }, + { 2 /* 9 */, 1, debug1_scene_header00_AnimatedMaterialTexScrollParams_01 }, + { -3 /* 10 */, 4, &debug1_scene_header00_AnimatedMaterialColorParams_02 } +}; +#endif + +#if ENABLE_CUTSCENE_IMPROVEMENTS +Vec3s debug1_scene_header00_ActorCutsceneCameraData[] = { + { 608, 279, -730 }, + { 0x0C3B, 0xE10A, 0x0000 }, + { 4000, -1, -1 }, + + { -506, 279, -730 }, + { 0x0C3B, 0x2067, 0x0000 }, + { -1, -1, -1 }, +}; + +ActorCsCamInfo debug1_scene_header00_ActorCutsceneCameraInfo[] = { + { CAM_SET_FIXED1, 3, &debug1_scene_header00_ActorCutsceneCameraData[0] }, + { CAM_SET_FIXED1, 3, &debug1_scene_header00_ActorCutsceneCameraData[3] }, +}; + +CutsceneEntry debug1_scene_header00_ActorCutsceneList[] = { + /* 0 */ { 500, 90, 0, -1, 1, CS_END_SFX_NONE, 255, CS_HUD_VISIBILITY_NONE, CS_END_CAM_SMOOTH, 20 }, + /* 1 */ { 501, 90, 1, -1, -1, CS_END_SFX_TRE_BOX_APPEAR, 255, CS_HUD_VISIBILITY_NONE, CS_END_CAM_SMOOTH, 35 }, +}; +#endif + /** * Header Child Night */ @@ -167,6 +246,13 @@ SceneCmd example_scene_header01[] = { SCENE_CMD_TRANSITION_ACTOR_LIST(1, example_scene_header01_transitionActors), SCENE_CMD_ENTRANCE_LIST(example_scene_header01_entranceList), SCENE_CMD_SPAWN_LIST(7, example_scene_header01_playerEntryList), +#if ENABLE_ANIMATED_MATERIALS + SCENE_CMD_ANIMATED_MATERIAL_LIST(debug1_scene_header00_AnimatedMaterial), +#endif +#if ENABLE_CUTSCENE_IMPROVEMENTS + SCENE_CMD_ACTOR_CUTSCENE_LIST(2, debug1_scene_header00_ActorCutsceneList), + SCENE_CMD_ACTOR_CUTSCENE_CAM_LIST(2, debug1_scene_header00_ActorCutsceneCameraInfo), +#endif SCENE_CMD_END(), }; @@ -305,6 +391,13 @@ SceneCmd example_scene_header02[] = { SCENE_CMD_TRANSITION_ACTOR_LIST(1, example_scene_header02_transitionActors), SCENE_CMD_ENTRANCE_LIST(example_scene_header02_entranceList), SCENE_CMD_SPAWN_LIST(7, example_scene_header02_playerEntryList), +#if ENABLE_ANIMATED_MATERIALS + SCENE_CMD_ANIMATED_MATERIAL_LIST(debug1_scene_header00_AnimatedMaterial), +#endif +#if ENABLE_CUTSCENE_IMPROVEMENTS + SCENE_CMD_ACTOR_CUTSCENE_LIST(2, debug1_scene_header00_ActorCutsceneList), + SCENE_CMD_ACTOR_CUTSCENE_CAM_LIST(2, debug1_scene_header00_ActorCutsceneCameraInfo), +#endif SCENE_CMD_END(), }; @@ -443,6 +536,13 @@ SceneCmd example_scene_header03[] = { SCENE_CMD_TRANSITION_ACTOR_LIST(1, example_scene_header03_transitionActors), SCENE_CMD_ENTRANCE_LIST(example_scene_header03_entranceList), SCENE_CMD_SPAWN_LIST(7, example_scene_header03_playerEntryList), +#if ENABLE_ANIMATED_MATERIALS + SCENE_CMD_ANIMATED_MATERIAL_LIST(debug1_scene_header00_AnimatedMaterial), +#endif +#if ENABLE_CUTSCENE_IMPROVEMENTS + SCENE_CMD_ACTOR_CUTSCENE_LIST(2, debug1_scene_header00_ActorCutsceneList), + SCENE_CMD_ACTOR_CUTSCENE_CAM_LIST(2, debug1_scene_header00_ActorCutsceneCameraInfo), +#endif SCENE_CMD_END(), }; diff --git a/spec b/spec index 28b254d29..8575e3380 100644 --- a/spec +++ b/spec @@ -963,7 +963,13 @@ beginseg #endif include "$(BUILD_DIR)/src/code/rainbow.o" include "$(BUILD_DIR)/src/code/helpers.o" +#if ENABLE_ANIMATED_MATERIALS include "$(BUILD_DIR)/src/code/animated_materials.o" +#endif +#if ENABLE_CUTSCENE_IMPROVEMENTS + include "$(BUILD_DIR)/src/code/cutscene_camera.o" + include "$(BUILD_DIR)/src/code/cutscene_manager.o" +#endif endseg #if ENABLE_HACKER_DEBUG diff --git a/src/code/animated_materials.c b/src/code/animated_materials.c index fbe802eb5..dd4221fe6 100644 --- a/src/code/animated_materials.c +++ b/src/code/animated_materials.c @@ -2,6 +2,9 @@ #include "global.h" #include "z64.h" #include "helpers.h" +#include "config.h" + +#if ENABLE_ANIMATED_MATERIALS static s32 sMatAnimStep; static u32 sMatAnimFlags; @@ -397,3 +400,5 @@ void AnimatedMat_DrawAlphaStepOpa(PlayState* play, AnimatedMaterial* matAnim, f3 void AnimatedMat_DrawAlphaStepXlu(PlayState* play, AnimatedMaterial* matAnim, f32 alphaRatio, u32 step) { AnimatedMat_DrawMain(play, matAnim, alphaRatio, step, 2); } + +#endif diff --git a/src/code/cutscene_camera.c b/src/code/cutscene_camera.c new file mode 100644 index 000000000..30e50d268 --- /dev/null +++ b/src/code/cutscene_camera.c @@ -0,0 +1,933 @@ +#include "global.h" +#include "string.h" +#include "z64olib.h" +#include "config.h" + +#if ENABLE_CUTSCENE_IMPROVEMENTS + +CutsceneCamera* sCurCsCamera; + +typedef s16 (*CsCamInterpolateCallback)(Vec3f*, f32*, s16*, CsCmdCamPoint*, CsCmdCamMisc*, CutsceneCameraInterp*); + +s16 CutsceneCamera_Interp_Off(Vec3f* camPos, f32* camFov, s16* camRoll, CsCmdCamPoint* pointCmd, CsCmdCamMisc* miscCmd, + CutsceneCameraInterp* interpState); +s16 CutsceneCamera_Interp_None(Vec3f* camPos, f32* camFov, s16* camRoll, CsCmdCamPoint* pointCmd, CsCmdCamMisc* miscCmd, + CutsceneCameraInterp* interpState); +s16 CutsceneCamera_Interp_MultiPointQuadratic(Vec3f* camPos, f32* camFov, s16* camRoll, CsCmdCamPoint* pointCmd, + CsCmdCamMisc* miscCmd, CutsceneCameraInterp* interpState); +s16 CutsceneCamera_Interp_MultiPointCubic(Vec3f* camPos, f32* camFov, s16* camRoll, CsCmdCamPoint* pointCmd, + CsCmdCamMisc* miscCmd, CutsceneCameraInterp* interpState); +s16 CutsceneCamera_Interp_Set(Vec3f* camPos, f32* camFov, s16* camRoll, CsCmdCamPoint* pointCmd, CsCmdCamMisc* miscCmd, + CutsceneCameraInterp* interpState); +s16 CutsceneCamera_Interp_Linear(Vec3f* camPos, f32* camFov, s16* camRoll, CsCmdCamPoint* pointCmd, + CsCmdCamMisc* miscCmd, CutsceneCameraInterp* interpState); +s16 CutsceneCamera_Interp_Scale(Vec3f* camPos, f32* camFov, s16* camRoll, CsCmdCamPoint* pointCmd, + CsCmdCamMisc* miscCmd, CutsceneCameraInterp* interpState); +s16 CutsceneCamera_Interp_Geo(Vec3f* camPos, f32* camFov, s16* camRoll, CsCmdCamPoint* pointCmd, CsCmdCamMisc* miscCmd, + CutsceneCameraInterp* interpState); +s16 CutsceneCamera_Interp_Unused(Vec3f* camPos, f32* camFov, s16* camRoll, CsCmdCamPoint* pointCmd, + CsCmdCamMisc* miscCmd, CutsceneCameraInterp* interpState); + +f32 func_80163660(Actor* actor); + +s16 CutsceneCamera_Interp_Off(Vec3f* camPos, f32* camFov, s16* camRoll, CsCmdCamPoint* pointCmd, CsCmdCamMisc* miscCmd, + CutsceneCameraInterp* interpState) { + return 0; +} + +/** + * Initializes Cutscene Camera Info + */ +s32 CutsceneCamera_Init(Camera* camera, CutsceneCamera* csCamera) { + csCamera->camera = camera; + + csCamera->nextSplineTimer = csCamera->updateSplineTimer = 0; + csCamera->cmdIndex = 0; + csCamera->splineIndex = 0xFFFF; + csCamera->splineNeedsInit = true; + csCamera->state = CS_CAM_STATE_UPDATE_ALL; + + sCurCsCamera = csCamera; + + memset(&csCamera->eyeInterp, 0, sizeof(CutsceneCameraInterp)); + memset(&csCamera->atInterp, 0, sizeof(CutsceneCameraInterp)); + + csCamera->eyeInterp.type = csCamera->atInterp.type = CS_CAM_INTERP_OFF; + + return 1; +} + +CsCamInterpolateCallback CutsceneCamera_Interpolate(u8 interpType) { + switch (interpType) { + case CS_CAM_INTERP_OFF: + default: + return CutsceneCamera_Interp_Off; + + case CS_CAM_INTERP_NONE: + return CutsceneCamera_Interp_None; + + case CS_CAM_INTERP_MP_QUAD: + return CutsceneCamera_Interp_MultiPointQuadratic; + + case CS_CAM_INTERP_MP_CUBIC: + return CutsceneCamera_Interp_MultiPointCubic; + + case CS_CAM_INTERP_SET: + return CutsceneCamera_Interp_Set; + + case CS_CAM_INTERP_LINEAR: + return CutsceneCamera_Interp_Linear; + + case CS_CAM_INTERP_SCALE: + return CutsceneCamera_Interp_Scale; + + case CS_CAM_INTERP_GEO: + return CutsceneCamera_Interp_Geo; + } +} + +u8 CutsceneCamera_ProcessSpline(CutsceneCamera* csCamera) { + s32 sp5C; + f32* camFov; + s16* camRoll; + CsCamInterpolateCallback interpHandler; + Player* player; + Actor* target; + s16 numPoints; + + sp5C = true; + if (csCamera->state == CS_CAM_STATE_DONE_SPLINE) { + return false; + } + + player = GET_PLAYER(csCamera->camera->play); + target = csCamera->camera->target; + + if (csCamera->eyeCmd[csCamera->atInterp.curPoint].interpType < + csCamera->atCmd[csCamera->eyeInterp.curPoint].interpType) { + sp5C = false; + } + + csCamera->eyeInterp.curPos = csCamera->camera->eye; + csCamera->atInterp.curPos = csCamera->camera->at; + + if (sp5C) { + camFov = NULL; + } else { + camFov = &csCamera->camera->fov; + } + + if (sp5C) { + camRoll = NULL; + } else { + camRoll = &csCamera->camera->roll; + } + + interpHandler = CutsceneCamera_Interpolate(csCamera->atCmd[csCamera->eyeInterp.curPoint].interpType); + + switch (csCamera->atCmd[csCamera->eyeInterp.curPoint].relativeTo) { + case CS_CAM_REL_2: + OLib_Vec3fDiff(&player->actor.world, &csCamera->camera->at, &csCamera->camera->at, OLIB_DIFF); + break; + + case CS_CAM_REL_3: + OLib_Vec3fDiff(&player->actor.world, &csCamera->camera->at, &csCamera->camera->at, OLIB_DIFF_OFFSET); + break; + + case CS_CAM_REL_1: + OLib_Vec3fDiff(&player->actor.world, &csCamera->camera->at, &csCamera->camera->at, OLIB_DIFF_OFFSET); + break; + + case CS_CAM_REL_4: + OLib_Vec3fDiff(&target->world, &csCamera->camera->at, &csCamera->camera->at, OLIB_DIFF_OFFSET); + break; + + case CS_CAM_REL_5: + OLib_Vec3fDiff(&target->world, &csCamera->camera->at, &csCamera->camera->at, OLIB_DIFF); + break; + + default: // CS_CAM_REL_0 + break; + } + + numPoints = interpHandler(&csCamera->camera->at, camFov, camRoll, &csCamera->atCmd[csCamera->eyeInterp.curPoint], + &csCamera->miscCmd[csCamera->eyeInterp.curPoint], &csCamera->eyeInterp); + + switch (csCamera->atCmd[csCamera->eyeInterp.curPoint].relativeTo) { + case CS_CAM_REL_2: + OLib_Vec3fAdd(&player->actor.world, &csCamera->camera->at, &csCamera->camera->at, OLIB_ADD); + break; + + case CS_CAM_REL_3: + OLib_Vec3fAdd(&player->actor.world, &csCamera->camera->at, &csCamera->camera->at, OLIB_ADD_OFFSET); + csCamera->camera->at.y += func_80163660(&player->actor); + break; + + case CS_CAM_REL_1: + OLib_Vec3fAdd(&player->actor.world, &csCamera->camera->at, &csCamera->camera->at, OLIB_ADD_OFFSET); + break; + + case CS_CAM_REL_4: + OLib_Vec3fAdd(&target->world, &csCamera->camera->at, &csCamera->camera->at, OLIB_ADD_OFFSET); + break; + + case CS_CAM_REL_5: + OLib_Vec3fAdd(&target->world, &csCamera->camera->at, &csCamera->camera->at, OLIB_ADD); + break; + + default: // CS_CAM_REL_0 + break; + } + + csCamera->eyeInterp.curPoint += numPoints; + + if (sp5C) { + camFov = &csCamera->camera->fov; + } else { + camFov = NULL; + } + + if (sp5C) { + camRoll = &csCamera->camera->roll; + } else { + camRoll = NULL; + } + + interpHandler = CutsceneCamera_Interpolate(csCamera->eyeCmd[csCamera->atInterp.curPoint].interpType); + + switch (csCamera->eyeCmd[csCamera->atInterp.curPoint].relativeTo) { + case CS_CAM_REL_2: + OLib_Vec3fDiff(&player->actor.world, &csCamera->camera->eye, &csCamera->camera->eye, OLIB_DIFF); + break; + + case CS_CAM_REL_3: + OLib_Vec3fDiff(&player->actor.world, &csCamera->camera->eye, &csCamera->camera->eye, OLIB_DIFF_OFFSET); + break; + + case CS_CAM_REL_1: + OLib_Vec3fDiff(&player->actor.world, &csCamera->camera->eye, &csCamera->camera->eye, OLIB_DIFF_OFFSET); + break; + + case CS_CAM_REL_4: + OLib_Vec3fDiff(&target->world, &csCamera->camera->eye, &csCamera->camera->eye, OLIB_DIFF_OFFSET); + break; + + case CS_CAM_REL_5: + OLib_Vec3fDiff(&target->world, &csCamera->camera->eye, &csCamera->camera->eye, OLIB_DIFF); + break; + + default: // CS_CAM_REL_0 + break; + } + + numPoints = interpHandler(&csCamera->camera->eye, camFov, camRoll, &csCamera->eyeCmd[csCamera->atInterp.curPoint], + &csCamera->miscCmd[csCamera->atInterp.curPoint], &csCamera->atInterp); + + switch (csCamera->eyeCmd[csCamera->atInterp.curPoint].relativeTo) { + case CS_CAM_REL_2: + OLib_Vec3fAdd(&player->actor.world, &csCamera->camera->eye, &csCamera->camera->eye, OLIB_ADD); + break; + + case CS_CAM_REL_3: + OLib_Vec3fAdd(&player->actor.world, &csCamera->camera->eye, &csCamera->camera->eye, OLIB_ADD_OFFSET); + csCamera->camera->eye.y += func_80163660(&player->actor); + break; + + case CS_CAM_REL_1: + OLib_Vec3fAdd(&player->actor.world, &csCamera->camera->eye, &csCamera->camera->eye, OLIB_ADD_OFFSET); + break; + + case CS_CAM_REL_4: + OLib_Vec3fAdd(&target->world, &csCamera->camera->eye, &csCamera->camera->eye, OLIB_ADD_OFFSET); + break; + + case CS_CAM_REL_5: + OLib_Vec3fAdd(&target->world, &csCamera->camera->eye, &csCamera->camera->eye, OLIB_ADD); + break; + + default: // CS_CAM_REL_0 + break; + } + + csCamera->atInterp.curPoint += numPoints; + + if ((csCamera->eyeInterp.curPoint >= csCamera->eyeInterp.numEntries) || + (csCamera->atInterp.curPoint >= csCamera->atInterp.numEntries)) { + return false; + } + + return true; +} + +/** + * Processes camera cutscene commands + */ +s32 CutsceneCamera_UpdateSplines(u8* script, CutsceneCamera* csCamera) { + CsCmdCamSpline* spline; + + switch (csCamera->state) { + case CS_CAM_STATE_DONE: + return 0; + + case CS_CAM_STATE_PAUSE: + return csCamera->nextSplineTimer; + + case CS_CAM_STATE_UPDATE_SPLINE: + if (csCamera->updateSplineTimer <= csCamera->duration) { + csCamera->updateSplineTimer++; + if (csCamera->updateSplineTimer <= csCamera->duration) { + // Process Spline + if (!CutsceneCamera_ProcessSpline(csCamera)) { + csCamera->state = CS_CAM_STATE_DONE_SPLINE; + } + } + } + break; + + case CS_CAM_STATE_DONE_SPLINE: + break; + + default: // CS_CAM_STATE_UPDATE_ALL + if (csCamera->splineNeedsInit == true) { + // Spline Header + spline = (CsCmdCamSpline*)&script[csCamera->cmdIndex]; + csCamera->atInterp.numEntries = csCamera->eyeInterp.numEntries = spline->numEntries; + csCamera->duration = spline->duration; + csCamera->cmdIndex += sizeof(CsCmdCamSpline); + + // At Point + csCamera->atCmd = (CsCmdCamPoint*)&script[csCamera->cmdIndex]; + csCamera->cmdIndex += (s16)(csCamera->eyeInterp.numEntries * sizeof(CsCmdCamPoint)); + + // Misc Point + csCamera->eyeCmd = (CsCmdCamPoint*)&script[csCamera->cmdIndex]; + csCamera->cmdIndex += (s16)(csCamera->eyeInterp.numEntries * sizeof(CsCmdCamPoint)); + + // Misc + csCamera->miscCmd = (CsCmdCamMisc*)&script[csCamera->cmdIndex]; + csCamera->cmdIndex += (s16)(csCamera->eyeInterp.numEntries * sizeof(CsCmdCamMisc)); + + // Other Params + csCamera->eyeInterp.curPoint = 0; + csCamera->atInterp.curPoint = 0; + + csCamera->splineNeedsInit = false; + //! FAKE: csCamera->splineIndex++; + csCamera->splineIndex = (csCamera->splineIndex & 0xFFFF) + 1; + csCamera->state = CS_CAM_STATE_UPDATE_ALL; + csCamera->nextSplineTimer = csCamera->updateSplineTimer = 0; + csCamera->eyeInterp.type = csCamera->atInterp.type = CS_CAM_INTERP_OFF; + } + + csCamera->nextSplineTimer++; + + if (csCamera->updateSplineTimer <= csCamera->duration) { + csCamera->updateSplineTimer++; + if (csCamera->updateSplineTimer <= csCamera->duration) { + // Process SubCommands + if (!CutsceneCamera_ProcessSpline(csCamera)) { + csCamera->state = CS_CAM_STATE_DONE_SPLINE; + } + } + } + break; + } + + if (csCamera->nextSplineTimer > csCamera->duration) { + // Next Spline + csCamera->splineNeedsInit = true; + spline = (CsCmdCamSpline*)&script[csCamera->cmdIndex]; + if (spline->numEntries == -1) { + csCamera->state = CS_CAM_STATE_DONE; + return 0; + } + } + + return csCamera->nextSplineTimer; +} + +// Unused +s16 func_80161BAC(void) { + return (sCurCsCamera->state == CS_CAM_STATE_PAUSE) || (sCurCsCamera->state == CS_CAM_STATE_UPDATE_SPLINE); +} + +void CutsceneCamera_SetState(s16 state) { + if (sCurCsCamera->state == CS_CAM_STATE_UPDATE_ALL) { + sCurCsCamera->state = state; + } +} + +void CutsceneCamera_Reset(void) { + sCurCsCamera->state = CS_CAM_STATE_UPDATE_ALL; +} + +// Linear interpolation from initial values to cmd values. Set weight to 100 to go all the way to the cmd value. +s16 CutsceneCamera_Interp_Linear(Vec3f* camPos, f32* camFov, s16* camRoll, CsCmdCamPoint* pointCmd, + CsCmdCamMisc* miscCmd, CutsceneCameraInterp* interpState) { + f32 lerp; + + if (interpState->type != CS_CAM_INTERP_LINEAR) { + // Initialize + interpState->type = CS_CAM_INTERP_LINEAR; + interpState->waypoint = 0; + interpState->curFrame = 0; + interpState->duration = 1; + if (camPos != NULL) { + interpState->initPos.x = camPos->x; + interpState->initPos.y = camPos->y; + interpState->initPos.z = camPos->z; + } + + if (camFov != NULL) { + interpState->initFov = *camFov; + } + + if (camRoll != NULL) { + interpState->initRoll = *camRoll; + } + } + + interpState->curFrame++; + + lerp = ((f32)interpState->curFrame / pointCmd->duration) * (pointCmd->weight / 100.0f); + + if (camPos != NULL) { + VEC3F_LERPIMPDST(camPos, &interpState->initPos, &pointCmd->pos, lerp); + } + + if (camFov != NULL) { + *camFov = F32_LERPIMP(interpState->initFov, miscCmd->fov, lerp); + } + + if (camRoll != NULL) { + s16 targetRoll; + s16 rollDiffToTarget; + + targetRoll = CAM_DEG_TO_BINANG(miscCmd->roll); + + rollDiffToTarget = (s16)(targetRoll - TRUNCF_BINANG(interpState->initRoll)); + + *camRoll = TRUNCF_BINANG(interpState->initRoll) + TRUNCF_BINANG(rollDiffToTarget * lerp); + } + + if (interpState->curFrame >= pointCmd->duration) { + // Finished + interpState->type = CS_CAM_INTERP_OFF; + return 1; + } + + return 0; +} + +s16 CutsceneCamera_Interp_Scale(Vec3f* camPos, f32* camFov, s16* camRoll, CsCmdCamPoint* pointCmd, + CsCmdCamMisc* miscCmd, CutsceneCameraInterp* interpState) { + f32 lerp; + f32 tmp1; + f32 tmp2; + + if (interpState->type != CS_CAM_INTERP_SCALE) { + // Initialize + interpState->type = CS_CAM_INTERP_SCALE; + interpState->waypoint = 0; + interpState->curFrame = 0; + interpState->duration = 1; + if (camPos != NULL) { + interpState->initPos.x = camPos->x; + interpState->initPos.y = camPos->y; + interpState->initPos.z = camPos->z; + } + if (camFov != NULL) { + interpState->initFov = *camFov; + } + if (camRoll != NULL) { + interpState->initRoll = *camRoll; + } + } + + tmp2 = (((pointCmd->weight + 100) * (pointCmd->duration / 2)) + + (((pointCmd->weight + 100) / 2) * (pointCmd->duration & 1))); + if (pointCmd->duration < 2) { + lerp = 1.0f; + } else { + tmp1 = (f32)(pointCmd->weight - 100) / (pointCmd->duration - 1); + lerp = ((interpState->curFrame * tmp1) + 100.0f) / tmp2; + } + + interpState->curFrame++; + + if (camPos != NULL) { + camPos->x += (pointCmd->pos.x - interpState->initPos.x) * lerp; + camPos->y += (pointCmd->pos.y - interpState->initPos.y) * lerp; + camPos->z += (pointCmd->pos.z - interpState->initPos.z) * lerp; + } + + if (camFov != NULL) { + *camFov += (miscCmd->fov - interpState->initFov) * lerp; + } + + if (camRoll != NULL) { + s16 targetRoll; + s16 rollDiffToTarget; + + targetRoll = CAM_DEG_TO_BINANG(miscCmd->roll); + + rollDiffToTarget = (s16)(targetRoll - TRUNCF_BINANG(interpState->initRoll)); + + *camRoll += TRUNCF_BINANG(rollDiffToTarget * lerp); + } + + if (interpState->curFrame >= pointCmd->duration) { + // Finished + interpState->type = CS_CAM_INTERP_OFF; + return 1; + } + + return 0; +} + +s16 CutsceneCamera_Interp_Geo(Vec3f* camPos, f32* camFov, s16* camRoll, CsCmdCamPoint* pointCmd, CsCmdCamMisc* miscCmd, + CutsceneCameraInterp* interpState) { + VecGeo sp40; + f32 lerp; + f32 tmp1; + f32 tmp2; + + if (interpState->type != CS_CAM_INTERP_GEO) { + // Initialize + interpState->type = CS_CAM_INTERP_GEO; + interpState->waypoint = 0; + interpState->curFrame = 0; + interpState->duration = 1; + if (camPos != NULL) { + interpState->unk_20 = OLib_Vec3fDist(&interpState->curPos, camPos) * Math_FTanF(DEG_TO_RAD(*camFov)); + } + if (camFov != NULL) { + interpState->initFov = *camFov; + } + if (camRoll != NULL) { + interpState->initRoll = *camRoll; + } + } + + tmp2 = (((pointCmd->weight + 100) * (pointCmd->duration / 2)) + + (((pointCmd->weight + 100) / 2) * (pointCmd->duration & 1))); + if (pointCmd->duration < 2) { + lerp = 1.0f; + } else { + tmp1 = (f32)(pointCmd->weight - 100) / (pointCmd->duration - 1); + lerp = ((interpState->curFrame * tmp1) + 100.0f) / tmp2; + } + + interpState->curFrame++; + + if (camPos != NULL) { + sp40 = OLib_Vec3fDiffToVecGeo(&interpState->curPos, camPos); + sp40.r = interpState->unk_20 / Math_FTanF(DEG_TO_RAD(*camFov)); + *camPos = OLib_AddVecGeoToVec3f(&interpState->curPos, &sp40); + } + + if (camFov != NULL) { + *camFov += (miscCmd->fov - interpState->initFov) * lerp; + } + + if (camRoll != NULL) { + s16 targetRoll; + s16 rollDiffToTarget; + + targetRoll = CAM_DEG_TO_BINANG(miscCmd->roll); + + rollDiffToTarget = (s16)(targetRoll - TRUNCF_BINANG(interpState->initRoll)); + + *camRoll += TRUNCF_BINANG(rollDiffToTarget * lerp); + } + + if (interpState->curFrame >= pointCmd->duration) { + // Finished + interpState->type = CS_CAM_INTERP_OFF; + return 1; + } + + return 0; +} + +// Updates the interpolation state but does not change the pos/fov/roll values +s16 CutsceneCamera_Interp_None(Vec3f* camPos, f32* camFov, s16* camRoll, CsCmdCamPoint* pointCmd, CsCmdCamMisc* miscCmd, + CutsceneCameraInterp* interpState) { + if (interpState->type != CS_CAM_INTERP_NONE) { + // Initialize + interpState->type = CS_CAM_INTERP_NONE; + interpState->waypoint = 0; + interpState->curFrame = 0; + interpState->duration = 1; + } + + interpState->curFrame++; + + if (interpState->curFrame >= pointCmd->duration) { + // Finishes + interpState->type = CS_CAM_INTERP_OFF; + return 1; + } + + return 0; +} + +// Immediately sets the values +s16 CutsceneCamera_Interp_Set(Vec3f* camPos, f32* camFov, s16* camRoll, CsCmdCamPoint* pointCmd, CsCmdCamMisc* miscCmd, + CutsceneCameraInterp* interpState) { + s16 pad; + + if (interpState->type != CS_CAM_INTERP_SET) { + // Initialize + interpState->type = CS_CAM_INTERP_SET; + interpState->waypoint = 0; + interpState->curFrame = 0; + interpState->duration = 1; + if (camFov != NULL) { + *camFov = miscCmd->fov; + } + if (camRoll != NULL) { + *camRoll = CAM_DEG_TO_BINANG(miscCmd->roll); + } + } + + if (camPos != NULL) { + camPos->x = pointCmd->pos.x; + camPos->y = pointCmd->pos.y; + camPos->z = pointCmd->pos.z; + } + + interpState->curFrame++; + + if (interpState->curFrame >= pointCmd->duration) { + // Finished + interpState->type = CS_CAM_INTERP_OFF; + return 1; + } + + return 0; +} + +void func_801624EC(f32 u, f32* coeff) { + f32 u1 = 1.0f - u; + + coeff[0] = u1 * u1 * 0.5f; + coeff[1] = u * u1 + 0.5f; + coeff[2] = u * u * 0.5f; +} + +s16 CutsceneCamera_Interp_MultiPointQuadratic(Vec3f* camPos, f32* camFov, s16* camRoll, CsCmdCamPoint* pointCmd, + CsCmdCamMisc* miscCmd, CutsceneCameraInterp* interpState) { + f32 new_var; + f32 coeff[3]; + s32 waypoints[3]; + + if (interpState->type != CS_CAM_INTERP_MP_QUAD) { + // Initialize + interpState->type = CS_CAM_INTERP_MP_QUAD; + interpState->waypoint = 0; + interpState->duration = pointCmd->duration; + interpState->curFrame = 0; + } + + new_var = (f32)interpState->curFrame / pointCmd[interpState->waypoint + 1].duration; + + if (interpState->waypoint < (interpState->duration - 1)) { + waypoints[0] = interpState->waypoint; + } else { + waypoints[0] = interpState->duration - 1; + } + + if ((interpState->waypoint + 1) < (interpState->duration - 1)) { + waypoints[1] = interpState->waypoint + 1; + } else { + waypoints[1] = interpState->duration - 1; + } + + if ((interpState->waypoint + 2) < (interpState->duration - 1)) { + waypoints[2] = interpState->waypoint + 2; + } else { + waypoints[2] = interpState->duration - 1; + } + + func_801624EC(new_var, coeff); + + if (camPos != NULL) { + camPos->x = (coeff[0] * pointCmd[waypoints[0]].pos.x) + (coeff[1] * pointCmd[waypoints[1]].pos.x) + + (coeff[2] * pointCmd[waypoints[2]].pos.x); + camPos->y = (coeff[0] * pointCmd[waypoints[0]].pos.y) + (coeff[1] * pointCmd[waypoints[1]].pos.y) + + (coeff[2] * pointCmd[waypoints[2]].pos.y); + camPos->z = (coeff[0] * pointCmd[waypoints[0]].pos.z) + (coeff[1] * pointCmd[waypoints[1]].pos.z) + + (coeff[2] * pointCmd[waypoints[2]].pos.z); + } + + if (camFov != NULL) { + *camFov = (coeff[0] * miscCmd[waypoints[0]].fov) + (coeff[1] * miscCmd[waypoints[1]].fov) + + (coeff[2] * miscCmd[waypoints[2]].fov); + } + + if (camRoll != NULL) { + s16 targetRolls[3]; + s32 sp28[2]; + s32 rollDiffToTarget; + + targetRolls[0] = CAM_DEG_TO_BINANG(miscCmd[waypoints[0]].roll); + targetRolls[1] = CAM_DEG_TO_BINANG(miscCmd[waypoints[1]].roll); + targetRolls[2] = CAM_DEG_TO_BINANG(miscCmd[waypoints[2]].roll); + + sp28[0] = (s16)(targetRolls[1] - targetRolls[0]); + sp28[1] = sp28[0] + (s16)(targetRolls[2] - targetRolls[1]); + + rollDiffToTarget = ((coeff[1] * sp28[0]) + (coeff[2] * sp28[1])); + *camRoll = targetRolls[0] + rollDiffToTarget; + } + + interpState->curFrame++; + + if (interpState->curFrame == pointCmd[interpState->waypoint + 1].duration) { + interpState->waypoint++; + interpState->curFrame = 0; + if (interpState->waypoint >= (interpState->duration - 2)) { + interpState->type = CS_CAM_INTERP_OFF; + return interpState->duration; + } + } + return 0; +} + +/** + * This code is very similar to the spline system in OoT's func_800BB0A0 + * in that it is based on the Super Mario 64 cutscene camera movement + */ +void func_801629BC(f32 u, f32* coeff) { + coeff[0] = (1.0f - u) * (1.0f - u) * (1.0f - u) * (1.0f / 6.0f); + coeff[1] = ((u * u * u * 0.5f) - u * u) + (2.0f / 3.0f); + coeff[2] = (u * u * u * -0.5f) + (u * u * 0.5f) + (u * 0.5f) + (1.0f / 6.0f); + coeff[3] = u * u * u * (1.0f / 6.0f); +} + +s16 CutsceneCamera_Interp_MultiPointCubic(Vec3f* camPos, f32* camFov, s16* camRoll, CsCmdCamPoint* pointCmd, + CsCmdCamMisc* miscCmd, CutsceneCameraInterp* interpState) { + f32 new_var; + f32 coeff[4]; + s32 waypoints[4]; + + if (interpState->type != CS_CAM_INTERP_MP_CUBIC) { + // Initialize + interpState->type = CS_CAM_INTERP_MP_CUBIC; + interpState->waypoint = 0; + interpState->duration = pointCmd->duration; + interpState->curFrame = 0; + } + + new_var = (f32)interpState->curFrame / pointCmd[interpState->waypoint + 1].duration; + + if (interpState->waypoint < (interpState->duration - 1)) { + waypoints[0] = interpState->waypoint; + } else { + waypoints[0] = interpState->duration - 1; + } + + if ((interpState->waypoint + 1) < (interpState->duration - 1)) { + waypoints[1] = interpState->waypoint + 1; + } else { + waypoints[1] = interpState->duration - 1; + } + + if ((interpState->waypoint + 2) < (interpState->duration - 1)) { + waypoints[2] = interpState->waypoint + 2; + } else { + waypoints[2] = interpState->duration - 1; + } + + if ((interpState->waypoint + 3) < (interpState->duration - 1)) { + waypoints[3] = interpState->waypoint + 3; + } else { + waypoints[3] = interpState->duration - 1; + } + + func_801629BC(new_var, coeff); + + if (camPos != NULL) { + camPos->x = (coeff[0] * pointCmd[waypoints[0]].pos.x) + (coeff[1] * pointCmd[waypoints[1]].pos.x) + + (coeff[2] * pointCmd[waypoints[2]].pos.x) + (coeff[3] * pointCmd[waypoints[3]].pos.x); + camPos->y = (coeff[0] * pointCmd[waypoints[0]].pos.y) + (coeff[1] * pointCmd[waypoints[1]].pos.y) + + (coeff[2] * pointCmd[waypoints[2]].pos.y) + (coeff[3] * pointCmd[waypoints[3]].pos.y); + camPos->z = (coeff[0] * pointCmd[waypoints[0]].pos.z) + (coeff[1] * pointCmd[waypoints[1]].pos.z) + + (coeff[2] * pointCmd[waypoints[2]].pos.z) + (coeff[3] * pointCmd[waypoints[3]].pos.z); + } + + if (camFov != NULL) { + *camFov = (coeff[0] * miscCmd[waypoints[0]].fov) + (coeff[1] * miscCmd[waypoints[1]].fov) + + (coeff[2] * miscCmd[waypoints[2]].fov) + (coeff[3] * miscCmd[waypoints[3]].fov); + } + + if (camRoll != NULL) { + s16 targetRolls[4]; + s32 sp2C[3]; + s32 rollDiffToTarget; + + targetRolls[0] = CAM_DEG_TO_BINANG(miscCmd[waypoints[0]].roll); + targetRolls[1] = CAM_DEG_TO_BINANG(miscCmd[waypoints[1]].roll); + targetRolls[2] = CAM_DEG_TO_BINANG(miscCmd[waypoints[2]].roll); + targetRolls[3] = CAM_DEG_TO_BINANG(miscCmd[waypoints[3]].roll); + + sp2C[0] = (s16)(targetRolls[1] - targetRolls[0]); + sp2C[1] = sp2C[0] + (s16)(targetRolls[2] - targetRolls[1]); + sp2C[2] = sp2C[1] + (s16)(targetRolls[3] - targetRolls[2]); + + rollDiffToTarget = ((coeff[1] * sp2C[0]) + (coeff[2] * sp2C[1]) + (coeff[3] * sp2C[2])); + *camRoll = targetRolls[0] + rollDiffToTarget; + } + + interpState->curFrame++; + + if (interpState->curFrame == pointCmd[interpState->waypoint + 1].duration) { + interpState->curFrame = 0; + interpState->waypoint++; + if (interpState->waypoint >= (interpState->duration - 3)) { + interpState->type = CS_CAM_INTERP_OFF; + return interpState->duration; + } + } + return 0; +} + +f32 sCsCamKnots[38]; + +// Only used by unused CutsceneCamera_Interp_Unused +void func_80162FF8(s16 arg0) { + f32 val = 0.0f; + s32 i; + + sCsCamKnots[0] = 0.0f; + sCsCamKnots[1] = 0.0f; + sCsCamKnots[2] = 0.0f; + + for (i = 3; i < arg0; i++) { + if (i == 3) { + val += 0.9f; + } else if ((i == 4) || (i == (arg0 - 1))) { + val += 0.6f; + } else { + val += 0.3f; + } + + sCsCamKnots[i] = val; + } + + val += 0.9f; + sCsCamKnots[i++] = val; + sCsCamKnots[i++] = val; + sCsCamKnots[i++] = val; +} + +#define FUNC_801631DC_ORDER 3 + +// Only used by unused CutsceneCamera_Interp_Unused +void func_801631DC(f32 progress, s32 arg2, f32* coeff) { + f32 coeffTemp[4][4]; + s32 i; + s32 j; + s32 k; + + for (i = 0; i < FUNC_801631DC_ORDER + 1; i++) { + for (j = 0; j < FUNC_801631DC_ORDER + 1; j++) { + coeffTemp[i][j] = 0.0f; + } + } + + coeffTemp[0][FUNC_801631DC_ORDER - 1] = 1.0f; + + for (i = 1; i < FUNC_801631DC_ORDER; i++) { + for (j = arg2 - i, k = (FUNC_801631DC_ORDER - 1) - i; j <= arg2; j++, k++) { + if (sCsCamKnots[j + i] != sCsCamKnots[j]) { + coeffTemp[i][k] = + ((progress - sCsCamKnots[j]) / (sCsCamKnots[j + i] - sCsCamKnots[j])) * coeffTemp[i - 1][k]; + } else { + coeffTemp[i][k] = 0.0f; + } + + if (sCsCamKnots[j + i + 1] != sCsCamKnots[j + 1]) { + coeffTemp[i][k] += + ((sCsCamKnots[j + i + 1] - progress) / (sCsCamKnots[j + i + 1] - sCsCamKnots[j + 1])) * + coeffTemp[i - 1][k + 1]; + } + } + } + for (j = 0; j < FUNC_801631DC_ORDER; j++) { + coeff[j] = coeffTemp[FUNC_801631DC_ORDER - 1][j]; + } +} + +s16 CutsceneCamera_Interp_Unused(Vec3f* camPos, f32* camFov, s16* camRoll, CsCmdCamPoint* pointCmd, + CsCmdCamMisc* miscCmd, CutsceneCameraInterp* interpState) { + s32 index; + f32 coeff[3]; + + if (interpState->type != CS_CAM_INTERP_MP_CUBIC) { + // Initialize + interpState->type = CS_CAM_INTERP_MP_CUBIC; + interpState->waypoint = 0; + interpState->duration = pointCmd->duration; + func_80162FF8(interpState->duration); + interpState->curFrame = 0; + } + + index = interpState->waypoint + 2; + func_801631DC(F32_LERPIMP(sCsCamKnots[index], sCsCamKnots[index + 1], + (f32)interpState->curFrame / miscCmd[interpState->waypoint].unused0), + index, coeff); + + if (camPos != NULL) { + camPos->x = (coeff[0] * pointCmd[interpState->waypoint].pos.x) + + (coeff[1] * pointCmd[interpState->waypoint + 1].pos.x) + + (coeff[2] * pointCmd[interpState->waypoint + 2].pos.x); + camPos->y = (coeff[0] * pointCmd[interpState->waypoint].pos.y) + + (coeff[1] * pointCmd[interpState->waypoint + 1].pos.y) + + (coeff[2] * pointCmd[interpState->waypoint + 2].pos.y); + camPos->z = (coeff[0] * pointCmd[interpState->waypoint].pos.z) + + (coeff[1] * pointCmd[interpState->waypoint + 1].pos.z) + + (coeff[2] * pointCmd[interpState->waypoint + 2].pos.z); + } + + if (camFov != NULL) { + *camFov = (coeff[0] * miscCmd[interpState->waypoint].fov) + + (coeff[1] * miscCmd[interpState->waypoint + 1].fov) + + (coeff[2] * miscCmd[interpState->waypoint + 2].fov); + } + + if (camRoll != NULL) { + *camRoll = CAM_DEG_TO_BINANG((coeff[0] * miscCmd[interpState->waypoint].roll) + + (coeff[1] * miscCmd[interpState->waypoint + 1].roll) + + (coeff[2] * miscCmd[interpState->waypoint + 2].roll)); + } + + interpState->curFrame++; + + if (interpState->curFrame >= miscCmd[interpState->waypoint].unused0) { + interpState->waypoint++; + interpState->curFrame = 0; + if (interpState->waypoint >= (interpState->duration - 2)) { + interpState->type = CS_CAM_INTERP_OFF; + return interpState->duration; + } + } + return 0; +} + +f32 func_80163660(Actor* actor) { + if (actor->category != ACTORCAT_PLAYER) { + return 38.0f - (actor->focus.pos.y - actor->world.pos.y); + } + + switch (gSaveContext.save.linkAge) { + case LINK_AGE_ADULT: + return 17.0f; + + default: + return 0.0f; + } +} + +#endif diff --git a/src/code/cutscene_manager.c b/src/code/cutscene_manager.c new file mode 100644 index 000000000..6b4061226 --- /dev/null +++ b/src/code/cutscene_manager.c @@ -0,0 +1,584 @@ +/** + * @file z_eventmgr.c + * + * Manages all cutscenes except for manual + */ + +#include "z64cutscene.h" + +#include "string.h" +#include "attributes.h" + +#include "global.h" +#include "z64olib.h" +#include "letterbox.h" +#include "config.h" +#include "z64camera.h" + +#if ENABLE_CUTSCENE_IMPROVEMENTS + +CutsceneEntry sGlobalCutsceneList[] = { + // CS_ID_GLOBAL_78 + { -100, -1, CS_CAM_ID_NONE, CS_SCRIPT_ID_NONE, CS_ID_NONE, CS_END_SFX_NONE_ALT, 255, CS_HUD_VISIBILITY_ALL_ALT, 255, + 255 }, + // CS_ID_GLOBAL_79 + { -100, -1, CS_CAM_ID_NONE, CS_SCRIPT_ID_NONE, CS_ID_NONE, CS_END_SFX_NONE_ALT, 255, CS_HUD_VISIBILITY_ALL_ALT, 255, + 255 }, + // CS_ID_GLOBAL_7A + { -100, -1, CS_CAM_ID_NONE, CS_SCRIPT_ID_NONE, CS_ID_NONE, CS_END_SFX_NONE_ALT, 255, CS_HUD_VISIBILITY_ALL_ALT, 255, + 255 }, + // CS_ID_GLOBAL_TALK + { 32765, -1, CS_CAM_ID_NONE, CS_SCRIPT_ID_NONE, CS_ID_NONE, CS_END_SFX_NONE_ALT, 255, CS_HUD_VISIBILITY_ALL_ALT, + CS_END_CAM_0, 255 }, + // CS_ID_GLOBAL_DOOR + { 32764, -1, CS_CAM_ID_NONE, CS_SCRIPT_ID_NONE, CS_ID_NONE, CS_END_SFX_NONE_ALT, 255, CS_HUD_VISIBILITY_ALL_ALT, + CS_END_CAM_0, 255 }, + // CS_ID_GLOBAL_END + { 0, -1, CS_CAM_ID_NONE, CS_SCRIPT_ID_NONE, CS_ID_NONE, CS_END_SFX_NONE, 255, CS_HUD_VISIBILITY_ALL_ALT, + CS_END_CAM_0, 32 }, +}; + +typedef enum { + /* 0 */ CS_START_0, + /* 1 */ CS_START_1, + /* 2 */ CS_START_2 +} ActorCutsceneStartMethod; + +typedef struct { + /* 0x00 */ s16 csId; + /* 0x02 */ s16 length; + /* 0x04 */ s16 endCsId; + /* 0x06 */ s16 subCamId; + /* 0x08 */ Actor* targetActor; + /* 0x0C */ s32 startMethod; + /* 0x10 */ PlayState* play; + /* 0x14 */ s16 retCamId; + /* 0x16 */ s16 isCameraStored; +} CutsceneManager; // size = 0x18 + +CutsceneManager sCutsceneMgr = { + CS_ID_NONE, 0, CS_ID_NONE, SUB_CAM_ID_DONE, NULL, CS_START_0, NULL, CAM_ID_MAIN, false, +}; + +CutsceneEntry* sSceneCutsceneList; +s16 sSceneCutsceneCount; +u8 sWaitingCutsceneList[16]; +static s32 sBssPad; +u8 sNextCutsceneList[16]; +static s32 sBssPad2; + +s16 CutsceneManager_SetHudVisibility(s16 csHudVisibility) { + u16 hudVisibility; + + switch (csHudVisibility) { + case CS_HUD_VISIBILITY_NONE: + hudVisibility = HUD_VISIBILITY_NOTHING_ALT; + break; + + case CS_HUD_VISIBILITY_ALL: + hudVisibility = HUD_VISIBILITY_ALL; + break; + + case CS_HUD_VISIBILITY_A_HEARTS_MAGIC: + hudVisibility = HUD_VISIBILITY_A_HEARTS_MAGIC_FORCE; + break; + + case CS_HUD_VISIBILITY_C_HEARTS_MAGIC: + hudVisibility = HUD_VISIBILITY_HEARTS_MAGIC_C; + break; + + case CS_HUD_VISIBILITY_ALL_NO_MINIMAP: + hudVisibility = HUD_VISIBILITY_ALL_NO_MINIMAP; + break; + + case CS_HUD_VISIBILITY_A_B_C: + hudVisibility = HUD_VISIBILITY_A_B_C; + break; + + case CS_HUD_VISIBILITY_B_MINIMAP: + hudVisibility = HUD_VISIBILITY_B_MINIMAP; + break; + + case CS_HUD_VISIBILITY_A: + hudVisibility = HUD_VISIBILITY_A; + break; + + default: + hudVisibility = HUD_VISIBILITY_ALL; + break; + } + + Interface_ChangeHudVisibilityMode(hudVisibility); + + return hudVisibility; +} + +CutsceneEntry* CutsceneManager_GetCutsceneEntryImpl(s16 csId) { + if (csId < CS_ID_GLOBAL_78) { + return &sSceneCutsceneList[csId]; + } else { + csId -= CS_ID_GLOBAL_78; + return &sGlobalCutsceneList[csId]; + } +} + +void CutsceneManager_Init(PlayState* play, CutsceneEntry* cutsceneList, s16 numEntries) { + s32 i; + + if (cutsceneList != NULL) { + sSceneCutsceneList = cutsceneList; + sSceneCutsceneCount = numEntries; + } + + for (i = 0; i < ARRAY_COUNT(sWaitingCutsceneList); i++) { + sWaitingCutsceneList[i] = 0; + sNextCutsceneList[i] = 0; + } + + sCutsceneMgr.endCsId = CS_ID_NONE; + sCutsceneMgr.play = play; + sCutsceneMgr.length = -1; + sCutsceneMgr.targetActor = NULL; + sCutsceneMgr.subCamId = SUB_CAM_ID_DONE; + sCutsceneMgr.isCameraStored = false; + sCutsceneMgr.csId = sCutsceneMgr.endCsId; +} + +/** + * Store camera into subCam 2, and keep subCam 2 INACTIVE to preserve the struct. + */ +void CutsceneManager_StoreCamera(Camera* camera) { + if ((camera != NULL) && (sCutsceneMgr.play != NULL)) { + memcpy(&sCutsceneMgr.play->subCameras[2], camera, sizeof(Camera)); + sCutsceneMgr.play->subCameras[2].camId = camera->camId; + Camera_ChangeStatus(&sCutsceneMgr.play->subCameras[2], CAM_STAT_UNK100); + sCutsceneMgr.isCameraStored = true; + } +} + +void CutsceneManager_ClearWaiting(void) { + s32 i; + + for (i = 0; i < ARRAY_COUNT(sWaitingCutsceneList); i++) { + sWaitingCutsceneList[i] = 0; + } +} + +void CutsceneManager_ClearNextCutscenes(void) { + s32 i; + + for (i = 0; i < ARRAY_COUNT(sNextCutsceneList); i++) { + sNextCutsceneList[i] = 0; + } +} + +s16 CutsceneManager_MarkNextCutscenes(void) { + s16 bit; + s32 i; + s32 j; + s32 count = 0; + s16 csIdMax = CS_ID_NONE; + s16 priorityMax = SHT_MAX; // lower number means higher priority + s16 csId; + s16 priority; + + for (i = 0; i < ARRAY_COUNT(sNextCutsceneList); i++) { + for (bit = 1, j = 0; j < 8; j++) { + if (sWaitingCutsceneList[i] & bit) { + csId = (i << 3) | j; + priority = CutsceneManager_GetCutsceneEntryImpl(csId)->priority; + + if ((priority ^ 0) == -1) { + sNextCutsceneList[i] |= bit; + } else if ((priority < priorityMax) && (priority > 0)) { + csIdMax = csId; + priorityMax = priority; + } + count++; + } + bit <<= 1; + } + } + if (csIdMax != CS_ID_NONE) { + sNextCutsceneList[csIdMax >> 3] |= 1 << (csIdMax & 7); + } + return count; +} + +#define RET_CAM sCutsceneMgr.play->cameraPtrs[sCutsceneMgr.retCamId] +#define CUR_CAM sCutsceneMgr.play->cameraPtrs[sCutsceneMgr.subCamId] + +void CutsceneManager_End(void) { + CutsceneEntry* csEntry; + s16 oldCamId; + s16 oldStateFlags; + + switch (sCutsceneMgr.startMethod) { + case CS_START_2: + sCutsceneMgr.targetActor->flags &= ~ACTOR_FLAG_FREEZE_EXCEPTION; + FALLTHROUGH; + case CS_START_1: + Player_SetCsActionWithHaltedActors(sCutsceneMgr.play, NULL, PLAYER_CSACTION_7); // PLAYER_CSACTION_END + sCutsceneMgr.startMethod = CS_START_0; + break; + + default: + break; + } + + csEntry = CutsceneManager_GetCutsceneEntryImpl(sCutsceneMgr.csId); + + switch (csEntry->endSfx) { + case CS_END_SFX_TRE_BOX_APPEAR: + Sfx_PlaySfxCentered(NA_SE_SY_TRE_BOX_APPEAR); + break; + + case CS_END_SFX_CORRECT_CHIME: + Sfx_PlaySfxCentered(NA_SE_SY_CORRECT_CHIME); + break; + + default: // CS_END_SFX_NONE + break; + } + + switch (csEntry->endCam) { + // case CS_END_CAM_SMOOTH: + // Play_CopyCamera(sCutsceneMgr.play, sCutsceneMgr.retCamId, sCutsceneMgr.subCamId); + // RET_CAM->stateFlags = + // (RET_CAM->stateFlags & ~CAM_STATE_CAMERA_IN_WATER) | (CUR_CAM->stateFlags & + // CAM_STATE_CAMERA_IN_WATER); + // CutsceneManager_Queue(CS_ID_GLOBAL_RETURN_TO_CAM); + // break; + + case CS_END_CAM_0: + default: + Play_CopyCamera(sCutsceneMgr.play, sCutsceneMgr.retCamId, sCutsceneMgr.subCamId); + RET_CAM->stateFlags = + (RET_CAM->stateFlags & ~CAM_STATE_CAMERA_IN_WATER) | (CUR_CAM->stateFlags & CAM_STATE_CAMERA_IN_WATER); + break; + + case CS_END_CAM_1: + oldCamId = RET_CAM->camId; + oldStateFlags = RET_CAM->stateFlags; + + if (sCutsceneMgr.isCameraStored) { + // Restore the camera that was stored in subCam 2 + memcpy(RET_CAM, &sCutsceneMgr.play->subCameras[2], sizeof(Camera)); + + RET_CAM->stateFlags = (RET_CAM->stateFlags & ~CAM_STATE_CAMERA_IN_WATER) | + (CUR_CAM->stateFlags & CAM_STATE_CAMERA_IN_WATER); + + RET_CAM->stateFlags = + (RET_CAM->stateFlags & ~CAM_STATE_CHECK_BG) | (oldStateFlags & CAM_STATE_CHECK_BG); + sCutsceneMgr.isCameraStored = false; + } + RET_CAM->camId = oldCamId; + break; + } + + if (sCutsceneMgr.subCamId != SUB_CAM_ID_DONE) { + Play_ClearCamera(sCutsceneMgr.play, sCutsceneMgr.subCamId); + Play_ChangeCameraStatus(sCutsceneMgr.play, sCutsceneMgr.retCamId, CAM_STAT_ACTIVE); + } + + sCutsceneMgr.csId = CS_ID_NONE; + sCutsceneMgr.endCsId = CS_ID_NONE; + sCutsceneMgr.length = -1; + sCutsceneMgr.targetActor = NULL; + sCutsceneMgr.subCamId = SUB_CAM_ID_DONE; +} + +s16 CutsceneManager_Update(void) { + s16 sp1E = 0; + + // if (CutsceneManager_IsNext(CS_ID_GLOBAL_RETURN_TO_CAM)) { + // CutsceneManager_StartWithPlayerCs(CS_ID_GLOBAL_RETURN_TO_CAM, &GET_PLAYER(sCutsceneMgr.play)->actor); + // } + + if (sCutsceneMgr.endCsId == CS_ID_NONE) { + if (sCutsceneMgr.csId != CS_ID_NONE) { + if (sCutsceneMgr.length > 0) { + sCutsceneMgr.length--; + } + sp1E = 1; + if (sCutsceneMgr.length == 0) { + CutsceneManager_Stop(sCutsceneMgr.csId); + } + } + } + + if (sCutsceneMgr.endCsId != CS_ID_NONE) { + CutsceneManager_End(); + sp1E = 2; + } + + CutsceneManager_ClearNextCutscenes(); + + if (sCutsceneMgr.csId == CS_ID_NONE) { + if ((CutsceneManager_MarkNextCutscenes() == 0) && (sp1E != 0)) { + ShrinkWindow_Letterbox_SetSizeTarget(0); + } else if (sp1E == 0) { + CutsceneManager_StoreCamera(Play_GetCamera(sCutsceneMgr.play, sCutsceneMgr.retCamId)); + } + } + return sp1E; +} + +void CutsceneManager_Queue(s16 csId) { + if (csId > CS_ID_NONE) { + sWaitingCutsceneList[csId >> 3] |= 1 << (csId & 7); + } +} + +s16 CutsceneManager_IsNext(s16 csId) { + if (csId == CS_ID_GLOBAL_END) { + if (sCutsceneMgr.csId == CS_ID_NONE) { + return 0x7F; + } else { + return 0; + } + } + if (csId <= CS_ID_NONE) { + return -1; + } + return (sNextCutsceneList[csId >> 3] & (1 << (csId & 7))) ? 1 : 0; +} + +/** + * Start an actor cutscene, activate Player Cutscene Action "Wait" + */ +s16 CutsceneManager_StartWithPlayerCs(s16 csId, Actor* actor) { + s16 startCsId = CutsceneManager_Start(csId, actor); + + if (startCsId > CS_ID_NONE) { + Player_SetCsActionWithHaltedActors(sCutsceneMgr.play, NULL, PLAYER_CSACTION_8); // PLAYER_CSACTION_WAIT + if (sCutsceneMgr.length == 0) { + CutsceneManager_Stop(sCutsceneMgr.csId); + } + sCutsceneMgr.startMethod = CS_START_1; + } + return startCsId; +} + +/** + * Start an actor cutscene, activate Player Cutscene Action "Wait", turn on ACTOR_FLAG_FREEZE_EXCEPTION + */ +s16 CutsceneManager_StartWithPlayerCsAndSetFlag(s16 csId, Actor* actor) { + s16 startCsId = CutsceneManager_Start(csId, actor); + + if (startCsId > CS_ID_NONE) { + Player_SetCsActionWithHaltedActors(sCutsceneMgr.play, NULL, PLAYER_CSACTION_8); + if (sCutsceneMgr.length == 0) { + CutsceneManager_Stop(sCutsceneMgr.csId); + } + if (actor != NULL) { + actor->flags |= ACTOR_FLAG_FREEZE_EXCEPTION; + sCutsceneMgr.startMethod = CS_START_2; + } else { + sCutsceneMgr.startMethod = CS_START_1; + } + } + return startCsId; +} + +s16 CutsceneManager_Start(s16 csId, Actor* actor) { + CutsceneEntry* csEntry; + Camera* subCam; + Camera* retCam; + s32 csType = 0; + Player* player = GET_PLAYER(sCutsceneMgr.play); + + // set the cutscene halt flag + if (!(player->stateFlags3 & PLAYER_STATE3_CS_HALT)) { + player->stateFlags3 |= PLAYER_STATE3_CS_HALT; + } + + if ((csId <= CS_ID_NONE) || (sCutsceneMgr.csId != CS_ID_NONE)) { + return csId; + } + + sCutsceneMgr.startMethod = CS_START_0; + csEntry = CutsceneManager_GetCutsceneEntryImpl(csId); + + ShrinkWindow_Letterbox_SetSizeTarget(csEntry->letterboxSize); + CutsceneManager_SetHudVisibility(csEntry->hudVisibility); + + if (csId == CS_ID_GLOBAL_END) { + csType = 1; + } else if (csEntry->scriptIndex != CS_SCRIPT_ID_NONE) { + // scripted cutscene + csType = 1; + } else if ((csId != CS_ID_GLOBAL_DOOR) && (csId != CS_ID_GLOBAL_TALK)) { + csType = 2; + } + + if (csType != 0) { + sCutsceneMgr.retCamId = Play_GetActiveCamId(sCutsceneMgr.play); + sCutsceneMgr.subCamId = Play_CreateSubCamera(sCutsceneMgr.play); + + subCam = Play_GetCamera(sCutsceneMgr.play, sCutsceneMgr.subCamId); + retCam = Play_GetCamera(sCutsceneMgr.play, sCutsceneMgr.retCamId); + + if ((retCam->setting == CAM_SET_START0) || /* (retCam->setting == CAM_SET_START2) || */ + (retCam->setting == CAM_SET_START1)) { + if (CutsceneManager_FindEntranceCsId() != csId) { + Camera_800E0348(retCam); + } else { + Camera_UnsetStateFlag(retCam, CAM_STATE_CHECK_BG); + } + } + + memcpy(subCam, retCam, sizeof(Camera)); + subCam->camId = sCutsceneMgr.subCamId; + Camera_UnsetStateFlag(subCam, CAM_STATE_DISTORTION | CAM_STATE_CHECK_BG_ALT); + + Play_ChangeCameraStatus(sCutsceneMgr.play, sCutsceneMgr.retCamId, CAM_STAT_WAIT); + Play_ChangeCameraStatus(sCutsceneMgr.play, sCutsceneMgr.subCamId, CAM_STAT_ACTIVE); + + subCam->target = sCutsceneMgr.targetActor = actor; + subCam->behaviorFlags = 0; + + if (csType == 1) { + Camera_ChangeSetting(subCam, CAM_SET_FREE0); + Cutscene_StartScripted(sCutsceneMgr.play, csEntry->scriptIndex); + sCutsceneMgr.length = csEntry->length; + } else { + if (csEntry->csCamId != CS_CAM_ID_NONE) { + Camera_ChangeActorCsCamIndex(subCam, csEntry->csCamId); + } else { + Camera_ChangeSetting(subCam, CAM_SET_FREE0); + } + sCutsceneMgr.length = csEntry->length; + } + } + sCutsceneMgr.csId = csId; + + return csId; +} + +s16 CutsceneManager_Stop(s16 csId) { + CutsceneEntry* csEntry; + Player* player = GET_PLAYER(sCutsceneMgr.play); + + // unset the cutscene halt flag + if (player->stateFlags3 & PLAYER_STATE3_CS_HALT) { + player->stateFlags3 &= ~PLAYER_STATE3_CS_HALT; + } + + if (csId <= CS_ID_NONE) { + return csId; + } + + csEntry = CutsceneManager_GetCutsceneEntryImpl(sCutsceneMgr.csId); + if ((sCutsceneMgr.length > 0) && (csEntry->scriptIndex == CS_SCRIPT_ID_NONE)) { + return -2; + } + if ((csId != CS_ID_GLOBAL_END) && (csEntry->scriptIndex != CS_SCRIPT_ID_NONE)) { + return -3; + } + + if (csId == CS_ID_GLOBAL_END) { + csId = sCutsceneMgr.csId; + } + if (csId == sCutsceneMgr.csId) { + sCutsceneMgr.endCsId = sCutsceneMgr.csId; + return sCutsceneMgr.endCsId; + } + return -1; +} + +s16 CutsceneManager_GetCurrentCsId(void) { + return sCutsceneMgr.csId; +} + +CutsceneEntry* CutsceneManager_GetCutsceneEntry(s16 csId) { + return CutsceneManager_GetCutsceneEntryImpl(csId); +} + +s16 CutsceneManager_GetAdditionalCsId(s16 csId) { + if (csId <= CS_ID_NONE) { + return CS_ID_NONE; + } + return CutsceneManager_GetCutsceneEntryImpl(csId)->additionalCsId; +} + +s16 CutsceneManager_GetLength(s16 csId) { + if (csId <= CS_ID_NONE) { + return -1; + } + return CutsceneManager_GetCutsceneEntryImpl(csId)->length; +} + +s16 CutsceneManager_GetCutsceneScriptIndex(s16 csId) { + if (csId <= CS_ID_NONE) { + return -1; + } + return CutsceneManager_GetCutsceneEntryImpl(csId)->scriptIndex; +} + +s16 CutsceneManager_GetCutsceneCustomValue(s16 csId) { + if (csId <= CS_ID_NONE) { + return -1; + } + return CutsceneManager_GetCutsceneEntryImpl(csId)->customValue; +} + +s16 CutsceneManager_GetCurrentSubCamId(s16 csId) { + return sCutsceneMgr.subCamId; +} + +s16 CutsceneManager_FindEntranceCsId(void) { + PlayState* play; + s32 csId; + + for (csId = 0; csId < sSceneCutsceneCount; csId++) { + //! FAKE: + if ((sSceneCutsceneList[csId].scriptIndex != CS_SCRIPT_ID_NONE) && + (sSceneCutsceneList[csId].scriptIndex < (play = sCutsceneMgr.play)->csCtx.scriptListCount) && + (sCutsceneMgr.play->spawn == + sCutsceneMgr.play->csCtx.scriptList[sSceneCutsceneList[csId].scriptIndex].spawn)) { + return csId; + } + } + + for (csId = 0; csId < sSceneCutsceneCount; csId++) { + if ((sSceneCutsceneList[csId].customValue >= 100) && + (sSceneCutsceneList[csId].customValue == (sCutsceneMgr.play->spawn + 100))) { + return csId; + } + } + + return -1; +} + +s32 CutsceneManager_800F22C4(s16 csId, Actor* actor) { + f32 dist; + s16 screenPosX; + s16 screenPosY; + + if ((sCutsceneMgr.csId == CS_ID_NONE) || (csId == CS_ID_NONE)) { + return 4; + } + + Actor_GetScreenPos(sCutsceneMgr.play, actor, &screenPosX, &screenPosY); + + dist = OLib_Vec3fDist(&actor->focus.pos, &Play_GetCamera(sCutsceneMgr.play, sCutsceneMgr.subCamId)->eye); + + if ((screenPosX > 40) && (screenPosX < SCREEN_WIDTH - 40) && (screenPosY > 40) && + (screenPosY < SCREEN_HEIGHT - 40) && (dist < 700.0f)) { + return 1; + } + if (sCutsceneMgr.length < 6) { + return 2; + } + if (csId == sCutsceneMgr.csId) { + return 0; + } + return 3; +} + +void CutsceneManager_SetReturnCamera(s16 camId) { + sCutsceneMgr.retCamId = camId; +} + +#endif diff --git a/src/code/shrink_window.c b/src/code/shrink_window.c index ad8da58d3..5969694e8 100644 --- a/src/code/shrink_window.c +++ b/src/code/shrink_window.c @@ -1,5 +1,135 @@ #include "global.h" +#if ENABLE_NEW_LETTERBOX + +#include "gfx.h" +#include "main.h" +#include "z_lib.h" + +typedef struct { + /* 0x0 */ s8 letterboxTarget; + /* 0x1 */ s8 letterboxSize; + /* 0x2 */ s8 pillarboxTarget; + /* 0x3 */ s8 pillarboxSize; +} ShrinkWindow; // size = 0x4 + +ShrinkWindow sShrinkWindow; +ShrinkWindow* sShrinkWindowPtr; + +void ShrinkWindow_Letterbox_SetSizeTarget(s32 target) { + sShrinkWindowPtr->letterboxTarget = target; +} + +s32 ShrinkWindow_Letterbox_GetSizeTarget(void) { + return sShrinkWindowPtr->letterboxTarget; +} + +void ShrinkWindow_Letterbox_SetSize(s32 size) { + sShrinkWindowPtr->letterboxSize = size; +} + +s32 ShrinkWindow_Letterbox_GetSize(void) { + return sShrinkWindowPtr->letterboxSize; +} + +void ShrinkWindow_Pillarbox_SetSizeTarget(s32 target) { + sShrinkWindowPtr->pillarboxTarget = target; +} + +s32 ShrinkWindow_Pillarbox_GetSizeTarget(void) { + return sShrinkWindowPtr->pillarboxTarget; +} + +void ShrinkWindow_Pillarbox_SetSize(s32 size) { + sShrinkWindowPtr->pillarboxSize = size; +} + +s32 ShrinkWindow_Pillarbox_GetSize(void) { + return sShrinkWindowPtr->pillarboxSize; +} + +void ShrinkWindow_Init(void) { + sShrinkWindowPtr = &sShrinkWindow; + bzero(sShrinkWindowPtr, sizeof(sShrinkWindow)); +} + +void ShrinkWindow_Destroy(void) { + sShrinkWindowPtr = NULL; +} + +void ShrinkWindow_Update(s32 framerateDivisor) { + s32 step = (framerateDivisor == 3) ? 10 : (30 / framerateDivisor); + s32 nextSize; + + nextSize = sShrinkWindowPtr->letterboxSize; + Math_StepToIGet(&nextSize, sShrinkWindowPtr->letterboxTarget, step); + sShrinkWindowPtr->letterboxSize = nextSize; + + nextSize = sShrinkWindowPtr->pillarboxSize; + Math_StepToIGet(&nextSize, sShrinkWindowPtr->pillarboxTarget, step); + sShrinkWindowPtr->pillarboxSize = nextSize; +} + +void ShrinkWindow_Draw(GraphicsContext* gfxCtx) { + Gfx* gfx; + s8 letterboxSize = sShrinkWindowPtr->letterboxSize; + s8 pillarboxSize = sShrinkWindowPtr->pillarboxSize; + + if (letterboxSize > 0) { + OPEN_DISPS(gfxCtx); + + gfx = OVERLAY_DISP; + + gDPPipeSync(gfx++); + gDPSetCycleType(gfx++, G_CYC_FILL); + gDPSetRenderMode(gfx++, G_RM_NOOP, G_RM_NOOP2); + gDPSetFillColor(gfx++, (GPACK_RGBA5551(0, 0, 0, 1) << 16) | GPACK_RGBA5551(0, 0, 0, 1)); + gDPFillRectangle(gfx++, 0, 0, gScreenWidth - 1, letterboxSize - 1); + gDPFillRectangle(gfx++, 0, gScreenHeight - letterboxSize, gScreenWidth - 1, gScreenHeight - 1); + + gDPPipeSync(gfx++); + gDPSetCycleType(gfx++, G_CYC_1CYCLE); + gDPSetRenderMode(gfx++, G_RM_XLU_SURF, G_RM_XLU_SURF2); + gDPSetPrimColor(gfx++, 0, 0, 0, 0, 0, 0); + gDPFillRectangle(gfx++, 0, letterboxSize, gScreenWidth, letterboxSize + 1); + gDPFillRectangle(gfx++, 0, gScreenHeight - letterboxSize - 1, gScreenWidth, gScreenHeight - letterboxSize); + + gDPPipeSync(gfx++); + OVERLAY_DISP = gfx++; + + CLOSE_DISPS(gfxCtx); + } + + if (pillarboxSize > 0) { + OPEN_DISPS(gfxCtx); + + gfx = OVERLAY_DISP; + + gDPPipeSync(gfx++); + gDPSetCycleType(gfx++, G_CYC_FILL); + gDPSetRenderMode(gfx++, G_RM_NOOP, G_RM_NOOP2); + gDPSetFillColor(gfx++, (GPACK_RGBA5551(0, 0, 0, 1) << 16) | GPACK_RGBA5551(0, 0, 0, 1)); + + gDPFillRectangle(gfx++, 0, 0, pillarboxSize - 1, gScreenHeight - 1); + gDPFillRectangle(gfx++, gScreenWidth - pillarboxSize, 0, gScreenWidth - 1, gScreenHeight - 1); + + gDPPipeSync(gfx++); + gDPSetCycleType(gfx++, G_CYC_1CYCLE); + gDPSetRenderMode(gfx++, G_RM_XLU_SURF, G_RM_XLU_SURF2); + gDPSetPrimColor(gfx++, 0, 0, 0, 0, 0, 0); + + gDPFillRectangle(gfx++, pillarboxSize, 0, pillarboxSize + 2, gScreenHeight); + gDPFillRectangle(gfx++, gScreenWidth - pillarboxSize - 2, 0, gScreenWidth - pillarboxSize, gScreenHeight); + + gDPPipeSync(gfx++); + OVERLAY_DISP = gfx++; + + CLOSE_DISPS(gfxCtx); + } +} + +#else + typedef enum LetterboxState { /* 0 */ LETTERBOX_STATE_IDLE, /* 1 */ LETTERBOX_STATE_GROWING, @@ -11,31 +141,50 @@ s32 sLetterboxState = LETTERBOX_STATE_IDLE; s32 sLetterboxSizeTarget = 0; s32 sLetterboxSize = 0; +#endif + void Letterbox_SetSizeTarget(s32 target) { +#if ENABLE_NEW_LETTERBOX + return ShrinkWindow_Letterbox_SetSizeTarget(target); +#else if (R_HREG_MODE == HREG_MODE_LETTERBOX && R_LETTERBOX_ENABLE_LOGS == 1) { PRINTF("shrink_window_setval(%d)\n", target); } sLetterboxSizeTarget = target; +#endif } u32 Letterbox_GetSizeTarget(void) { +#if ENABLE_NEW_LETTERBOX + return ShrinkWindow_Letterbox_GetSizeTarget(); +#else return sLetterboxSizeTarget; +#endif } void Letterbox_SetSize(s32 size) { +#if ENABLE_NEW_LETTERBOX + return ShrinkWindow_Letterbox_SetSize(size); +#else if (R_HREG_MODE == HREG_MODE_LETTERBOX && R_LETTERBOX_ENABLE_LOGS == 1) { PRINTF("shrink_window_setnowval(%d)\n", size); } sLetterboxSize = size; +#endif } u32 Letterbox_GetSize(void) { +#if ENABLE_NEW_LETTERBOX + return ShrinkWindow_Letterbox_GetSize(); +#else return sLetterboxSize; +#endif } void Letterbox_Init(void) { +#if !ENABLE_NEW_LETTERBOX if (R_HREG_MODE == HREG_MODE_LETTERBOX && R_LETTERBOX_ENABLE_LOGS == 1) { PRINTF("shrink_window_init()\n"); } @@ -43,17 +192,21 @@ void Letterbox_Init(void) { sLetterboxState = LETTERBOX_STATE_IDLE; sLetterboxSizeTarget = 0; sLetterboxSize = 0; +#endif } void Letterbox_Destroy(void) { +#if !ENABLE_NEW_LETTERBOX if (R_HREG_MODE == HREG_MODE_LETTERBOX && R_LETTERBOX_ENABLE_LOGS == 1) { PRINTF("shrink_window_cleanup()\n"); } sLetterboxSize = 0; +#endif } void Letterbox_Update(s32 updateRate) { +#if !ENABLE_NEW_LETTERBOX s32 step; if (updateRate == 3) { @@ -107,4 +260,5 @@ void Letterbox_Update(s32 updateRate) { R_LETTERBOX_TARGET_SIZE = sLetterboxSizeTarget; R_LETTERBOX_STEP = step; } +#endif } diff --git a/src/code/z_actor.c b/src/code/z_actor.c index 3e80120e9..37baa9f23 100644 --- a/src/code/z_actor.c +++ b/src/code/z_actor.c @@ -4,6 +4,7 @@ #include "rand.h" #include "terminal.h" #include "versions.h" +#include "config.h" #include "overlays/actors/ovl_Arms_Hook/z_arms_hook.h" #include "overlays/actors/ovl_En_Part/z_en_part.h" @@ -326,6 +327,12 @@ void Attention_Init(Attention* attention, Actor* actor, PlayState* play) { void Attention_Draw(Attention* attention, PlayState* play) { Actor* actor; // used for both the reticle actor and arrow hover actor +#if ENABLE_CUTSCENE_IMPROVEMENTS + if (GET_PLAYER(play)->stateFlags3 & PLAYER_STATE3_CS_HALT) { + return; + } +#endif + actor = attention->reticleActor; OPEN_DISPS(play->state.gfxCtx, "../z_actor.c", 2029); @@ -2315,38 +2322,44 @@ void Actor_InitContext(PlayState* play, ActorContext* actorCtx, ActorEntry* play func_8002FA60(play); } -u32 sCategoryFreezeMasks[ACTORCAT_MAX] = { +typedef struct ActorFreezeMasks { + u32 mask1; // stateFlags1 + u32 mask2; // stateFlags2 + u32 mask3; // stateFlags3 +} ActorFreezeMasks; + +ActorFreezeMasks sCategoryFreezeMasks[ACTORCAT_MAX] = { // ACTORCAT_SWITCH - PLAYER_STATE1_TALKING | PLAYER_STATE1_DEAD | PLAYER_STATE1_28, + { PLAYER_STATE1_TALKING | PLAYER_STATE1_DEAD | PLAYER_STATE1_28, 0, PLAYER_STATE3_CS_HALT }, // ACTORCAT_BG - PLAYER_STATE1_TALKING | PLAYER_STATE1_DEAD | PLAYER_STATE1_28, + { PLAYER_STATE1_TALKING | PLAYER_STATE1_DEAD | PLAYER_STATE1_28, 0, PLAYER_STATE3_CS_HALT }, // ACTORCAT_PLAYER - 0, + { 0, 0, PLAYER_STATE3_CS_HALT }, // ACTORCAT_EXPLOSIVE - PLAYER_STATE1_TALKING | PLAYER_STATE1_DEAD | PLAYER_STATE1_10 | PLAYER_STATE1_28, + { PLAYER_STATE1_TALKING | PLAYER_STATE1_DEAD | PLAYER_STATE1_10 | PLAYER_STATE1_28, 0, PLAYER_STATE3_CS_HALT }, // ACTORCAT_NPC - PLAYER_STATE1_DEAD, + { PLAYER_STATE1_DEAD, 0, PLAYER_STATE3_CS_HALT }, // ACTORCAT_ENEMY - PLAYER_STATE1_TALKING | PLAYER_STATE1_DEAD | PLAYER_STATE1_28 | PLAYER_STATE1_29, + { PLAYER_STATE1_TALKING | PLAYER_STATE1_DEAD | PLAYER_STATE1_28 | PLAYER_STATE1_29, 0, PLAYER_STATE3_CS_HALT }, // ACTORCAT_PROP - PLAYER_STATE1_DEAD | PLAYER_STATE1_28, + { PLAYER_STATE1_DEAD | PLAYER_STATE1_28, 0, PLAYER_STATE3_CS_HALT }, // ACTORCAT_ITEMACTION - 0, + { 0, 0, 0 }, // ACTORCAT_MISC - PLAYER_STATE1_TALKING | PLAYER_STATE1_DEAD | PLAYER_STATE1_28 | PLAYER_STATE1_29, + { PLAYER_STATE1_TALKING | PLAYER_STATE1_DEAD | PLAYER_STATE1_28 | PLAYER_STATE1_29, 0, PLAYER_STATE3_CS_HALT }, // ACTORCAT_BOSS - PLAYER_STATE1_TALKING | PLAYER_STATE1_DEAD | PLAYER_STATE1_10 | PLAYER_STATE1_28, + { PLAYER_STATE1_TALKING | PLAYER_STATE1_DEAD | PLAYER_STATE1_10 | PLAYER_STATE1_28, 0, PLAYER_STATE3_CS_HALT }, // ACTORCAT_DOOR - 0, + { 0, 0, 0 }, // ACTORCAT_CHEST - PLAYER_STATE1_TALKING | PLAYER_STATE1_DEAD | PLAYER_STATE1_28, + { PLAYER_STATE1_TALKING | PLAYER_STATE1_DEAD | PLAYER_STATE1_28, 0, PLAYER_STATE3_CS_HALT }, }; void Actor_UpdateAll(PlayState* play, ActorContext* actorCtx) { s32 i; Actor* actor; Player* player; - u32* categoryFreezeMaskP; + ActorFreezeMasks* categoryFreezeMaskP; u32 freezeExceptionFlag; u32 canFreezeCategory; Actor* sp74; @@ -2395,7 +2408,10 @@ void Actor_UpdateAll(PlayState* play, ActorContext* actorCtx) { } for (i = 0; i < ARRAY_COUNT(actorCtx->actorLists); i++, categoryFreezeMaskP++) { - canFreezeCategory = (*categoryFreezeMaskP & player->stateFlags1); + ActorFreezeMasks curEntry = *categoryFreezeMaskP; + + canFreezeCategory = (curEntry.mask1 & player->stateFlags1) || (curEntry.mask2 & player->stateFlags2) || + (curEntry.mask3 & player->stateFlags3); actor = actorCtx->actorLists[i].head; while (actor != NULL) { diff --git a/src/code/z_camera.c b/src/code/z_camera.c index 2802a97c8..3cd1830ce 100644 --- a/src/code/z_camera.c +++ b/src/code/z_camera.c @@ -3,6 +3,7 @@ #include "quake.h" #include "terminal.h" #include "overlays/actors/ovl_En_Horse/z_en_horse.h" +#include "config.h" #pragma increment_block_number "gc-eu:192 gc-eu-mq:192 gc-jp:192 gc-jp-ce:192 gc-jp-mq:192 gc-us:192 gc-us-mq:192" \ "ntsc-1.0:192 ntsc-1.1:192 ntsc-1.2:192 pal-1.0:192 pal-1.1:192" @@ -39,6 +40,11 @@ s32 Camera_QRegInit(void); #define CAM_DEBUG_RELOAD_PARAMS true #endif +#define CAMERA_CHECK_FLAGS(settings, mask) \ + ((settings.flags & 0x20000000) ? sCameraSettings[camera->setting].unk_00 & (mask) \ + : sCameraSettings[camera->setting].flags & (mask)) +#define CAM_DATA_IS_BG (1 << 12) // if not set, then cam data is for actor cutscenes + /** * Camera data is stored in both read-only data and OREG as s16, and then converted to the appropriate type during * runtime. If a small f32 is being stored as an s16, it is common to store that value 100 times larger than the @@ -1849,7 +1855,7 @@ s32 Camera_Normal2(Camera* camera) { case 10: case 20: case 25: - bgCamFuncData = (BgCamFuncData*)Camera_GetBgCamFuncData(camera); + bgCamFuncData = (BgCamFuncData*)Camera_GetBgCamOrActorCsCamFuncData(camera, camera->bgCamIndex); rwData->unk_00 = Camera_Vec3sToVec3f(&bgCamFuncData->pos); rwData->unk_20 = bgCamFuncData->rot.x; rwData->unk_22 = bgCamFuncData->rot.y; @@ -3994,7 +4000,7 @@ s32 Camera_KeepOn0(Camera* camera) { CAM_DEBUG_RELOAD_PREG(camera); - bgCamFuncData = (BgCamFuncData*)Camera_GetBgCamFuncData(camera); + bgCamFuncData = (BgCamFuncData*)Camera_GetBgCamOrActorCsCamFuncData(camera, camera->bgCamIndex); *eyeNext = Camera_Vec3sToVec3f(&bgCamFuncData->pos); *eye = *eyeNext; @@ -4059,7 +4065,7 @@ s32 Camera_Fixed1(Camera* camera) { if (RELOAD_PARAMS(camera) || CAM_DEBUG_RELOAD_PARAMS) { CameraModeValue* values = sCameraSettings[camera->setting].cameraModes[camera->mode].values; - bgCamFuncData = (BgCamFuncData*)Camera_GetBgCamFuncData(camera); + bgCamFuncData = (BgCamFuncData*)Camera_GetBgCamOrActorCsCamFuncData(camera, camera->bgCamIndex); rwData->eyePosRotTarget.pos = Camera_Vec3sToVec3f(&bgCamFuncData->pos); rwData->eyePosRotTarget.rot = bgCamFuncData->rot; rwData->fov = bgCamFuncData->fov; @@ -4139,7 +4145,7 @@ s32 Camera_Fixed2(Camera* camera) { roData->interfaceField = GET_NEXT_RO_DATA(values); rwData->fov = roData->fov * 100.0f; - bgCamFuncData = (BgCamFuncData*)Camera_GetBgCamFuncData(camera); + bgCamFuncData = (BgCamFuncData*)Camera_GetBgCamOrActorCsCamFuncData(camera, camera->bgCamIndex); if (bgCamFuncData != NULL) { rwData->eye = Camera_Vec3sToVec3f(&bgCamFuncData->pos); if (bgCamFuncData->fov != -1) { @@ -4204,7 +4210,7 @@ s32 Camera_Fixed3(Camera* camera) { Fixed3ReadWriteData* rwData = &camera->paramData.fixd3.rwData; s32 pad; - bgCamFuncData = (BgCamFuncData*)Camera_GetBgCamFuncData(camera); + bgCamFuncData = (BgCamFuncData*)Camera_GetBgCamOrActorCsCamFuncData(camera, camera->bgCamIndex); eyeAtOffset = OLib_Vec3fDiffToVecGeo(eye, at); @@ -4291,7 +4297,7 @@ s32 Camera_Fixed4(Camera* camera) { roData->fov = GET_NEXT_RO_DATA(values); roData->interfaceField = GET_NEXT_RO_DATA(values); - bgCamFuncData = (BgCamFuncData*)Camera_GetBgCamFuncData(camera); + bgCamFuncData = (BgCamFuncData*)Camera_GetBgCamOrActorCsCamFuncData(camera, camera->bgCamIndex); if (bgCamFuncData != NULL) { rwData->eyeTarget = Camera_Vec3sToVec3f(&bgCamFuncData->pos); } else { @@ -4694,7 +4700,7 @@ s32 Camera_Data4(Camera* camera) { roData->fov = GET_NEXT_RO_DATA(values); roData->interfaceField = GET_NEXT_RO_DATA(values); - bgCamFuncData = (BgCamFuncData*)Camera_GetBgCamFuncData(camera); + bgCamFuncData = (BgCamFuncData*)Camera_GetBgCamOrActorCsCamFuncData(camera, camera->bgCamIndex); rwData->eyePosRot.pos = Camera_Vec3sToVec3f(&bgCamFuncData->pos); rwData->eyePosRot.rot = bgCamFuncData->rot; fov = bgCamFuncData->fov; @@ -4953,7 +4959,7 @@ s32 Camera_Unique3(Camera* camera) { break; } - bgCamFuncData = (BgCamFuncData*)Camera_GetBgCamFuncData(camera); + bgCamFuncData = (BgCamFuncData*)Camera_GetBgCamOrActorCsCamFuncData(camera, camera->bgCamIndex); camera->eyeNext = Camera_Vec3sToVec3f(&bgCamFuncData->pos); camera->eye = camera->eyeNext; bgCamRot = bgCamFuncData->rot; @@ -5068,7 +5074,7 @@ s32 Camera_Unique0(Camera* camera) { func_80043B60(camera); camera->stateFlags &= ~CAM_STATE_CHECK_BG; - bgCamFuncData = (BgCamFuncData*)Camera_GetBgCamFuncData(camera); + bgCamFuncData = (BgCamFuncData*)Camera_GetBgCamOrActorCsCamFuncData(camera, camera->bgCamIndex); rwData->eyeAndDirection.point = Camera_Vec3sToVec3f(&bgCamFuncData->pos); *eye = camera->eyeNext = rwData->eyeAndDirection.point; @@ -5227,7 +5233,7 @@ s32 Camera_Unique7(Camera* camera) { } CAM_DEBUG_RELOAD_PREG(camera); - bgCamFuncData = (BgCamFuncData*)Camera_GetBgCamFuncData(camera); + bgCamFuncData = (BgCamFuncData*)Camera_GetBgCamOrActorCsCamFuncData(camera, camera->bgCamIndex); *eyeNext = Camera_Vec3sToVec3f(&bgCamFuncData->pos); *eye = *eyeNext; @@ -7210,7 +7216,7 @@ s32 Camera_Special6(Camera* camera) { eyeAtOffset = OLib_Vec3fDiffToVecGeo(eye, at); - bgCamFuncData = (BgCamFuncData*)Camera_GetBgCamFuncData(camera); + bgCamFuncData = (BgCamFuncData*)Camera_GetBgCamOrActorCsCamFuncData(camera, camera->bgCamIndex); bgCamPos = Camera_Vec3sToVec3f(&bgCamFuncData->pos); bgCamRot = bgCamFuncData->rot; fov = bgCamFuncData->fov; @@ -7354,7 +7360,7 @@ s32 Camera_Special9(Camera* camera) { if (doorParams->timer1 <= 0) { camera->animState++; if (roData->interfaceField & SPECIAL9_FLAG_0) { - bgCamFuncData = (BgCamFuncData*)Camera_GetBgCamFuncData(camera); + bgCamFuncData = (BgCamFuncData*)Camera_GetBgCamOrActorCsCamFuncData(camera, camera->bgCamIndex); *eyeNext = Camera_Vec3sToVec3f(&bgCamFuncData->pos); spAC = *eye = *eyeNext; } else { @@ -7777,7 +7783,8 @@ s32 Camera_UpdateWater(Camera* camera) { Player* player = camera->player; s16 prevBgId; - if (!(camera->stateFlags & CAM_STATE_CHECK_WATER) || sCameraSettings[camera->setting].unk_00 & 0x40000000) { + if (!(camera->stateFlags & CAM_STATE_CHECK_WATER) || + CAMERA_CHECK_FLAGS(sCameraSettings[camera->setting], 0x40000000)) { return 0; } @@ -8114,6 +8121,10 @@ Vec3s Camera_Update(Camera* camera) { camera->nextBgId = bgId; if (bgId == BGCHECK_SCENE) { camera->nextBgCamIndex = bgCamIndex; + +#if ENABLE_CUTSCENE_IMPROVEMENTS + camera->nextBgCamIndex |= CAM_DATA_IS_BG; +#endif } } } @@ -8155,15 +8166,18 @@ Vec3s Camera_Update(Camera* camera) { Camera_CalcAtDefault(camera, &eyeAtAngle, 0.0f, false); } + if (D_8011D3F0 != 0) { + D_8011D3F0--; + } + if (camera->status == CAM_STAT_ACTIVE) { if ((gSaveContext.gameMode != GAMEMODE_NORMAL) && (gSaveContext.gameMode != GAMEMODE_END_CREDITS)) { sCameraInterfaceField = CAM_INTERFACE_FIELD(CAM_LETTERBOX_NONE, CAM_HUD_VISIBILITY_ALL, 0); Camera_UpdateInterface(sCameraInterfaceField); } else if ((D_8011D3F0 != 0) && (camera->camId == CAM_ID_MAIN)) { - D_8011D3F0--; sCameraInterfaceField = CAM_INTERFACE_FIELD(CAM_LETTERBOX_LARGE, CAM_HUD_VISIBILITY_NOTHING_ALT, 0); Camera_UpdateInterface(sCameraInterfaceField); - } else if (camera->play->transitionMode != TRANS_MODE_OFF) { + } else if ((camera->play->transitionMode != TRANS_MODE_OFF) && (camera->camId != CAM_ID_MAIN)) { sCameraInterfaceField = CAM_INTERFACE_FIELD(CAM_LETTERBOX_IGNORE, CAM_HUD_VISIBILITY_NOTHING_ALT, 0); Camera_UpdateInterface(sCameraInterfaceField); } else if (camera->play->csCtx.state != CS_STATE_IDLE) { @@ -8617,7 +8631,7 @@ s32 Camera_RequestBgCam(Camera* camera, s32 requestedBgCamIndex) { } if (!(camera->behaviorFlags & CAM_BEHAVIOR_BG_PROCESSED)) { - requestedCamSetting = Camera_GetBgCamSetting(camera, requestedBgCamIndex); + requestedCamSetting = Camera_GetBgCamOrActorCsCamSetting(camera, requestedBgCamIndex); camera->behaviorFlags |= CAM_BEHAVIOR_BG_PROCESSED; #if DEBUG_FEATURES settingChangeSuccessful = Camera_RequestSettingImpl(camera, requestedCamSetting, @@ -8828,7 +8842,7 @@ s32 Camera_ChangeDoorCam(Camera* camera, Actor* doorActor, s16 bgCamIndex, f32 a Camera_RequestSetting(camera, CAM_SET_DOORC); PRINTF(".... change default door camera (set %d)\n", CAM_SET_DOORC); } else { - s32 setting = Camera_GetBgCamSetting(camera, bgCamIndex); + s32 setting = Camera_GetBgCamOrActorCsCamSetting(camera, bgCamIndex); camera->behaviorFlags |= CAM_BEHAVIOR_BG_PROCESSED; @@ -8959,3 +8973,220 @@ s16 Camera_SetFinishedFlag(Camera* camera) { return camera->camId; } + +/** + * Returns the CameraSettingType of the camera from either the bgCam or the actorCsCam at index `camDataId` + */ +s16 Camera_GetBgCamOrActorCsCamSetting(Camera* camera, u32 camDataId) { +#if ENABLE_CUTSCENE_IMPROVEMENTS + if (camDataId & CAM_DATA_IS_BG) { + return BgCheck_GetBgCamSettingImpl(&camera->play->colCtx, camDataId & ~CAM_DATA_IS_BG, BGCHECK_SCENE); + } else { + return Play_GetActorCsCamSetting(camera->play, camDataId); + } +#else + return BgCheck_GetBgCamSettingImpl(&camera->play->colCtx, camDataId, BGCHECK_SCENE); +#endif +} + +/** + * Returns either the bgCam data or the actorCsCam data at index `camDataId` + */ +Vec3s* Camera_GetBgCamOrActorCsCamFuncData(Camera* camera, u32 camDataId) { +#if ENABLE_CUTSCENE_IMPROVEMENTS + if (camDataId & CAM_DATA_IS_BG) { + return BgCheck_GetBgCamFuncDataImpl(&camera->play->colCtx, camDataId & ~CAM_DATA_IS_BG, BGCHECK_SCENE); + } else { + return Play_GetActorCsCamFuncData(camera->play, camDataId); + } +#else + return BgCheck_GetBgCamFuncDataImpl(&camera->play->colCtx, camDataId, BGCHECK_SCENE); +#endif +} + +#if ENABLE_CUTSCENE_IMPROVEMENTS + +s16 sGlobalCamDataSettings[] = { + /* -66 */ CAM_SET_NORMAL4, // CS_CAM_ID_GLOBAL_NORMAL4 + /* -65 */ CAM_SET_PIVOT_FROM_SIDE, // CS_CAM_ID_GLOBAL_PIVOT_FROM_SIDE + /* -64 */ CAM_SET_DIRECTED_YAW, // CS_CAM_ID_GLOBAL_DIRECTED_YAW + /* -63 */ CAM_SET_DUNGEON2, // CS_CAM_ID_GLOBAL_DUNGEON2 + /* -62 */ CAM_SET_JABU_TENTACLE, // CS_CAM_ID_GLOBAL_JABU_TENTACLE + /* -61 */ CAM_SET_CS_C, // CS_CAM_ID_GLOBAL_CS_C + /* -60 */ CAM_SET_FISHING, // CS_CAM_ID_GLOBAL_FISHING + /* -59 */ CAM_SET_NORMAL2, // CS_CAM_ID_GLOBAL_NORMAL2 + /* -58 */ CAM_SET_PIVOT_VERTICAL, // CS_CAM_ID_GLOBAL_PIVOT_VERTICAL + /* -57 */ CAM_SET_TURN_AROUND, // CS_CAM_ID_GLOBAL_TURN_AROUND + /* -56 */ CAM_SET_FIRE_BIRDS_EYE, // CS_CAM_ID_GLOBAL_FIRE_BIRDS_EYE + /* -55 */ CAM_SET_MEADOW_UNUSED, // CS_CAM_ID_GLOBAL_MEADOW_UNUSED + /* -54 */ CAM_SET_MEADOW_BIRDS_EYE, // CS_CAM_ID_GLOBAL_MEADOW_BIRDS_EYE + /* -53 */ CAM_SET_BIG_OCTO, // CS_CAM_ID_GLOBAL_BIG_OCTO + /* -52 */ CAM_SET_FOREST_DEFEAT_POE, // CS_CAM_ID_GLOBAL_FOREST_DEFEAT_POE + /* -51 */ CAM_SET_FOREST_UNUSED, // CS_CAM_ID_GLOBAL_FOREST_UNUSED + /* -50 */ CAM_SET_FIRE_STAIRCASE, // CS_CAM_ID_GLOBAL_FIRE_STAIRCASE + /* -49 */ CAM_SET_ELEVATOR_PLATFORM, // CS_CAM_ID_GLOBAL_ELEVATOR_PLATFORM + /* -48 */ CAM_SET_SCENE_TRANSITION, // CS_CAM_ID_GLOBAL_SCENE_TRANSITION + /* -47 */ CAM_SET_SCENE_UNUSED, // CS_CAM_ID_GLOBAL_SCENE_UNUSED + /* -46 */ CAM_SET_BEAN_LOST_WOODS, // CS_CAM_ID_GLOBAL_BEAN_LOST_WOODS + /* -45 */ CAM_SET_BEAN_GENERIC, // CS_CAM_ID_GLOBAL_BEAN_GENERIC + /* -44 */ CAM_SET_CS_ATTENTION, // CS_CAM_ID_GLOBAL_CS_ATTENTION + /* -43 */ CAM_SET_CS_3, // CS_CAM_ID_GLOBAL_CS_3 + /* -42 */ CAM_SET_ITEM_UNUSED, // CS_CAM_ID_GLOBAL_ITEM_UNUSED + /* -41 */ CAM_SET_SLOW_CHEST_CS, // CS_CAM_ID_GLOBAL_SLOW_CHEST_CS + /* -40 */ CAM_SET_FOREST_BIRDS_EYE, // CS_CAM_ID_GLOBAL_FOREST_BIRDS_EYE + /* -39 */ CAM_SET_CS_TWISTED_HALLWAY, // CS_CAM_ID_GLOBAL_CS_TWISTED_HALLWAY + /* -38 */ CAM_SET_CS_0, // CS_CAM_ID_GLOBAL_CS_0 + /* -37 */ CAM_SET_PIVOT_WATER_SURFACE, // CS_CAM_ID_GLOBAL_PIVOT_WATER_SURFACE + /* -36 */ CAM_SET_PIVOT_CORNER, // CS_CAM_ID_GLOBAL_PIVOT_CORNER + /* -35 */ CAM_SET_FREE2, // CS_CAM_ID_GLOBAL_FREE2 + /* -34 */ CAM_SET_FREE0, // CS_CAM_ID_GLOBAL_FREE0 + /* -33 */ CAM_SET_START1, // CS_CAM_ID_GLOBAL_START1 + /* -32 */ CAM_SET_START0, // CS_CAM_ID_GLOBAL_START0 + /* -31 */ CAM_SET_CRAWLSPACE, // CS_CAM_ID_GLOBAL_CRAWLSPACE + /* -30 */ CAM_SET_DOORC, // CS_CAM_ID_GLOBAL_DOORC + /* -29 */ CAM_SET_DOOR0, // CS_CAM_ID_GLOBAL_DOOR0 + /* -28 */ CAM_SET_PREREND_SIDE_SCROLL, // CS_CAM_ID_GLOBAL_PREREND_SIDE_SCROLL + /* -27 */ CAM_SET_PREREND_PIVOT, // CS_CAM_ID_GLOBAL_PREREND_PIVOT + /* -26 */ CAM_SET_PREREND_FIXED, // CS_CAM_ID_GLOBAL_PREREND_FIXED + /* -25 */ CAM_SET_PIVOT_IN_FRONT, // CS_CAM_ID_GLOBAL_PIVOT_IN_FRONT + /* -24 */ CAM_SET_PIVOT_SHOP_BROWSING, // CS_CAM_ID_GLOBAL_PIVOT_SHOP_BROWSING + /* -23 */ CAM_SET_PIVOT_CRAWLSPACE, // CS_CAM_ID_GLOBAL_PIVOT_CRAWLSPACE + /* -22 */ CAM_SET_CHU_BOWLING, // CS_CAM_ID_GLOBAL_CHU_BOWLING + /* -21 */ CAM_SET_MARKET_BALCONY, // CS_CAM_ID_GLOBAL_MARKET_BALCONY + /* -20 */ CAM_SET_TOWER_UNUSED, // CS_CAM_ID_GLOBAL_TOWER_UNUSED + /* -19 */ CAM_SET_TOWER_CLIMB, // CS_CAM_ID_GLOBAL_TOWER_CLIMB + /* -18 */ CAM_SET_BOSS_GANON, // CS_CAM_ID_GLOBAL_BOSS_GANON + /* -17 */ CAM_SET_BOSS_GANONDORF, // CS_CAM_ID_GLOBAL_BOSS_GANONDORF + /* -16 */ CAM_SET_BOSS_TWINROVA_FLOOR, // CS_CAM_ID_GLOBAL_BOSS_TWINROVA_FLOOR + /* -15 */ CAM_SET_BOSS_TWINROVA_PLATFORM, // CS_CAM_ID_GLOBAL_BOSS_TWINROVA_PLATFORM + /* -14 */ CAM_SET_BOSS_MORPHA, // CS_CAM_ID_GLOBAL_BOSS_MORPHA + /* -13 */ CAM_SET_BOSS_BONGO, // CS_CAM_ID_GLOBAL_BOSS_BONGO + /* -12 */ CAM_SET_BOSS_VOLVAGIA, // CS_CAM_ID_GLOBAL_BOSS_VOLVAGIA + /* -11 */ CAM_SET_BOSS_PHANTOM_GANON, // CS_CAM_ID_GLOBAL_BOSS_PHANTOM_GANON + /* -10 */ CAM_SET_BOSS_BARINADE, // CS_CAM_ID_GLOBAL_BOSS_BARINADE + /* -9 */ CAM_SET_BOSS_DODONGO, // CS_CAM_ID_GLOBAL_BOSS_DODONGO + /* -8 */ CAM_SET_BOSS_GOHMA, // CS_CAM_ID_GLOBAL_BOSS_GOHMA + /* -7 */ CAM_SET_HORSE, // CS_CAM_ID_GLOBAL_HORSE + /* -6 */ CAM_SET_NORMAL3, // CS_CAM_ID_GLOBAL_NORMAL3 + /* -5 */ CAM_SET_DUNGEON1, // CS_CAM_ID_GLOBAL_DUNGEON1 + /* -4 */ CAM_SET_DUNGEON0, // CS_CAM_ID_GLOBAL_DUNGEON0 + /* -3 */ CAM_SET_NORMAL1, // CS_CAM_ID_GLOBAL_NORMAL1 + /* -2 */ CAM_SET_NORMAL0, // CS_CAM_ID_GLOBAL_NORMAL0 + /* -1 */ CAM_SET_NONE, // CS_CAM_ID_NONE + /* 0 */ CAM_SET_NONE, +}; + +s16* sGlobalCamDataSettingsPtr = &sGlobalCamDataSettings[ARRAY_COUNT(sGlobalCamDataSettings) - 1]; + +s16 Camera_ChangeSettingFlags(Camera* camera, s16 setting, s16 flags) { + // Reject settings change based on priority + if ((camera->behaviorFlags & CAM_BEHAVIOR_SETTING_CHECK_PRIORITY) && + ((sCameraSettings[camera->setting].flags & 0xF) >= (sCameraSettings[setting].flags & 0xF))) { + camera->behaviorFlags |= CAM_BEHAVIOR_BG_SUCCESS; + if (!(flags & CAM_REQUEST_SETTING_IGNORE_PRIORITY)) { + camera->behaviorFlags |= CAM_BEHAVIOR_SETTING_CHECK_PRIORITY; + } + return -2; + } + + // Reject settings change based on NONE setting + if (setting == CAM_SET_NONE) { + return 0; + } + + // Reject settings change based on an invalid setting + if (setting >= CAM_SET_MAX) { + return -99; + } + + // Reject settings change based on setting already set (and flags) + if ((setting == camera->setting) && !(flags & CAM_REQUEST_SETTING_FORCE_CHANGE)) { + camera->behaviorFlags |= CAM_REQUEST_SETTING_PRESERVE_BG_CAM_INDEX; + if (!(flags & CAM_REQUEST_SETTING_IGNORE_PRIORITY)) { + camera->behaviorFlags |= CAM_BEHAVIOR_SETTING_CHECK_PRIORITY; + } + return -1; + } + + camera->behaviorFlags |= CAM_REQUEST_SETTING_PRESERVE_BG_CAM_INDEX; + + if (!(flags & CAM_REQUEST_SETTING_IGNORE_PRIORITY)) { + camera->behaviorFlags |= CAM_BEHAVIOR_SETTING_CHECK_PRIORITY; + } + + Camera_SetNewModeStateFlags(camera); + + if (!(sCameraSettings[camera->setting].flags & 0x40000000)) { + camera->prevSetting = camera->setting; + } + + if (flags & CAM_REQUEST_SETTING_RESTORE_PREV_BG_CAM_INDEX) { + camera->bgCamIndex = camera->prevBgCamIndex; + camera->prevBgCamIndex = -1; + } else if (!(flags & CAM_REQUEST_SETTING_PRESERVE_BG_CAM_INDEX)) { + if (!(sCameraSettings[camera->setting].flags & 0x40000000)) { + camera->prevBgCamIndex = camera->bgCamIndex; + } + camera->bgCamIndex = -1; + } + + camera->setting = setting; + + if (Camera_RequestModeImpl(camera, camera->mode, true) >= 0) { + Camera_CopyDataToRegs(camera, camera->mode); + } + + return setting; +} + +s32 Camera_ChangeSetting(Camera* camera, s16 setting) { + s32 settingChangeSuccessful = Camera_ChangeSettingFlags(camera, setting, 0); + + if (settingChangeSuccessful >= 0) { + camera->bgCamIndex = -1; + } + return settingChangeSuccessful; +} + +s32 Camera_ChangeActorCsCamIndex(Camera* camera, s32 bgCamIndex) { + s16 setting; + + if ((bgCamIndex == -1) || + ((bgCamIndex == camera->bgCamIndex) && !(camera->behaviorFlags & CAM_BEHAVIOR_BG_PROCESSED))) { + camera->behaviorFlags |= CAM_BEHAVIOR_BG_PROCESSED; + return -1; + } + + if (bgCamIndex < 0) { + setting = sGlobalCamDataSettingsPtr[bgCamIndex]; + } else if (!(camera->behaviorFlags & CAM_BEHAVIOR_BG_PROCESSED)) { + setting = Camera_GetBgCamOrActorCsCamSetting(camera, bgCamIndex); + } else { + return -1; + } + + camera->behaviorFlags |= CAM_BEHAVIOR_BG_PROCESSED; + + // Sets camera setting based on bg/scene data + if ((Camera_ChangeSettingFlags( + camera, setting, CAM_REQUEST_SETTING_PRESERVE_BG_CAM_INDEX | CAM_REQUEST_SETTING_FORCE_CHANGE) >= 0) || + (sCameraSettings[camera->setting].flags & 0x80000000)) { + camera->bgCamIndex = bgCamIndex; + camera->behaviorFlags |= CAM_BEHAVIOR_BG_SUCCESS; + Camera_CopyDataToRegs(camera, camera->mode); + } + + return bgCamIndex | 0x80000000; +} + +void Camera_800E0348(Camera* camera) { + if (!RELOAD_PARAMS(camera)) { + camera->animState = 999; + Camera_SetStateFlag(camera, CAM_STATE_BLOCK_BG | CAM_STATE_CAM_FUNC_FINISH | CAM_STATE_CHECK_BG | + CAM_STATE_CHECK_WATER); + } else { + camera->animState = 666; + } +} + +#endif diff --git a/src/code/z_camera_data.inc.c b/src/code/z_camera_data.inc.c index 0676150c6..2c796631e 100644 --- a/src/code/z_camera_data.inc.c +++ b/src/code/z_camera_data.inc.c @@ -12,6 +12,13 @@ typedef struct CameraMode { CameraModeValue* values; } CameraMode; +/** + * Flags: + * (flags & 0xF): Priority (lower value has higher priority) + * (flags & 0x20000000): Ignore flags + * (flags & 0x40000000): Store previous setting and bgCamData, also ignores water checks + * (flags & 0x80000000): Set camera setting based on bg/scene data and reset action function state + */ typedef struct CameraSetting { union { u32 unk_00; @@ -21,6 +28,7 @@ typedef struct CameraSetting { u32 validModes : 30; }; }; + u32 flags; CameraMode* cameraModes; } CameraSetting; @@ -2344,73 +2352,86 @@ CameraMode sCamSetNormal4Modes[] = { CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP1, sSetNormal0ModeFollowBoomerangData), // CAM_MODE_FOLLOW_BOOMERANG }; +#if ENABLE_CUTSCENE_IMPROVEMENTS +CameraModeValue D_801B5824[] = { + CAM_FUNCDATA_FIXD1(-40, 100, 60, CAM_INTERFACE_FIELD(CAM_LETTERBOX_IGNORE, CAM_HUD_VISIBILITY_IGNORE, 0)), +}; + +CameraMode sCamSetFixed1Modes[] = { + CAM_SETTING_MODE_ENTRY(CAM_FUNC_FIXED1, D_801B5824), // CAM_MODE_NORMAL +}; +#endif + CameraSetting sCameraSettings[] = { - { { 0x00000000 }, NULL }, // CAM_SET_NONE - { { 0x051FFFFF }, sCamSetNormal0Modes }, // CAM_SET_NORMAL0 - { { 0x051FFFFF }, sCamSetNormal1Modes }, // CAM_SET_NORMAL1 - { { 0x051FFFFF }, sCamSetDungeon0Modes }, // CAM_SET_DUNGEON0 - { { 0x051FFFFF }, sCamSetDungeon1Modes }, // CAM_SET_DUNGEON1 - { { 0x050FF7FF }, sCamSetNormal3Modes }, // CAM_SET_NORMAL3 - { { 0x8500018F }, sCamSetHorseModes }, // CAM_SET_HORSE - { { 0x051FFFFF }, sCamSetBossGohmaModes }, // CAM_SET_BOSS_GOHMA - { { 0x051FFFFF }, sCamSetBossDodongoModes }, // CAM_SET_BOSS_DODONGO - { { 0x051FFFFF }, sCamSetBossBarinadeModes }, // CAM_SET_BOSS_BARINADE - { { 0x051FFFFF }, sCamSetBossPhantomGanonModes }, // CAM_SET_BOSS_PHANTOM_GANON - { { 0x051FFFFF }, sCamSetBossVolvagiaModes }, // CAM_SET_BOSS_VOLVAGIA - { { 0x051FFFFF }, sCamSetBossBongoModes }, // CAM_SET_BOSS_BONGO - { { 0x051FFFFF }, sCamSetBossMorphaModes }, // CAM_SET_BOSS_MORPHA - { { 0x051FFFFF }, sCamSetBossTwinrovaPlatformModes }, // CAM_SET_BOSS_TWINROVA_PLATFORM - { { 0x051FFFFF }, sCamSetBossTwinrovaFloorModes }, // CAM_SET_BOSS_TWINROVA_FLOOR - { { 0x051FFFFF }, sCamSetBossGanondorfModes }, // CAM_SET_BOSS_GANONDORF - { { 0x051FFFFF }, sCamSetBossGanonModes }, // CAM_SET_BOSS_GANON - { { 0x851FFFFF }, sCamSetTowerClimbModes }, // CAM_SET_TOWER_CLIMB - { { 0x851FFFFF }, sCamSetTowerUnusedModes }, // CAM_SET_TOWER_UNUSED - { { 0x8500000D }, sCamSetMarketBalconyModes }, // CAM_SET_MARKET_BALCONY - { { 0x85000001 }, sCamSetChuBowlingModes }, // CAM_SET_CHU_BOWLING - { { 0x85000001 }, sCamSetPivotCrawlspaceModes }, // CAM_SET_PIVOT_CRAWLSPACE - { { 0x85000001 }, sCamSetPivotShopBrowsingModes }, // CAM_SET_PIVOT_SHOP_BROWSING - { { 0x851E1FFF }, sCamSetPivotInFrontModes }, // CAM_SET_PIVOT_IN_FRONT - { { 0x8C00000D }, sCamSetPreRendFixedModes }, // CAM_SET_PREREND_FIXED - { { 0x8C00000D }, sCamSetPreRendPivotModes }, // CAM_SET_PREREND_PIVOT - { { 0x8C000001 }, sCamSetPreRendSideScrollModes }, // CAM_SET_PREREND_SIDE_SCROLL - { { 0xC5000001 }, sCamSetDoor0Modes }, // CAM_SET_DOOR0 - { { 0xC5000003 }, sCamSetDoorCModes }, // CAM_SET_DOORC - { { 0xC5000001 }, sCamSetCrawlspaceModes }, // CAM_SET_CRAWLSPACE - { { 0xC5000001 }, sCamSetStart0Modes }, // CAM_SET_START0 - { { 0xC5000001 }, sCamSetStart1Modes }, // CAM_SET_START1 - { { 0x05000001 }, sCamSetFree0Modes }, // CAM_SET_FREE0 - { { 0x05000001 }, sCamSetFree2Modes }, // CAM_SET_FREE2 - { { 0x85000001 }, sCamSetPivotCornerModes }, // CAM_SET_PIVOT_CORNER - { { 0x05000003 }, sCamSetPivotWaterSurfaceModes }, // CAM_SET_PIVOT_WATER_SURFACE - { { 0xCE000001 }, sCamSetCs0Modes }, // CAM_SET_CS_0 - { { 0x4E000001 }, sCamSetCsTwistedHallwayModes }, // CAM_SET_CS_TWISTED_HALLWAY - { { 0x05000009 }, sCamSetForestBirdsEyeModes }, // CAM_SET_FOREST_BIRDS_EYE - { { 0x45000001 }, sCamSetSlowChestCsModes }, // CAM_SET_SLOW_CHEST_CS - { { 0x45000001 }, sCamSetItemUnusedModes }, // CAM_SET_ITEM_UNUSED - { { 0x45000001 }, sCamSetCs3Modes }, // CAM_SET_CS_3 - { { 0x45000001 }, sCamSetCsAttentionModes }, // CAM_SET_CS_ATTENTION - { { 0x451FFFFF }, sCamSetBeanGenericModes }, // CAM_SET_BEAN_GENERIC - { { 0x451FFFFF }, sCamSetBeanLostWoodsModes }, // CAM_SET_BEAN_LOST_WOODS - { { 0xC5000001 }, sCamSetSceneUnusedModes }, // CAM_SET_SCENE_UNUSED - { { 0x45000001 }, sCamSetSceneTransitionModes }, // CAM_SET_SCENE_TRANSITION - { { 0x05000001 }, sCamSetElevatorPlatformModes }, // CAM_SET_ELEVATOR_PLATFORM - { { 0x45000001 }, sCamSetFireStaircaseModes }, // CAM_SET_FIRE_STAIRCASE - { { 0x45000001 }, sCamSetForestUnusedModes }, // CAM_SET_FOREST_UNUSED - { { 0x45000001 }, sCamSetForestDefeatPoeModes }, // CAM_SET_FOREST_DEFEAT_POE - { { 0x451FFFFF }, sCamSetBigOctoModes }, // CAM_SET_BIG_OCTO - { { 0x05000033 }, sCamSetMeadowBirdsEyeModes }, // CAM_SET_MEADOW_BIRDS_EYE - { { 0x05000033 }, sCamSetMeadowUnusedModes }, // CAM_SET_MEADOW_UNUSED - { { 0x05000033 }, sCamSetFireBirdsEyeModes }, // CAM_SET_FIRE_BIRDS_EYE - { { 0x4A000001 }, sCamSetTurnAroundModes }, // CAM_SET_TURN_AROUND - { { 0x05000001 }, sCamSetPivotVerticalModes }, // CAM_SET_PIVOT_VERTICAL - { { 0x051FFFFF }, sCamSetNorm2Modes }, // CAM_SET_NORMAL2 - { { 0x0501E05F }, sCamSetFishingModes }, // CAM_SET_FISHING - { { 0x45000001 }, sCamSetCsCModes }, // CAM_SET_CS_C - { { 0x051FFFFF }, sCamSetJabuTentacleModes }, // CAM_SET_JABU_TENTACLE - { { 0x051FFFFF }, sCamSetDungeon2Modes }, // CAM_SET_DUNGEON2 - { { 0x051FFFFF }, sCamSetDirectedYawModes }, // CAM_SET_DIRECTED_YAW - { { 0xC5000ECD }, sCamSetPivotFromSideModes }, // CAM_SET_PIVOT_FROM_SIDE - { { 0x051FFFFF }, sCamSetNormal4Modes }, // CAM_SET_NORMAL4 + { { 0x00000000 }, 0x20000000, NULL }, // CAM_SET_NONE + { { 0x051FFFFF }, 0x20000000, sCamSetNormal0Modes }, // CAM_SET_NORMAL0 + { { 0x051FFFFF }, 0x20000000, sCamSetNormal1Modes }, // CAM_SET_NORMAL1 + { { 0x051FFFFF }, 0x20000000, sCamSetDungeon0Modes }, // CAM_SET_DUNGEON0 + { { 0x051FFFFF }, 0x20000000, sCamSetDungeon1Modes }, // CAM_SET_DUNGEON1 + { { 0x050FF7FF }, 0x20000000, sCamSetNormal3Modes }, // CAM_SET_NORMAL3 + { { 0x8500018F }, 0x20000000, sCamSetHorseModes }, // CAM_SET_HORSE + { { 0x051FFFFF }, 0x20000000, sCamSetBossGohmaModes }, // CAM_SET_BOSS_GOHMA + { { 0x051FFFFF }, 0x20000000, sCamSetBossDodongoModes }, // CAM_SET_BOSS_DODONGO + { { 0x051FFFFF }, 0x20000000, sCamSetBossBarinadeModes }, // CAM_SET_BOSS_BARINADE + { { 0x051FFFFF }, 0x20000000, sCamSetBossPhantomGanonModes }, // CAM_SET_BOSS_PHANTOM_GANON + { { 0x051FFFFF }, 0x20000000, sCamSetBossVolvagiaModes }, // CAM_SET_BOSS_VOLVAGIA + { { 0x051FFFFF }, 0x20000000, sCamSetBossBongoModes }, // CAM_SET_BOSS_BONGO + { { 0x051FFFFF }, 0x20000000, sCamSetBossMorphaModes }, // CAM_SET_BOSS_MORPHA + { { 0x051FFFFF }, 0x20000000, sCamSetBossTwinrovaPlatformModes }, // CAM_SET_BOSS_TWINROVA_PLATFORM + { { 0x051FFFFF }, 0x20000000, sCamSetBossTwinrovaFloorModes }, // CAM_SET_BOSS_TWINROVA_FLOOR + { { 0x051FFFFF }, 0x20000000, sCamSetBossGanondorfModes }, // CAM_SET_BOSS_GANONDORF + { { 0x051FFFFF }, 0x20000000, sCamSetBossGanonModes }, // CAM_SET_BOSS_GANON + { { 0x851FFFFF }, 0x20000000, sCamSetTowerClimbModes }, // CAM_SET_TOWER_CLIMB + { { 0x851FFFFF }, 0x20000000, sCamSetTowerUnusedModes }, // CAM_SET_TOWER_UNUSED + { { 0x8500000D }, 0x20000000, sCamSetMarketBalconyModes }, // CAM_SET_MARKET_BALCONY + { { 0x85000001 }, 0x20000000, sCamSetChuBowlingModes }, // CAM_SET_CHU_BOWLING + { { 0x85000001 }, 0x20000000, sCamSetPivotCrawlspaceModes }, // CAM_SET_PIVOT_CRAWLSPACE + { { 0x85000001 }, 0x20000000, sCamSetPivotShopBrowsingModes }, // CAM_SET_PIVOT_SHOP_BROWSING + { { 0x851E1FFF }, 0x20000000, sCamSetPivotInFrontModes }, // CAM_SET_PIVOT_IN_FRONT + { { 0x8C00000D }, 0x20000000, sCamSetPreRendFixedModes }, // CAM_SET_PREREND_FIXED + { { 0x8C00000D }, 0x20000000, sCamSetPreRendPivotModes }, // CAM_SET_PREREND_PIVOT + { { 0x8C000001 }, 0x20000000, sCamSetPreRendSideScrollModes }, // CAM_SET_PREREND_SIDE_SCROLL + { { 0xC5000001 }, 0x20000000, sCamSetDoor0Modes }, // CAM_SET_DOOR0 + { { 0xC5000003 }, 0x20000000, sCamSetDoorCModes }, // CAM_SET_DOORC + { { 0xC5000001 }, 0x20000000, sCamSetCrawlspaceModes }, // CAM_SET_CRAWLSPACE + { { 0xC5000001 }, 0x20000000, sCamSetStart0Modes }, // CAM_SET_START0 + { { 0xC5000001 }, 0x20000000, sCamSetStart1Modes }, // CAM_SET_START1 + { { 0x05000001 }, 0x20000000, sCamSetFree0Modes }, // CAM_SET_FREE0 + { { 0x05000001 }, 0x20000000, sCamSetFree2Modes }, // CAM_SET_FREE2 + { { 0x85000001 }, 0x20000000, sCamSetPivotCornerModes }, // CAM_SET_PIVOT_CORNER + { { 0x05000003 }, 0x20000000, sCamSetPivotWaterSurfaceModes }, // CAM_SET_PIVOT_WATER_SURFACE + { { 0xCE000001 }, 0x20000000, sCamSetCs0Modes }, // CAM_SET_CS_0 + { { 0x4E000001 }, 0x20000000, sCamSetCsTwistedHallwayModes }, // CAM_SET_CS_TWISTED_HALLWAY + { { 0x05000009 }, 0x20000000, sCamSetForestBirdsEyeModes }, // CAM_SET_FOREST_BIRDS_EYE + { { 0x45000001 }, 0x20000000, sCamSetSlowChestCsModes }, // CAM_SET_SLOW_CHEST_CS + { { 0x45000001 }, 0x20000000, sCamSetItemUnusedModes }, // CAM_SET_ITEM_UNUSED + { { 0x45000001 }, 0x20000000, sCamSetCs3Modes }, // CAM_SET_CS_3 + { { 0x45000001 }, 0x20000000, sCamSetCsAttentionModes }, // CAM_SET_CS_ATTENTION + { { 0x451FFFFF }, 0x20000000, sCamSetBeanGenericModes }, // CAM_SET_BEAN_GENERIC + { { 0x451FFFFF }, 0x20000000, sCamSetBeanLostWoodsModes }, // CAM_SET_BEAN_LOST_WOODS + { { 0xC5000001 }, 0x20000000, sCamSetSceneUnusedModes }, // CAM_SET_SCENE_UNUSED + { { 0x45000001 }, 0x20000000, sCamSetSceneTransitionModes }, // CAM_SET_SCENE_TRANSITION + { { 0x05000001 }, 0x20000000, sCamSetElevatorPlatformModes }, // CAM_SET_ELEVATOR_PLATFORM + { { 0x45000001 }, 0x20000000, sCamSetFireStaircaseModes }, // CAM_SET_FIRE_STAIRCASE + { { 0x45000001 }, 0x20000000, sCamSetForestUnusedModes }, // CAM_SET_FOREST_UNUSED + { { 0x45000001 }, 0x20000000, sCamSetForestDefeatPoeModes }, // CAM_SET_FOREST_DEFEAT_POE + { { 0x451FFFFF }, 0x20000000, sCamSetBigOctoModes }, // CAM_SET_BIG_OCTO + { { 0x05000033 }, 0x20000000, sCamSetMeadowBirdsEyeModes }, // CAM_SET_MEADOW_BIRDS_EYE + { { 0x05000033 }, 0x20000000, sCamSetMeadowUnusedModes }, // CAM_SET_MEADOW_UNUSED + { { 0x05000033 }, 0x20000000, sCamSetFireBirdsEyeModes }, // CAM_SET_FIRE_BIRDS_EYE + { { 0x4A000001 }, 0x20000000, sCamSetTurnAroundModes }, // CAM_SET_TURN_AROUND + { { 0x05000001 }, 0x20000000, sCamSetPivotVerticalModes }, // CAM_SET_PIVOT_VERTICAL + { { 0x051FFFFF }, 0x20000000, sCamSetNorm2Modes }, // CAM_SET_NORMAL2 + { { 0x0501E05F }, 0x20000000, sCamSetFishingModes }, // CAM_SET_FISHING + { { 0x45000001 }, 0x20000000, sCamSetCsCModes }, // CAM_SET_CS_C + { { 0x051FFFFF }, 0x20000000, sCamSetJabuTentacleModes }, // CAM_SET_JABU_TENTACLE + { { 0x051FFFFF }, 0x20000000, sCamSetDungeon2Modes }, // CAM_SET_DUNGEON2 + { { 0x051FFFFF }, 0x20000000, sCamSetDirectedYawModes }, // CAM_SET_DIRECTED_YAW + { { 0xC5000ECD }, 0x20000000, sCamSetPivotFromSideModes }, // CAM_SET_PIVOT_FROM_SIDE + { { 0x051FFFFF }, 0x20000000, sCamSetNormal4Modes }, // CAM_SET_NORMAL4 +#if ENABLE_CUTSCENE_IMPROVEMENTS + { { 0x00000001 }, 0x80000005, sCamSetFixed1Modes }, // CAM_SET_FIXED1 +#endif }; s32 Camera_Normal0(Camera* camera); @@ -2556,6 +2577,9 @@ s32 (*sCameraFunctions[])(Camera*) = { Camera_Special7, // CAM_FUNC_SPEC7 Camera_Special8, // CAM_FUNC_SPEC8 Camera_Special9, // CAM_FUNC_SPEC9 +#if ENABLE_CUTSCENE_IMPROVEMENTS + Camera_Fixed3, // CAM_FUNC_FIXED1 +#endif }; s32 sInitRegs = 1; diff --git a/src/code/z_demo.c b/src/code/z_demo.c index e0bc95f07..16edfa5e3 100644 --- a/src/code/z_demo.c +++ b/src/code/z_demo.c @@ -35,6 +35,10 @@ #include "assets/scenes/misc/hakaana_ouke/hakaana_ouke_scene.h" +#if ENABLE_CUTSCENE_IMPROVEMENTS +struct CutsceneCamera sCutsceneCameraInfo; +#endif + u16 sCurTextId = 0; u16 sCurOcarinaAction = 0; @@ -165,7 +169,14 @@ void Cutscene_DrawDebugInfo(PlayState* play, Gfx** dlist, CutsceneContext* csCtx void Cutscene_InitContext(PlayState* play, CutsceneContext* csCtx) { csCtx->state = CS_STATE_IDLE; + csCtx->curFrame = 0; csCtx->timer = 0.0f; + csCtx->scriptListCount = 0; + csCtx->scriptIndex = 0; +#if ENABLE_CUTSCENE_IMPROVEMENTS + csCtx->scriptList = NULL; +#endif + Audio_SetCutsceneFlag(0); } void Cutscene_StartManual(PlayState* play, CutsceneContext* csCtx) { @@ -2334,6 +2345,9 @@ void CutsceneHandler_StopScript(PlayState* play, CutsceneContext* csCtx) { Camera_SetFinishedFlag(play->cameraPtrs[sReturnToCamId]); } +#if ENABLE_CUTSCENE_IMPROVEMENTS + CutsceneManager_Stop(CS_ID_GLOBAL_END); +#endif Audio_SetCutsceneFlag(0); csCtx->state = CS_STATE_IDLE; } @@ -2351,7 +2365,6 @@ void Cutscene_SetupScripted(PlayState* play, CutsceneContext* csCtx) { sCurTextId = 0; sCurOcarinaAction = 0; - csCtx->unk_12 = 0; csCtx->playerCue = NULL; for (i = 0; i < ARRAY_COUNT(csCtx->actorCues); i++) { @@ -2365,18 +2378,27 @@ void Cutscene_SetupScripted(PlayState* play, CutsceneContext* csCtx) { csCtx->curFrame = 0xFFFF; - csCtx->camEyeSplinePointsAppliedFrame = CS_CAM_DATA_NOT_APPLIED; - gCamAtSplinePointsAppliedFrame = CS_CAM_DATA_NOT_APPLIED; - gCamEyePointAppliedFrame = CS_CAM_DATA_NOT_APPLIED; - gCamAtPointAppliedFrame = CS_CAM_DATA_NOT_APPLIED; +#if ENABLE_CUTSCENE_IMPROVEMENTS + if (csCtx->scriptList != NULL) { + csCtx->subCamId = CutsceneManager_GetCurrentSubCamId(CS_ID_GLOBAL_END); + CutsceneCamera_Init(Play_GetCamera(play, csCtx->subCamId), &sCutsceneCameraInfo); + csCtx->camEyeSplinePointsAppliedFrame = CS_CAM_DATA_NOT_APPLIED; + } else +#endif + { + csCtx->camEyeSplinePointsAppliedFrame = CS_CAM_DATA_NOT_APPLIED; + gCamAtSplinePointsAppliedFrame = CS_CAM_DATA_NOT_APPLIED; + gCamEyePointAppliedFrame = CS_CAM_DATA_NOT_APPLIED; + gCamAtPointAppliedFrame = CS_CAM_DATA_NOT_APPLIED; - csCtx->camAtReady = false; - csCtx->camEyeReady = false; + csCtx->camAtReady = false; + csCtx->camEyeReady = false; - sReturnToCamId = play->activeCamId; + sReturnToCamId = play->activeCamId; - if (gUseCutsceneCam) { - csCtx->subCamId = Play_CreateSubCamera(play); + if (gUseCutsceneCam) { + csCtx->subCamId = Play_CreateSubCamera(play); + } } if (gSaveContext.cutsceneTrigger == 0) { @@ -2488,3 +2510,12 @@ void Cutscene_SetScript(PlayState* play, void* script) { play->csCtx.script = script; } } + +void Cutscene_StartScripted(PlayState* play, u8 scriptIndex) { +#if ENABLE_CUTSCENE_IMPROVEMENTS + if (play->csCtx.scriptList != NULL) { + Cutscene_SetScript(play, play->csCtx.scriptList[scriptIndex].script); + gSaveContext.cutsceneTrigger = 1; + } +#endif +} diff --git a/src/code/z_lib.c b/src/code/z_lib.c index d5f59a2a8..36200f73c 100644 --- a/src/code/z_lib.c +++ b/src/code/z_lib.c @@ -627,3 +627,30 @@ void Sfx_PlaySfxAtPos(Vec3f* projectedPos, u16 sfxId) { Audio_PlaySfxGeneral(sfxId, projectedPos, 4, &gSfxDefaultFreqAndVolScale, &gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb); } + +s32 Math_StepToIImpl(s32 start, s32 target, s32 step) { + s32 ret; + + if (target >= start) { + ret = start + step; + if (target >= ret) { + return ret; + } + } else { + ret = start - step; + if (ret >= target) { + return ret; + } + } + return target; +} + +void Math_StepToIGet(s32* pValue, s32 target, s32 step) { + *pValue = Math_StepToIImpl(*pValue, target, step); +} + +s32 Math_StepToI(s32* pValue, s32 target, s32 step) { + Math_StepToIGet(pValue, target, step); + + return target == *pValue; +} diff --git a/src/code/z_olib.c b/src/code/z_olib.c index 298f151e2..9ad837008 100644 --- a/src/code/z_olib.c +++ b/src/code/z_olib.c @@ -1,6 +1,7 @@ #include "z64math.h" #include "libc64/math64.h" #include "z_lib.h" +#include "z64olib.h" /** * Calculates the distances between `a` and `b` @@ -209,3 +210,68 @@ Vec3s OLib_Vec3fDiffBinAng(Vec3f* a, Vec3f* b) { return anglesBinAng; } + +/** + * Takes the sum of positions `a` (x,y,z coordinates) and `geo` (geographic coordinates), result is in x,y,z position + * Identical to Quake_AddVec from OoT + */ +Vec3f OLib_AddVecGeoToVec3f(Vec3f* a, VecGeo* geo) { + Vec3f sum; + Vec3f b = OLib_VecGeoToVec3f(geo); + + sum.x = a->x + b.x; + sum.y = a->y + b.y; + sum.z = a->z + b.z; + + return sum; +} + +/** + * Gets a x,y,z position diff depending on the mode + */ +void OLib_Vec3fDiff(PosRot* a, Vec3f* b, Vec3f* dest, s16 mode) { + VecGeo geo; + + switch (mode) { + case OLIB_DIFF_OFFSET: + geo = OLib_Vec3fDiffToVecGeo(&a->pos, b); + geo.yaw -= a->rot.y; + *dest = OLib_VecGeoToVec3f(&geo); + break; + + case OLIB_DIFF: + dest->x = b->x - a->pos.x; + dest->y = b->y - a->pos.y; + dest->z = b->z - a->pos.z; + break; + + default: // OLIB_DIFF_COPY + *dest = *b; + break; + } +} + +/** + * Gets a x,y,z position sum depending on the mode + */ +void OLib_Vec3fAdd(PosRot* a, Vec3f* b, Vec3f* dest, s16 mode) { + VecGeo geo; + + switch (mode) { + case OLIB_ADD_OFFSET: + geo = OLib_Vec3fToVecGeo(b); + geo.yaw += a->rot.y; + *dest = OLib_AddVecGeoToVec3f(&a->pos, &geo); + break; + + case OLIB_ADD: + dest->x = a->pos.x + b->x; + dest->y = a->pos.y + b->y; + dest->z = a->pos.z + b->z; + break; + + default: // OLIB_ADD_COPY + *dest = *b; + break; + } +} diff --git a/src/code/z_parameter.c b/src/code/z_parameter.c index 1c8de94e6..5ed3ecab6 100644 --- a/src/code/z_parameter.c +++ b/src/code/z_parameter.c @@ -632,6 +632,321 @@ void Interface_UpdateHudAlphas(PlayState* play, s16 dimmingAlpha) { interfaceCtx->magicAlpha = risingAlpha; } + break; + + case HUD_VISIBILITY_HEARTS_MAGIC_C: + if ((interfaceCtx->bAlpha != 0) && (interfaceCtx->bAlpha > dimmingAlpha)) { + interfaceCtx->bAlpha = dimmingAlpha; + } + + if ((interfaceCtx->aAlpha != 0) && (interfaceCtx->aAlpha > dimmingAlpha)) { + interfaceCtx->aAlpha = dimmingAlpha; + } + + if ((interfaceCtx->minimapAlpha != 0) && (interfaceCtx->minimapAlpha > dimmingAlpha)) { + interfaceCtx->minimapAlpha = dimmingAlpha; + } + + if (interfaceCtx->cLeftAlpha != 255) { + interfaceCtx->cLeftAlpha = risingAlpha; + } + + if (interfaceCtx->cDownAlpha != 255) { + interfaceCtx->cDownAlpha = risingAlpha; + } + + if (interfaceCtx->cRightAlpha != 255) { + interfaceCtx->cRightAlpha = risingAlpha; + } + + if (interfaceCtx->magicAlpha != 255) { + interfaceCtx->magicAlpha = risingAlpha; + } + + if (interfaceCtx->healthAlpha != 255) { + interfaceCtx->healthAlpha = risingAlpha; + } + + break; + + case HUD_VISIBILITY_ALL_NO_MINIMAP: + if ((interfaceCtx->minimapAlpha != 0) && (interfaceCtx->minimapAlpha > dimmingAlpha)) { + interfaceCtx->minimapAlpha = dimmingAlpha; + } + + if (interfaceCtx->bAlpha != 255) { + interfaceCtx->bAlpha = risingAlpha; + } + + if (interfaceCtx->aAlpha != 255) { + interfaceCtx->aAlpha = risingAlpha; + } + + if (interfaceCtx->cLeftAlpha != 255) { + interfaceCtx->cLeftAlpha = risingAlpha; + } + + if (interfaceCtx->cDownAlpha != 255) { + interfaceCtx->cDownAlpha = risingAlpha; + } + + if (interfaceCtx->cRightAlpha != 255) { + interfaceCtx->cRightAlpha = risingAlpha; + } + + if (interfaceCtx->magicAlpha != 255) { + interfaceCtx->magicAlpha = risingAlpha; + } + + if (interfaceCtx->healthAlpha != 255) { + interfaceCtx->healthAlpha = risingAlpha; + } + + break; + + case HUD_VISIBILITY_A_B_C: + if ((interfaceCtx->minimapAlpha != 0) && (interfaceCtx->minimapAlpha > dimmingAlpha)) { + interfaceCtx->minimapAlpha = dimmingAlpha; + } + + if ((interfaceCtx->magicAlpha != 0) && (interfaceCtx->magicAlpha > dimmingAlpha)) { + interfaceCtx->magicAlpha = dimmingAlpha; + } + + if ((interfaceCtx->healthAlpha != 0) && (interfaceCtx->healthAlpha > dimmingAlpha)) { + interfaceCtx->healthAlpha = dimmingAlpha; + } + + if (interfaceCtx->bAlpha != 255) { + interfaceCtx->bAlpha = risingAlpha; + } + + if (interfaceCtx->aAlpha != 255) { + interfaceCtx->aAlpha = risingAlpha; + } + + if (interfaceCtx->cLeftAlpha != 255) { + interfaceCtx->cLeftAlpha = risingAlpha; + } + + if (interfaceCtx->cDownAlpha != 255) { + interfaceCtx->cDownAlpha = risingAlpha; + } + + if (interfaceCtx->cRightAlpha != 255) { + interfaceCtx->cRightAlpha = risingAlpha; + } + + break; + + case HUD_VISIBILITY_B_MINIMAP: + if ((interfaceCtx->aAlpha != 0) && (interfaceCtx->aAlpha > dimmingAlpha)) { + interfaceCtx->aAlpha = dimmingAlpha; + } + + if ((interfaceCtx->cLeftAlpha != 0) && (interfaceCtx->cLeftAlpha > dimmingAlpha)) { + interfaceCtx->cLeftAlpha = dimmingAlpha; + } + + if ((interfaceCtx->cDownAlpha != 0) && (interfaceCtx->cDownAlpha > dimmingAlpha)) { + interfaceCtx->cDownAlpha = dimmingAlpha; + } + + if ((interfaceCtx->cRightAlpha != 0) && (interfaceCtx->cRightAlpha > dimmingAlpha)) { + interfaceCtx->cRightAlpha = dimmingAlpha; + } + + if ((interfaceCtx->magicAlpha != 0) && (interfaceCtx->magicAlpha > dimmingAlpha)) { + interfaceCtx->magicAlpha = dimmingAlpha; + } + + if ((interfaceCtx->healthAlpha != 0) && (interfaceCtx->healthAlpha > dimmingAlpha)) { + interfaceCtx->healthAlpha = dimmingAlpha; + } + + if (interfaceCtx->bAlpha != 255) { + interfaceCtx->bAlpha = risingAlpha; + } + + if (interfaceCtx->minimapAlpha != 255) { + interfaceCtx->minimapAlpha = risingAlpha; + } + + break; + + case HUD_VISIBILITY_HEARTS_MAGIC_MINIMAP: + if ((interfaceCtx->bAlpha != 0) && (interfaceCtx->bAlpha > dimmingAlpha)) { + interfaceCtx->bAlpha = dimmingAlpha; + } + + if ((interfaceCtx->aAlpha != 0) && (interfaceCtx->aAlpha > dimmingAlpha)) { + interfaceCtx->aAlpha = dimmingAlpha; + } + + if ((interfaceCtx->cLeftAlpha != 0) && (interfaceCtx->cLeftAlpha > dimmingAlpha)) { + interfaceCtx->cLeftAlpha = dimmingAlpha; + } + + if ((interfaceCtx->cDownAlpha != 0) && (interfaceCtx->cDownAlpha > dimmingAlpha)) { + interfaceCtx->cDownAlpha = dimmingAlpha; + } + + if ((interfaceCtx->cRightAlpha != 0) && (interfaceCtx->cRightAlpha > dimmingAlpha)) { + interfaceCtx->cRightAlpha = dimmingAlpha; + } + + if (interfaceCtx->healthAlpha != 255) { + interfaceCtx->healthAlpha = risingAlpha; + } + + if (interfaceCtx->magicAlpha != 255) { + interfaceCtx->magicAlpha = risingAlpha; + } + + if (interfaceCtx->minimapAlpha != 255) { + interfaceCtx->minimapAlpha = risingAlpha; + } + + break; + + case HUD_VISIBILITY_A_HEARTS_MAGIC_MINIMAP: + if ((interfaceCtx->bAlpha != 0) && (interfaceCtx->bAlpha > dimmingAlpha)) { + interfaceCtx->bAlpha = dimmingAlpha; + } + + if ((interfaceCtx->cLeftAlpha != 0) && (interfaceCtx->cLeftAlpha > dimmingAlpha)) { + interfaceCtx->cLeftAlpha = dimmingAlpha; + } + + if ((interfaceCtx->cDownAlpha != 0) && (interfaceCtx->cDownAlpha > dimmingAlpha)) { + interfaceCtx->cDownAlpha = dimmingAlpha; + } + + if ((interfaceCtx->cRightAlpha != 0) && (interfaceCtx->cRightAlpha > dimmingAlpha)) { + interfaceCtx->cRightAlpha = dimmingAlpha; + } + + if (interfaceCtx->aAlpha != 255) { + interfaceCtx->aAlpha = risingAlpha; + } + + if (interfaceCtx->minimapAlpha != 255) { + interfaceCtx->minimapAlpha = risingAlpha; + } + + if (interfaceCtx->magicAlpha != 255) { + interfaceCtx->magicAlpha = risingAlpha; + } + + if (interfaceCtx->healthAlpha != 255) { + interfaceCtx->healthAlpha = risingAlpha; + } + + break; + + case HUD_VISIBILITY_B_MAGIC: + if ((interfaceCtx->aAlpha != 0) && (interfaceCtx->aAlpha > dimmingAlpha)) { + interfaceCtx->aAlpha = dimmingAlpha; + } + + if ((interfaceCtx->cLeftAlpha != 0) && (interfaceCtx->cLeftAlpha > dimmingAlpha)) { + interfaceCtx->cLeftAlpha = dimmingAlpha; + } + + if ((interfaceCtx->cDownAlpha != 0) && (interfaceCtx->cDownAlpha > dimmingAlpha)) { + interfaceCtx->cDownAlpha = dimmingAlpha; + } + + if ((interfaceCtx->cRightAlpha != 0) && (interfaceCtx->cRightAlpha > dimmingAlpha)) { + interfaceCtx->cRightAlpha = dimmingAlpha; + } + + if ((interfaceCtx->minimapAlpha != 0) && (interfaceCtx->minimapAlpha > dimmingAlpha)) { + interfaceCtx->minimapAlpha = dimmingAlpha; + } + + if ((interfaceCtx->healthAlpha != 0) && (interfaceCtx->healthAlpha > dimmingAlpha)) { + interfaceCtx->healthAlpha = dimmingAlpha; + } + + if (interfaceCtx->bAlpha != 255) { + interfaceCtx->bAlpha = risingAlpha; + } + + if (interfaceCtx->magicAlpha != 255) { + interfaceCtx->magicAlpha = risingAlpha; + } + + break; + + case HUD_VISIBILITY_A_B: + if (interfaceCtx->aAlpha != 255) { + interfaceCtx->aAlpha = risingAlpha; + } + + if (interfaceCtx->bAlpha != 255) { + interfaceCtx->bAlpha = risingAlpha; + } + + if ((interfaceCtx->cLeftAlpha != 0) && (interfaceCtx->cLeftAlpha > dimmingAlpha)) { + interfaceCtx->cLeftAlpha = dimmingAlpha; + } + + if ((interfaceCtx->cDownAlpha != 0) && (interfaceCtx->cDownAlpha > dimmingAlpha)) { + interfaceCtx->cDownAlpha = dimmingAlpha; + } + + if ((interfaceCtx->cRightAlpha != 0) && (interfaceCtx->cRightAlpha > dimmingAlpha)) { + interfaceCtx->cRightAlpha = dimmingAlpha; + } + + if ((interfaceCtx->minimapAlpha != 0) && (interfaceCtx->minimapAlpha > dimmingAlpha)) { + interfaceCtx->minimapAlpha = dimmingAlpha; + } + + if ((interfaceCtx->magicAlpha != 0) && (interfaceCtx->magicAlpha > dimmingAlpha)) { + interfaceCtx->magicAlpha = dimmingAlpha; + } + + if ((interfaceCtx->healthAlpha != 0) && (interfaceCtx->healthAlpha > dimmingAlpha)) { + interfaceCtx->healthAlpha = dimmingAlpha; + } + + break; + + case HUD_VISIBILITY_A_B_HEARTS_MAGIC_MINIMAP: + if ((interfaceCtx->cLeftAlpha != 0) && (interfaceCtx->cLeftAlpha > dimmingAlpha)) { + interfaceCtx->cLeftAlpha = dimmingAlpha; + } + + if ((interfaceCtx->cDownAlpha != 0) && (interfaceCtx->cDownAlpha > dimmingAlpha)) { + interfaceCtx->cDownAlpha = dimmingAlpha; + } + + if ((interfaceCtx->cRightAlpha != 0) && (interfaceCtx->cRightAlpha > dimmingAlpha)) { + interfaceCtx->cRightAlpha = dimmingAlpha; + } + + if (interfaceCtx->bAlpha != 255) { + interfaceCtx->bAlpha = risingAlpha; + } + + if (interfaceCtx->aAlpha != 255) { + interfaceCtx->aAlpha = risingAlpha; + } + + if (interfaceCtx->minimapAlpha != 255) { + interfaceCtx->minimapAlpha = risingAlpha; + } + + if (interfaceCtx->magicAlpha != 255) { + interfaceCtx->magicAlpha = risingAlpha; + } + + if (interfaceCtx->healthAlpha != 255) { + interfaceCtx->healthAlpha = risingAlpha; + } + break; } diff --git a/src/code/z_play.c b/src/code/z_play.c index e6465607d..1c2bc924f 100644 --- a/src/code/z_play.c +++ b/src/code/z_play.c @@ -9,8 +9,9 @@ #include "n64dd.h" #endif #include "z64frame_advance.h" +#include "z64camera.h" -#if INCLUDE_EXAMPLE_SCENE +#if CAN_INCLUDE_EXAMPLE_SCENE #include "assets/scenes/example/example_scene.h" #endif @@ -247,6 +248,9 @@ void Play_Destroy(GameState* thisx) { } Letterbox_Destroy(); +#if ENABLE_NEW_LETTERBOX + ShrinkWindow_Destroy(); +#endif TransitionFade_Destroy(&this->transitionFadeFlash); VisMono_Destroy(&gPlayVisMono); @@ -308,6 +312,9 @@ void Play_Init(GameState* thisx) { #endif KaleidoManager_Init(this); +#if ENABLE_NEW_LETTERBOX + ShrinkWindow_Init(); +#endif View_Init(&this->view, gfxCtx); Audio_SetExtraFilter(0); Quake_Init(); @@ -393,6 +400,11 @@ void Play_Init(GameState* thisx) { gSaveContext.sceneLayer = GET_EVENTCHKINF(EVENTCHKINF_48) ? 3 : 2; } +#if ENABLE_CUTSCENE_IMPROVEMENTS + // initialize default values to avoid issues + CutsceneManager_Init(this, NULL, 0); +#endif + Play_SpawnScene( this, gEntranceTable[((void)0, gSaveContext.save.entranceIndex) + ((void)0, gSaveContext.sceneLayer)].sceneId, gEntranceTable[((void)0, gSaveContext.save.entranceIndex) + ((void)0, gSaveContext.sceneLayer)].spawn); @@ -497,6 +509,14 @@ void Play_Init(GameState* thisx) { Camera_InitDataUsingPlayer(&this->mainCamera, player); Camera_RequestMode(&this->mainCamera, CAM_MODE_NORMAL); +#if ENABLE_CUTSCENE_IMPROVEMENTS + if ((player->actor.params & 0xFF) != 0xFF) { + Camera_ChangeActorCsCamIndex(&this->mainCamera, player->actor.params & 0xFF); + } + + CutsceneManager_StoreCamera(&this->mainCamera); +#endif + playerStartBgCamIndex = PARAMS_GET_U(player->actor.params, 0, 8); if (playerStartBgCamIndex != 0xFF) { PRINTF("player has start camera ID (" VT_FGCOL(BLUE) "%d" VT_RST ")\n", playerStartBgCamIndex); @@ -1079,6 +1099,10 @@ void Play_Update(PlayState* this) { PLAY_LOG(3777); Letterbox_Update(R_UPDATE_RATE); +#if ENABLE_NEW_LETTERBOX + ShrinkWindow_Update(R_UPDATE_RATE); +#endif + PLAY_LOG(3783); TransitionFade_Update(&this->transitionFadeFlash, R_UPDATE_RATE); } else { @@ -1135,11 +1159,29 @@ skip: } } -#if INCLUDE_EXAMPLE_SCENE - if (this->sceneId == SCENE_EXAMPLE && CHECK_BTN_ALL(this->state.input[0].cur.button, BTN_L | BTN_R) && - CHECK_BTN_ALL(this->state.input[0].press.button, BTN_A) && !Play_InCsMode(this)) { - Cutscene_SetScript(this, gExampleCS); - gSaveContext.cutsceneTrigger = 1; +#if CAN_INCLUDE_EXAMPLE_SCENE + if (this->sceneId == SCENE_EXAMPLE) { + if (CHECK_BTN_ALL(this->state.input[0].cur.button, BTN_Z | BTN_R) && + CHECK_BTN_ALL(this->state.input[0].press.button, BTN_A) && !Play_InCsMode(this)) { + Cutscene_SetScript(this, gExampleCS); + gSaveContext.cutsceneTrigger = 1; + } + +#if ENABLE_CUTSCENE_IMPROVEMENTS + if (!Play_InCsMode(this)) { + // get the additional cutscene id and use it if the value is not -1 + s16 optCsId = CutsceneManager_GetAdditionalCsId(0); + s16 csId = optCsId >= 0 ? optCsId : 0; + + // check if the cutscene is the next on the queue, if it is play it, + // otherwise add it to the queue when the button L is pressed + if (CutsceneManager_IsNext(csId)) { + CutsceneManager_Start(csId, &GET_PLAYER(this)->actor); + } else if (CHECK_BTN_ALL(this->state.input[0].press.button, BTN_L)) { + CutsceneManager_Queue(csId); + } + } +#endif } #endif } @@ -1326,6 +1368,10 @@ void Play_Draw(PlayState* this) { #endif if (!DEBUG_FEATURES || (R_HREG_MODE != HREG_MODE_PLAY) || R_PLAY_RUN_DRAW) { +#if ENABLE_NEW_LETTERBOX + ShrinkWindow_Draw(gfxCtx); +#endif + POLY_OPA_DISP = Play_SetFog(this, POLY_OPA_DISP); POLY_XLU_DISP = Play_SetFog(this, POLY_XLU_DISP); @@ -1667,6 +1713,11 @@ void Play_Main(GameState* thisx) { Play_Draw(this); PLAY_LOG(4587); + +#if ENABLE_CUTSCENE_IMPROVEMENTS + CutsceneManager_Update(); + CutsceneManager_ClearWaiting(); +#endif } // original name: "Game_play_demo_mode_check" @@ -1778,6 +1829,10 @@ void Play_InitScene(PlayState* this, s32 spawn) { this->sceneMaterialAnims = NULL; #endif +#if ENABLE_CUTSCENE_IMPROVEMENTS + this->actorCsCamList = NULL; +#endif + this->numActorEntries = 0; Object_InitContext(this, &this->objectCtx); @@ -2204,3 +2259,17 @@ s32 func_800C0DB4(PlayState* this, Vec3f* pos) { return false; } } + +#if ENABLE_CUTSCENE_IMPROVEMENTS +u16 Play_GetActorCsCamSetting(PlayState* this, s32 csCamDataIndex) { + ActorCsCamInfo* actorCsCamList = &this->actorCsCamList[csCamDataIndex]; + + return actorCsCamList->setting; +} + +Vec3s* Play_GetActorCsCamFuncData(PlayState* this, s32 csCamDataIndex) { + ActorCsCamInfo* actorCsCamList = &this->actorCsCamList[csCamDataIndex]; + + return SEGMENTED_TO_VIRTUAL(actorCsCamList->actorCsCamFuncData); +} +#endif diff --git a/src/code/z_player_lib.c b/src/code/z_player_lib.c index 75275899d..55ffb830c 100644 --- a/src/code/z_player_lib.c +++ b/src/code/z_player_lib.c @@ -3,6 +3,7 @@ #include "assets/objects/gameplay_keep/gameplay_keep.h" #include "assets/objects/object_link_boy/object_link_boy.h" #include "assets/objects/object_link_child/object_link_child.h" +#include "config.h" #pragma increment_block_number "gc-eu:0 gc-eu-mq:0 gc-jp:128 gc-jp-ce:128 gc-jp-mq:128 gc-us:128 gc-us-mq:128" @@ -607,7 +608,11 @@ void Player_SetBootData(PlayState* play, Player* this) { int Player_InBlockingCsMode(PlayState* play, Player* this) { return (this->stateFlags1 & (PLAYER_STATE1_DEAD | PLAYER_STATE1_29)) || (this->csAction != PLAYER_CSACTION_NONE) || (play->transitionTrigger == TRANS_TRIGGER_START) || (this->stateFlags1 & PLAYER_STATE1_0) || +#if ENABLE_CUTSCENE_IMPROVEMENTS + (this->stateFlags3 & (PLAYER_STATE3_FLYING_WITH_HOOKSHOT | PLAYER_STATE3_CS_HALT)) || +#else (this->stateFlags3 & PLAYER_STATE3_FLYING_WITH_HOOKSHOT) || +#endif ((gSaveContext.magicState != MAGIC_STATE_IDLE) && (Player_ActionToMagicSpell(this, this->itemAction) >= 0)); } diff --git a/src/code/z_scene.c b/src/code/z_scene.c index 151d2e220..9be8ea631 100644 --- a/src/code/z_scene.c +++ b/src/code/z_scene.c @@ -533,6 +533,18 @@ void Scene_CommandAnimatedMaterials(PlayState* play, SceneCmd* cmd) { #endif } +void Scene_CommandCutsceneList(PlayState* play, SceneCmd* cmd) { +#if ENABLE_CUTSCENE_IMPROVEMENTS + CutsceneManager_Init(play, SEGMENTED_TO_VIRTUAL(cmd->cutsceneList.segment), cmd->cutsceneList.num); +#endif +} + +void Scene_CommandActorCutsceneCamList(PlayState* play, SceneCmd* cmd) { +#if ENABLE_CUTSCENE_IMPROVEMENTS + play->actorCsCamList = SEGMENTED_TO_VIRTUAL(cmd->actorCsCamList.segment); +#endif +} + SceneCmdHandlerFunc sSceneCmdHandlers[SCENE_CMD_ID_MAX] = { Scene_CommandPlayerEntryList, // SCENE_CMD_ID_SPAWN_LIST Scene_CommandActorEntryList, // SCENE_CMD_ID_ACTOR_LIST @@ -563,7 +575,9 @@ SceneCmdHandlerFunc sSceneCmdHandlers[SCENE_CMD_ID_MAX] = { #if ENABLE_F3DEX3 Scene_CommandOccPlaneCandList, // SCENE_CMD_ID_OCC_PLANE_CAND_LIST #endif - Scene_CommandAnimatedMaterials, // SCENE_CMD_ID_ANIMATED_MATERIAL_LIST + Scene_CommandAnimatedMaterials, // SCENE_CMD_ID_ANIMATED_MATERIAL_LIST + Scene_CommandCutsceneList, // SCENE_CMD_ID_ACTOR_CUTSCENE_LIST + Scene_CommandActorCutsceneCamList, // SCENE_CMD_ID_ACTOR_CUTSCENE_CAM_LIST }; RomFile sNaviQuestHintFiles[] = { diff --git a/src/code/z_scene_table.c b/src/code/z_scene_table.c index c616926c0..cf391ab12 100644 --- a/src/code/z_scene_table.c +++ b/src/code/z_scene_table.c @@ -86,8 +86,10 @@ void Scene_DrawConfigFishingPond(PlayState* play); void Scene_DrawConfigGanonsTowerCollapseInterior(PlayState* play); void Scene_DrawConfigInsideGanonsCastleCollapse(PlayState* play); +#if ENABLE_ANIMATED_MATERIALS void Scene_DrawConfigMatAnim(PlayState* play); void Scene_DrawConfigMatAnimManualStep(PlayState* play); +#endif // Entrance Table definition #define DEFINE_ENTRANCE(_0, sceneId, spawn, continueBgm, displayTitleCard, endTransType, startTransType) \ @@ -196,8 +198,10 @@ SceneDrawConfigFunc sSceneDrawConfigs[SDC_MAX] = { Scene_DrawConfigFishingPond, // SDC_FISHING_POND Scene_DrawConfigGanonsTowerCollapseInterior, // SDC_GANONS_TOWER_COLLAPSE_INTERIOR Scene_DrawConfigInsideGanonsCastleCollapse, // SDC_INSIDE_GANONS_CASTLE_COLLAPSE - Scene_DrawConfigMatAnim, // SDC_MAT_ANIM - Scene_DrawConfigMatAnimManualStep, // SDC_MAT_ANIM_MANUAL_STEP +#if ENABLE_ANIMATED_MATERIALS + Scene_DrawConfigMatAnim, // SDC_MAT_ANIM + Scene_DrawConfigMatAnimManualStep, // SDC_MAT_ANIM_MANUAL_STEP +#endif }; #if PLATFORM_N64 // Scene_Draw is at end of file in GC/iQue versions @@ -1709,15 +1713,12 @@ void Scene_DrawConfigBesitu(PlayState* play) { CLOSE_DISPS(play->state.gfxCtx, "../z_scene_table.c", 7910); } +#if ENABLE_ANIMATED_MATERIALS /** * Allows the usage of the animated material system in scenes. */ void Scene_DrawConfigMatAnim(PlayState* play) { -#if ENABLE_ANIMATED_MATERIALS AnimatedMat_Draw(play, play->sceneMaterialAnims); -#else - Scene_DrawConfigDefault(play); -#endif } /** @@ -1725,12 +1726,9 @@ void Scene_DrawConfigMatAnim(PlayState* play) { * rather than always animating like `Scene_DrawConfigMatAnim`. */ void Scene_DrawConfigMatAnimManualStep(PlayState* play) { -#if ENABLE_ANIMATED_MATERIALS AnimatedMat_DrawStep(play, play->sceneMaterialAnims, play->roomCtx.drawParams[0]); -#else - Scene_DrawConfigDefault(play); -#endif } +#endif #if !PLATFORM_N64 // Scene_Draw is at beginning of file in N64 versions diff --git a/src/overlays/actors/ovl_En_Holl/z_en_holl.c b/src/overlays/actors/ovl_En_Holl/z_en_holl.c index af3defe56..2dd6b7d81 100644 --- a/src/overlays/actors/ovl_En_Holl/z_en_holl.c +++ b/src/overlays/actors/ovl_En_Holl/z_en_holl.c @@ -1,4 +1,5 @@ #include "z_en_holl.h" +#include "config.h" #define FLAGS ACTOR_FLAG_4 @@ -403,7 +404,14 @@ void EnHoll_WaitRoomLoaded(EnHoll* this, PlayState* play) { void EnHoll_Update(Actor* thisx, PlayState* play) { EnHoll* this = (EnHoll*)thisx; +#if ENABLE_CUTSCENE_IMPROVEMENTS + if ((play->transitionTrigger == TRANS_TRIGGER_OFF) && (play->transitionMode == TRANS_MODE_OFF) && + !(GET_PLAYER(play)->stateFlags3 & PLAYER_STATE3_CS_HALT)) { + this->actionFunc(this, play); + } +#else this->actionFunc(this, play); +#endif } #include "assets/overlays/ovl_En_Holl/ovl_En_Holl.c" diff --git a/src/overlays/actors/ovl_En_Okuta/z_en_okuta.c b/src/overlays/actors/ovl_En_Okuta/z_en_okuta.c index 0360e7337..5329f4904 100644 --- a/src/overlays/actors/ovl_En_Okuta/z_en_okuta.c +++ b/src/overlays/actors/ovl_En_Okuta/z_en_okuta.c @@ -1,5 +1,6 @@ #include "z_en_okuta.h" #include "assets/objects/object_okuta/object_okuta.h" +#include "config.h" #define FLAGS (ACTOR_FLAG_ATTENTION_ENABLED | ACTOR_FLAG_HOSTILE) @@ -578,6 +579,12 @@ void EnOkuta_Update(Actor* thisx, PlayState* play2) { Vec3f prevPos; s32 canRestorePrevPos; +#if ENABLE_CUTSCENE_IMPROVEMENTS + if (player->stateFlags3 & PLAYER_STATE3_CS_HALT) { + return; + } +#endif + if (!(player->stateFlags1 & (PLAYER_STATE1_TALKING | PLAYER_STATE1_DEAD | PLAYER_STATE1_28 | PLAYER_STATE1_29))) { if (this->actor.params == 0) { EnOkuta_ColliderCheck(this, play); diff --git a/src/overlays/gamestates/ovl_debug_opening/debug_opening.c b/src/overlays/gamestates/ovl_debug_opening/debug_opening.c index c6d20066d..22f2a36f1 100644 --- a/src/overlays/gamestates/ovl_debug_opening/debug_opening.c +++ b/src/overlays/gamestates/ovl_debug_opening/debug_opening.c @@ -254,6 +254,10 @@ void DebugOpening_Init(GameState* thisx) { gSaveContext.save.dayTime = gSaveContext.skyboxTime = CLOCK_TIME(15, 0); Helpers_InitSkybox(&this->state, &this->envCtx, &this->skyboxCtx, DEBUG_OPENING_SKYBOX_ID); +#if ENABLE_NEW_LETTERBOX + ShrinkWindow_Init(); +#endif + this->state.main = DebugOpening_Main; this->state.destroy = DebugOpening_Destroy; diff --git a/src/overlays/gamestates/ovl_file_choose/z_file_choose.c b/src/overlays/gamestates/ovl_file_choose/z_file_choose.c index d92273334..874da7ac6 100644 --- a/src/overlays/gamestates/ovl_file_choose/z_file_choose.c +++ b/src/overlays/gamestates/ovl_file_choose/z_file_choose.c @@ -2308,6 +2308,9 @@ void FileSelect_InitContext(GameState* thisx) { } void FileSelect_Destroy(GameState* thisx) { +#if ENABLE_NEW_LETTERBOX + ShrinkWindow_Destroy(); +#endif } void FileSelect_Init(GameState* thisx) { @@ -2345,6 +2348,9 @@ void FileSelect_Init(GameState* thisx) { #endif Matrix_Init(&this->state); +#if ENABLE_NEW_LETTERBOX + ShrinkWindow_Init(); +#endif View_Init(&this->view, this->state.gfxCtx); this->state.main = FileSelect_Main; this->state.destroy = FileSelect_Destroy; diff --git a/src/overlays/gamestates/ovl_opening/z_opening.c b/src/overlays/gamestates/ovl_opening/z_opening.c index 1ae248381..4d9495121 100644 --- a/src/overlays/gamestates/ovl_opening/z_opening.c +++ b/src/overlays/gamestates/ovl_opening/z_opening.c @@ -29,6 +29,9 @@ void TitleSetup_Main(GameState* thisx) { } void TitleSetup_Destroy(GameState* thisx) { +#if ENABLE_NEW_LETTERBOX + ShrinkWindow_Destroy(); +#endif } void TitleSetup_Init(GameState* thisx) { @@ -36,6 +39,9 @@ void TitleSetup_Init(GameState* thisx) { R_UPDATE_RATE = 1; Matrix_Init(&this->state); +#if ENABLE_NEW_LETTERBOX + ShrinkWindow_Init(); +#endif View_Init(&this->view, this->state.gfxCtx); this->state.main = TitleSetup_Main; this->state.destroy = TitleSetup_Destroy; diff --git a/src/overlays/gamestates/ovl_select/z_select.c b/src/overlays/gamestates/ovl_select/z_select.c index a49261e37..ddf5b3368 100644 --- a/src/overlays/gamestates/ovl_select/z_select.c +++ b/src/overlays/gamestates/ovl_select/z_select.c @@ -28,6 +28,10 @@ void MapSelect_Init(GameState* thisx) { this->pageDownStops[6] = 91; // Escaping Ganon's Tower 3 this->pageDownIndex = 0; this->sceneTotal = ARRAY_COUNT(sScenes); + +#if ENABLE_NEW_LETTERBOX + ShrinkWindow_Init(); +#endif View_Init(&this->view, this->state.gfxCtx); this->view.flags = (VIEW_PROJECTION_ORTHO | VIEW_VIEWPORT); this->verticalInputAccumulator = 0; @@ -106,6 +110,10 @@ void MapSelect_Destroy(GameState* thisx) { PRINTF("%c", BEL); // "view_cleanup will hang, so it won't be called" PRINTF("*** view_cleanupはハングアップするので、呼ばない ***\n"); + +#if ENABLE_NEW_LETTERBOX + ShrinkWindow_Destroy(); +#endif } void MapSelect_UpdateMenu(MapSelectState* this) { diff --git a/src/overlays/gamestates/ovl_title/z_title.c b/src/overlays/gamestates/ovl_title/z_title.c index 6aa88c349..2d41440b7 100644 --- a/src/overlays/gamestates/ovl_title/z_title.c +++ b/src/overlays/gamestates/ovl_title/z_title.c @@ -169,6 +169,10 @@ void ConsoleLogo_Destroy(GameState* thisx) { #if PLATFORM_N64 func_800014E8(); #endif + +#if ENABLE_NEW_LETTERBOX + ShrinkWindow_Destroy(); +#endif } void ConsoleLogo_Init(GameState* thisx) { @@ -192,6 +196,9 @@ void ConsoleLogo_Init(GameState* thisx) { DMA_REQUEST_SYNC(this->staticSegment, (uintptr_t)_nintendo_rogo_staticSegmentRomStart, size, "../z_title.c", 615); R_UPDATE_RATE = 1; Matrix_Init(&this->state); +#if ENABLE_NEW_LETTERBOX + ShrinkWindow_Init(); +#endif View_Init(&this->view, this->state.gfxCtx); this->state.main = ConsoleLogo_Main; this->state.destroy = ConsoleLogo_Destroy;