diff --git a/Makefile b/Makefile index f83c2a158..3a7e3a700 100644 --- a/Makefile +++ b/Makefile @@ -716,11 +716,11 @@ endif $(BUILD_DIR)/assets/text/%.enc.nes.h: assets/text/%.h $(EXTRACTED_DIR)/text/%.h $(NES_CHARMAP) $(call print_two_args,Encoding:,$<,$@) - $(V)$(CPP) $(CPPFLAGS) -I$(EXTRACTED_DIR) -MD -MP -MF $(@:.o=.d) -MT $@ $< | $(PYTHON) tools/msgenc.py --encoding utf-8 --charmap $(NES_CHARMAP) - $@ + $(V)$(CPP) $(CPPFLAGS) -I$(EXTRACTED_DIR) -Iinclude -MD -MP -MF $(@:.o=.d) -MT $@ $< | $(PYTHON) tools/msgenc.py --encoding utf-8 --charmap $(NES_CHARMAP) - $@ $(BUILD_DIR)/assets/text/%.enc.jpn.h: assets/text/%.h $(EXTRACTED_DIR)/text/%.h assets/text/charmap.jpn.txt $(call print_two_args,Encoding:,$<,$@) - $(V)$(CPP) $(CPPFLAGS) -I$(EXTRACTED_DIR) -MD -MP -MF $(@:.o=.d) -MT $@ $< | $(PYTHON) tools/msgenc.py --encoding SHIFT-JIS --wchar --charmap assets/text/charmap.jpn.txt - $@ + $(V)$(CPP) $(CPPFLAGS) -I$(EXTRACTED_DIR) -Iinclude -MD -MP -MF $(@:.o=.d) -MT $@ $< | $(PYTHON) tools/msgenc.py --encoding SHIFT-JIS --wchar --charmap assets/text/charmap.jpn.txt - $@ # Dependencies for encoded message headers. These dependencies are not automatic as these headers are generated # as part of the build. A clean build must know to generate them before the relevant .d files are created. diff --git a/assets/scenes/example/example_scene.h b/assets/scenes/example/example_scene.h index 84159cc92..a69be8f0c 100644 --- a/assets/scenes/example/example_scene.h +++ b/assets/scenes/example/example_scene.h @@ -14,8 +14,12 @@ #include "sequence.h" #include "animated_materials.h" #include "array_count.h" +#include "save.h" extern SceneCmd example_scene_header00[]; +#if ENABLE_MM_TITLE_CARDS +extern TitleCardInfo titleCardInfo; +#endif extern SceneCmd* example_scene_alternateHeaders[]; extern RomFile example_scene_roomList[]; extern u8 _example_room_0SegmentRomStart[]; diff --git a/assets/scenes/example/example_scene_main.c b/assets/scenes/example/example_scene_main.c index dd746cb0d..4bceb553d 100644 --- a/assets/scenes/example/example_scene_main.c +++ b/assets/scenes/example/example_scene_main.c @@ -25,10 +25,28 @@ SceneCmd example_scene_header00[] = { #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 +#if ENABLE_MM_TITLE_CARDS + SCENE_CMD_TITLE_CARD(&titleCardInfo), #endif SCENE_CMD_END(), }; +#if ENABLE_MM_TITLE_CARDS +TitleCardInfo titleCardInfo = { + .textId = 0x8000, + .rgba = { 160, 160, 160, 255 }, + .nextHudVisibility = HUD_VISIBILITY_NOTHING, + .duration = 30, + .textDelayTimer = 0, + .textPos = { TC_TEXT_POS_X, TC_TEXT_POS_Y }, + .gradientWidth = TC_GRADIENT_WIDTH, + .gradientHeight = TC_GRADIENT_HEIGHT, + .alphaFadeOutIncr = TC_ALPHA_FADE_OUT_INCR, + .alphaFadeInIncr = TC_ALPHA_FADE_IN_INCR, +}; +#endif + SceneCmd* example_scene_alternateHeaders[] = { example_scene_header01, example_scene_header02, @@ -252,6 +270,9 @@ SceneCmd example_scene_header01[] = { #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 +#if ENABLE_MM_TITLE_CARDS + SCENE_CMD_TITLE_CARD(&titleCardInfo), #endif SCENE_CMD_END(), }; @@ -397,6 +418,9 @@ SceneCmd example_scene_header02[] = { #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 +#if ENABLE_MM_TITLE_CARDS + SCENE_CMD_TITLE_CARD(&titleCardInfo), #endif SCENE_CMD_END(), }; @@ -542,6 +566,9 @@ SceneCmd example_scene_header03[] = { #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 +#if ENABLE_MM_TITLE_CARDS + SCENE_CMD_TITLE_CARD(&titleCardInfo), #endif SCENE_CMD_END(), }; diff --git a/assets/text/message_data.h b/assets/text/message_data.h index 34fc5e91e..16adf6ae4 100644 --- a/assets/text/message_data.h +++ b/assets/text/message_data.h @@ -1,4 +1,29 @@ #include "text/message_data.h" +#include "config.h" + +#if ENABLE_MM_TITLE_CARDS + +DEFINE_MESSAGE(0x8000, TEXTBOX_TYPE_BLACK, TEXTBOX_POS_VARIABLE, +MSG(/* MISSING */) +, +MSG("Example Scene") +, +MSG(/* MISSING */) +, +MSG(/* MISSING */) +) + +DEFINE_MESSAGE(0x9000, TEXTBOX_TYPE_BLACK, TEXTBOX_POS_VARIABLE, +MSG(/* MISSING */) +, +MSG("Undefined Scene") +, +MSG(/* MISSING */) +, +MSG(/* MISSING */) +) + +#endif /* * The following two messages should be kept last and in this order. diff --git a/assets/textures/hud/hud.c b/assets/textures/hud/hud.c new file mode 100644 index 000000000..4bb000246 --- /dev/null +++ b/assets/textures/hud/hud.c @@ -0,0 +1,5 @@ +#include "hud.h" + +u64 gSceneTitleCardGradientTex[] = { +#include "assets/textures/hud/title_card_gradient.i8.inc.c" +}; diff --git a/assets/textures/hud/hud.h b/assets/textures/hud/hud.h new file mode 100644 index 000000000..7be0fba6b --- /dev/null +++ b/assets/textures/hud/hud.h @@ -0,0 +1,8 @@ +#ifndef TEXTURES_HUD_H +#define TEXTURES_HUD_H + +#include "ultra64/ultratypes.h" + +extern u64 gSceneTitleCardGradientTex[]; + +#endif diff --git a/assets/textures/hud/title_card_gradient.i8.png b/assets/textures/hud/title_card_gradient.i8.png new file mode 100644 index 000000000..b237c2aed Binary files /dev/null and b/assets/textures/hud/title_card_gradient.i8.png differ diff --git a/include/config/config_game.h b/include/config/config_game.h index b3ba048d7..d92afdac3 100644 --- a/include/config/config_game.h +++ b/include/config/config_game.h @@ -86,4 +86,15 @@ */ #define ENABLE_CUTSCENE_IMPROVEMENTS true +/** + * Enable MM Title Cards + */ +#define ENABLE_MM_TITLE_CARDS true +#define TC_TEXT_POS_X 25 +#define TC_TEXT_POS_Y 67 +#define TC_GRADIENT_WIDTH 60 +#define TC_GRADIENT_HEIGHT 28 +#define TC_ALPHA_FADE_OUT_INCR 40 +#define TC_ALPHA_FADE_IN_INCR 30 + #endif diff --git a/include/message.h b/include/message.h index 3948f2dd0..b1521b33c 100644 --- a/include/message.h +++ b/include/message.h @@ -3,12 +3,18 @@ #include "view.h" #include "versions.h" +#include "config.h" +#include "color.h" #include "font.h" struct OcarinaStaff; struct Actor; struct PlayState; +#if ENABLE_MM_TITLE_CARDS +struct TitleCardInfo; +#endif + typedef enum TextBoxIcon { /* 0 */ TEXTBOX_ICON_TRIANGLE, /* 1 */ TEXTBOX_ICON_SQUARE, @@ -108,7 +114,14 @@ typedef enum MessageMode { /* 0x34 */ MSGMODE_TEXT_AWAIT_NEXT, /* 0x35 */ MSGMODE_TEXT_DONE, /* 0x36 */ MSGMODE_TEXT_CLOSING, - /* 0x37 */ MSGMODE_PAUSED // Causes the message system to do nothing until external code sets a new message mode or calls a public function + /* 0x37 */ MSGMODE_PAUSED, // Causes the message system to do nothing until external code sets a new message mode or calls a public function +#if ENABLE_MM_TITLE_CARDS + MSGMODE_SCENE_TITLE_CARD_FADE_IN_BACKGROUND, + MSGMODE_SCENE_TITLE_CARD_FADE_IN_TEXT, + MSGMODE_SCENE_TITLE_CARD_DISPLAYING, + MSGMODE_SCENE_TITLE_CARD_FADE_OUT_TEXT, + MSGMODE_SCENE_TITLE_CARD_FADE_OUT_BACKGROUND, +#endif } MessageMode; typedef enum TextState { @@ -188,6 +201,9 @@ typedef struct MessageContext { /* 0xE40C */ s16 disableWarpSongs; // disables ability to warp with warp songs /* 0xE40E */ s16 disableSunsSong; // disables Suns Song effect from occurring after song is played /* 0xE410 */ u8 lastOcarinaButtonIndex; +#if ENABLE_MM_TITLE_CARDS + struct TitleCardInfo* titleCardInfo; +#endif } MessageContext; // size = 0xE418 void Message_UpdateOcarinaMemoryGame(struct PlayState* play); @@ -203,6 +219,11 @@ void Message_Update(struct PlayState* play); void Message_SetTables(void); void Message_Init(struct PlayState* play); +#if ENABLE_MM_TITLE_CARDS +void Message_SetTitleCardInfo(struct PlayState* play, struct TitleCardInfo* info); +void Message_DisplaySceneTitleCard(struct PlayState* play); +#endif + extern s16 gOcarinaSongItemMap[]; #endif diff --git a/include/scene.h b/include/scene.h index 940e24b68..736554246 100644 --- a/include/scene.h +++ b/include/scene.h @@ -9,6 +9,7 @@ #include "z_math.h" #include "path.h" #include "config.h" +#include "color.h" #include "command_macros_base.h" @@ -262,6 +263,27 @@ typedef struct { } ActorCsCamInfo; // size = 0x8 #endif +#if ENABLE_MM_TITLE_CARDS +typedef struct SCmdTitleCard { + /* 0x0 */ u8 code; + /* 0x1 */ u8 data1; + /* 0x4 */ void* segment; +} SCmdTitleCard; // size = 0x8 + +typedef struct TitleCardInfo { + u16 textId; + Color_RGBA8 rgba; // MM default: R: 140, G: 40, B: 160, A: 255 + u8 nextHudVisibility; + u8 duration; // MM default: 30 + u8 textDelayTimer; // MM default: 0 + Vec2s textPos; // HackerOoT default: X: 25, Y: 67 + u8 gradientWidth; // HackerOoT default: 60 + u8 gradientHeight; // HackerOoT default: 28 + u8 alphaFadeOutIncr; // HackerOoT default: -40 + u8 alphaFadeInIncr; // HackerOoT default: 30 +} TitleCardInfo; +#endif + typedef union SceneCmd { SCmdBase base; SCmdPlayerEntryList playerEntryList; @@ -299,6 +321,9 @@ typedef union SceneCmd { SCmdCsCameraList actorCsCamList; SCmdCutsceneList cutsceneList; #endif +#if ENABLE_MM_TITLE_CARDS + SCmdTitleCard titleCard; +#endif } SceneCmd; // size = 0x8 typedef BAD_RETURN(s32) (*SceneCmdHandlerFunc)(struct PlayState*, SceneCmd*); @@ -486,6 +511,9 @@ typedef enum SceneCommandTypeID { #if ENABLE_CUTSCENE_IMPROVEMENTS SCENE_CMD_ID_ACTOR_CUTSCENE_LIST, SCENE_CMD_ID_ACTOR_CUTSCENE_CAM_LIST, +#endif +#if ENABLE_MM_TITLE_CARDS + SCENE_CMD_ID_TITLE_CARD, #endif /* 0x1A */ SCENE_CMD_ID_MAX } SceneCommandTypeID; @@ -587,6 +615,11 @@ typedef enum SceneCommandTypeID { { SCENE_CMD_ID_ACTOR_CUTSCENE_CAM_LIST, numCams, CMD_PTR(camList) } #endif +#if ENABLE_MM_TITLE_CARDS +#define SCENE_CMD_TITLE_CARD(titleCardInfo) \ + { SCENE_CMD_ID_TITLE_CARD, 0, CMD_PTR(titleCardInfo) } +#endif + s32 Scene_ExecuteCommands(struct PlayState* play, SceneCmd* sceneCmd); void Scene_ResetTransitionActorList(struct GameState* state, TransitionActorList* transitionActors); diff --git a/spec/spec b/spec/spec index 59b31f7a3..f321bbe16 100644 --- a/spec/spec +++ b/spec/spec @@ -4200,6 +4200,7 @@ beginseg number 6 endseg +#if !ENABLE_MM_TITLE_CARDS beginseg name "g_pn_01" compress @@ -4598,6 +4599,7 @@ beginseg romalign 0x1000 include "$(BUILD_DIR)/assets/textures/place_title_cards/g_pn_57.o" endseg +#endif beginseg name "z_select_static" @@ -4628,6 +4630,9 @@ beginseg compress romalign 0x1000 include "$(BUILD_DIR)/assets/textures/parameter_static/parameter_static.o" +#if ENABLE_MM_TITLE_CARDS + include "$(BUILD_DIR)/assets/textures/hud/hud.o" +#endif number 2 endseg diff --git a/src/code/z_camera.c b/src/code/z_camera.c index 5bed6ef55..91a7b67dc 100644 --- a/src/code/z_camera.c +++ b/src/code/z_camera.c @@ -9006,7 +9006,7 @@ s16 Camera_SetFinishedFlag(Camera* camera) { */ s16 Camera_GetBgCamOrActorCsCamSetting(Camera* camera, u32 camDataId) { #if ENABLE_CUTSCENE_IMPROVEMENTS - if (camDataId & CAM_DATA_IS_BG) { + if (camDataId & CAM_DATA_IS_BG || camera->play->actorCsCamList == NULL) { return BgCheck_GetBgCamSettingImpl(&camera->play->colCtx, camDataId & ~CAM_DATA_IS_BG, BGCHECK_SCENE); } else { return Play_GetActorCsCamSetting(camera->play, camDataId); diff --git a/src/code/z_demo.c b/src/code/z_demo.c index 0068a5cce..f3ecab2ae 100644 --- a/src/code/z_demo.c +++ b/src/code/z_demo.c @@ -401,8 +401,12 @@ void CutsceneCmd_Misc(PlayState* play, CutsceneContext* csCtx, CsCmdMisc* cmd) { case CS_MISC_SHOW_TITLE_CARD: if (isFirstFrame) { +#if ENABLE_MM_TITLE_CARDS + Message_DisplaySceneTitleCard(play); +#else TitleCard_InitPlaceName(play, &play->actorCtx.titleCtx, player->giObjectSegment, 160, 120, PLACE_NAME_TEX_WIDTH, PLACE_NAME_TEX_HEIGHT, 20); +#endif } break; @@ -2487,6 +2491,13 @@ void Cutscene_HandleEntranceTriggers(PlayState* play) { break; } } + +#if ENABLE_MM_TITLE_CARDS + if (gSaveContext.showTitleCard) { + Message_DisplaySceneTitleCard(play); + gSaveContext.showTitleCard = false; + } +#endif } void Cutscene_HandleConditionalTriggers(PlayState* play) { diff --git a/src/code/z_message.c b/src/code/z_message.c index 4e72ca2fe..5cb0554e0 100644 --- a/src/code/z_message.c +++ b/src/code/z_message.c @@ -8,6 +8,7 @@ #include "language_array.h" #include "memory_utils.h" #include "message_data_static.h" +#include "config.h" #if PLATFORM_N64 #include "n64dd.h" #endif @@ -27,6 +28,10 @@ #include "assets/textures/parameter_static/parameter_static.h" +#if ENABLE_MM_TITLE_CARDS +#include "assets/textures/hud/hud.h" +#endif + #pragma increment_block_number "gc-eu:128 gc-eu-mq:128 gc-jp:0 gc-jp-ce:0 gc-jp-mq:0 gc-us:0 gc-us-mq:0 ntsc-1.0:16" \ "ntsc-1.1:16 ntsc-1.2:16 pal-1.0:0 pal-1.1:0" @@ -299,6 +304,72 @@ s16 sOcarinaButtonCEnvR; s16 sOcarinaButtonCEnvB; s16 sOcarinaButtonCEnvG; +#if ENABLE_MM_TITLE_CARDS +void Message_DrawText(PlayState* play, Gfx** gfxP); +void Message_OpenText(PlayState* play, u16 textId); +void Message_Decode(PlayState* play); + +static u16 titleCardPrevHudVisibility = HUD_VISIBILITY_ALL; + +void Message_SetTitleCardInfo(struct PlayState* play, TitleCardInfo* info) { + if (info == NULL) { + PRINTF("[HackerOoT:Error]: TitleCardInfo is NULL!\n"); + } + + play->msgCtx.titleCardInfo = info; +} + +void Message_DrawSceneTitleCard(PlayState* play, Gfx** gfxP) { + MessageContext* msgCtx = &play->msgCtx; + + if (msgCtx->titleCardInfo != NULL) { + Color_RGBA8* rgba = &msgCtx->titleCardInfo->rgba; + Gfx* gfx; + + gfx = *gfxP; + Gfx_SetupDL_39Ptr(&gfx); + + gDPSetCombineLERP(gfx++, PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE, 0, PRIMITIVE, + ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE, 0); + gDPSetTextureFilter(gfx++, G_TF_BILERP); + gDPSetAlphaDither(gfx++, G_AD_NOTPATTERN); + gDPSetPrimColor(gfx++, 0, 0, 0, 0, 0, msgCtx->textboxColorAlphaCurrent); + gDPSetEnvColor(gfx++, rgba->r, rgba->g, rgba->b, rgba->a); + gDPLoadTextureBlock(gfx++, gSceneTitleCardGradientTex, G_IM_FMT_I, G_IM_SIZ_8b, 64, 1, 0, + G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, 6, G_TX_NOMASK, G_TX_NOLOD, + G_TX_NOLOD); + gSPTextureRectangle(gfx++, 0, msgCtx->titleCardInfo->gradientWidth << 2, 320 << 2, + (msgCtx->titleCardInfo->gradientWidth + msgCtx->titleCardInfo->gradientHeight) << 2, + G_TX_RENDERTILE, 0, 0, 204, 1 << 10); + gDPPipeSync(gfx++); + gDPSetCombineLERP(gfx++, 0, 0, 0, PRIMITIVE, TEXEL0, 0, PRIMITIVE, 0, 0, 0, 0, PRIMITIVE, TEXEL0, 0, PRIMITIVE, + 0); + gDPSetEnvColor(gfx++, 0, 0, 0, 255); + + Message_DrawText(play, &gfx); + *gfxP = gfx++; + } +} + +void Message_DisplaySceneTitleCard(PlayState* play) { + MessageContext* msgCtx = &play->msgCtx; + TitleCardInfo* info = msgCtx->titleCardInfo; + + if (info != NULL) { + msgCtx->msgLength = 0; + Message_OpenText(play, info->textId); + Message_Decode(play); + msgCtx->msgMode = MSGMODE_SCENE_TITLE_CARD_FADE_IN_BACKGROUND; + msgCtx->textDelayTimer = info->textDelayTimer; + msgCtx->textboxColorAlphaCurrent = msgCtx->textboxColorAlphaTarget = msgCtx->textColorAlpha = 0; + msgCtx->stateTimer = info->duration; + + titleCardPrevHudVisibility = gSaveContext.hudVisibilityMode; + Interface_ChangeHudVisibilityMode(info->nextHudVisibility); + } +} +#endif + void Message_ResetOcarinaNoteState(void) { R_OCARINA_BUTTONS_YPOS(0) = 189; R_OCARINA_BUTTONS_YPOS(1) = 184; @@ -1436,12 +1507,23 @@ void Message_DrawText(PlayState* play, Gfx** gfxP) { Font* font = &play->msgCtx.font; Gfx* gfx = *gfxP; - msgCtx->textPosX = WIDE_INCR(R_TEXT_INIT_XPOS, 23); +#if ENABLE_MM_TITLE_CARDS + if (msgCtx->msgMode >= MSGMODE_SCENE_TITLE_CARD_FADE_IN_BACKGROUND && + msgCtx->msgMode <= MSGMODE_SCENE_TITLE_CARD_FADE_OUT_BACKGROUND) { + if (msgCtx->titleCardInfo != NULL) { + msgCtx->textPosX = msgCtx->titleCardInfo->textPos.x; + msgCtx->textPosY = msgCtx->titleCardInfo->textPos.y; + } + } else +#endif + { + msgCtx->textPosX = WIDE_INCR(R_TEXT_INIT_XPOS, 23); - if (!sTextIsCredits) { - msgCtx->textPosY = R_TEXT_INIT_YPOS; - } else { - msgCtx->textPosY = YREG(1); + if (!sTextIsCredits) { + msgCtx->textPosY = R_TEXT_INIT_YPOS; + } else { + msgCtx->textPosY = YREG(1); + } } if (msgCtx->textBoxType == TEXTBOX_TYPE_NONE_NO_SHADOW) { @@ -3942,6 +4024,15 @@ void Message_DrawMain(PlayState* play, Gfx** p) { case MSGMODE_TEXT_CLOSING: case MSGMODE_PAUSED: break; +#if ENABLE_MM_TITLE_CARDS + case MSGMODE_SCENE_TITLE_CARD_FADE_IN_BACKGROUND: + case MSGMODE_SCENE_TITLE_CARD_FADE_IN_TEXT: + case MSGMODE_SCENE_TITLE_CARD_DISPLAYING: + case MSGMODE_SCENE_TITLE_CARD_FADE_OUT_TEXT: + case MSGMODE_SCENE_TITLE_CARD_FADE_OUT_BACKGROUND: + Message_DrawSceneTitleCard(play, &gfx); + break; +#endif case MSGMODE_UNK_20: default: msgCtx->msgMode = MSGMODE_TEXT_DISPLAYING; @@ -4460,6 +4551,57 @@ void Message_Update(PlayState* play) { break; case MSGMODE_PAUSED: break; +#if ENABLE_MM_TITLE_CARDS + case MSGMODE_SCENE_TITLE_CARD_FADE_IN_BACKGROUND: + if (msgCtx->titleCardInfo != NULL) { + msgCtx->textboxColorAlphaCurrent += msgCtx->titleCardInfo->alphaFadeInIncr; + + if (msgCtx->textboxColorAlphaCurrent >= 255) { + msgCtx->textboxColorAlphaCurrent = 255; + msgCtx->msgMode = MSGMODE_SCENE_TITLE_CARD_FADE_IN_TEXT; + } + } + break; + case MSGMODE_SCENE_TITLE_CARD_FADE_IN_TEXT: + if (msgCtx->titleCardInfo != NULL) { + msgCtx->textColorAlpha += msgCtx->titleCardInfo->alphaFadeInIncr; + + if (msgCtx->textColorAlpha >= 255) { + msgCtx->textColorAlpha = 255; + msgCtx->msgMode = MSGMODE_SCENE_TITLE_CARD_DISPLAYING; + } + } + break; + case MSGMODE_SCENE_TITLE_CARD_DISPLAYING: + msgCtx->stateTimer--; + if (msgCtx->stateTimer == 0) { + msgCtx->msgMode = MSGMODE_SCENE_TITLE_CARD_FADE_OUT_TEXT; + } + break; + case MSGMODE_SCENE_TITLE_CARD_FADE_OUT_TEXT: + if (msgCtx->titleCardInfo != NULL) { + msgCtx->textColorAlpha -= msgCtx->titleCardInfo->alphaFadeOutIncr; + + if (msgCtx->textColorAlpha <= 0) { + msgCtx->textColorAlpha = 0; + msgCtx->msgMode = MSGMODE_SCENE_TITLE_CARD_FADE_OUT_BACKGROUND; + } + } + break; + case MSGMODE_SCENE_TITLE_CARD_FADE_OUT_BACKGROUND: + if (msgCtx->titleCardInfo != NULL) { + msgCtx->textboxColorAlphaCurrent -= msgCtx->titleCardInfo->alphaFadeOutIncr; + + if (msgCtx->textboxColorAlphaCurrent <= 0) { + msgCtx->textboxColorAlphaCurrent = 0; + msgCtx->msgLength = 0; + msgCtx->msgMode = MSGMODE_NONE; + msgCtx->stateTimer = 0; + Interface_ChangeHudVisibilityMode(titleCardPrevHudVisibility); + } + } + break; +#endif default: msgCtx->lastOcarinaButtonIndex = OCARINA_BTN_INVALID; break; diff --git a/src/code/z_play.c b/src/code/z_play.c index 8f2a13c18..30b2ba70c 100644 --- a/src/code/z_play.c +++ b/src/code/z_play.c @@ -76,6 +76,22 @@ UNK_TYPE D_8012D1F4 = 0; // unused Input* D_8012D1F8 = NULL; +#if ENABLE_MM_TITLE_CARDS +// default title card info to use if there's no entry in the scene +static TitleCardInfo sDefaultTitleCard = { + .textId = 0x9000, + .rgba = { 140, 40, 160, 255 }, + .nextHudVisibility = HUD_VISIBILITY_NOTHING, + .duration = 30, + .textDelayTimer = 0, + .textPos = { TC_TEXT_POS_X, TC_TEXT_POS_Y }, + .gradientWidth = TC_GRADIENT_WIDTH, + .gradientHeight = TC_GRADIENT_HEIGHT, + .alphaFadeOutIncr = TC_ALPHA_FADE_OUT_INCR, + .alphaFadeInIncr = TC_ALPHA_FADE_IN_INCR, +}; +#endif + void Play_SpawnScene(PlayState* this, s32 sceneId, s32 spawn); // This macro prints the number "1" with a file and line number if R_ENABLE_PLAY_LOGS is enabled. @@ -1899,6 +1915,10 @@ void Play_SpawnScene(PlayState* this, s32 sceneId, s32 spawn) { PRINTF("\nSCENE SIZE %fK\n", (scene->sceneFile.vromEnd - scene->sceneFile.vromStart) / 1024.0f); +#if ENABLE_MM_TITLE_CARDS + this->msgCtx.titleCardInfo = &sDefaultTitleCard; +#endif + #if PLATFORM_N64 if ((B_80121220 != NULL) && (scene->unk_12 > 0)) { this->sceneSegment = Play_LoadFileFromDiskDrive(this, &scene->sceneFile); diff --git a/src/code/z_scene.c b/src/code/z_scene.c index 541989ec0..cf75927f6 100644 --- a/src/code/z_scene.c +++ b/src/code/z_scene.c @@ -9,6 +9,7 @@ #include "terminal.h" #include "translation.h" #include "versions.h" +#include "config.h" #include "z_actor_dlftbls.h" #include "z_lib.h" #include "play_state.h" @@ -522,23 +523,27 @@ void Scene_SetTransitionForNextEntrance(PlayState* play) { play->transitionType = ENTRANCE_INFO_START_TRANS_TYPE(gEntranceTable[entranceIndex].field); } -void Scene_CommandAnimatedMaterials(PlayState* play, SceneCmd* cmd) { #if ENABLE_ANIMATED_MATERIALS +void Scene_CommandAnimatedMaterials(PlayState* play, SceneCmd* cmd) { play->sceneMaterialAnims = SEGMENTED_TO_VIRTUAL(cmd->textureAnimations.segment); -#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 + +#if ENABLE_CUTSCENE_IMPROVEMENTS +void Scene_CommandCutsceneList(PlayState* play, SceneCmd* cmd) { + CutsceneManager_Init(play, SEGMENTED_TO_VIRTUAL(cmd->cutsceneList.segment), cmd->cutsceneList.num); } void Scene_CommandActorCutsceneCamList(PlayState* play, SceneCmd* cmd) { -#if ENABLE_CUTSCENE_IMPROVEMENTS play->actorCsCamList = SEGMENTED_TO_VIRTUAL(cmd->actorCsCamList.segment); -#endif } +#endif + +#if ENABLE_MM_TITLE_CARDS +void Scene_CommandTitleCard(PlayState* play, SceneCmd* cmd) { + Message_SetTitleCardInfo(play, SEGMENTED_TO_VIRTUAL(cmd->titleCard.segment)); +} +#endif SceneCmdHandlerFunc sSceneCmdHandlers[SCENE_CMD_ID_MAX] = { Scene_CommandPlayerEntryList, // SCENE_CMD_ID_SPAWN_LIST @@ -570,9 +575,16 @@ 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 +#if ENABLE_ANIMATED_MATERIALS + Scene_CommandAnimatedMaterials, // SCENE_CMD_ID_ANIMATED_MATERIAL_LIST +#endif +#if ENABLE_CUTSCENE_IMPROVEMENTS Scene_CommandCutsceneList, // SCENE_CMD_ID_ACTOR_CUTSCENE_LIST Scene_CommandActorCutsceneCamList, // SCENE_CMD_ID_ACTOR_CUTSCENE_CAM_LIST +#endif +#if ENABLE_MM_TITLE_CARDS + Scene_CommandTitleCard, // SCENE_CMD_ID_TITLE_CARD +#endif }; RomFile sNaviQuestHintFiles[] = { diff --git a/src/code/z_scene_table.c b/src/code/z_scene_table.c index 21fa2e0f5..f6ce52eff 100644 --- a/src/code/z_scene_table.c +++ b/src/code/z_scene_table.c @@ -115,6 +115,31 @@ EntranceInfo gEntranceTable[] = { #undef DEFINE_ENTRANCE +#if ENABLE_MM_TITLE_CARDS +// Linker symbol declarations (used in the table below) +#define DEFINE_SCENE(name, _1, _2, _3, _4, _5) DECLARE_ROM_SEGMENT(name) + +#include "tables/scene_table.h" + +#undef DEFINE_SCENE + +// Scene Table definition +#define DEFINE_SCENE(name, _1, _2, drawConfig, unk_10, unk_12) \ + { ROM_FILE(name), ROM_FILE_UNSET, unk_10, drawConfig, unk_12, 0 }, + +// Handle `none` as a special case for scenes without a title card +#define _noneSegmentRomStart NULL +#define _noneSegmentRomEnd NULL + +SceneTableEntry gSceneTable[] = { +#include "tables/scene_table.h" +}; + +#undef _noneSegmentRomStart +#undef _noneSegmentRomEnd + +#undef DEFINE_SCENE +#else // Linker symbol declarations (used in the table below) #define DEFINE_SCENE(name, title, _2, _3, _4, _5) \ DECLARE_ROM_SEGMENT(name) \ @@ -140,6 +165,7 @@ SceneTableEntry gSceneTable[] = { #undef _noneSegmentRomEnd #undef DEFINE_SCENE +#endif Gfx sDefaultDisplayList[] = { gsSPSegment(0x08, gEmptyDL), diff --git a/src/overlays/actors/ovl_player_actor/z_player.c b/src/overlays/actors/ovl_player_actor/z_player.c index f315b29dd..23c355419 100644 --- a/src/overlays/actors/ovl_player_actor/z_player.c +++ b/src/overlays/actors/ovl_player_actor/z_player.c @@ -3598,7 +3598,9 @@ void Player_UseItem(PlayState* play, Player* this, s32 item) { // Handle "cutscene items" if (!Player_CheckHostileLockOn(this) || ((itemAction >= PLAYER_IA_BOTTLE_POTION_RED) && (itemAction <= PLAYER_IA_BOTTLE_FAIRY))) { +#if !ENABLE_MM_TITLE_CARDS TitleCard_Clear(play, &play->actorCtx.titleCtx); +#endif this->unk_6AD = 4; this->itemAction = itemAction; } @@ -10813,8 +10815,10 @@ void Player_Init(Actor* thisx, PlayState* play2) { ((play->sceneId != SCENE_BOMBCHU_SHOP) || GET_EVENTCHKINF(EVENTCHKINF_25)) #endif ) { +#if !ENABLE_MM_TITLE_CARDS TitleCard_InitPlaceName(play, &play->actorCtx.titleCtx, this->giObjectSegment, 160, 120, PLACE_NAME_TEX_WIDTH, PLACE_NAME_TEX_HEIGHT, 20); +#endif } }