pokeemerald/src/title_screen.c
2019-03-16 12:25:02 -05:00

791 lines
22 KiB
C

#include "global.h"
#include "battle.h"
#include "title_screen.h"
#include "sprite.h"
#include "gba/m4a_internal.h"
#include "clear_save_data_menu.h"
#include "decompress.h"
#include "event_data.h"
#include "intro.h"
#include "m4a.h"
#include "main.h"
#include "main_menu.h"
#include "palette.h"
#include "reset_rtc_screen.h"
#include "berry_fix_program.h"
#include "sound.h"
#include "sprite.h"
#include "task.h"
#include "scanline_effect.h"
#include "gpu_regs.h"
#include "trig.h"
#include "graphics.h"
#include "constants/rgb.h"
#include "constants/songs.h"
#define VERSION_BANNER_SHAPE 1
#define VERSION_BANNER_RIGHT_TILEOFFSET 64
#define VERSION_BANNER_BYTES 0x1000
#define VERSION_BANNER_LEFT_X 98
#define VERSION_BANNER_RIGHT_X 162
#define VERSION_BANNER_Y 2
#define VERSION_BANNER_Y_GOAL 66
#define START_BANNER_X 128
#define CLEAR_SAVE_BUTTON_COMBO (B_BUTTON | SELECT_BUTTON | DPAD_UP)
#define RESET_RTC_BUTTON_COMBO (B_BUTTON | SELECT_BUTTON | DPAD_LEFT)
#define BERRY_UPDATE_BUTTON_COMBO (B_BUTTON | SELECT_BUTTON)
#define A_B_START_SELECT (A_BUTTON | B_BUTTON | START_BUTTON | SELECT_BUTTON)
extern struct MusicPlayerInfo gMPlayInfo_BGM;
// this file's functions
static void MainCB2(void);
static void Task_TitleScreenPhase1(u8);
static void Task_TitleScreenPhase2(u8);
static void Task_TitleScreenPhase3(u8);
static void CB2_GoToMainMenu(void);
static void CB2_GoToClearSaveDataScreen(void);
static void CB2_GoToResetRtcScreen(void);
static void CB2_GoToBerryFixScreen(void);
static void CB2_GoToCopyrightScreen(void);
static void UpdateLegendaryMarkingColor(u8);
static void SpriteCB_VersionBannerLeft(struct Sprite *sprite);
static void SpriteCB_VersionBannerRight(struct Sprite *sprite);
static void SpriteCB_PressStartCopyrightBanner(struct Sprite *sprite);
static void SpriteCB_PokemonLogoShine(struct Sprite *sprite);
// const rom data
static const u16 sUnusedUnknownPal[] = INCBIN_U16("graphics/title_screen/unk_853EF78.gbapal");
static const u32 sTitleScreenRayquazaGfx[] = INCBIN_U32("graphics/title_screen/rayquaza.4bpp.lz");
static const u32 sTitleScreenRayquazaTilemap[] = INCBIN_U32("graphics/title_screen/rayquaza.bin.lz");
static const u32 sTitleScreenLogoShineGfx[] = INCBIN_U32("graphics/title_screen/logo_shine.4bpp.lz");
static const u32 sTitleScreenCloudsGfx[] = INCBIN_U32("graphics/title_screen/clouds.4bpp.lz");
// This is BLDALPHA data. It's equivalent to:
//
// BLDALPHA_BLEND(0, 16)
// BLDALPHA_BLEND(1, 16)
// ...
// BLDALPHA_BLEND(14, 16)
// BLDALPHA_BLEND(15, 16)
// BLDALPHA_BLEND(16, 15)
// BLDALPHA_BLEND(16, 14)
// ...
// BLDALPHA_BLEND(16, 1)
// BLDALPHA_BLEND(16, 0)
// BLDALPHA_BLEND(16, 0)
// BLDALPHA_BLEND(16, 0)
// ... (repeated until array has 32 entries)
const u16 gIntroWaterDropAlphaBlend[] =
{
0x0010, 0x0110, 0x0210, 0x0310, 0x0410, 0x0510, 0x0610, 0x0710,
0x0810, 0x0910, 0x0a10, 0x0b10, 0x0c10, 0x0d10, 0x0e10, 0x0f10,
0x100f, 0x100e, 0x100d, 0x100c, 0x100b, 0x100a, 0x1009, 0x1008,
0x1007, 0x1006, 0x1005, 0x1004, 0x1003, 0x1002, 0x1001, 0x1000,
0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
};
static const struct OamData sVersionBannerLeftOamData =
{
.y = 160,
.affineMode = 0,
.objMode = 0,
.mosaic = 0,
.bpp = 1,
.shape = VERSION_BANNER_SHAPE,
.x = 0,
.matrixNum = 0,
.size = 3,
.tileNum = 0,
.priority = 0,
.paletteNum = 0,
.affineParam = 0,
};
static const struct OamData sVersionBannerRightOamData =
{
.y = 160,
.affineMode = 0,
.objMode = 0,
.mosaic = 0,
.bpp = 1,
.shape = VERSION_BANNER_SHAPE,
.x = 0,
.matrixNum = 0,
.size = 3,
.tileNum = 0,
.priority = 0,
.paletteNum = 0,
.affineParam = 0,
};
static const union AnimCmd sVersionBannerLeftAnimSequence[] =
{
ANIMCMD_FRAME(0, 30),
ANIMCMD_END,
};
static const union AnimCmd sVersionBannerRightAnimSequence[] =
{
ANIMCMD_FRAME(VERSION_BANNER_RIGHT_TILEOFFSET, 30),
ANIMCMD_END,
};
static const union AnimCmd *const sVersionBannerLeftAnimTable[] =
{
sVersionBannerLeftAnimSequence,
};
static const union AnimCmd *const sVersionBannerRightAnimTable[] =
{
sVersionBannerRightAnimSequence,
};
static const struct SpriteTemplate sVersionBannerLeftSpriteTemplate =
{
.tileTag = 1000,
.paletteTag = 1000,
.oam = &sVersionBannerLeftOamData,
.anims = sVersionBannerLeftAnimTable,
.images = NULL,
.affineAnims = gDummySpriteAffineAnimTable,
.callback = SpriteCB_VersionBannerLeft,
};
static const struct SpriteTemplate sVersionBannerRightSpriteTemplate =
{
.tileTag = 1000,
.paletteTag = 1000,
.oam = &sVersionBannerRightOamData,
.anims = sVersionBannerRightAnimTable,
.images = NULL,
.affineAnims = gDummySpriteAffineAnimTable,
.callback = SpriteCB_VersionBannerRight,
};
static const struct CompressedSpriteSheet sSpriteSheet_EmeraldVersion[] =
{
{gTitleScreenEmeraldVersionGfx, VERSION_BANNER_BYTES, 1000},
{NULL},
};
static const struct OamData sOamData_CopyrightBanner =
{
.y = 160,
.affineMode = 0,
.objMode = 0,
.mosaic = 0,
.bpp = 0,
.shape = 1,
.x = 0,
.matrixNum = 0,
.size = 1,
.tileNum = 0,
.priority = 0,
.paletteNum = 0,
.affineParam = 0,
};
static const union AnimCmd sCopyrightBannerAnim0[] =
{
ANIMCMD_FRAME(1, 4),
ANIMCMD_END,
};
static const union AnimCmd sCopyrightBannerAnim1[] =
{
ANIMCMD_FRAME(5, 4),
ANIMCMD_END,
};
static const union AnimCmd sCopyrightBannerAnim2[] =
{
ANIMCMD_FRAME(9, 4),
ANIMCMD_END,
};
static const union AnimCmd sCopyrightBannerAnim3[] =
{
ANIMCMD_FRAME(13, 4),
ANIMCMD_END,
};
static const union AnimCmd sCopyrightBannerAnim4[] =
{
ANIMCMD_FRAME(17, 4),
ANIMCMD_END,
};
static const union AnimCmd sCopyrightBannerAnim5[] =
{
ANIMCMD_FRAME(21, 4),
ANIMCMD_END,
};
static const union AnimCmd sCopyrightBannerAnim6[] =
{
ANIMCMD_FRAME(25, 4),
ANIMCMD_END,
};
static const union AnimCmd sCopyrightBannerAnim7[] =
{
ANIMCMD_FRAME(29, 4),
ANIMCMD_END,
};
static const union AnimCmd sCopyrightBannerAnim8[] =
{
ANIMCMD_FRAME(33, 4),
ANIMCMD_END,
};
static const union AnimCmd sCopyrightBannerAnim9[] =
{
ANIMCMD_FRAME(37, 4),
ANIMCMD_END,
};
static const union AnimCmd *const sStartCopyrightBannerAnimTable[] =
{
sCopyrightBannerAnim0,
sCopyrightBannerAnim1,
sCopyrightBannerAnim2,
sCopyrightBannerAnim3,
sCopyrightBannerAnim4,
sCopyrightBannerAnim5,
sCopyrightBannerAnim6,
sCopyrightBannerAnim7,
sCopyrightBannerAnim8,
sCopyrightBannerAnim9,
};
static const struct SpriteTemplate sStartCopyrightBannerSpriteTemplate =
{
.tileTag = 1001,
.paletteTag = 1001,
.oam = &sOamData_CopyrightBanner,
.anims = sStartCopyrightBannerAnimTable,
.images = NULL,
.affineAnims = gDummySpriteAffineAnimTable,
.callback = SpriteCB_PressStartCopyrightBanner,
};
static const struct CompressedSpriteSheet sSpriteSheet_PressStart[] =
{
{gTitleScreenPressStartGfx, 0x520, 1001},
{NULL},
};
static const struct SpritePalette sSpritePalette_PressStart[] =
{
{gTitleScreenPressStartPal, 1001},
{NULL},
};
static const struct OamData sPokemonLogoShineOamData =
{
.y = 160,
.affineMode = 0,
.objMode = 0,
.mosaic = 0,
.bpp = 0,
.shape = 0,
.x = 0,
.matrixNum = 0,
.size = 3,
.tileNum = 0,
.priority = 0,
.paletteNum = 0,
.affineParam = 0,
};
static const union AnimCmd sPokemonLogoShineAnimSequence[] =
{
ANIMCMD_FRAME(0, 4),
ANIMCMD_END,
};
static const union AnimCmd *const sPokemonLogoShineAnimTable[] =
{
sPokemonLogoShineAnimSequence,
};
static const struct SpriteTemplate sPokemonLogoShineSpriteTemplate =
{
.tileTag = 1002,
.paletteTag = 1001,
.oam = &sPokemonLogoShineOamData,
.anims = sPokemonLogoShineAnimTable,
.images = NULL,
.affineAnims = gDummySpriteAffineAnimTable,
.callback = SpriteCB_PokemonLogoShine,
};
static const struct CompressedSpriteSheet sPokemonLogoShineSpriteSheet[] =
{
{sTitleScreenLogoShineGfx, 0x800, 1002},
{NULL},
};
// code
static void SpriteCB_VersionBannerLeft(struct Sprite *sprite)
{
if (gTasks[sprite->data[1]].data[1] != 0)
{
sprite->oam.objMode = 0;
sprite->pos1.y = VERSION_BANNER_Y_GOAL;
}
else
{
if (sprite->pos1.y != VERSION_BANNER_Y_GOAL)
sprite->pos1.y++;
if (sprite->data[0] != 0)
sprite->data[0]--;
SetGpuReg(REG_OFFSET_BLDALPHA, gIntroWaterDropAlphaBlend[sprite->data[0]]);
}
}
static void SpriteCB_VersionBannerRight(struct Sprite *sprite)
{
if (gTasks[sprite->data[1]].data[1] != 0)
{
sprite->oam.objMode = 0;
sprite->pos1.y = VERSION_BANNER_Y_GOAL;
}
else
{
if (sprite->pos1.y != VERSION_BANNER_Y_GOAL)
sprite->pos1.y++;
}
}
static void SpriteCB_PressStartCopyrightBanner(struct Sprite *sprite)
{
if (sprite->data[0] == 1)
{
sprite->data[1]++;
// Alternate between hidden and shown every 16th frame
if (sprite->data[1] & 0x10)
sprite->invisible = FALSE;
else
sprite->invisible = TRUE;
}
else
{
sprite->invisible = FALSE;
}
}
static void CreatePressStartBanner(s16 x, s16 y)
{
u8 i;
u8 spriteId;
x -= 64;
for (i = 0; i < 5; i++, x += 32)
{
spriteId = CreateSprite(&sStartCopyrightBannerSpriteTemplate, x, y, 0);
StartSpriteAnim(&gSprites[spriteId], i);
gSprites[spriteId].data[0] = 1;
}
}
static void CreateCopyrightBanner(s16 x, s16 y)
{
u8 i;
u8 spriteId;
x -= 64;
for (i = 0; i < 5; i++, x += 32)
{
spriteId = CreateSprite(&sStartCopyrightBannerSpriteTemplate, x, y, 0);
StartSpriteAnim(&gSprites[spriteId], i + 5);
}
}
static void SpriteCB_PokemonLogoShine(struct Sprite *sprite)
{
if (sprite->pos1.x < 272)
{
if (sprite->data[0]) // Flash background
{
u16 backgroundColor;
if (sprite->pos1.x < DISPLAY_WIDTH / 2)
{
// Brighten background color
if (sprite->data[1] < 31)
sprite->data[1]++;
if (sprite->data[1] < 31)
sprite->data[1]++;
}
else
{
// Darken background color
if (sprite->data[1] != 0)
sprite->data[1]--;
if (sprite->data[1] != 0)
sprite->data[1]--;
}
backgroundColor = _RGB(sprite->data[1], sprite->data[1], sprite->data[1]);
if (sprite->pos1.x == DISPLAY_WIDTH / 2 + 12
|| sprite->pos1.x == DISPLAY_WIDTH / 2 + 16
|| sprite->pos1.x == DISPLAY_WIDTH / 2 + 20
|| sprite->pos1.x == DISPLAY_WIDTH / 2 + 24)
gPlttBufferFaded[0] = RGB(24, 31, 12);
else
gPlttBufferFaded[0] = backgroundColor;
}
sprite->pos1.x += 4;
}
else
{
gPlttBufferFaded[0] = RGB_BLACK;
DestroySprite(sprite);
}
}
static void SpriteCB_PokemonLogoShine2(struct Sprite *sprite)
{
if (sprite->pos1.x < 272)
sprite->pos1.x += 8;
else
DestroySprite(sprite);
}
static void StartPokemonLogoShine(u8 flashBg)
{
u8 spriteId;
switch (flashBg)
{
case 0:
case 2:
spriteId = CreateSprite(&sPokemonLogoShineSpriteTemplate, 0, 68, 0);
gSprites[spriteId].oam.objMode = 2;
gSprites[spriteId].data[0] = flashBg;
break;
case 1:
spriteId = CreateSprite(&sPokemonLogoShineSpriteTemplate, 0, 68, 0);
gSprites[spriteId].oam.objMode = 2;
gSprites[spriteId].data[0] = flashBg;
gSprites[spriteId].invisible = TRUE;
spriteId = CreateSprite(&sPokemonLogoShineSpriteTemplate, 0, 68, 0);
gSprites[spriteId].callback = SpriteCB_PokemonLogoShine2;
gSprites[spriteId].oam.objMode = 2;
spriteId = CreateSprite(&sPokemonLogoShineSpriteTemplate, -80, 68, 0);
gSprites[spriteId].callback = SpriteCB_PokemonLogoShine2;
gSprites[spriteId].oam.objMode = 2;
break;
}
}
static void VBlankCB(void)
{
ScanlineEffect_InitHBlankDmaTransfer();
LoadOam();
ProcessSpriteCopyRequests();
TransferPlttBuffer();
SetGpuReg(REG_OFFSET_BG1VOFS, gBattle_BG1_Y);
}
#define tCounter data[0]
#define tSkipToNext data[1]
void CB2_InitTitleScreen(void)
{
switch (gMain.state)
{
default:
case 0:
SetVBlankCallback(NULL);
SetGpuReg(REG_OFFSET_BLDCNT, 0);
SetGpuReg(REG_OFFSET_BLDALPHA, 0);
SetGpuReg(REG_OFFSET_BLDY, 0);
*((u16 *)PLTT) = RGB_WHITE;
SetGpuReg(REG_OFFSET_DISPCNT, 0);
SetGpuReg(REG_OFFSET_BG2CNT, 0);
SetGpuReg(REG_OFFSET_BG1CNT, 0);
SetGpuReg(REG_OFFSET_BG0CNT, 0);
SetGpuReg(REG_OFFSET_BG2HOFS, 0);
SetGpuReg(REG_OFFSET_BG2VOFS, 0);
SetGpuReg(REG_OFFSET_BG1HOFS, 0);
SetGpuReg(REG_OFFSET_BG1VOFS, 0);
SetGpuReg(REG_OFFSET_BG0HOFS, 0);
SetGpuReg(REG_OFFSET_BG0VOFS, 0);
DmaFill16(3, 0, (void *)VRAM, VRAM_SIZE);
DmaFill32(3, 0, (void *)OAM, OAM_SIZE);
DmaFill16(3, 0, (void *)(PLTT + 2), PLTT_SIZE - 2);
ResetPaletteFade();
gMain.state = 1;
break;
case 1:
LZ77UnCompVram(gTitleScreenPokemonLogoGfx, (void *)VRAM);
LZ77UnCompVram(gUnknown_08DE0644, (void *)(BG_SCREEN_ADDR(9)));
LoadPalette(gTitleScreenBgPalettes, 0, 0x1E0);
LZ77UnCompVram(sTitleScreenRayquazaGfx, (void *)(BG_CHAR_ADDR(2)));
LZ77UnCompVram(sTitleScreenRayquazaTilemap, (void *)(BG_SCREEN_ADDR(26)));
LZ77UnCompVram(sTitleScreenCloudsGfx, (void *)(BG_CHAR_ADDR(3)));
LZ77UnCompVram(gUnknown_08DDE458, (void *)(BG_SCREEN_ADDR(27)));
ScanlineEffect_Stop();
ResetTasks();
ResetSpriteData();
FreeAllSpritePalettes();
gReservedSpritePaletteCount = 9;
LoadCompressedSpriteSheet(&sSpriteSheet_EmeraldVersion[0]);
LoadCompressedSpriteSheet(&sSpriteSheet_PressStart[0]);
LoadCompressedSpriteSheet(&sPokemonLogoShineSpriteSheet[0]);
LoadPalette(gTitleScreenEmeraldVersionPal, 0x100, 0x20);
LoadSpritePalette(&sSpritePalette_PressStart[0]);
gMain.state = 2;
break;
case 2:
{
u8 taskId = CreateTask(Task_TitleScreenPhase1, 0);
gTasks[taskId].tCounter = 256;
gTasks[taskId].tSkipToNext = FALSE;
gTasks[taskId].data[2] = -16;
gTasks[taskId].data[3] = -32;
gMain.state = 3;
break;
}
case 3:
BeginNormalPaletteFade(0xFFFFFFFF, 1, 0x10, 0, 0xFFFF);
SetVBlankCallback(VBlankCB);
gMain.state = 4;
break;
case 4:
PanFadeAndZoomScreen(0x78, 0x50, 0x100, 0);
SetGpuReg(REG_OFFSET_BG2X_L, -29 * 256);
SetGpuReg(REG_OFFSET_BG2X_H, -1);
SetGpuReg(REG_OFFSET_BG2Y_L, -32 * 256);
SetGpuReg(REG_OFFSET_BG2Y_H, -1);
SetGpuReg(REG_OFFSET_WIN0H, 0);
SetGpuReg(REG_OFFSET_WIN0V, 0);
SetGpuReg(REG_OFFSET_WIN1H, 0);
SetGpuReg(REG_OFFSET_WIN1V, 0);
SetGpuReg(REG_OFFSET_WININ, 0x1F1F);
SetGpuReg(REG_OFFSET_WINOUT, 0x3F1F);
SetGpuReg(REG_OFFSET_BLDCNT, BLDCNT_TGT1_BG2 | BLDCNT_EFFECT_LIGHTEN);
SetGpuReg(REG_OFFSET_BLDALPHA, 0);
SetGpuReg(REG_OFFSET_BLDY, 0xC);
SetGpuReg(REG_OFFSET_BG0CNT, BGCNT_PRIORITY(3) | BGCNT_CHARBASE(2) | BGCNT_SCREENBASE(26) | BGCNT_16COLOR | BGCNT_TXT256x256);
SetGpuReg(REG_OFFSET_BG1CNT, BGCNT_PRIORITY(2) | BGCNT_CHARBASE(3) | BGCNT_SCREENBASE(27) | BGCNT_16COLOR | BGCNT_TXT256x256);
SetGpuReg(REG_OFFSET_BG2CNT, BGCNT_PRIORITY(1) | BGCNT_CHARBASE(0) | BGCNT_SCREENBASE(9) | BGCNT_256COLOR | BGCNT_AFF256x256);
EnableInterrupts(INTR_FLAG_VBLANK);
SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_MODE_1
| DISPCNT_OBJ_1D_MAP
| DISPCNT_BG2_ON
| DISPCNT_OBJ_ON
| DISPCNT_WIN0_ON
| DISPCNT_OBJWIN_ON);
m4aSongNumStart(MUS_TITLE3);
gMain.state = 5;
break;
case 5:
if (!UpdatePaletteFade())
{
StartPokemonLogoShine(0);
ScanlineEffect_InitWave(0, DISPLAY_HEIGHT, 4, 4, 0, SCANLINE_EFFECT_REG_BG1HOFS, TRUE);
SetMainCallback2(MainCB2);
}
break;
}
}
static void MainCB2(void)
{
RunTasks();
AnimateSprites();
BuildOamBuffer();
UpdatePaletteFade();
}
// Shine the Pokemon logo two more times, and fade in the version banner
static void Task_TitleScreenPhase1(u8 taskId)
{
// Skip to next phase when A, B, Start, or Select is pressed
if ((gMain.newKeys & A_B_START_SELECT) || gTasks[taskId].data[1] != 0)
{
gTasks[taskId].tSkipToNext = TRUE;
gTasks[taskId].tCounter = 0;
}
if (gTasks[taskId].tCounter != 0)
{
u16 frameNum = gTasks[taskId].tCounter;
if (frameNum == 176)
StartPokemonLogoShine(1);
else if (frameNum == 64)
StartPokemonLogoShine(2);
gTasks[taskId].tCounter--;
}
else
{
u8 spriteId;
SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_MODE_1 | DISPCNT_OBJ_1D_MAP | DISPCNT_BG2_ON | DISPCNT_OBJ_ON);
SetGpuReg(REG_OFFSET_WININ, 0);
SetGpuReg(REG_OFFSET_WINOUT, 0);
SetGpuReg(REG_OFFSET_BLDCNT, BLDCNT_TGT1_OBJ | BLDCNT_EFFECT_BLEND | BLDCNT_TGT2_ALL);
SetGpuReg(REG_OFFSET_BLDALPHA, BLDALPHA_BLEND(16, 0));
SetGpuReg(REG_OFFSET_BLDY, 0);
// Create left side of version banner
spriteId = CreateSprite(&sVersionBannerLeftSpriteTemplate, VERSION_BANNER_LEFT_X, VERSION_BANNER_Y, 0);
gSprites[spriteId].data[0] = 64;
gSprites[spriteId].data[1] = taskId;
// Create right side of version banner
spriteId = CreateSprite(&sVersionBannerRightSpriteTemplate, VERSION_BANNER_RIGHT_X, VERSION_BANNER_Y, 0);
gSprites[spriteId].data[1] = taskId;
gTasks[taskId].tCounter = 144;
gTasks[taskId].func = Task_TitleScreenPhase2;
}
}
// Create "Press Start" and copyright banners, and slide Pokemon logo up
static void Task_TitleScreenPhase2(u8 taskId)
{
u32 yPos;
// Skip to next phase when A, B, Start, or Select is pressed
if ((gMain.newKeys & A_B_START_SELECT) || gTasks[taskId].tSkipToNext)
{
gTasks[taskId].tSkipToNext = TRUE;
gTasks[taskId].tCounter = 0;
}
if (gTasks[taskId].tCounter != 0)
{
gTasks[taskId].tCounter--;
}
else
{
gTasks[taskId].tSkipToNext = TRUE;
SetGpuReg(REG_OFFSET_BLDCNT, BLDCNT_TGT1_BG1 | BLDCNT_EFFECT_BLEND | BLDCNT_TGT2_BG0 | BLDCNT_TGT2_BD);
SetGpuReg(REG_OFFSET_BLDALPHA, BLDALPHA_BLEND(6, 15));
SetGpuReg(REG_OFFSET_BLDY, 0);
SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_MODE_1
| DISPCNT_OBJ_1D_MAP
| DISPCNT_BG0_ON
| DISPCNT_BG1_ON
| DISPCNT_BG2_ON
| DISPCNT_OBJ_ON);
CreatePressStartBanner(START_BANNER_X, 108);
CreateCopyrightBanner(START_BANNER_X, 148);
gTasks[taskId].data[4] = 0;
gTasks[taskId].func = Task_TitleScreenPhase3;
}
if (!(gTasks[taskId].tCounter & 3) && gTasks[taskId].data[2] != 0)
gTasks[taskId].data[2]++;
if (!(gTasks[taskId].tCounter & 1) && gTasks[taskId].data[3] != 0)
gTasks[taskId].data[3]++;
// Slide Pokemon logo up
yPos = gTasks[taskId].data[3] * 256;
SetGpuReg(REG_OFFSET_BG2Y_L, yPos);
SetGpuReg(REG_OFFSET_BG2Y_H, yPos / 0x10000);
gTasks[taskId].data[5] = 15;
gTasks[taskId].data[6] = 6;
}
// Show Rayquaza silhouette and process main title screen input
static void Task_TitleScreenPhase3(u8 taskId)
{
if ((gMain.newKeys & A_BUTTON) || (gMain.newKeys & START_BUTTON))
{
FadeOutBGM(4);
BeginNormalPaletteFade(0xFFFFFFFF, 0, 0, 0x10, 0xFFFF);
SetMainCallback2(CB2_GoToMainMenu);
}
else if ((gMain.heldKeys & CLEAR_SAVE_BUTTON_COMBO) == CLEAR_SAVE_BUTTON_COMBO)
{
SetMainCallback2(CB2_GoToClearSaveDataScreen);
}
else if ((gMain.heldKeys & RESET_RTC_BUTTON_COMBO) == RESET_RTC_BUTTON_COMBO
&& CanResetRTC() == TRUE)
{
FadeOutBGM(4);
BeginNormalPaletteFade(0xFFFFFFFF, 0, 0, 0x10, 0);
SetMainCallback2(CB2_GoToResetRtcScreen);
}
else if ((gMain.heldKeys & BERRY_UPDATE_BUTTON_COMBO) == BERRY_UPDATE_BUTTON_COMBO)
{
FadeOutBGM(4);
BeginNormalPaletteFade(0xFFFFFFFF, 0, 0, 0x10, 0);
SetMainCallback2(CB2_GoToBerryFixScreen);
}
else
{
SetGpuReg(REG_OFFSET_BG2Y_L, 0);
SetGpuReg(REG_OFFSET_BG2Y_H, 0);
gTasks[taskId].tCounter++;
if (gTasks[taskId].tCounter & 1)
{
gTasks[taskId].data[4]++;
gBattle_BG1_Y = gTasks[taskId].data[4] / 2;
gBattle_BG1_X = 0;
}
UpdateLegendaryMarkingColor(gTasks[taskId].tCounter);
if ((gMPlayInfo_BGM.status & 0xFFFF) == 0)
{
BeginNormalPaletteFade(0xFFFFFFFF, 0, 0, 0x10, 0xFFFF);
SetMainCallback2(CB2_GoToCopyrightScreen);
}
}
}
static void CB2_GoToMainMenu(void)
{
if (!UpdatePaletteFade())
SetMainCallback2(CB2_InitMainMenu);
}
static void CB2_GoToCopyrightScreen(void)
{
if (!UpdatePaletteFade())
SetMainCallback2(CB2_InitCopyrightScreenAfterTitleScreen);
}
static void CB2_GoToClearSaveDataScreen(void)
{
if (!UpdatePaletteFade())
SetMainCallback2(CB2_InitClearSaveDataScreen);
}
static void CB2_GoToResetRtcScreen(void)
{
if (!UpdatePaletteFade())
SetMainCallback2(CB2_InitResetRtcScreen);
}
static void CB2_GoToBerryFixScreen(void)
{
if (!UpdatePaletteFade())
{
m4aMPlayAllStop();
SetMainCallback2(CB2_InitBerryFixProgram);
}
}
static void UpdateLegendaryMarkingColor(u8 frameNum)
{
if ((frameNum % 4) == 0) // Change color every 4th frame
{
s32 intensity = Cos(frameNum, 128) + 128;
s32 r = 31 - ((intensity * 32 - intensity) / 256);
s32 g = 31 - (intensity * 22 / 256);
s32 b = 12;
u16 color = RGB(r, g, b);
LoadPalette(&color, 0xEF, sizeof(color));
}
}