#include "global.h" #include "menu.h" #include "main.h" #include "entity.h" #include "functions.h" #include "readKeyInput.h" #include "screen.h" #include "structures.h" typedef struct { u8 filler0[0x4]; u8 gameLanguage; u8 state; u8 subState; u8 filler7[0x1]; u16 timer; u8 fillerA[0x6]; u8 lightRaysPaletteGroup; u8 lightRaysAlphaBlendIndex; u8 counter; u8 filler13[0x19]; int swordBgScaleRatio; } IntroState; // TODO: This occupies the same memory region as gMenu extern IntroState gIntroState; enum { ADVANCE_NONE, ADVANCE_TIMER_EXPIRED, ADVANCE_KEY_PRESSED, }; static void HandleNintendoCapcomLogos(void); static void HandleTitlescreen(void); static void UpdateSwordBgAffineData(void); static void ExitTitlescreen(void); static void HandleJapaneseTitlescreenAnimationIntro(void); static void HandleTitlescreenAnimationIntro(void); static u32 GetAdvanceState(void); static void UpdateLightRays(void); static void UpdatePressStartIcon(void); static void (*const sIntroSequenceHandlers[])(void) = { HandleNintendoCapcomLogos, HandleTitlescreen, ExitTitlescreen, }; static const u16 sLightRaysAlphaBlends[] = { BLDALPHA_BLEND(9, 9), BLDALPHA_BLEND(8, 10), BLDALPHA_BLEND(7, 11), BLDALPHA_BLEND(6, 12), BLDALPHA_BLEND(5, 13), BLDALPHA_BLEND(6, 12), BLDALPHA_BLEND(7, 11), BLDALPHA_BLEND(8, 10), }; static u32 AdvanceIntroSequence(u32 transition) { gUnk_02032EC0.transitionType = transition; gUnk_03001000.funcIndex = 2; _DmaZero(&gIntroState, sizeof(gIntroState)); DoFade(7, 8); } void HandleIntroScreen(void) { sub_080AD90C(); switch (gUnk_03001000.funcIndex) { case 0: sub_08056418(); _DmaZero(&gUnk_02032EC0, 0x3b4); AdvanceIntroSequence(0); break; case 1: sIntroSequenceHandlers[gUnk_02032EC0.transitionType](); break; case 2: if (gFadeControl.active) { return; } sub_0801DA90(1); gUnk_03001000.funcIndex = 1; break; } sub_080AD918(); } static void HandleNintendoCapcomLogos(void) { u32 advance; u32 paletteGroup; advance = GetAdvanceState(); if (gIntroState.state == 0) { sub_0801DA90(1); gIntroState.state = 1; gIntroState.timer = 120; LoadGfxGroup(16); LoadGfxGroup(1); if (((struct_02000000 *)0x2000000)->gameLanguage == 0) { paletteGroup = 1; } else { paletteGroup = 2; } LoadPaletteGroup(paletteGroup); gScreen.lcd.displayControl |= 0x400; gScreen.bg.bg2yOffset = 1; DoFade(6, 8); advance = ADVANCE_NONE; } else { if (advance == ADVANCE_TIMER_EXPIRED) { advance = ADVANCE_KEY_PRESSED; } } if (advance == ADVANCE_KEY_PRESSED) { gUnk_02000010.listenForKeyPresses = 1; AdvanceIntroSequence(1); } } extern u16 gUnk_03001010[5]; static void HandleTitlescreen(void) { int advance; u32 paletteGroup; gIntroState.counter++; switch (gIntroState.state) { case 0: gIntroState.state = 1; gIntroState.subState = 0; gIntroState.timer = 30; gIntroState.gameLanguage = 7; EraseAllEntities(); sub_0801CFA8(0); sub_080ADD30(); gUnk_02024490.unk0 = 1; LoadGfxGroup(2); if (((struct_02000000*)0x2000000)->gameLanguage == 0) { paletteGroup = 3; } else { paletteGroup = 4; } LoadPaletteGroup(paletteGroup); if (((struct_02000000*)0x2000000)->gameLanguage == 0) { gScreen.controls.layerFXControl = 0x844; gScreen.controls.alphaBlend = BLDALPHA_BLEND(9, 9); gScreen.bg.bg1xOffset = 0x1c09; gScreen.affine.bg2Control = 0x1d02; gScreen.affine.bg3Control = 0x1e03; gScreen.lcd.displayControl |= 0x1e00; gScreen.bg.bg2xOffset = 0xff60; } else { gScreen.controls.layerFXControl = 0x241; gScreen.controls.alphaBlend = BLDALPHA_BLEND(9, 9); gScreen.bg.bg0Control = 0x1d02; gScreen.bg.bg1xOffset = 0x1E03; gScreen.affine.bg2Control = 0x7C89; gScreen.lcd.displayControl |= 1; gScreen.lcd.displayControl |= 0x1300; gIntroState.swordBgScaleRatio = 0x10; UpdateSwordBgAffineData(); } sub_080A3210(); PlaySFX(3); //fanfare DoFade(6, 8); break; case 1: if (gFadeControl.active) { return; } if (((struct_02000000*)0x2000000)->gameLanguage == 0) { HandleJapaneseTitlescreenAnimationIntro(); } else { HandleTitlescreenAnimationIntro(); } break; case 2: if (--gIntroState.timer == 0) { gIntroState.timer = 3600; gIntroState.state++; } UpdatePressStartIcon(); break; default: advance = GetAdvanceState(); if (advance != ADVANCE_NONE) { if (advance == ADVANCE_KEY_PRESSED) { PlaySFX(0x6a); } else { advance = ADVANCE_NONE; } AdvanceIntroSequence(advance); PlaySFX(0x80080000); } UpdatePressStartIcon(); if ((gIntroState.timer & 0x20) == 0) { gUnk_03001010[4] = 0xe000; gUnk_03001010[1] = 0x84; sub_080ADA14(0x1ff,0); } } if (gIntroState.gameLanguage != ((struct_02000000*)0x2000000)->gameLanguage) { gIntroState.gameLanguage = ((struct_02000000*)0x2000000)->gameLanguage; LoadGfxGroup(3); } UpdateLightRays(); sub_0805E5C0(); sub_080AD9B0(); } static void UpdatePressStartIcon(void) { gUnk_03001010[2] = 0; gUnk_03001010[3] = 0; gUnk_03001010[4] = 0xE020; gUnk_03001010[0] = 120; gUnk_03001010[1] = 152; sub_080ADA14(511, 1); return; } static void UpdateSwordBgAffineData(void) { struct BgAffineSrcData aff; aff.texY = 0x8000; aff.texX = 0x8000; aff.scrX = 0x78; aff.scrY = 0x48; aff.alpha = 0; aff.sy = aff.sx = gIntroState.swordBgScaleRatio; BgAffineSet(&aff, (struct BgAffineDstData*)&gBgControls, 1); } static void HandleJapaneseTitlescreenAnimationIntro(void) { Entity *pEVar2; switch (gIntroState.subState) { case 0: if (!gFadeControl.active) { if ((gIntroState.counter & 1) == 0) { gScreen.bg.bg2xOffset++; } if (GetAdvanceState() == ADVANCE_KEY_PRESSED || gScreen.bg.bg2xOffset == 0) { gIntroState.subState++; gScreen.bg.bg2xOffset = 0; gScreen.bg.bg1xOffset = 0xc09; gFadeControl.field_0x4 = 0x40; DoFade(6, 0x10); PlaySFX(0xf8); } } break; case 1: if (!gFadeControl.active) { gFadeControl.field_0x4 = -1; gIntroState.subState++; gIntroState.timer = 90; pEVar2 = CreateObject(0xb4,0,0); if (pEVar2 != NULL) { pEVar2->x.HALF.HI = 0; pEVar2->y.HALF.HI = 0x48; } } break; case 2: if (GetAdvanceState() != ADVANCE_NONE) { gIntroState.state++; gIntroState.timer = 60; } } } static void HandleTitlescreenAnimationIntro(void) { switch (gIntroState.subState) { case 0: if (!gFadeControl.active) { gIntroState.subState = 1; gScreen.lcd.displayControl |= 0x400; PlaySFX(0xF6); } break; case 1: gIntroState.swordBgScaleRatio += 0x10; if (gIntroState.swordBgScaleRatio > 0x100) { gIntroState.swordBgScaleRatio = 0x100; gIntroState.timer = 40; gIntroState.subState++; DoFade(6, 16); } UpdateSwordBgAffineData(); break; case 2: if (--gIntroState.timer == 0) { gIntroState.timer = 300; gIntroState.subState++; CreateObject(0xBD, 0, 0); DoFade(6, 16); PlaySFX(0xF8); } break; default: if (!gFadeControl.active && GetAdvanceState() != ADVANCE_NONE) { gIntroState.state++; gIntroState.timer = 60; } break; } } static void ExitTitlescreen(void) { if (!gFadeControl.active) { InitScreen(SCREEN_CHOOSE_FILE); } } static u32 GetAdvanceState(void) { u32 newKeys; if (gFadeControl.active) { return ADVANCE_NONE; } if (!gUnk_02000010.listenForKeyPresses) { newKeys = 0; } else { newKeys = gUnk_03000FF0.newKeys & (A_BUTTON | START_BUTTON); } if (--gIntroState.timer == 0) { return ADVANCE_TIMER_EXPIRED; } if (newKeys) { return ADVANCE_KEY_PRESSED; } return ADVANCE_NONE; } static void UpdateLightRays(void) { // Periodically rotate the palette to give a shimmeriming effect. if ((gIntroState.counter & 0x7) == 0) { gIntroState.lightRaysPaletteGroup++; gIntroState.lightRaysPaletteGroup &= 0x3; LoadPaletteGroup(5 + gIntroState.lightRaysPaletteGroup); } // Periodiccally update the transparency of the light rays. if ((gIntroState.counter & 0x1F) == 0) { gIntroState.lightRaysAlphaBlendIndex = (gIntroState.lightRaysAlphaBlendIndex + 1) & 0x7; gScreen.controls.alphaBlend = sLightRaysAlphaBlends[gIntroState.lightRaysAlphaBlendIndex]; } }