pokefirered/src/pokemon_storage_system_graphics.c
2024-06-16 18:50:46 +02:00

1544 lines
49 KiB
C

#include "global.h"
#include "gflib.h"
#include "event_data.h"
#include "graphics.h"
#include "new_menu_helpers.h"
#include "pokemon_icon.h"
#include "pokemon_storage_system_internal.h"
#include "strings.h"
#include "task.h"
#include "trig.h"
static void SpriteCB_BoxMonIconScrollOut(struct Sprite *sprite);
static void SetBoxSpeciesAndPersonalities(u8 boxId);
static void MovePartySpriteToNextSlot(struct Sprite *sprite, u16 idx);
static void SpriteCB_MovePartySpriteToNextSlot(struct Sprite *sprite);
static void DestroyBoxMonIcon(struct Sprite *sprite);
static void SpriteCB_HeldMon(struct Sprite *sprite);
static void Task_InitBox(u8 taskId);
static s8 DetermineBoxScrollDirection(u8 boxId);
static void LoadWallpaperGfx(u8 wallpaperId, s8 direction);
static bool32 WaitForWallpaperGfxLoad(void);
static void DrawWallpaper(void *unused, const void *tilemap, s8 direction, u8 offset);
static void TrimOldWallpaper(void *buffer);
static void InitBoxTitle(u8 wallpaperId);
static void CreateIncomingBoxTitle(u8 wallpaperId, s8 direction);
static void SpriteCB_IncomingBoxTitle(struct Sprite *sprite);
static void SpriteCB_OutgoingBoxTitle(struct Sprite *sprite);
static s16 GetBoxTitleBaseX(const u8 *boxName);
static void CycleBoxTitleSprites(void);
static void CycleBoxTitleColor(void);
static void CreateBoxScrollArrows(void);
static void StartBoxScrollArrowsSlide(s8 direction);
static void StopBoxScrollArrowsSlide(void);
static void SpriteCB_BoxScrollArrow(struct Sprite *sprite);
static const struct OamData sOamData_MonIcon;
static const struct SpriteTemplate sSpriteTemplate_MonIcon = {
.tileTag = GFXTAG_MON_ICON,
.paletteTag = PALTAG_MON_ICON_0,
.oam = &sOamData_MonIcon,
.anims = gDummySpriteAnimTable,
.images = NULL,
.affineAnims = gDummySpriteAffineAnimTable,
.callback = SpriteCallbackDummy
};
static const struct OamData sOamData_MonIcon = {
.y = 0,
.affineMode = ST_OAM_AFFINE_OFF,
.objMode = ST_OAM_OBJ_NORMAL,
.mosaic = FALSE,
.bpp = ST_OAM_4BPP,
.shape = SPRITE_SHAPE(32x32),
.x = 0,
.matrixNum = 0,
.size = SPRITE_SIZE(32x32),
.tileNum = 0x000,
.priority = 0,
.paletteNum = 0
};
static const union AffineAnimCmd sAffineAnim_ReleaseMon_Release[] = {
AFFINEANIMCMD_FRAME(-2, -2, 0, 120),
AFFINEANIMCMD_END
};
static const union AffineAnimCmd sAffineAnim_ReleaseMon_ComeBack[] = {
AFFINEANIMCMD_FRAME(16, 16, 0, 0),
AFFINEANIMCMD_FRAME(16, 16, 0, 15),
AFFINEANIMCMD_END
};
static const union AffineAnimCmd *const sAffineAnims_ReleaseMon[] = {
[RELEASE_ANIM_RELEASE] = sAffineAnim_ReleaseMon_Release,
[RELEASE_ANIM_COME_BACK] = sAffineAnim_ReleaseMon_ComeBack,
};
static const u16 sWallpaperPalettes_Forest[] = INCBIN_U16("graphics/pokemon_storage/wallpapers/forest/tiles.gbapal");
static const u32 sWallpaperTiles_Forest[] = INCBIN_U32("graphics/pokemon_storage/wallpapers/forest/tiles.4bpp.lz");
static const u32 sWallpaperTilemap_Forest[] = INCBIN_U32("graphics/pokemon_storage/wallpapers/forest/tilemap.bin.lz");
static const u16 sWallpaperPalettes_City[] = INCBIN_U16("graphics/pokemon_storage/wallpapers/city/tiles.gbapal");
static const u32 sWallpaperTiles_City[] = INCBIN_U32("graphics/pokemon_storage/wallpapers/city/tiles.4bpp.lz");
static const u32 sWallpaperTilemap_City[] = INCBIN_U32("graphics/pokemon_storage/wallpapers/city/tilemap.bin.lz");
static const u16 sWallpaperPalettes_Desert[] = INCBIN_U16("graphics/pokemon_storage/wallpapers/desert/tiles.gbapal");
static const u32 sWallpaperTiles_Desert[] = INCBIN_U32("graphics/pokemon_storage/wallpapers/desert/tiles.4bpp.lz");
static const u32 sWallpaperTilemap_Desert[] = INCBIN_U32("graphics/pokemon_storage/wallpapers/desert/tilemap.bin.lz");
static const u16 sWallpaperPalettes_Savanna[] = INCBIN_U16("graphics/pokemon_storage/wallpapers/savanna/tiles.gbapal");
static const u32 sWallpaperTiles_Savanna[] = INCBIN_U32("graphics/pokemon_storage/wallpapers/savanna/tiles.4bpp.lz");
static const u32 sWallpaperTilemap_Savanna[] = INCBIN_U32("graphics/pokemon_storage/wallpapers/savanna/tilemap.bin.lz");
static const u16 sWallpaperPalettes_Crag[] = INCBIN_U16("graphics/pokemon_storage/wallpapers/crag/tiles.gbapal");
static const u32 sWallpaperTiles_Crag[] = INCBIN_U32("graphics/pokemon_storage/wallpapers/crag/tiles.4bpp.lz");
static const u32 sWallpaperTilemap_Crag[] = INCBIN_U32("graphics/pokemon_storage/wallpapers/crag/tilemap.bin.lz");
static const u16 sWallpaperPalettes_Volcano[] = INCBIN_U16("graphics/pokemon_storage/wallpapers/volcano/tiles.gbapal");
static const u32 sWallpaperTiles_Volcano[] = INCBIN_U32("graphics/pokemon_storage/wallpapers/volcano/tiles.4bpp.lz");
static const u8 sUnusedSpace1[4] = {};
static const u32 sWallpaperTilemap_Volcano[] = INCBIN_U32("graphics/pokemon_storage/wallpapers/volcano/tilemap.bin.lz");
static const u16 sWallpaperPalettes_Snow[] = INCBIN_U16("graphics/pokemon_storage/wallpapers/snow/tiles.gbapal");
static const u32 sWallpaperTiles_Snow[] = INCBIN_U32("graphics/pokemon_storage/wallpapers/snow/tiles.4bpp.lz");
static const u32 sWallpaperTilemap_Snow[] = INCBIN_U32("graphics/pokemon_storage/wallpapers/snow/tilemap.bin.lz");
static const u16 sWallpaperPalettes_Cave[] = INCBIN_U16("graphics/pokemon_storage/wallpapers/cave/tiles.gbapal");
static const u32 sWallpaperTiles_Cave[] = INCBIN_U32("graphics/pokemon_storage/wallpapers/cave/tiles.4bpp.lz");
static const u32 sWallpaperTilemap_Cave[] = INCBIN_U32("graphics/pokemon_storage/wallpapers/cave/tilemap.bin.lz");
static const u16 sWallpaperPalettes_Beach[] = INCBIN_U16("graphics/pokemon_storage/wallpapers/beach/tiles.gbapal");
static const u32 sWallpaperTiles_Beach[] = INCBIN_U32("graphics/pokemon_storage/wallpapers/beach/tiles.4bpp.lz");
static const u32 sWallpaperTilemap_Beach[] = INCBIN_U32("graphics/pokemon_storage/wallpapers/beach/tilemap.bin.lz");
static const u16 sWallpaperPalettes_Seafloor[] = INCBIN_U16("graphics/pokemon_storage/wallpapers/seafloor/tiles.gbapal");
static const u32 sWallpaperTiles_Seafloor[] = INCBIN_U32("graphics/pokemon_storage/wallpapers/seafloor/tiles.4bpp.lz");
static const u32 sWallpaperTilemap_Seafloor[] = INCBIN_U32("graphics/pokemon_storage/wallpapers/seafloor/tilemap.bin.lz");
static const u16 sWallpaperPalettes_River[] = INCBIN_U16("graphics/pokemon_storage/wallpapers/river/tiles.gbapal");
static const u32 sWallpaperTiles_River[] = INCBIN_U32("graphics/pokemon_storage/wallpapers/river/tiles.4bpp.lz");
static const u32 sWallpaperTilemap_River[] = INCBIN_U32("graphics/pokemon_storage/wallpapers/river/tilemap.bin.lz");
static const u16 sWallpaperPalettes_Sky[] = INCBIN_U16("graphics/pokemon_storage/wallpapers/sky/tiles.gbapal");
static const u32 sWallpaperTiles_Sky[] = INCBIN_U32("graphics/pokemon_storage/wallpapers/sky/tiles.4bpp.lz");
static const u32 sWallpaperTilemap_Sky[] = INCBIN_U32("graphics/pokemon_storage/wallpapers/sky/tilemap.bin.lz");
static const u16 sWallpaperPalettes_Stars[] = INCBIN_U16("graphics/pokemon_storage/wallpapers/stars/tiles.gbapal");
static const u8 sUnusedSpace2[32] = {};
static const u32 sWallpaperTiles_Stars[] = INCBIN_U32("graphics/pokemon_storage/wallpapers/stars/tiles.4bpp.lz");
static const u32 sWallpaperTilemap_Stars[] = INCBIN_U32("graphics/pokemon_storage/wallpapers/stars/tilemap.bin.lz");
static const u16 sWallpaperPalettes_Pokecenter[] = INCBIN_U16("graphics/pokemon_storage/wallpapers/pokecenter/tiles.gbapal");
static const u32 sWallpaperTiles_Pokecenter[] = INCBIN_U32("graphics/pokemon_storage/wallpapers/pokecenter/tiles.4bpp.lz");
static const u32 sWallpaperTilemap_Pokecenter[] = INCBIN_U32("graphics/pokemon_storage/wallpapers/pokecenter/tilemap.bin.lz");
static const u16 sWallpaperPalettes_Tiles[] = INCBIN_U16("graphics/pokemon_storage/wallpapers/tiles/tiles.gbapal");
static const u32 sWallpaperTiles_Tiles[] = INCBIN_U32("graphics/pokemon_storage/wallpapers/tiles/tiles.4bpp.lz");
static const u32 sWallpaperTilemap_Tiles[] = INCBIN_U32("graphics/pokemon_storage/wallpapers/tiles/tilemap.bin.lz");
static const u16 sWallpaperPalettes_Simple[] = INCBIN_U16("graphics/pokemon_storage/wallpapers/simple/tiles.gbapal");
static const u32 sWallpaperTiles_Simple[] = INCBIN_U32("graphics/pokemon_storage/wallpapers/simple/tiles.4bpp.lz");
static const u32 sWallpaperTilemap_Simple[] = INCBIN_U32("graphics/pokemon_storage/wallpapers/simple/tilemap.bin.lz");
// Shadow color, text color
static const u16 sBoxTitleColors[][2] = {
{RGB( 7, 7, 7), RGB_WHITE},
{RGB( 7, 7, 7), RGB_WHITE},
{RGB( 7, 7, 7), RGB_WHITE},
{RGB( 7, 7, 7), RGB_WHITE},
{RGB( 7, 7, 7), RGB_WHITE},
{RGB( 7, 7, 7), RGB_WHITE},
{RGB( 7, 7, 7), RGB_WHITE},
{RGB( 7, 7, 7), RGB_WHITE},
{RGB( 7, 7, 7), RGB_WHITE},
{RGB( 7, 7, 7), RGB_WHITE},
{RGB( 7, 7, 7), RGB_WHITE},
{RGB( 7, 7, 7), RGB_WHITE},
{RGB( 7, 7, 7), RGB_WHITE},
{RGB( 7, 7, 7), RGB_WHITE},
{RGB( 7, 7, 7), RGB_WHITE},
{RGB( 7, 7, 7), RGB_WHITE}
};
static const struct Wallpaper sWallpapers[] = {
{sWallpaperTiles_Forest, sWallpaperTilemap_Forest, sWallpaperPalettes_Forest },
{sWallpaperTiles_City, sWallpaperTilemap_City, sWallpaperPalettes_City },
{sWallpaperTiles_Desert, sWallpaperTilemap_Desert, sWallpaperPalettes_Desert },
{sWallpaperTiles_Savanna, sWallpaperTilemap_Savanna, sWallpaperPalettes_Savanna },
{sWallpaperTiles_Crag, sWallpaperTilemap_Crag, sWallpaperPalettes_Crag },
{sWallpaperTiles_Volcano, sWallpaperTilemap_Volcano, sWallpaperPalettes_Volcano },
{sWallpaperTiles_Snow, sWallpaperTilemap_Snow, sWallpaperPalettes_Snow },
{sWallpaperTiles_Cave, sWallpaperTilemap_Cave, sWallpaperPalettes_Cave },
{sWallpaperTiles_Beach, sWallpaperTilemap_Beach, sWallpaperPalettes_Beach },
{sWallpaperTiles_Seafloor, sWallpaperTilemap_Seafloor, sWallpaperPalettes_Seafloor },
{sWallpaperTiles_River, sWallpaperTilemap_River, sWallpaperPalettes_River },
{sWallpaperTiles_Sky, sWallpaperTilemap_Sky, sWallpaperPalettes_Sky },
{sWallpaperTiles_Stars, sWallpaperTilemap_Stars, sWallpaperPalettes_Stars },
{sWallpaperTiles_Pokecenter, sWallpaperTilemap_Pokecenter, sWallpaperPalettes_Pokecenter},
{sWallpaperTiles_Tiles, sWallpaperTilemap_Tiles, sWallpaperPalettes_Tiles },
{sWallpaperTiles_Simple, sWallpaperTilemap_Simple, sWallpaperPalettes_Simple },
};
static const u16 sBoxScrollArrow_Gfx[] = INCBIN_U16("graphics/pokemon_storage/box_scroll_arrow.4bpp");
static const u16 sUnusedColor = RGB(26, 29, 8);
static const struct SpriteSheet sSpriteSheet_BoxScrollArrow = {
sBoxScrollArrow_Gfx, 0x0080, GFXTAG_BOX_SCROLL_ARROW
};
static const struct OamData sOamData_BoxTitle = {
.y = 0,
.affineMode = ST_OAM_AFFINE_OFF,
.objMode = ST_OAM_OBJ_NORMAL,
.mosaic = FALSE,
.bpp = ST_OAM_4BPP,
.shape = SPRITE_SHAPE(32x16),
.x = 0,
.matrixNum = 0,
.size = SPRITE_SIZE(32x16),
.tileNum = 0,
.priority = 2,
.paletteNum = 0
};
static const union AnimCmd sAnim_BoxTitle_Left[] = {
ANIMCMD_FRAME(0, 5),
ANIMCMD_END
};
static const union AnimCmd sAnim_BoxTitle_Right[] = {
ANIMCMD_FRAME(8, 5),
ANIMCMD_END
};
static const union AnimCmd *const sAnims_BoxTitle[] = {
sAnim_BoxTitle_Left,
sAnim_BoxTitle_Right,
};
static const struct SpriteTemplate sSpriteTemplate_BoxTitle = {
.tileTag = GFXTAG_BOX_TITLE,
.paletteTag = PALTAG_BOX_TITLE,
.oam = &sOamData_BoxTitle,
.anims = sAnims_BoxTitle,
.images = NULL,
.affineAnims = gDummySpriteAffineAnimTable,
.callback = SpriteCallbackDummy
};
static const struct OamData sOamData_BoxScrollArrow = {
.y = 0,
.affineMode = ST_OAM_AFFINE_OFF,
.objMode = ST_OAM_OBJ_NORMAL,
.mosaic = FALSE,
.bpp = ST_OAM_4BPP,
.shape = SPRITE_SHAPE(8x16),
.x = 0,
.matrixNum = 0,
.size = SPRITE_SIZE(8x16),
.tileNum = 0x000,
.priority = 2,
.paletteNum = 0
};
static const union AnimCmd sAnim_BoxScrollArrow_Left[] = {
ANIMCMD_FRAME(0, 5),
ANIMCMD_END
};
static const union AnimCmd sAnim_BoxScrollArrow_Right[] = {
ANIMCMD_FRAME(2, 5),
ANIMCMD_END
};
static const union AnimCmd *const sAnims_BoxScrollArrow[] = {
sAnim_BoxScrollArrow_Left,
sAnim_BoxScrollArrow_Right,
};
static const struct SpriteTemplate sSpriteTemplate_BoxScrollArrow = {
.tileTag = GFXTAG_BOX_SCROLL_ARROW,
.paletteTag = PALTAG_MISC_2,
.oam = &sOamData_BoxScrollArrow,
.anims = sAnims_BoxScrollArrow,
.images = NULL,
.affineAnims = gDummySpriteAffineAnimTable,
.callback = SpriteCB_BoxScrollArrow,
};
void InitMonIconFields(void)
{
u16 i;
LoadMonIconPalettes();
for (i = 0; i < MAX_MON_ICONS; i++)
gStorage->numIconsPerSpecies[i] = 0;
for (i = 0; i < MAX_MON_ICONS; i++)
gStorage->iconSpeciesList[i] = SPECIES_NONE;
for (i = 0; i < PARTY_SIZE; i++)
gStorage->partySprites[i] = NULL;
for (i = 0; i < IN_BOX_COUNT; i++)
gStorage->boxMonsSprites[i] = NULL;
gStorage->movingMonSprite = NULL;
gStorage->unusedField1 = 0;
}
static u8 GetMonIconPriorityByCursorArea(void)
{
return (IsCursorInBox() ? 2 : 1);
}
void CreateMovingMonIcon(void)
{
u32 personality = GetMonData(&gStorage->movingMon, MON_DATA_PERSONALITY);
u16 species = GetMonData(&gStorage->movingMon, MON_DATA_SPECIES_OR_EGG);
u8 priority = GetMonIconPriorityByCursorArea();
gStorage->movingMonSprite = CreateMonIconSprite(species, personality, 0, 0, priority, 7);
gStorage->movingMonSprite->callback = SpriteCB_HeldMon;
}
static void InitBoxMonSprites(u8 boxId)
{
u8 boxPosition;
u16 i, j, count;
u16 species;
u32 personality;
count = 0;
boxPosition = 0;
for (i = 0; i < IN_BOX_ROWS; i++)
{
for (j = 0; j < IN_BOX_COLUMNS; j++)
{
species = GetBoxMonDataAt(boxId, boxPosition, MON_DATA_SPECIES_OR_EGG);
if (species != SPECIES_NONE)
{
personality = GetBoxMonDataAt(boxId, boxPosition, MON_DATA_PERSONALITY);
gStorage->boxMonsSprites[count] = CreateMonIconSprite(species, personality, 8 * (3 * j) + 100, 8 * (3 * i) + 44, 2, 19 - j);
}
else
gStorage->boxMonsSprites[count] = NULL;
boxPosition++;
count++;
}
}
if (gStorage->boxOption == OPTION_MOVE_ITEMS)
{
for (boxPosition = 0; boxPosition < IN_BOX_COUNT; boxPosition++)
{
if (GetBoxMonDataAt(boxId, boxPosition, MON_DATA_HELD_ITEM) == 0)
gStorage->boxMonsSprites[boxPosition]->oam.objMode = ST_OAM_OBJ_BLEND;
}
}
}
void CreateBoxMonIconAtPos(u8 boxPosition)
{
u16 species = GetCurrentBoxMonData(boxPosition, MON_DATA_SPECIES_OR_EGG);
if (species != SPECIES_NONE)
{
s16 x = 8 * (3 * (boxPosition % IN_BOX_COLUMNS)) + 100;
s16 y = 8 * (3 * (boxPosition / IN_BOX_COLUMNS)) + 44;
u32 personality = GetCurrentBoxMonData(boxPosition, MON_DATA_PERSONALITY);
gStorage->boxMonsSprites[boxPosition] = CreateMonIconSprite(species, personality, x, y, 2, 19 - (boxPosition % IN_BOX_COLUMNS));
if (gStorage->boxOption == OPTION_MOVE_ITEMS)
gStorage->boxMonsSprites[boxPosition]->oam.objMode = ST_OAM_OBJ_BLEND;
}
}
#define sDistance data[1]
#define sSpeed data[2]
#define sDestX data[3]
#define sDelay data[4]
#define sPosX data[5]
static void StartBoxMonIconsScrollOut(s16 speed)
{
u16 i;
for (i = 0; i < IN_BOX_COUNT; i++)
{
if (gStorage->boxMonsSprites[i] != NULL)
{
gStorage->boxMonsSprites[i]->sSpeed = speed;
gStorage->boxMonsSprites[i]->sDelay = 1;
gStorage->boxMonsSprites[i]->callback = SpriteCB_BoxMonIconScrollOut;
}
}
}
static void SpriteCB_BoxMonIconScrollIn(struct Sprite *sprite)
{
if (sprite->sDistance != 0)
{
sprite->sDistance--;
sprite->x += sprite->sSpeed;
}
else
{
gStorage->iconScrollNumIncoming--;
sprite->x = sprite->sDestX;
sprite->callback = SpriteCallbackDummy;
}
}
static void SpriteCB_BoxMonIconScrollOut(struct Sprite *sprite)
{
if (sprite->sDelay != 0)
sprite->sDelay--;
else
{
sprite->x += sprite->sSpeed;
sprite->sPosX = sprite->x + sprite->x2;
// Check if mon icon has scrolled out of view of the box area
if (sprite->sPosX <= 68 || sprite->sPosX >= 252)
sprite->callback = SpriteCallbackDummy;
}
}
static void DestroyAllIconsInColumn(u8 column)
{
u16 row;
u8 boxPosition = column;
for (row = 0; row < IN_BOX_ROWS; row++)
{
if (gStorage->boxMonsSprites[boxPosition] != NULL)
{
DestroyBoxMonIcon(gStorage->boxMonsSprites[boxPosition]);
gStorage->boxMonsSprites[boxPosition] = NULL;
}
boxPosition += IN_BOX_COLUMNS;
}
}
static u8 CreateBoxMonIconsInColumn(u8 column, u16 distance, s16 speed)
{
s32 i;
u16 y = 44;
s16 xDest = 8 * (3 * column) + 100;
u16 x = xDest - ((distance + 1) * speed);
u8 subpriority = 19 - column;
u8 count = 0;
u8 boxPosition = column;
if (gStorage->boxOption != OPTION_MOVE_ITEMS)
{
for (i = 0; i < IN_BOX_ROWS; i++)
{
if (gStorage->boxSpecies[boxPosition] != SPECIES_NONE)
{
gStorage->boxMonsSprites[boxPosition] = CreateMonIconSprite(gStorage->boxSpecies[boxPosition],
gStorage->boxPersonalities[boxPosition],
x, y, 2, subpriority);
if (gStorage->boxMonsSprites[boxPosition] != NULL)
{
gStorage->boxMonsSprites[boxPosition]->sDistance = distance;
gStorage->boxMonsSprites[boxPosition]->sSpeed = speed;
gStorage->boxMonsSprites[boxPosition]->sDestX = xDest;
gStorage->boxMonsSprites[boxPosition]->callback = SpriteCB_BoxMonIconScrollIn;
count++;
}
}
boxPosition += IN_BOX_COLUMNS;
y += 24;
}
}
else
{
for (i = 0; i < IN_BOX_ROWS; i++)
{
if (gStorage->boxSpecies[boxPosition] != SPECIES_NONE)
{
gStorage->boxMonsSprites[boxPosition] = CreateMonIconSprite(gStorage->boxSpecies[boxPosition],
gStorage->boxPersonalities[boxPosition],
x, y, 2, subpriority);
if (gStorage->boxMonsSprites[boxPosition] != NULL)
{
gStorage->boxMonsSprites[boxPosition]->sDistance = distance;
gStorage->boxMonsSprites[boxPosition]->sSpeed = speed;
gStorage->boxMonsSprites[boxPosition]->sDestX = xDest;
gStorage->boxMonsSprites[boxPosition]->callback = SpriteCB_BoxMonIconScrollIn;
if (GetBoxMonDataAt(gStorage->incomingBoxId, boxPosition, MON_DATA_HELD_ITEM) == 0)
gStorage->boxMonsSprites[boxPosition]->oam.objMode = ST_OAM_OBJ_BLEND;
count++;
}
}
boxPosition += IN_BOX_COLUMNS;
y += 24;
}
}
return count;
}
#undef sDistance
#undef sSpeed
#undef sDestX
#undef sDelay
#undef sPosX
static void InitBoxMonIconScroll(u8 boxId, s8 direction)
{
gStorage->iconScrollState = 0;
gStorage->iconScrollToBoxId = boxId;
gStorage->iconScrollDirection = direction;
gStorage->iconScrollDistance = 32;
gStorage->iconScrollSpeed = -(6 * direction);
gStorage->iconScrollNumIncoming = 0;
SetBoxSpeciesAndPersonalities(boxId);
if (direction > 0)
gStorage->iconScrollCurColumn = 0;
else
gStorage->iconScrollCurColumn = IN_BOX_COLUMNS - 1;
gStorage->iconScrollPos = (24 * gStorage->iconScrollCurColumn) + 100;
StartBoxMonIconsScrollOut(gStorage->iconScrollSpeed);
}
static bool8 UpdateBoxMonIconScroll(void)
{
if (gStorage->iconScrollDistance != 0)
gStorage->iconScrollDistance--;
switch (gStorage->iconScrollState)
{
case 0:
gStorage->iconScrollPos += gStorage->iconScrollSpeed;
if (gStorage->iconScrollPos <= 64 || gStorage->iconScrollPos >= 252)
{
// A column of icons has gone offscreen, destroy them
DestroyAllIconsInColumn(gStorage->iconScrollCurColumn);
gStorage->iconScrollPos += gStorage->iconScrollDirection * 24;
gStorage->iconScrollState++;
}
break;
case 1:
// Create the new incoming column of icons
gStorage->iconScrollPos += gStorage->iconScrollSpeed;
gStorage->iconScrollNumIncoming += CreateBoxMonIconsInColumn(gStorage->iconScrollCurColumn, gStorage->iconScrollDistance, gStorage->iconScrollSpeed);
if ((gStorage->iconScrollDirection > 0 && gStorage->iconScrollCurColumn == IN_BOX_COLUMNS - 1)
|| (gStorage->iconScrollDirection < 0 && gStorage->iconScrollCurColumn == 0))
{
// Scroll has reached final column
gStorage->iconScrollState++;
}
else
{
// Continue scrolling
gStorage->iconScrollCurColumn += gStorage->iconScrollDirection;
gStorage->iconScrollState = 0;
}
break;
case 2:
// Wait to make sure all icons have arrived
if (gStorage->iconScrollNumIncoming == 0)
{
gStorage->iconScrollDistance++;
return FALSE;
}
break;
default:
return FALSE;
}
return TRUE;
}
static void SetBoxSpeciesAndPersonalities(u8 boxId)
{
s32 i, j, boxPosition;
boxPosition = 0;
for (i = 0; i < IN_BOX_ROWS; i++)
{
for (j = 0; j < IN_BOX_COLUMNS; j++)
{
gStorage->boxSpecies[boxPosition] = GetBoxMonDataAt(boxId, boxPosition, MON_DATA_SPECIES_OR_EGG);
if (gStorage->boxSpecies[boxPosition] != SPECIES_NONE)
gStorage->boxPersonalities[boxPosition] = GetBoxMonDataAt(boxId, boxPosition, MON_DATA_PERSONALITY);
boxPosition++;
}
}
gStorage->incomingBoxId = boxId;
}
void DestroyBoxMonIconAtPosition(u8 boxPosition)
{
if (gStorage->boxMonsSprites[boxPosition] != NULL)
{
DestroyBoxMonIcon(gStorage->boxMonsSprites[boxPosition]);
gStorage->boxMonsSprites[boxPosition] = NULL;
}
}
void SetBoxMonIconObjMode(u8 boxPosition, u8 objMode)
{
if (gStorage->boxMonsSprites[boxPosition] != NULL)
{
gStorage->boxMonsSprites[boxPosition]->oam.objMode = objMode;
}
}
void CreatePartyMonsSprites(bool8 visible)
{
u16 i, count;
u16 species = GetMonData(&gPlayerParty[0], MON_DATA_SPECIES_OR_EGG);
u32 personality = GetMonData(&gPlayerParty[0], MON_DATA_PERSONALITY);
gStorage->partySprites[0] = CreateMonIconSprite(species, personality, 104, 64, 1, 12);
count = 1;
for (i = 1; i < PARTY_SIZE; i++)
{
species = GetMonData(&gPlayerParty[i], MON_DATA_SPECIES_OR_EGG);
if (species != SPECIES_NONE)
{
personality = GetMonData(&gPlayerParty[i], MON_DATA_PERSONALITY);
gStorage->partySprites[i] = CreateMonIconSprite(species, personality, 152, 8 * (3 * (i - 1)) + 16, 1, 12);
count++;
}
else
gStorage->partySprites[i] = NULL;
}
if (!visible)
{
for (i = 0; i < count; i++)
{
gStorage->partySprites[i]->y -= 160;
gStorage->partySprites[i]->invisible = TRUE;
}
}
if (gStorage->boxOption == OPTION_MOVE_ITEMS)
{
for (i = 0; i < PARTY_SIZE; i++)
{
if (gStorage->partySprites[i] != NULL && GetMonData(&gPlayerParty[i], MON_DATA_HELD_ITEM) == 0)
gStorage->partySprites[i]->oam.objMode = ST_OAM_OBJ_BLEND;
}
}
}
void CompactPartySprites(void)
{
u16 i, targetPartyId;
gStorage->numPartySpritesToCompact = 0;
for (i = 0, targetPartyId = 0; i < PARTY_SIZE; i++)
{
if (gStorage->partySprites[i] != NULL)
{
if (i != targetPartyId)
{
MovePartySpriteToNextSlot(gStorage->partySprites[i], targetPartyId);
gStorage->partySprites[i] = NULL;
gStorage->numPartySpritesToCompact++;
}
targetPartyId++;
}
}
}
u8 GetNumPartySpritesCompacting(void)
{
return gStorage->numPartySpritesToCompact;
}
#define sPartyId data[1]
#define sMonX data[2]
#define sMonY data[3]
#define sSpeedX data[4]
#define sSpeedY data[5]
#define sMoveSteps data[6]
static void MovePartySpriteToNextSlot(struct Sprite *sprite, u16 partyId)
{
s16 x, y;
sprite->sPartyId = partyId;
if (partyId == 0)
x = 104, y = 64;
else
x = 152, y = 8 * (3 * (partyId - 1)) + 16;
sprite->sMonX = (u16)(sprite->x) * 8;
sprite->sMonY = (u16)(sprite->y) * 8;
sprite->sSpeedX = ((x * 8) - sprite->sMonX) / 8;
sprite->sSpeedY = ((y * 8) - sprite->sMonY) / 8;
sprite->sMoveSteps = 8;
sprite->callback = SpriteCB_MovePartySpriteToNextSlot;
}
static void SpriteCB_MovePartySpriteToNextSlot(struct Sprite *sprite)
{
if (sprite->sMoveSteps != 0)
{
s16 x = sprite->sMonX += sprite->sSpeedX;
s16 y = sprite->sMonY += sprite->sSpeedY;
sprite->x = x / 8u;
sprite->y = y / 8u;
sprite->sMoveSteps--;
}
else
{
if (sprite->sPartyId == 0)
{
sprite->x = 104;
sprite->y = 64;
}
else
{
sprite->x = 152;
sprite->y = 8 * (3 * (sprite->sPartyId - 1)) + 16;
}
sprite->callback = SpriteCallbackDummy;
gStorage->partySprites[sprite->sPartyId] = sprite;
gStorage->numPartySpritesToCompact--;
}
}
#undef sPartyId
#undef sMonX
#undef sMonY
#undef sSpeedX
#undef sSpeedY
#undef sMoveSteps
void DestroyMovingMonIcon(void)
{
if (gStorage->movingMonSprite != NULL)
{
DestroyBoxMonIcon(gStorage->movingMonSprite);
gStorage->movingMonSprite = NULL;
}
}
void MovePartySprites(s16 yDelta)
{
u16 i, posY;
for (i = 0; i < PARTY_SIZE; i++)
{
if (gStorage->partySprites[i] != NULL)
{
gStorage->partySprites[i]->y += yDelta;
posY = gStorage->partySprites[i]->y + gStorage->partySprites[i]->y2 + gStorage->partySprites[i]->centerToCornerVecY;
posY += 16;
if (posY > 192)
gStorage->partySprites[i]->invisible = TRUE;
else
gStorage->partySprites[i]->invisible = FALSE;
}
}
}
void DestroyPartyMonIcon(u8 partyId)
{
if (gStorage->partySprites[partyId] != NULL)
{
DestroyBoxMonIcon(gStorage->partySprites[partyId]);
gStorage->partySprites[partyId] = NULL;
}
}
void DestroyAllPartyMonIcons(void)
{
u16 i;
for (i = 0; i < PARTY_SIZE; i++)
{
if (gStorage->partySprites[i] != NULL)
{
DestroyBoxMonIcon(gStorage->partySprites[i]);
gStorage->partySprites[i] = NULL;
}
}
}
void SetPartyMonIconObjMode(u8 partyId, u8 objMode)
{
if (gStorage->partySprites[partyId] != NULL)
gStorage->partySprites[partyId]->oam.objMode = objMode;
}
void SetMovingMonSprite(u8 mode, u8 id)
{
if (mode == MODE_PARTY)
{
gStorage->movingMonSprite = gStorage->partySprites[id];
gStorage->partySprites[id] = NULL;
}
else if (mode == MODE_BOX)
{
gStorage->movingMonSprite = gStorage->boxMonsSprites[id];
gStorage->boxMonsSprites[id] = NULL;
}
else
return;
gStorage->movingMonSprite->callback = SpriteCB_HeldMon;
gStorage->movingMonSprite->oam.priority = GetMonIconPriorityByCursorArea();
gStorage->movingMonSprite->subpriority = 7;
}
void SetPlacedMonSprite(u8 boxId, u8 position)
{
if (boxId == TOTAL_BOXES_COUNT) // party mon
{
gStorage->partySprites[position] = gStorage->movingMonSprite;
gStorage->partySprites[position]->oam.priority = 1;
gStorage->partySprites[position]->subpriority = 12;
}
else
{
gStorage->boxMonsSprites[position] = gStorage->movingMonSprite;
gStorage->boxMonsSprites[position]->oam.priority = 2;
gStorage->boxMonsSprites[position]->subpriority = 19 - (position % IN_BOX_COLUMNS);
}
gStorage->movingMonSprite->callback = SpriteCallbackDummy;
gStorage->movingMonSprite = NULL;
}
void SetShiftMonSpritePtr(u8 boxId, u8 position)
{
if (boxId == TOTAL_BOXES_COUNT) // party mon
gStorage->shiftMonSpritePtr = &gStorage->partySprites[position];
else
gStorage->shiftMonSpritePtr = &gStorage->boxMonsSprites[position];
gStorage->movingMonSprite->callback = SpriteCallbackDummy;
gStorage->shiftTimer = 0;
}
bool8 ShiftMons(void)
{
if (gStorage->shiftTimer == 16)
return FALSE;
gStorage->shiftTimer++;
if (gStorage->shiftTimer & 1)
{
(*gStorage->shiftMonSpritePtr)->y--;
gStorage->movingMonSprite->y++;
}
(*gStorage->shiftMonSpritePtr)->x2 = gSineTable[gStorage->shiftTimer * 8] / 16;
gStorage->movingMonSprite->x2 = -(gSineTable[gStorage->shiftTimer * 8] / 16);
if (gStorage->shiftTimer == 8)
{
gStorage->movingMonSprite->oam.priority = (*gStorage->shiftMonSpritePtr)->oam.priority;
gStorage->movingMonSprite->subpriority = (*gStorage->shiftMonSpritePtr)->subpriority;
(*gStorage->shiftMonSpritePtr)->oam.priority = GetMonIconPriorityByCursorArea();
(*gStorage->shiftMonSpritePtr)->subpriority = 7;
}
if (gStorage->shiftTimer == 16)
{
struct Sprite *sprite = gStorage->movingMonSprite;
gStorage->movingMonSprite = (*gStorage->shiftMonSpritePtr);
*gStorage->shiftMonSpritePtr = sprite;
gStorage->movingMonSprite->callback = SpriteCB_HeldMon;
(*gStorage->shiftMonSpritePtr)->callback = SpriteCallbackDummy;
}
return TRUE;
}
void DoReleaseMonAnim(u8 mode, u8 position)
{
switch (mode)
{
case MODE_PARTY:
gStorage->releaseMonSpritePtr = &gStorage->partySprites[position];
break;
case MODE_BOX:
gStorage->releaseMonSpritePtr = &gStorage->boxMonsSprites[position];
break;
case MODE_MOVE:
gStorage->releaseMonSpritePtr = &gStorage->movingMonSprite;
break;
default:
return;
}
if (*gStorage->releaseMonSpritePtr != NULL)
{
InitSpriteAffineAnim(*gStorage->releaseMonSpritePtr);
(*gStorage->releaseMonSpritePtr)->oam.affineMode = ST_OAM_AFFINE_NORMAL;
(*gStorage->releaseMonSpritePtr)->affineAnims = sAffineAnims_ReleaseMon;
StartSpriteAffineAnim(*gStorage->releaseMonSpritePtr, RELEASE_ANIM_RELEASE);
}
}
bool8 TryHideReleaseMonSprite(void)
{
if (*gStorage->releaseMonSpritePtr == NULL || (*gStorage->releaseMonSpritePtr)->invisible)
return FALSE;
if ((*gStorage->releaseMonSpritePtr)->affineAnimEnded)
(*gStorage->releaseMonSpritePtr)->invisible = TRUE;
return TRUE;
}
void DestroyReleaseMonIcon(void)
{
if (*gStorage->releaseMonSpritePtr != NULL)
{
FreeOamMatrix((*gStorage->releaseMonSpritePtr)->oam.matrixNum);
DestroyBoxMonIcon(*gStorage->releaseMonSpritePtr);
*gStorage->releaseMonSpritePtr = NULL;
}
}
void DoReleaseMonComeBackAnim(void)
{
if (*gStorage->releaseMonSpritePtr != NULL)
{
(*gStorage->releaseMonSpritePtr)->invisible = FALSE;
StartSpriteAffineAnim(*gStorage->releaseMonSpritePtr, RELEASE_ANIM_COME_BACK);
}
}
bool8 ResetReleaseMonSpritePtr(void)
{
if (gStorage->releaseMonSpritePtr == NULL)
return FALSE;
if ((*gStorage->releaseMonSpritePtr)->affineAnimEnded)
gStorage->releaseMonSpritePtr = NULL;
return TRUE;
}
void SetMovingMonPriority(u8 priority)
{
gStorage->movingMonSprite->oam.priority = priority;
}
static void SpriteCB_HeldMon(struct Sprite *sprite)
{
sprite->x = gStorage->cursorSprite->x;
sprite->y = gStorage->cursorSprite->y + gStorage->cursorSprite->y2 + 4;
}
static u16 TryLoadMonIconTiles(u16 species, u32 personality)
{
u16 i, offset;
// Find the currently-allocated slot
for (i = 0; i < MAX_MON_ICONS; i++)
{
if (gStorage->iconSpeciesList[i] == species)
break;
}
if (i == MAX_MON_ICONS)
{
// Find the first empty slot
for (i = 0; i < MAX_MON_ICONS; i++)
{
if (gStorage->iconSpeciesList[i] == SPECIES_NONE)
break;
}
if (i == MAX_MON_ICONS)
return 0xFFFF;
}
gStorage->iconSpeciesList[i] = species;
gStorage->numIconsPerSpecies[i]++;
offset = 16 * i;
CpuCopy32(GetMonIconTiles(species, personality), (void *)(OBJ_VRAM0) + offset * 32, 0x200);
return offset;
}
static void RemoveSpeciesFromIconList(u16 species)
{
u16 i;
for (i = 0; i < MAX_MON_ICONS; i++)
{
if (gStorage->iconSpeciesList[i] == species)
{
if (--gStorage->numIconsPerSpecies[i] == 0)
gStorage->iconSpeciesList[i] = SPECIES_NONE;
break;
}
}
}
struct Sprite *CreateMonIconSprite(u16 species, u32 personality, s16 x, s16 y, u8 oamPriority, u8 subpriority)
{
u16 tileNum;
u8 spriteId;
struct SpriteTemplate template = sSpriteTemplate_MonIcon;
species = GetIconSpecies(species, personality);
template.paletteTag = PALTAG_MON_ICON_0 + gSpeciesInfo[species].iconPalIndex;
tileNum = TryLoadMonIconTiles(species, personality);
if (tileNum == 0xFFFF)
return NULL;
spriteId = CreateSprite(&template, x, y, subpriority);
if (spriteId == MAX_SPRITES)
{
RemoveSpeciesFromIconList(species);
return NULL;
}
gSprites[spriteId].oam.tileNum = tileNum;
gSprites[spriteId].oam.priority = oamPriority;
gSprites[spriteId].data[0] = species;
return &gSprites[spriteId];
}
static void DestroyBoxMonIcon(struct Sprite *sprite)
{
RemoveSpeciesFromIconList(sprite->data[0]);
DestroySprite(sprite);
}
#define tState data[0]
#define tDmaIdx data[1]
#define tBoxId data[2]
void CreateInitBoxTask(u8 boxId)
{
u8 taskId = CreateTask(Task_InitBox, 2);
gTasks[taskId].tBoxId = boxId;
}
bool8 IsInitBoxActive(void)
{
return FuncIsActiveTask(Task_InitBox);
}
static void Task_InitBox(u8 taskId)
{
struct Task *task = &gTasks[taskId];
switch (task->tState)
{
case 0:
gStorage->wallpaperOffset = 0;
gStorage->bg2_X = 0;
task->tDmaIdx = RequestDma3Fill(0, gStorage->wallpaperBgTilemapBuffer, sizeof(gStorage->wallpaperBgTilemapBuffer), DMA3_32BIT);
break;
case 1:
if (WaitDma3Request(task->tDmaIdx) == -1)
return;
SetBgTilemapBuffer(2, gStorage->wallpaperBgTilemapBuffer);
ShowBg(2);
break;
case 2:
LoadWallpaperGfx(task->tBoxId, 0);
break;
case 3:
if (!WaitForWallpaperGfxLoad())
return;
InitBoxTitle(task->tBoxId);
CreateBoxScrollArrows();
InitBoxMonSprites(task->tBoxId);
SetGpuReg(REG_OFFSET_BG2CNT, BGCNT_PRIORITY(2) | BGCNT_CHARBASE(2) | BGCNT_SCREENBASE(27) | BGCNT_TXT512x256);
break;
case 4:
DestroyTask(taskId);
break;
default:
task->tState = 0;
return;
}
task->tState++;
}
#undef tState
#undef tDmaIdx
#undef tBoxId
void SetUpScrollToBox(u8 boxId)
{
s8 direction = DetermineBoxScrollDirection(boxId);
gStorage->scrollSpeed = (direction > 0) ? 6 : -6;
gStorage->scrollUnused1 = (direction > 0) ? 1 : 2;
gStorage->scrollTimer = 32;
gStorage->scrollToBoxIdUnused = boxId;
gStorage->scrollUnused2 = (direction <= 0) ? 5 : 0;
gStorage->scrollDirectionUnused = direction;
gStorage->scrollUnused3 = (direction > 0) ? 264 : 56;
gStorage->scrollUnused4 = (direction <= 0) ? 5 : 0;
gStorage->scrollUnused5 = 0;
gStorage->scrollUnused6 = 2;
gStorage->scrollToBoxId = boxId;
gStorage->scrollDirection = direction;
gStorage->scrollState = 0;
}
bool8 ScrollToBox(void)
{
bool8 isStillScrolling;
switch (gStorage->scrollState)
{
case 0:
LoadWallpaperGfx(gStorage->scrollToBoxId, gStorage->scrollDirection);
gStorage->scrollState++;
case 1:
if (!WaitForWallpaperGfxLoad())
return TRUE;
InitBoxMonIconScroll(gStorage->scrollToBoxId, gStorage->scrollDirection);
CreateIncomingBoxTitle(gStorage->scrollToBoxId, gStorage->scrollDirection);
StartBoxScrollArrowsSlide(gStorage->scrollDirection);
break;
case 2:
isStillScrolling = UpdateBoxMonIconScroll();
if (gStorage->scrollTimer != 0)
{
gStorage->bg2_X += gStorage->scrollSpeed;
if (--gStorage->scrollTimer != 0)
return TRUE;
CycleBoxTitleSprites();
StopBoxScrollArrowsSlide();
}
return isStillScrolling;
}
gStorage->scrollState++;
return TRUE;
}
static s8 DetermineBoxScrollDirection(u8 boxId)
{
u8 i;
u8 currentBox = StorageGetCurrentBox();
for (i = 0; currentBox != boxId; i++)
{
currentBox++;
if (currentBox >= TOTAL_BOXES_COUNT)
currentBox = 0;
}
return (i < TOTAL_BOXES_COUNT / 2) ? 1 : -1;
}
void SetWallpaperForCurrentBox(u8 wallpaperId)
{
SetBoxWallpaper(StorageGetCurrentBox(), wallpaperId);
gStorage->wallpaperChangeState = 0;
}
bool8 DoWallpaperGfxChange(void)
{
switch (gStorage->wallpaperChangeState)
{
case 0:
BeginNormalPaletteFade(gStorage->wallpaperPalBits, 1, 0, 16, RGB_WHITEALPHA);
gStorage->wallpaperChangeState++;
break;
case 1:
if (!UpdatePaletteFade())
{
u8 curBox = StorageGetCurrentBox();
LoadWallpaperGfx(curBox, 0);
gStorage->wallpaperChangeState++;
}
break;
case 2:
if (WaitForWallpaperGfxLoad() == TRUE)
{
CycleBoxTitleColor();
BeginNormalPaletteFade(gStorage->wallpaperPalBits, 1, 16, 0, RGB_WHITEALPHA);
gStorage->wallpaperChangeState++;
}
break;
case 3:
if (!UpdatePaletteFade())
gStorage->wallpaperChangeState++;
break;
case 4:
return FALSE;
}
return TRUE;
}
static void LoadWallpaperGfx(u8 boxId, s8 direction)
{
u8 wallpaperId;
const struct Wallpaper *wallpaper;
gStorage->wallpaperLoadState = 0;
gStorage->wallpaperLoadBoxId = boxId;
gStorage->wallpaperLoadDir = direction;
if (gStorage->wallpaperLoadDir != 0)
{
gStorage->wallpaperOffset = !gStorage->wallpaperOffset;
TrimOldWallpaper(gStorage->wallpaperBgTilemapBuffer);
}
wallpaperId = GetBoxWallpaper(gStorage->wallpaperLoadBoxId);
wallpaper = &sWallpapers[wallpaperId];
LZ77UnCompWram(wallpaper->tileMap, gStorage->wallpaperTilemap);
DrawWallpaper(gStorage->wallpaperBgTilemapBuffer, gStorage->wallpaperTilemap, gStorage->wallpaperLoadDir, gStorage->wallpaperOffset);
if (gStorage->wallpaperLoadDir != 0)
LoadPalette(wallpaper->palettes, BG_PLTT_ID(4) + BG_PLTT_ID(gStorage->wallpaperOffset * 2), 2 * PLTT_SIZE_4BPP);
else
CpuCopy16(wallpaper->palettes, &gPlttBufferUnfaded[BG_PLTT_ID(4) + BG_PLTT_ID(gStorage->wallpaperOffset * 2)], 2 * PLTT_SIZE_4BPP);
DecompressAndLoadBgGfxUsingHeap(2, wallpaper->tiles, 0, 256 * gStorage->wallpaperOffset, 0);
CopyBgTilemapBufferToVram(2);
}
static bool32 WaitForWallpaperGfxLoad(void)
{
if (IsDma3ManagerBusyWithBgCopy() == TRUE)
return FALSE;
return TRUE;
}
static void DrawWallpaper(void *unused, const void *tilemap, s8 direction, u8 offset)
{
s16 paletteNum = (offset * 2) + 3;
s16 x = ((gStorage->bg2_X / 8 + 10) + (direction * 24)) & 0x3F;
CopyRectToBgTilemapBufferRect(2, tilemap, 0, 0, 20, 18, x, 2, 20, 18, 17, offset << 8, paletteNum);
if (direction == 0)
return;
else if (direction > 0)
x *= 1, x += 20; // x * 1 is needed to match
else
x -= 4;
FillBgTilemapBufferRect(2, 0, x, 2, 4, 18, 17);
}
static void TrimOldWallpaper(void *tilemapBuffer)
{
u16 i;
u16 *dest = tilemapBuffer;
s16 right = ((gStorage->bg2_X / 8 + 10) + 20) & 0x3F;
if (right < 32)
dest += right + 0x260;
else
dest += right + 0x640;
for (i = 0; i < 44; i++)
{
*dest++ = 0;
right = (right + 1) & 0x3F;
if (right == 0)
dest -= 0x420;
if (right == 32)
dest += 0x3e0;
}
}
static void InitBoxTitle(u8 boxId)
{
u8 tagIndex;
s16 x;
u16 i;
struct SpriteSheet spriteSheet = {gStorage->boxTitleTiles, 0x200, GFXTAG_BOX_TITLE};
struct SpritePalette palettes[] = {
{gStorage->boxTitlePal, PALTAG_BOX_TITLE},
{}
};
u16 wallpaperId = GetBoxWallpaper(boxId);
gStorage->boxTitlePal[14] = sBoxTitleColors[wallpaperId][0];
gStorage->boxTitlePal[15] = sBoxTitleColors[wallpaperId][1];
LoadSpritePalettes(palettes);
gStorage->wallpaperPalBits = 0x3F0;
tagIndex = IndexOfSpritePaletteTag(PALTAG_BOX_TITLE);
gStorage->boxTitlePalOffset = OBJ_PLTT_ID(tagIndex) + 14;
gStorage->wallpaperPalBits |= (1 << 16) << tagIndex;
tagIndex = IndexOfSpritePaletteTag(PALTAG_BOX_TITLE);
gStorage->boxTitleAltPalOffset = OBJ_PLTT_ID(tagIndex) + 14;
gStorage->wallpaperPalBits |= (1 << 16) << tagIndex;
StringCopyPadded(gStorage->boxTitleText, GetBoxNamePtr(boxId), 0, 8);
DrawTextWindowAndBufferTiles(gStorage->boxTitleText, gStorage->boxTitleTiles, 0, 0, gStorage->boxTitleUnused, 2);
LoadSpriteSheet(&spriteSheet);
x = GetBoxTitleBaseX(GetBoxNamePtr(boxId));
for (i = 0; i < 2; i++)
{
u8 spriteId = CreateSprite(&sSpriteTemplate_BoxTitle, x + i * 32, 28, 24);
gStorage->curBoxTitleSprites[i] = &gSprites[spriteId];
StartSpriteAnim(gStorage->curBoxTitleSprites[i], i);
}
gStorage->boxTitleCycleId = 0;
}
static void CreateIncomingBoxTitle(u8 boxId, s8 direction)
{
u16 palOffset;
s16 x, adjustedX;
u16 i;
struct SpriteSheet spriteSheet = {gStorage->boxTitleTiles, 0x200, GFXTAG_BOX_TITLE};
struct SpriteTemplate template = sSpriteTemplate_BoxTitle;
gStorage->boxTitleCycleId = !gStorage->boxTitleCycleId;
if (gStorage->boxTitleCycleId == 0)
{
spriteSheet.tag = GFXTAG_BOX_TITLE;
palOffset = gStorage->boxTitlePalOffset;
}
else
{
spriteSheet.tag = GFXTAG_BOX_TITLE_ALT;
palOffset = gStorage->boxTitlePalOffset;
template.tileTag = GFXTAG_BOX_TITLE_ALT;
template.paletteTag = PALTAG_BOX_TITLE;
}
StringCopyPadded(gStorage->boxTitleText, GetBoxNamePtr(boxId), 0, BOX_NAME_LENGTH);
DrawTextWindowAndBufferTiles(gStorage->boxTitleText, gStorage->boxTitleTiles, 0, 0, gStorage->boxTitleUnused, 2);
LoadSpriteSheet(&spriteSheet);
LoadPalette(sBoxTitleColors[GetBoxWallpaper(boxId)], palOffset, sizeof(sBoxTitleColors[0]));
x = GetBoxTitleBaseX(GetBoxNamePtr(boxId));
adjustedX = x;
adjustedX += direction * 192;
// Title is split across two sprites
for (i = 0; i < 2; i++)
{
u8 spriteId = CreateSprite(&template, i * 32 + adjustedX, 28, 24);
gStorage->nextBoxTitleSprites[i] = &gSprites[spriteId];
gStorage->nextBoxTitleSprites[i]->data[0] = (-direction) * 6;
gStorage->nextBoxTitleSprites[i]->data[1] = i * 32 + x;
gStorage->nextBoxTitleSprites[i]->data[2] = 0;
gStorage->nextBoxTitleSprites[i]->callback = SpriteCB_IncomingBoxTitle;
StartSpriteAnim(gStorage->nextBoxTitleSprites[i], i);
gStorage->curBoxTitleSprites[i]->data[0] = (-direction) * 6;
gStorage->curBoxTitleSprites[i]->data[1] = 1;
gStorage->curBoxTitleSprites[i]->callback = SpriteCB_OutgoingBoxTitle;
}
}
static void CycleBoxTitleSprites(void)
{
if (gStorage->boxTitleCycleId == 0)
FreeSpriteTilesByTag(GFXTAG_BOX_TITLE_ALT);
else
FreeSpriteTilesByTag(GFXTAG_BOX_TITLE);
gStorage->curBoxTitleSprites[0] = gStorage->nextBoxTitleSprites[0];
gStorage->curBoxTitleSprites[1] = gStorage->nextBoxTitleSprites[1];
}
static void SpriteCB_IncomingBoxTitle(struct Sprite *sprite)
{
if (sprite->data[2] != 0)
sprite->data[2]--;
else if ((sprite->x += sprite->data[0]) == sprite->data[1])
sprite->callback = SpriteCallbackDummy;
}
static void SpriteCB_OutgoingBoxTitle(struct Sprite *sprite)
{
if (sprite->data[1] != 0)
sprite->data[1]--;
else
{
sprite->x += sprite->data[0];
sprite->data[2] = sprite->x + sprite->x2;
if (sprite->data[2] < 0x40 || sprite->data[2] > 0x100)
DestroySprite(sprite);
}
}
static void CycleBoxTitleColor(void)
{
u8 boxId = StorageGetCurrentBox();
u8 wallpaperId = GetBoxWallpaper(boxId);
if (gStorage->boxTitleCycleId == 0)
CpuCopy16(sBoxTitleColors[wallpaperId], &gPlttBufferUnfaded[gStorage->boxTitlePalOffset], PLTT_SIZEOF(2));
else
CpuCopy16(sBoxTitleColors[wallpaperId], &gPlttBufferUnfaded[gStorage->boxTitleAltPalOffset], PLTT_SIZEOF(2));
}
static s16 GetBoxTitleBaseX(const u8 *string)
{
return DISPLAY_WIDTH - 64 - GetStringWidth(FONT_NORMAL_COPY_1, string, 0) / 2;
}
// Sprite data for box scroll arrows
#define sState data[0]
#define sTimer data[1]
#define sSpeed data[3]
static void CreateBoxScrollArrows(void)
{
u16 i;
LoadSpriteSheet(&sSpriteSheet_BoxScrollArrow);
for (i = 0; i < 2; i++)
{
u8 spriteId = CreateSprite(&sSpriteTemplate_BoxScrollArrow, 92 + i * 136, 28, 22);
if (spriteId != MAX_SPRITES)
{
struct Sprite *sprite = &gSprites[spriteId];
StartSpriteAnim(sprite, i);
sprite->sSpeed = (i == 0) ? -1 : 1;
gStorage->arrowSprites[i] = sprite;
}
}
if (IsCursorOnBoxTitle())
AnimateBoxScrollArrows(TRUE);
}
// Slide box scroll arrows horizontally for box change
static void StartBoxScrollArrowsSlide(s8 direction)
{
u16 i;
for (i = 0; i < 2; i++)
{
gStorage->arrowSprites[i]->x2 = 0;
gStorage->arrowSprites[i]->sState = 2;
}
if (direction < 0)
{
gStorage->arrowSprites[0]->sTimer = 29;
gStorage->arrowSprites[1]->sTimer = 5;
gStorage->arrowSprites[0]->data[2] = 72;
gStorage->arrowSprites[1]->data[2] = 72;
}
else
{
gStorage->arrowSprites[0]->sTimer = 5;
gStorage->arrowSprites[1]->sTimer = 29;
gStorage->arrowSprites[0]->data[2] = DISPLAY_WIDTH + 8;
gStorage->arrowSprites[1]->data[2] = DISPLAY_WIDTH + 8;
}
gStorage->arrowSprites[0]->data[7] = 0;
gStorage->arrowSprites[1]->data[7] = 1;
}
// New box's scroll arrows have entered, stop sliding and set their position
static void StopBoxScrollArrowsSlide(void)
{
u16 i;
for (i = 0; i < 2; i++)
{
gStorage->arrowSprites[i]->x = 136 * i + 92;
gStorage->arrowSprites[i]->x2 = 0;
gStorage->arrowSprites[i]->invisible = FALSE;
}
AnimateBoxScrollArrows(TRUE);
}
// Bounce scroll arrows while title is selected
void AnimateBoxScrollArrows(bool8 animate)
{
u16 i;
if (animate)
{
// Start arrows moving
for (i = 0; i < 2; i++)
{
gStorage->arrowSprites[i]->sState = 1;
gStorage->arrowSprites[i]->sTimer = 0;
gStorage->arrowSprites[i]->data[2] = 0;
gStorage->arrowSprites[i]->data[4] = 0;
}
}
else
{
// Stop arrows moving
for (i = 0; i < 2; i++)
gStorage->arrowSprites[i]->sState = 0;
}
}
static void SpriteCB_BoxScrollArrow(struct Sprite *sprite)
{
switch (sprite->sState)
{
case 0:
sprite->x2 = 0;
break;
case 1:
if (++sprite->sTimer > 3)
{
sprite->sTimer = 0;
sprite->x2 += sprite->sSpeed;
if (++sprite->data[2] > 5)
{
sprite->data[2] = 0;
sprite->x2 = 0;
}
}
break;
case 2:
sprite->sState = 3;
break;
case 3:
sprite->x -= gStorage->scrollSpeed;
if (sprite->x <= 72 || sprite->x >= DISPLAY_WIDTH + 8)
sprite->invisible = TRUE;
if (--sprite->sTimer == 0)
{
sprite->x = sprite->data[2];
sprite->invisible = FALSE;
sprite->sState = 4;
}
break;
case 4:
sprite->x -= gStorage->scrollSpeed;
break;
}
}
#undef sState
#undef sTimer
#undef sSpeed
// Arrows for Deposit/Jump Box selection
struct Sprite *CreateChooseBoxArrows(u16 x, u16 y, u8 animId, u8 priority, u8 subpriority)
{
u8 spriteId = CreateSprite(&sSpriteTemplate_BoxScrollArrow, x, y, subpriority);
if (spriteId == MAX_SPRITES)
return NULL;
animId %= 2;
StartSpriteAnim(&gSprites[spriteId], animId);
gSprites[spriteId].oam.priority = priority;
gSprites[spriteId].callback = SpriteCallbackDummy;
return &gSprites[spriteId];
}