pokeemerald/src/title_screen.c

818 lines
23 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_RIGHT_TILEOFFSET 64
#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)
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/unused.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");
// Used to blend "Emerald Version" as it passes over over the Pokémon banner.
// Also used by the intro to blend the Game Freak name/logo in and out as they appear and disappear
const u16 gTitleScreenAlphaBlend[64] =
{
BLDALPHA_BLEND(16, 0),
BLDALPHA_BLEND(16, 1),
BLDALPHA_BLEND(16, 2),
BLDALPHA_BLEND(16, 3),
BLDALPHA_BLEND(16, 4),
BLDALPHA_BLEND(16, 5),
BLDALPHA_BLEND(16, 6),
BLDALPHA_BLEND(16, 7),
BLDALPHA_BLEND(16, 8),
BLDALPHA_BLEND(16, 9),
BLDALPHA_BLEND(16, 10),
BLDALPHA_BLEND(16, 11),
BLDALPHA_BLEND(16, 12),
BLDALPHA_BLEND(16, 13),
BLDALPHA_BLEND(16, 14),
BLDALPHA_BLEND(16, 15),
BLDALPHA_BLEND(15, 16),
BLDALPHA_BLEND(14, 16),
BLDALPHA_BLEND(13, 16),
BLDALPHA_BLEND(12, 16),
BLDALPHA_BLEND(11, 16),
BLDALPHA_BLEND(10, 16),
BLDALPHA_BLEND(9, 16),
BLDALPHA_BLEND(8, 16),
BLDALPHA_BLEND(7, 16),
BLDALPHA_BLEND(6, 16),
BLDALPHA_BLEND(5, 16),
BLDALPHA_BLEND(4, 16),
BLDALPHA_BLEND(3, 16),
BLDALPHA_BLEND(2, 16),
BLDALPHA_BLEND(1, 16),
BLDALPHA_BLEND(0, 16),
[32 ... 63] = BLDALPHA_BLEND(0, 16)
};
static const struct OamData sVersionBannerLeftOamData =
{
.y = DISPLAY_HEIGHT,
.affineMode = ST_OAM_AFFINE_OFF,
.objMode = ST_OAM_OBJ_NORMAL,
.mosaic = FALSE,
.bpp = ST_OAM_8BPP,
.shape = SPRITE_SHAPE(64x32),
.x = 0,
.matrixNum = 0,
.size = SPRITE_SIZE(64x32),
.tileNum = 0,
.priority = 0,
.paletteNum = 0,
.affineParam = 0,
};
static const struct OamData sVersionBannerRightOamData =
{
.y = DISPLAY_HEIGHT,
.affineMode = ST_OAM_AFFINE_OFF,
.objMode = ST_OAM_OBJ_NORMAL,
.mosaic = FALSE,
.bpp = ST_OAM_8BPP,
.shape = SPRITE_SHAPE(64x32),
.x = 0,
.matrixNum = 0,
.size = SPRITE_SIZE(64x32),
.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[] =
{
{
.data = gTitleScreenEmeraldVersionGfx,
.size = 0x1000,
.tag = 1000
},
{},
};
static const struct OamData sOamData_CopyrightBanner =
{
.y = DISPLAY_HEIGHT,
.affineMode = ST_OAM_AFFINE_OFF,
.objMode = ST_OAM_OBJ_NORMAL,
.mosaic = FALSE,
.bpp = ST_OAM_4BPP,
.shape = SPRITE_SHAPE(32x8),
.x = 0,
.matrixNum = 0,
.size = SPRITE_SIZE(32x8),
.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[] =
{
{
.data = gTitleScreenPressStartGfx,
.size = 0x520,
.tag = 1001
},
{},
};
static const struct SpritePalette sSpritePalette_PressStart[] =
{
{
.data = gTitleScreenPressStartPal,
.tag = 1001
},
{},
};
static const struct OamData sPokemonLogoShineOamData =
{
.y = DISPLAY_HEIGHT,
.affineMode = ST_OAM_AFFINE_OFF,
.objMode = ST_OAM_OBJ_NORMAL,
.mosaic = FALSE,
.bpp = ST_OAM_4BPP,
.shape = SPRITE_SHAPE(64x64),
.x = 0,
.matrixNum = 0,
.size = SPRITE_SIZE(64x64),
.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[] =
{
{
.data = sTitleScreenLogoShineGfx,
.size = 0x800,
.tag = 1002
},
{},
};
// code
static void SpriteCB_VersionBannerLeft(struct Sprite *sprite)
{
if (gTasks[sprite->data[1]].data[1] != 0)
{
sprite->oam.objMode = ST_OAM_OBJ_NORMAL;
sprite->y = VERSION_BANNER_Y_GOAL;
}
else
{
if (sprite->y != VERSION_BANNER_Y_GOAL)
sprite->y++;
if (sprite->data[0] != 0)
sprite->data[0]--;
SetGpuReg(REG_OFFSET_BLDALPHA, gTitleScreenAlphaBlend[sprite->data[0]]);
}
}
static void SpriteCB_VersionBannerRight(struct Sprite *sprite)
{
if (gTasks[sprite->data[1]].data[1] != 0)
{
sprite->oam.objMode = ST_OAM_OBJ_NORMAL;
sprite->y = VERSION_BANNER_Y_GOAL;
}
else
{
if (sprite->y != VERSION_BANNER_Y_GOAL)
sprite->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] & 16)
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->x < DISPLAY_WIDTH + 32)
{
if (sprite->data[0]) // Flash background
{
u16 backgroundColor;
if (sprite->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->x == DISPLAY_WIDTH / 2 + 12
|| sprite->x == DISPLAY_WIDTH / 2 + 16
|| sprite->x == DISPLAY_WIDTH / 2 + 20
|| sprite->x == DISPLAY_WIDTH / 2 + 24)
gPlttBufferFaded[0] = RGB(24, 31, 12);
else
gPlttBufferFaded[0] = backgroundColor;
}
sprite->x += 4;
}
else
{
gPlttBufferFaded[0] = RGB_BLACK;
DestroySprite(sprite);
}
}
static void SpriteCB_PokemonLogoShine2(struct Sprite *sprite)
{
if (sprite->x < DISPLAY_WIDTH + 32)
sprite->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 = ST_OAM_OBJ_WINDOW;
gSprites[spriteId].data[0] = flashBg;
break;
case 1:
spriteId = CreateSprite(&sPokemonLogoShineSpriteTemplate, 0, 68, 0);
gSprites[spriteId].oam.objMode = ST_OAM_OBJ_WINDOW;
gSprites[spriteId].data[0] = flashBg;
gSprites[spriteId].invisible = TRUE;
spriteId = CreateSprite(&sPokemonLogoShineSpriteTemplate, 0, 68, 0);
gSprites[spriteId].callback = SpriteCB_PokemonLogoShine2;
gSprites[spriteId].oam.objMode = ST_OAM_OBJ_WINDOW;
spriteId = CreateSprite(&sPokemonLogoShineSpriteTemplate, -80, 68, 0);
gSprites[spriteId].callback = SpriteCB_PokemonLogoShine2;
gSprites[spriteId].oam.objMode = ST_OAM_OBJ_WINDOW;
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:
// bg2
LZ77UnCompVram(gTitleScreenPokemonLogoGfx, (void *)(BG_CHAR_ADDR(0)));
LZ77UnCompVram(gTitleScreenPokemonLogoTilemap, (void *)(BG_SCREEN_ADDR(9)));
LoadPalette(gTitleScreenBgPalettes, BG_PLTT_ID(0), 15 * PLTT_SIZE_4BPP);
// bg3
LZ77UnCompVram(sTitleScreenRayquazaGfx, (void *)(BG_CHAR_ADDR(2)));
LZ77UnCompVram(sTitleScreenRayquazaTilemap, (void *)(BG_SCREEN_ADDR(26)));
// bg1
LZ77UnCompVram(sTitleScreenCloudsGfx, (void *)(BG_CHAR_ADDR(3)));
LZ77UnCompVram(gTitleScreenCloudsTilemap, (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, OBJ_PLTT_ID(0), PLTT_SIZE_4BPP);
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(PALETTES_ALL, 1, 0x10, 0, RGB_WHITEALPHA);
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, WININ_WIN0_BG_ALL | WININ_WIN0_OBJ | WININ_WIN1_BG_ALL | WININ_WIN1_OBJ);
SetGpuReg(REG_OFFSET_WINOUT, WINOUT_WIN01_BG_ALL | WINOUT_WIN01_OBJ | WINOUT_WINOBJ_ALL);
SetGpuReg(REG_OFFSET_BLDCNT, BLDCNT_TGT1_BG2 | BLDCNT_EFFECT_LIGHTEN);
SetGpuReg(REG_OFFSET_BLDALPHA, 0);
SetGpuReg(REG_OFFSET_BLDY, 12);
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_TITLE);
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 (JOY_NEW(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 (JOY_NEW(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 ((JOY_NEW(A_BUTTON)) || (JOY_NEW(START_BUTTON)))
{
FadeOutBGM(4);
BeginNormalPaletteFade(PALETTES_ALL, 0, 0, 0x10, RGB_WHITEALPHA);
SetMainCallback2(CB2_GoToMainMenu);
}
else if (JOY_HELD(CLEAR_SAVE_BUTTON_COMBO) == CLEAR_SAVE_BUTTON_COMBO)
{
SetMainCallback2(CB2_GoToClearSaveDataScreen);
}
else if (JOY_HELD(RESET_RTC_BUTTON_COMBO) == RESET_RTC_BUTTON_COMBO
&& CanResetRTC() == TRUE)
{
FadeOutBGM(4);
BeginNormalPaletteFade(PALETTES_ALL, 0, 0, 0x10, RGB_BLACK);
SetMainCallback2(CB2_GoToResetRtcScreen);
}
else if (JOY_HELD(BERRY_UPDATE_BUTTON_COMBO) == BERRY_UPDATE_BUTTON_COMBO)
{
FadeOutBGM(4);
BeginNormalPaletteFade(PALETTES_ALL, 0, 0, 0x10, RGB_BLACK);
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(PALETTES_ALL, 0, 0, 0x10, RGB_WHITEALPHA);
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, BG_PLTT_ID(14) + 15, sizeof(color));
}
}