#include "global.h" #include "gflib.h" #include "decompress.h" #include "graphics.h" #include "item_menu_icons.h" #include "constants/items.h" enum { TAG_BAG = 100, TAG_SWAP_LINE, TAG_ITEM_ICON, TAG_ITEM_ICON_ALT, }; #define NUM_SWAP_LINE_SPRITES 9 // Indexes for sItemMenuIconSpriteIds enum { SPR_BAG, SPR_SWAP_LINE_START, SPR_ITEM_ICON = SPR_SWAP_LINE_START + NUM_SWAP_LINE_SPRITES, SPR_ITEM_ICON_ALT, SPR_COUNT }; enum { ANIM_SWAP_LINE_START, ANIM_SWAP_LINE_MID, ANIM_SWAP_LINE_END, }; enum { AFFINEANIM_BAG_IDLE, AFFINEANIM_BAG_SHAKE, }; static EWRAM_DATA u8 sItemMenuIconSpriteIds[SPR_COUNT] = {0}; static EWRAM_DATA void *sItemIconTilesBuffer = NULL; static EWRAM_DATA void *sItemIconTilesBufferPadded = NULL; static void SpriteCB_BagVisualSwitchingPockets(struct Sprite *sprite); static void SpriteCB_ShakeBagSprite(struct Sprite *sprite); static const struct OamData sOamData_Bag = { .affineMode = ST_OAM_AFFINE_NORMAL, .shape = SPRITE_SHAPE(64x64), .size = SPRITE_SIZE(64x64), .priority = 1, .paletteNum = 0 }; static const union AnimCmd sAnim_Bag_OpenPokeBallsPocket[] = { ANIMCMD_FRAME( 0, 5), ANIMCMD_FRAME(0x40, 0), ANIMCMD_END }; static const union AnimCmd sAnim_Bag_OpenItemsPocket[] = { ANIMCMD_FRAME( 0, 5), ANIMCMD_FRAME(0x80, 0), ANIMCMD_END }; static const union AnimCmd sAnim_Bag_OpenKeyItemsPocket[] = { ANIMCMD_FRAME( 0, 5), ANIMCMD_FRAME(0xc0, 0), ANIMCMD_END }; static const union AnimCmd *const sAnims_Bag[] = { [POCKET_ITEMS - 1] = sAnim_Bag_OpenItemsPocket, [POCKET_KEY_ITEMS - 1] = sAnim_Bag_OpenKeyItemsPocket, [POCKET_POKE_BALLS - 1] = sAnim_Bag_OpenPokeBallsPocket, }; static const union AffineAnimCmd sAffineAnim_BagIdle[] = { AFFINEANIMCMD_FRAME(0x100, 0x100, 0, 0), AFFINEANIMCMD_END }; static const union AffineAnimCmd sAffineAnim_BagShake[] = { AFFINEANIMCMD_FRAME(0, 0, -2, 2), AFFINEANIMCMD_FRAME(0, 0, 2, 4), AFFINEANIMCMD_FRAME(0, 0, -2, 4), AFFINEANIMCMD_FRAME(0, 0, 2, 2), AFFINEANIMCMD_END }; static const union AffineAnimCmd *const sAffineAnimTable_Bag[] = { [AFFINEANIM_BAG_IDLE] = sAffineAnim_BagIdle, [AFFINEANIM_BAG_SHAKE] = sAffineAnim_BagShake }; const struct CompressedSpriteSheet gSpriteSheet_BagMale = { .data = gBagMale_Gfx, .size = 0x2000, .tag = TAG_BAG }; const struct CompressedSpriteSheet gSpriteSheet_BagFemale = { .data = gBagFemale_Gfx, .size = 0x2000, .tag = TAG_BAG }; const struct CompressedSpritePalette gSpritePalette_Bag = { .data = gBag_Pal, .tag = TAG_BAG }; static const struct SpriteTemplate sSpriteTemplate_Bag = { .tileTag = TAG_BAG, .paletteTag = TAG_BAG, .oam = &sOamData_Bag, .anims = sAnims_Bag, .images = NULL, .affineAnims = sAffineAnimTable_Bag, .callback = SpriteCallbackDummy }; static const struct OamData sOamData_SwapLine = { .affineMode = ST_OAM_AFFINE_OFF, .shape = SPRITE_SHAPE(16x16), .size = SPRITE_SIZE(16x16), .priority = 1, .paletteNum = 1 }; static const union AnimCmd sAnim_SwapLine_Start[] = { ANIMCMD_FRAME(0, 0), ANIMCMD_END }; static const union AnimCmd sAnim_SwapLine_Mid[] = { ANIMCMD_FRAME(4, 0), ANIMCMD_END }; static const union AnimCmd sAnim_SwapLine_End[] = { ANIMCMD_FRAME(0, 0, .hFlip = TRUE), ANIMCMD_END }; static const union AnimCmd *const sAnims_SwapLine[] = { [ANIM_SWAP_LINE_START] = sAnim_SwapLine_Start, [ANIM_SWAP_LINE_MID] = sAnim_SwapLine_Mid, [ANIM_SWAP_LINE_END] = sAnim_SwapLine_End }; const struct CompressedSpriteSheet gBagSwapSpriteSheet = { .data = gSwapLine_Gfx, .size = 0x100, .tag = TAG_SWAP_LINE }; const struct CompressedSpritePalette gBagSwapSpritePalette = { .data = gSwapLine_Pal, .tag = TAG_SWAP_LINE }; static const struct SpriteTemplate sSpriteTemplate_SwapLine = { .tileTag = TAG_SWAP_LINE, .paletteTag = TAG_SWAP_LINE, .oam = &sOamData_SwapLine, .anims = sAnims_SwapLine, .images = NULL, .affineAnims = gDummySpriteAffineAnimTable, .callback = SpriteCallbackDummy }; static const struct OamData sOamData_ItemIcon = { .affineMode = ST_OAM_AFFINE_OFF, .shape = SPRITE_SHAPE(32x32), .size = SPRITE_SIZE(32x32), .priority = 1, .paletteNum = 2 }; static const union AnimCmd sAnim_ItemIcon[] = { ANIMCMD_FRAME(0, 0), ANIMCMD_END }; static const union AnimCmd *const sAnims_ItemIcon[] = { sAnim_ItemIcon }; static const struct SpriteTemplate sSpriteTemplate_ItemIcon = { .tileTag = TAG_ITEM_ICON, .paletteTag = TAG_ITEM_ICON, .oam = &sOamData_ItemIcon, .anims = sAnims_ItemIcon, .images = NULL, .affineAnims = gDummySpriteAffineAnimTable, .callback = SpriteCallbackDummy }; #include "data/item_icon_table.h" void ResetItemMenuIconState(void) { u16 i; for (i = 0; i < SPR_COUNT; i++) sItemMenuIconSpriteIds[i] = SPRITE_NONE; } void CreateBagSprite(u8 animNum) { sItemMenuIconSpriteIds[SPR_BAG] = CreateSprite(&sSpriteTemplate_Bag, 40, 68, 0); SetBagVisualPocketId(animNum); } void SetBagVisualPocketId(u8 animNum) { struct Sprite *sprite = &gSprites[sItemMenuIconSpriteIds[SPR_BAG]]; sprite->y2 = -5; sprite->callback = SpriteCB_BagVisualSwitchingPockets; StartSpriteAnim(sprite, animNum); } static void SpriteCB_BagVisualSwitchingPockets(struct Sprite *sprite) { if (sprite->y2 != 0) sprite->y2++; else sprite->callback = SpriteCallbackDummy; } void ShakeBagSprite(void) { struct Sprite *sprite = &gSprites[sItemMenuIconSpriteIds[SPR_BAG]]; if (sprite->affineAnimEnded) { StartSpriteAffineAnim(sprite, AFFINEANIM_BAG_SHAKE); sprite->callback = SpriteCB_ShakeBagSprite; } } static void SpriteCB_ShakeBagSprite(struct Sprite *sprite) { if (sprite->affineAnimEnded) { StartSpriteAffineAnim(sprite, AFFINEANIM_BAG_IDLE); sprite->callback = SpriteCallbackDummy; } } void CreateSwapLine(void) { u8 i; u8 * spriteIds = &sItemMenuIconSpriteIds[SPR_SWAP_LINE_START]; for (i = 0; i < NUM_SWAP_LINE_SPRITES; i++) { spriteIds[i] = CreateSprite(&sSpriteTemplate_SwapLine, i * 16 + 96, 7, 0); switch (i) { case 0: // ANIM_SWAP_LINE_START, by default break; case NUM_SWAP_LINE_SPRITES - 1: StartSpriteAnim(&gSprites[spriteIds[i]], ANIM_SWAP_LINE_END); break; default: StartSpriteAnim(&gSprites[spriteIds[i]], ANIM_SWAP_LINE_MID); break; } gSprites[spriteIds[i]].invisible = TRUE; } } void SetSwapLineInvisibility(bool8 invisible) { u8 i; u8 * spriteIds = &sItemMenuIconSpriteIds[SPR_SWAP_LINE_START]; for (i = 0; i < NUM_SWAP_LINE_SPRITES; i++) gSprites[spriteIds[i]].invisible = invisible; } void UpdateSwapLinePos(s16 x, u16 y) { u8 i; u8 * spriteIds = &sItemMenuIconSpriteIds[SPR_SWAP_LINE_START]; for (i = 0; i < NUM_SWAP_LINE_SPRITES; i++) { gSprites[spriteIds[i]].x2 = x; gSprites[spriteIds[i]].y = y + 7; } } static bool8 TryAllocItemIconTilesBuffers(void) { void ** ptr1, ** ptr2; ptr1 = &sItemIconTilesBuffer; *ptr1 = Alloc(0x120); if (*ptr1 == NULL) return FALSE; ptr2 = &sItemIconTilesBufferPadded; *ptr2 = AllocZeroed(0x200); if (*ptr2 == NULL) { Free(*ptr1); return FALSE; } return TRUE; } void CopyItemIconPicTo4x4Buffer(const void *src, void *dest) { u8 i; for (i = 0; i < 3; i++) CpuCopy16(src + 0x60 * i, dest + 0x80 * i, 0x60); } u8 AddItemIconObject(u16 tilesTag, u16 paletteTag, u16 itemId) { struct SpriteTemplate template; struct SpriteSheet spriteSheet; struct CompressedSpritePalette spritePalette; u8 spriteId; if (!TryAllocItemIconTilesBuffers()) return MAX_SPRITES; LZDecompressWram(GetItemIconGfxPtr(itemId, 0), sItemIconTilesBuffer); CopyItemIconPicTo4x4Buffer(sItemIconTilesBuffer, sItemIconTilesBufferPadded); spriteSheet.data = sItemIconTilesBufferPadded; spriteSheet.size = 0x200; spriteSheet.tag = tilesTag; LoadSpriteSheet(&spriteSheet); spritePalette.data = GetItemIconGfxPtr(itemId, 1); spritePalette.tag = paletteTag; LoadCompressedSpritePalette(&spritePalette); CpuCopy16(&sSpriteTemplate_ItemIcon, &template, sizeof(struct SpriteTemplate)); template.tileTag = tilesTag; template.paletteTag = paletteTag; spriteId = CreateSprite(&template, 0, 0, 0); Free(sItemIconTilesBuffer); Free(sItemIconTilesBufferPadded); return spriteId; } u8 AddItemIconObjectWithCustomObjectTemplate(const struct SpriteTemplate * origTemplate, u16 tilesTag, u16 paletteTag, u16 itemId) { struct SpriteTemplate template; struct SpriteSheet spriteSheet; struct CompressedSpritePalette spritePalette; u8 spriteId; if (!TryAllocItemIconTilesBuffers()) return MAX_SPRITES; LZDecompressWram(GetItemIconGfxPtr(itemId, 0), sItemIconTilesBuffer); CopyItemIconPicTo4x4Buffer(sItemIconTilesBuffer, sItemIconTilesBufferPadded); spriteSheet.data = sItemIconTilesBufferPadded; spriteSheet.size = 0x200; spriteSheet.tag = tilesTag; LoadSpriteSheet(&spriteSheet); spritePalette.data = GetItemIconGfxPtr(itemId, 1); spritePalette.tag = paletteTag; LoadCompressedSpritePalette(&spritePalette); CpuCopy16(origTemplate, &template, sizeof(struct SpriteTemplate)); template.tileTag = tilesTag; template.paletteTag = paletteTag; spriteId = CreateSprite(&template, 0, 0, 0); Free(sItemIconTilesBuffer); Free(sItemIconTilesBufferPadded); return spriteId; } void CreateItemMenuIcon(u16 itemId, u8 idx) { u8 * spriteIds = &sItemMenuIconSpriteIds[SPR_ITEM_ICON]; u8 spriteId; if (spriteIds[idx] == SPRITE_NONE) { // Either TAG_ITEM_ICON or TAG_ITEM_ICON_ALT FreeSpriteTilesByTag(TAG_ITEM_ICON + idx); FreeSpritePaletteByTag(TAG_ITEM_ICON + idx); spriteId = AddItemIconObject(TAG_ITEM_ICON + idx, TAG_ITEM_ICON + idx, itemId); if (spriteId != MAX_SPRITES) { spriteIds[idx] = spriteId; gSprites[spriteId].x2 = 24; gSprites[spriteId].y2 = 140; } } } void DestroyItemMenuIcon(u8 idx) { u8 * spriteIds = &sItemMenuIconSpriteIds[SPR_ITEM_ICON]; if (spriteIds[idx] != SPRITE_NONE) { DestroySpriteAndFreeResources(&gSprites[spriteIds[idx]]); spriteIds[idx] = SPRITE_NONE; } } const void *GetItemIconGfxPtr(u16 itemId, u8 attrId) { if (itemId > ITEMS_COUNT) itemId = ITEM_NONE; return sItemIconTable[itemId][attrId]; } void CreateBerryPouchItemIcon(u16 itemId, u8 idx) { u8 * spriteIds = &sItemMenuIconSpriteIds[SPR_ITEM_ICON]; u8 spriteId; if (spriteIds[idx] == SPRITE_NONE) { // Either TAG_ITEM_ICON or TAG_ITEM_ICON_ALT FreeSpriteTilesByTag(TAG_ITEM_ICON + idx); FreeSpritePaletteByTag(TAG_ITEM_ICON + idx); spriteId = AddItemIconObject(TAG_ITEM_ICON + idx, TAG_ITEM_ICON + idx, itemId); if (spriteId != MAX_SPRITES) { spriteIds[idx] = spriteId; gSprites[spriteId].x2 = 24; gSprites[spriteId].y2 = 147; // This value is the only difference from CreateItemMenuIcon } } }