mirror of https://github.com/zeldaret/tmc.git
420 lines
12 KiB
C
420 lines
12 KiB
C
#include "audio.h"
|
|
#include "global.h"
|
|
#include "main.h"
|
|
#include "entity.h"
|
|
#include "utils.h"
|
|
#include "screen.h"
|
|
#include "object.h"
|
|
#include "textbox.h"
|
|
#include "structures.h"
|
|
#include "functions.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.lastState = transition;
|
|
gMain.funcIndex = 2;
|
|
MemClear(&gIntroState, sizeof(gIntroState));
|
|
DoFade(7, 8);
|
|
}
|
|
|
|
void HandleIntroScreen(void) {
|
|
FlushSprites();
|
|
switch (gMain.funcIndex) {
|
|
case 0:
|
|
MessageInitialize();
|
|
MemClear(&gUnk_02032EC0, sizeof(gUnk_02032EC0));
|
|
AdvanceIntroSequence(0);
|
|
break;
|
|
case 1:
|
|
sIntroSequenceHandlers[gUnk_02032EC0.lastState]();
|
|
break;
|
|
case 2:
|
|
if (gFadeControl.active) {
|
|
return;
|
|
}
|
|
DispReset(1);
|
|
gMain.funcIndex = 1;
|
|
break;
|
|
}
|
|
sub_080AD918();
|
|
}
|
|
|
|
static void HandleNintendoCapcomLogos(void) {
|
|
u32 advance;
|
|
u32 paletteGroup;
|
|
|
|
advance = GetAdvanceState();
|
|
if (gIntroState.state == 0) {
|
|
DispReset(1);
|
|
gIntroState.state = 1;
|
|
gIntroState.timer = 120;
|
|
LoadGfxGroup(16);
|
|
LoadGfxGroup(1);
|
|
if (gSaveHeader->gameLanguage == 0) {
|
|
paletteGroup = 1;
|
|
} else {
|
|
paletteGroup = 2;
|
|
}
|
|
LoadPaletteGroup(paletteGroup);
|
|
gScreen.lcd.displayControl |= DISPCNT_BG2_ON;
|
|
gScreen.bg1.updated = 1;
|
|
DoFade(6, 8);
|
|
advance = ADVANCE_NONE;
|
|
#if defined(DEMO_USA)
|
|
if (gUnk_02000010.listenForKeyPresses == 0) {
|
|
if ((gInput.heldKeys & 0x204) == 0x204) { // TODO
|
|
gUnk_02000010.field_0x7 = 1;
|
|
SoundReq(0x73);
|
|
} else {
|
|
if ((gInput.heldKeys & 0x104) == 0x104) { // TODO
|
|
gUnk_02000010.field_0x7 = 2;
|
|
SoundReq(0xcd);
|
|
} else {
|
|
gUnk_02000010.field_0x7 = 0;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
} else {
|
|
if (advance == ADVANCE_TIMER_EXPIRED) {
|
|
advance = ADVANCE_KEY_PRESSED;
|
|
}
|
|
}
|
|
|
|
if (advance == ADVANCE_KEY_PRESSED) {
|
|
gUnk_02000010.listenForKeyPresses = 1;
|
|
AdvanceIntroSequence(1);
|
|
}
|
|
}
|
|
|
|
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);
|
|
ResetPalettes();
|
|
gGFXSlots.unk0 = 1;
|
|
LoadGfxGroup(2);
|
|
if (gSaveHeader->gameLanguage == 0) {
|
|
paletteGroup = 3;
|
|
} else {
|
|
paletteGroup = 4;
|
|
}
|
|
LoadPaletteGroup(paletteGroup);
|
|
if (gSaveHeader->gameLanguage == 0) {
|
|
// Blend first and second layer
|
|
gScreen.controls.layerFXControl = BLDCNT_TGT1_BG2 | BLDCNT_TGT2_BG3 | BLDCNT_EFFECT_BLEND;
|
|
gScreen.controls.alphaBlend = BLDALPHA_BLEND(9, 9);
|
|
gScreen.bg1.control = BGCNT_SCREENBASE(28) | BGCNT_PRIORITY(1) | BGCNT_CHARBASE(2);
|
|
gScreen.bg2.control = BGCNT_SCREENBASE(29) | BGCNT_PRIORITY(2);
|
|
gScreen.bg3.control = BGCNT_SCREENBASE(30) | BGCNT_PRIORITY(3);
|
|
gScreen.lcd.displayControl |= DISPCNT_BG1_ON | DISPCNT_BG2_ON | DISPCNT_BG3_ON | DISPCNT_OBJ_ON;
|
|
gScreen.bg1.yOffset = -160;
|
|
} else {
|
|
gScreen.controls.layerFXControl = BLDCNT_TGT1_BG0 | BLDCNT_TGT2_BG1 | BLDCNT_EFFECT_BLEND;
|
|
gScreen.controls.alphaBlend = BLDALPHA_BLEND(9, 9);
|
|
gScreen.bg0.control = BGCNT_SCREENBASE(29) | BGCNT_PRIORITY(2);
|
|
gScreen.bg1.control = BGCNT_SCREENBASE(30) | BGCNT_PRIORITY(3);
|
|
gScreen.bg2.control = BGCNT_SCREENBASE(28) | BGCNT_PRIORITY(1) | BGCNT_CHARBASE(2) | BGCNT_256COLOR |
|
|
BGCNT_WRAP | BGCNT_TXT512x256;
|
|
gScreen.lcd.displayControl |= DISPCNT_MODE_1;
|
|
gScreen.lcd.displayControl |= DISPCNT_BG0_ON | DISPCNT_BG1_ON | DISPCNT_OBJ_ON;
|
|
gIntroState.swordBgScaleRatio = 0x10;
|
|
UpdateSwordBgAffineData();
|
|
}
|
|
InitSoundPlayingInfo();
|
|
SoundReq(BGM_TITLE_SCREEN);
|
|
DoFade(6, 8);
|
|
break;
|
|
case 1:
|
|
if (gFadeControl.active) {
|
|
return;
|
|
}
|
|
if (gSaveHeader->gameLanguage == 0) {
|
|
HandleJapaneseTitlescreenAnimationIntro();
|
|
} else {
|
|
HandleTitlescreenAnimationIntro();
|
|
}
|
|
break;
|
|
case 2:
|
|
#if defined(JP) || defined(DEMO_JP) || defined(EU)
|
|
if (GetAdvanceState()) {
|
|
#else
|
|
if (--gIntroState.timer == 0) {
|
|
#endif
|
|
gIntroState.timer = 3600;
|
|
gIntroState.state++;
|
|
}
|
|
#if defined(USA) || defined(DEMO_USA)
|
|
UpdatePressStartIcon();
|
|
#endif
|
|
break;
|
|
default:
|
|
advance = GetAdvanceState();
|
|
if (advance != ADVANCE_NONE) {
|
|
if (advance == ADVANCE_KEY_PRESSED) {
|
|
SoundReq(SFX_TEXTBOX_SELECT);
|
|
} else {
|
|
advance = ADVANCE_NONE;
|
|
}
|
|
AdvanceIntroSequence(advance);
|
|
SoundReq(SONG_VOL_FADE_OUT);
|
|
}
|
|
#if defined(JP) || defined(DEMO_JP) || defined(DEMO_JP)
|
|
gOamCmd._4 = 0;
|
|
gOamCmd._6 = 0;
|
|
gOamCmd._8 = 0xE020;
|
|
gOamCmd.x = 120;
|
|
gOamCmd.y = 152;
|
|
sub_080ADA14(511, 1);
|
|
#elif defined(EU)
|
|
gOamCmd._4 = 0;
|
|
gOamCmd._6 = 0;
|
|
gOamCmd._8 = 0xE020;
|
|
gOamCmd.x = 120;
|
|
gOamCmd.y = 152;
|
|
sub_080ADA14(510, 1);
|
|
#else
|
|
UpdatePressStartIcon();
|
|
#endif
|
|
if ((gIntroState.timer & 0x20) == 0) {
|
|
gOamCmd._8 = 0xe000;
|
|
gOamCmd.y = 0x84;
|
|
#ifdef EU
|
|
sub_080ADA14(0x1fe, 0);
|
|
#else
|
|
sub_080ADA14(0x1ff, 0);
|
|
#endif
|
|
}
|
|
}
|
|
if (gIntroState.gameLanguage != gSaveHeader->gameLanguage) {
|
|
gIntroState.gameLanguage = gSaveHeader->gameLanguage;
|
|
LoadGfxGroup(3);
|
|
}
|
|
UpdateLightRays();
|
|
UpdateEntities();
|
|
sub_080AD9B0();
|
|
}
|
|
|
|
#if defined(USA) || defined(DEMO_USA)
|
|
static void UpdatePressStartIcon(void) {
|
|
gOamCmd._4 = 0;
|
|
gOamCmd._6 = 0;
|
|
gOamCmd._8 = 0xE020;
|
|
gOamCmd.x = 120;
|
|
gOamCmd.y = 152;
|
|
sub_080ADA14(511, 1);
|
|
}
|
|
#endif
|
|
|
|
static void UpdateSwordBgAffineData(void) {
|
|
struct BgAffineSrcData aff;
|
|
aff.texY = 0x8000;
|
|
aff.texX = 0x8000;
|
|
aff.scrX = DISPLAY_WIDTH / 2;
|
|
aff.scrY = DISPLAY_HEIGHT / 2 - 8;
|
|
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.bg1.yOffset++;
|
|
}
|
|
|
|
if (GetAdvanceState() == ADVANCE_KEY_PRESSED || gScreen.bg1.yOffset == 0) {
|
|
gIntroState.subState++;
|
|
gScreen.bg1.yOffset = 0;
|
|
gScreen.bg1.control = BGCNT_SCREENBASE(12) | BGCNT_PRIORITY(1) | BGCNT_CHARBASE(2);
|
|
gFadeControl.mask = 0x00000040;
|
|
DoFade(6, 0x10);
|
|
SoundReq(SFX_F8);
|
|
}
|
|
}
|
|
break;
|
|
case 1:
|
|
if (!gFadeControl.active) {
|
|
gFadeControl.mask = 0xFFFFFFFF;
|
|
gIntroState.subState++;
|
|
#if defined(JP) || defined(EU) || defined(DEMO_JP)
|
|
gIntroState.timer = 120;
|
|
#else
|
|
gIntroState.timer = 90;
|
|
#endif
|
|
pEVar2 = CreateObject(OBJECT_B4, 0, 0);
|
|
if (pEVar2 != NULL) {
|
|
pEVar2->x.HALF.HI = 0;
|
|
pEVar2->y.HALF.HI = DISPLAY_HEIGHT / 2 - 8;
|
|
}
|
|
}
|
|
break;
|
|
case 2:
|
|
if (GetAdvanceState() != ADVANCE_NONE) {
|
|
gIntroState.state++;
|
|
#if defined(JP) || defined(EU) || defined(DEMO_JP)
|
|
gIntroState.timer = 30;
|
|
#else
|
|
gIntroState.timer = 60;
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
static void HandleTitlescreenAnimationIntro(void) {
|
|
switch (gIntroState.subState) {
|
|
case 0:
|
|
if (!gFadeControl.active) {
|
|
gIntroState.subState = 1;
|
|
gScreen.lcd.displayControl |= DISPCNT_BG2_ON;
|
|
SoundReq(SFX_EVAPORATE);
|
|
}
|
|
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) {
|
|
#if defined(JP) || defined(EU) || defined(DEMO_JP)
|
|
gIntroState.timer = 360;
|
|
#else
|
|
gIntroState.timer = 300;
|
|
#endif
|
|
gIntroState.subState++;
|
|
CreateObject(OBJECT_BD, 0, 0);
|
|
DoFade(6, 16);
|
|
SoundReq(SFX_F8);
|
|
}
|
|
break;
|
|
default:
|
|
if (!gFadeControl.active && GetAdvanceState() != ADVANCE_NONE) {
|
|
gIntroState.state++;
|
|
#if defined(JP) || defined(EU) || defined(DEMO_JP)
|
|
gIntroState.timer = 30;
|
|
#else
|
|
gIntroState.timer = 60;
|
|
#endif
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
#ifdef DEMO_JP
|
|
extern u8 gUnk_02002A40;
|
|
#endif
|
|
|
|
static void ExitTitlescreen(void) {
|
|
if (!gFadeControl.active) {
|
|
#ifdef DEMO_JP
|
|
MemCopy(&sLightRaysAlphaBlends[8], &gUnk_02002A40, 0x4B4);
|
|
InitScreen(SCREEN_GAMEPLAY);
|
|
#else
|
|
InitScreen(SCREEN_CHOOSE_FILE);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
static u32 GetAdvanceState(void) {
|
|
u32 newKeys;
|
|
|
|
if (gFadeControl.active) {
|
|
return ADVANCE_NONE;
|
|
}
|
|
|
|
if (!gUnk_02000010.listenForKeyPresses) {
|
|
newKeys = 0;
|
|
} else {
|
|
newKeys = gInput.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 shimmering effect.
|
|
if ((gIntroState.counter & 0x7) == 0) {
|
|
gIntroState.lightRaysPaletteGroup++;
|
|
gIntroState.lightRaysPaletteGroup &= 0x3;
|
|
LoadPaletteGroup(5 + gIntroState.lightRaysPaletteGroup);
|
|
}
|
|
|
|
// Periodically update the transparency of the light rays.
|
|
if ((gIntroState.counter & 0x1F) == 0) {
|
|
gIntroState.lightRaysAlphaBlendIndex = (gIntroState.lightRaysAlphaBlendIndex + 1) & 0x7;
|
|
gScreen.controls.alphaBlend = sLightRaysAlphaBlends[gIntroState.lightRaysAlphaBlendIndex];
|
|
}
|
|
}
|