#include "global.h" #include "graphics.h" #include "mail.h" #include "palette.h" #include "pokemon_sprite_visualizer.h" #include "pokemon_icon.h" #include "sprite.h" #include "data.h" #include "constants/pokemon_icon.h" struct MonIconSpriteTemplate { const struct OamData *oam; const u8 *image; const union AnimCmd *const *anims; const union AffineAnimCmd *const *affineAnims; void (*callback)(struct Sprite *); u16 paletteTag; }; static u8 CreateMonIconSprite(struct MonIconSpriteTemplate *, s16, s16, u8); static void FreeAndDestroyMonIconSprite_(struct Sprite *sprite); const struct SpritePalette gMonIconPaletteTable[] = { { gMonIconPalettes[0], POKE_ICON_BASE_PAL_TAG + 0 }, { gMonIconPalettes[1], POKE_ICON_BASE_PAL_TAG + 1 }, { gMonIconPalettes[2], POKE_ICON_BASE_PAL_TAG + 2 }, { gMonIconPalettes[3], POKE_ICON_BASE_PAL_TAG + 3 }, { gMonIconPalettes[4], POKE_ICON_BASE_PAL_TAG + 4 }, { gMonIconPalettes[5], POKE_ICON_BASE_PAL_TAG + 5 }, }; static const struct OamData sMonIconOamData = { .y = 0, .affineMode = ST_OAM_AFFINE_OFF, .objMode = ST_OAM_OBJ_NORMAL, .bpp = ST_OAM_4BPP, .shape = SPRITE_SHAPE(32x32), .x = 0, .size = SPRITE_SIZE(32x32), .tileNum = 0, .priority = 1, .paletteNum = 0, }; // fastest to slowest static const union AnimCmd sAnim_0[] = { ANIMCMD_FRAME(0, 6), ANIMCMD_FRAME(1, 6), ANIMCMD_JUMP(0), }; static const union AnimCmd sAnim_1[] = { ANIMCMD_FRAME(0, 8), ANIMCMD_FRAME(1, 8), ANIMCMD_JUMP(0), }; static const union AnimCmd sAnim_2[] = { ANIMCMD_FRAME(0, 14), ANIMCMD_FRAME(1, 14), ANIMCMD_JUMP(0), }; static const union AnimCmd sAnim_3[] = { ANIMCMD_FRAME(0, 22), ANIMCMD_FRAME(1, 22), ANIMCMD_JUMP(0), }; static const union AnimCmd sAnim_4[] = { ANIMCMD_FRAME(0, 29), ANIMCMD_FRAME(0, 29), // frame 0 is repeated ANIMCMD_JUMP(0), }; static const union AnimCmd *const sMonIconAnims[] = { sAnim_0, sAnim_1, sAnim_2, sAnim_3, sAnim_4, }; static const union AffineAnimCmd sAffineAnim_0[] = { AFFINEANIMCMD_FRAME(0, 0, 0, 10), AFFINEANIMCMD_END, }; static const union AffineAnimCmd sAffineAnim_1[] = { AFFINEANIMCMD_FRAME(-2, -2, 0, 122), AFFINEANIMCMD_END, }; static const union AffineAnimCmd *const sMonIconAffineAnims[] = { sAffineAnim_0, sAffineAnim_1, }; static const u16 sSpriteImageSizes[3][4] = { [ST_OAM_SQUARE] = { [SPRITE_SIZE(8x8)] = 8 * 8 / 2, [SPRITE_SIZE(16x16)] = 16 * 16 / 2, [SPRITE_SIZE(32x32)] = 32 * 32 / 2, [SPRITE_SIZE(64x64)] = 64 * 64 / 2, }, [ST_OAM_H_RECTANGLE] = { [SPRITE_SIZE(16x8)] = 16 * 8 / 2, [SPRITE_SIZE(32x8)] = 32 * 8 / 2, [SPRITE_SIZE(32x16)] = 32 * 16 / 2, [SPRITE_SIZE(64x32)] = 64 * 32 / 2, }, [ST_OAM_V_RECTANGLE] = { [SPRITE_SIZE(8x16)] = 8 * 16 / 2, [SPRITE_SIZE(8x32)] = 8 * 32 / 2, [SPRITE_SIZE(16x32)] = 16 * 32 / 2, [SPRITE_SIZE(32x64)] = 32 * 64 / 2, }, }; u8 CreateMonIcon(u16 species, void (*callback)(struct Sprite *), s16 x, s16 y, u8 subpriority, u32 personality) { u8 spriteId; struct MonIconSpriteTemplate iconTemplate = { .oam = &sMonIconOamData, .image = GetMonIconPtr(species, personality), .anims = sMonIconAnims, .affineAnims = sMonIconAffineAnims, .callback = callback, .paletteTag = POKE_ICON_BASE_PAL_TAG + gSpeciesInfo[species].iconPalIndex, }; species = SanitizeSpeciesId(species); if (species > NUM_SPECIES) iconTemplate.paletteTag = POKE_ICON_BASE_PAL_TAG; #if P_GENDER_DIFFERENCES else if (gSpeciesInfo[species].iconSpriteFemale != NULL && IsPersonalityFemale(species, personality)) iconTemplate.paletteTag = POKE_ICON_BASE_PAL_TAG + gSpeciesInfo[species].iconPalIndexFemale; #endif spriteId = CreateMonIconSprite(&iconTemplate, x, y, subpriority); UpdateMonIconFrame(&gSprites[spriteId]); return spriteId; } u8 CreateMonIconNoPersonality(u16 species, void (*callback)(struct Sprite *), s16 x, s16 y, u8 subpriority) { u8 spriteId; struct MonIconSpriteTemplate iconTemplate = { .oam = &sMonIconOamData, .image = NULL, .anims = sMonIconAnims, .affineAnims = sMonIconAffineAnims, .callback = callback, .paletteTag = POKE_ICON_BASE_PAL_TAG + gSpeciesInfo[species].iconPalIndex, }; iconTemplate.image = GetMonIconTiles(species, 0); spriteId = CreateMonIconSprite(&iconTemplate, x, y, subpriority); UpdateMonIconFrame(&gSprites[spriteId]); return spriteId; } u16 GetIconSpecies(u16 species, u32 personality) { species = SanitizeSpeciesId(species); if (species == SPECIES_UNOWN) species = GetUnownSpeciesId(personality); return species; } u16 GetUnownLetterByPersonality(u32 personality) { if (!personality) return 0; else return GET_UNOWN_LETTER(personality); } u16 GetIconSpeciesNoPersonality(u16 species) { species = SanitizeSpeciesId(species); if (MailSpeciesToSpecies(species, &species) == SPECIES_UNOWN) return species += SPECIES_UNOWN_B; // TODO return GetIconSpecies(species, 0); } const u8 *GetMonIconPtr(u16 species, u32 personality) { return GetMonIconTiles(GetIconSpecies(species, personality), personality); } void FreeAndDestroyMonIconSprite(struct Sprite *sprite) { FreeAndDestroyMonIconSprite_(sprite); } void LoadMonIconPalettes(void) { u8 i; for (i = 0; i < ARRAY_COUNT(gMonIconPaletteTable); i++) LoadSpritePalette(&gMonIconPaletteTable[i]); } // unused void SafeLoadMonIconPalette(u16 species) { u8 palIndex; palIndex = gSpeciesInfo[SanitizeSpeciesId(species)].iconPalIndex; if (IndexOfSpritePaletteTag(gMonIconPaletteTable[palIndex].tag) == 0xFF) LoadSpritePalette(&gMonIconPaletteTable[palIndex]); } void LoadMonIconPalette(u16 species) { u8 palIndex = gSpeciesInfo[SanitizeSpeciesId(species)].iconPalIndex; if (IndexOfSpritePaletteTag(gMonIconPaletteTable[palIndex].tag) == 0xFF) LoadSpritePalette(&gMonIconPaletteTable[palIndex]); } void LoadMonIconPalettePersonality(u16 species, u32 personality) { u8 palIndex; species = SanitizeSpeciesId(species); #if P_GENDER_DIFFERENCES if (gSpeciesInfo[species].iconSpriteFemale != NULL && IsPersonalityFemale(species, personality)) palIndex = gSpeciesInfo[species].iconPalIndexFemale; else #endif palIndex = gSpeciesInfo[species].iconPalIndex; if (IndexOfSpritePaletteTag(gMonIconPaletteTable[palIndex].tag) == 0xFF) LoadSpritePalette(&gMonIconPaletteTable[palIndex]); } void FreeMonIconPalettes(void) { u8 i; for (i = 0; i < ARRAY_COUNT(gMonIconPaletteTable); i++) FreeSpritePaletteByTag(gMonIconPaletteTable[i].tag); } // unused void SafeFreeMonIconPalette(u16 species) { u8 palIndex; palIndex = gSpeciesInfo[SanitizeSpeciesId(species)].iconPalIndex; FreeSpritePaletteByTag(gMonIconPaletteTable[palIndex].tag); } void FreeMonIconPalette(u16 species) { u8 palIndex; palIndex = gSpeciesInfo[SanitizeSpeciesId(species)].iconPalIndex; FreeSpritePaletteByTag(gMonIconPaletteTable[palIndex].tag); } void SpriteCB_MonIcon(struct Sprite *sprite) { UpdateMonIconFrame(sprite); } const u8 *GetMonIconTiles(u16 species, u32 personality) { const u8 *iconSprite; if (species > NUM_SPECIES) species = SPECIES_NONE; #if P_GENDER_DIFFERENCES if (gSpeciesInfo[species].iconSpriteFemale != NULL && IsPersonalityFemale(species, personality)) iconSprite = gSpeciesInfo[species].iconSpriteFemale; else #endif if (gSpeciesInfo[species].iconSprite != NULL) iconSprite = gSpeciesInfo[species].iconSprite; else iconSprite = gSpeciesInfo[SPECIES_NONE].iconSprite; return iconSprite; } void TryLoadAllMonIconPalettesAtOffset(u16 offset) { s32 i; if (offset <= BG_PLTT_ID(16 - ARRAY_COUNT(gMonIconPaletteTable))) { for (i = 0; i < (int)ARRAY_COUNT(gMonIconPaletteTable); i++) { LoadPalette(gMonIconPaletteTable[i].data, offset, PLTT_SIZE_4BPP); offset += 16; } } } u8 GetValidMonIconPalIndex(u16 species) { return gSpeciesInfo[SanitizeSpeciesId(species)].iconPalIndex; } u8 GetMonIconPaletteIndexFromSpecies(u16 species) { return gSpeciesInfo[SanitizeSpeciesId(species)].iconPalIndex; } const u16 *GetValidMonIconPalettePtr(u16 species) { return gMonIconPaletteTable[gSpeciesInfo[SanitizeSpeciesId(species)].iconPalIndex].data; } u8 UpdateMonIconFrame(struct Sprite *sprite) { u8 result = 0; if (sprite->animDelayCounter == 0) { s16 frame = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.imageValue; switch (frame) { case -1: break; case -2: sprite->animCmdIndex = 0; break; default: RequestSpriteCopy( // pointer arithmetic is needed to get the correct pointer to perform the sprite copy on. // because sprite->images is a struct def, it has to be casted to (u8 *) before any // arithmetic can be performed. (u8 *)sprite->images + (sSpriteImageSizes[sprite->oam.shape][sprite->oam.size] * frame), (u8 *)(OBJ_VRAM0 + sprite->oam.tileNum * TILE_SIZE_4BPP), sSpriteImageSizes[sprite->oam.shape][sprite->oam.size]); sprite->animDelayCounter = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.duration & 0xFF; sprite->animCmdIndex++; result = sprite->animCmdIndex; break; } } else { sprite->animDelayCounter--; } return result; } static u8 CreateMonIconSprite(struct MonIconSpriteTemplate *iconTemplate, s16 x, s16 y, u8 subpriority) { u8 spriteId; struct SpriteFrameImage image = { NULL, sSpriteImageSizes[iconTemplate->oam->shape][iconTemplate->oam->size] }; struct SpriteTemplate spriteTemplate = { .tileTag = TAG_NONE, .paletteTag = iconTemplate->paletteTag, .oam = iconTemplate->oam, .anims = iconTemplate->anims, .images = &image, .affineAnims = iconTemplate->affineAnims, .callback = iconTemplate->callback, }; spriteId = CreateSprite(&spriteTemplate, x, y, subpriority); gSprites[spriteId].animPaused = TRUE; gSprites[spriteId].animBeginning = FALSE; gSprites[spriteId].images = (const struct SpriteFrameImage *)iconTemplate->image; return spriteId; } static void FreeAndDestroyMonIconSprite_(struct Sprite *sprite) { struct SpriteFrameImage image = { NULL, sSpriteImageSizes[sprite->oam.shape][sprite->oam.size] }; sprite->images = ℑ DestroySprite(sprite); } void SetPartyHPBarSprite(struct Sprite *sprite, u8 animNum) { sprite->animNum = animNum; sprite->animDelayCounter = 0; sprite->animCmdIndex = 0; }