From fa9d7d248d7659cd79a64a741cd19d4922086677 Mon Sep 17 00:00:00 2001 From: PCG <75729017+PCG06@users.noreply.github.com> Date: Tue, 21 Jul 2026 17:32:57 +0530 Subject: [PATCH] =?UTF-8?q?Show=20Pok=C3=A9mon=20Icons=20in=20Dynamic=20Mu?= =?UTF-8?q?ltichoice=20(#10452)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/tutorials/how_to_dynmultichoice.md | 37 ++++++----- include/constants/script_menu.h | 1 + include/pokemon_icon.h | 1 + src/pokemon_icon.c | 30 +++++++++ src/script_menu.c | 84 ++++++++++++++++--------- 5 files changed, 109 insertions(+), 44 deletions(-) diff --git a/docs/tutorials/how_to_dynmultichoice.md b/docs/tutorials/how_to_dynmultichoice.md index e1d284e928..3042c79bf0 100644 --- a/docs/tutorials/how_to_dynmultichoice.md +++ b/docs/tutorials/how_to_dynmultichoice.md @@ -4,7 +4,7 @@ The dynamic multichoice macros is a feature created by SBird to replace the much ## The Macros There are three types of macros that you can use in your scripting, `dynmultichoice`, `dynmultipush`, and `dynmultistack`. -### **dynmultichoice`** +### **`dynmultichoice`** `dynmultichoice` is the simplest macro and what you'll use the most. Here's a sample of using `dynmultichoice` in your script: ``` EventScript_ExampleScript:: @@ -51,24 +51,24 @@ Here is a look at the macro and it's arguments: - Determines the **y-coordinate** of where your menu starts from its top-left corner (explanation below) #### ignoreBPress -- **Expected Value:**True/False -- Controls whether the player **can exit using the B button**. If set to **true**, the player **cannot exit**. | +- **Expected Value:** True/False +- Controls whether the player **can exit using the B button**. If set to **true**, the player **cannot exit**. #### maxBeforeScroll -- **Expected Value:**Integer -- Controls **how many options are shown** before the player has to scroll. | +- **Expected Value:** Integer +- Controls **how many options are shown** before the player has to scroll. #### initialSelected -- **Expected Value:**Integer -- **Chooses which option** (from a 0-index) **is already selected** upon opening the menu. | +- **Expected Value:** Integer +- **Chooses which option** (from a 0-index) **is already selected** upon opening the menu. #### callbacks -- **Expected Value:**Constant -- Designates **which callback** is used. Elaborated more later. | +- **Expected Value:** Constant +- Designates **which callback** is used. Elaborated more later. #### argv -- **Expected Value:**String -- **The choices** that the player can choose from the menu. | +- **Expected Value:** String +- **The choices** that the player can choose from the menu. *How to position arguments `left` and `top`*: @@ -558,9 +558,15 @@ static const struct DynamicListMenuEventCollection sDynamicListMenuEventCollecti }, [DYN_MULTICHOICE_CB_SHOW_ITEM] = { - .OnInit = MultichoiceDynamicEventShowItem_OnInit, + .OnInit = MultichoiceDynamicEventShowSprite_OnInit, .OnSelectionChanged = MultichoiceDynamicEventShowItem_OnSelectionChanged, - .OnDestroy = MultichoiceDynamicEventShowItem_OnDestroy + .OnDestroy = MultichoiceDynamicEventShowSprite_OnDestroy + }, + [DYN_MULTICHOICE_CB_SHOW_PKMN] = + { + .OnInit = MultichoiceDynamicEventShowSprite_OnInit, + .OnSelectionChanged = MultichoiceDynamicEventShowPkmn_OnSelectionChanged, + .OnDestroy = MultichoiceDynamicEventShowSprite_OnDestroy } }; ``` @@ -575,4 +581,7 @@ For `DYN_MULTICHOICE_CB_SHOW_ITEM`, the breakdown is as follows: - `.OnSelectionChanged`: Destroys the previous sprite, then draws the new sprite on screen. - `.OnDestroy`: Destroys the current sprite on screen. -`DYN_MULTICHOICE_CB_SHOW_ITEM` shows the item whose constant is equal to the current highlight option's ID. Each constant is listed in [`include/constants/items.h`](../../include/constants/items.h). An item with the ID 0 will show nothing, an item with the ID 1 will show a PokéBall, an item with the ID 2 will show a Great Ball, and so on. \ No newline at end of file +### Current callbacks that show sprites +- `DYN_MULTICHOICE_CB_SHOW_ITEM` shows the item whose constant is equal to the current highlight option's ID. Each constant is listed in [`include/constants/items.h`](../../include/constants/items.h). An item with the ID 0 will show nothing, an item with the ID 1 will show a PokéBall, an item with the ID 2 will show a Great Ball, and so on. + +- `DYN_MULTICHOICE_CB_SHOW_PKMN` shows the Pokémon's icon whose constant is equal to the current highlight option's ID. Each constant is listed in [`include/constants/species.h`](../../include/constants/species.h). A Pokémon with the ID 0 will show the decamark, a Pokémon with the ID 1 will show a Bulbasaur, a Pokémon with the ID 2 will show an Ivysaur, and so on. diff --git a/include/constants/script_menu.h b/include/constants/script_menu.h index 9813ab6a93..87724f26b4 100644 --- a/include/constants/script_menu.h +++ b/include/constants/script_menu.h @@ -230,6 +230,7 @@ enum { DYN_MULTICHOICE_CB_DEBUG, DYN_MULTICHOICE_CB_SHOW_ITEM, + DYN_MULTICHOICE_CB_SHOW_PKMN, //add new callback choices after this comment! DYN_MULTICHOICE_CB_NONE, diff --git a/include/pokemon_icon.h b/include/pokemon_icon.h index ad221c7a17..71bda4a75e 100644 --- a/include/pokemon_icon.h +++ b/include/pokemon_icon.h @@ -37,4 +37,5 @@ void SetPartyHPBarSprite(struct Sprite *sprite, u8 animNum); u8 GetMonIconPaletteIndexFromSpecies(enum Species species); void SafeFreeMonIconPalette(enum Species species); +u8 CreateTaggedMonIcon(u32 tileTag, u32 paletteTag, enum Species species); #endif // GUARD_POKEMON_ICON_H diff --git a/src/pokemon_icon.c b/src/pokemon_icon.c index 2b12fd80ce..02fc096cd3 100644 --- a/src/pokemon_icon.c +++ b/src/pokemon_icon.c @@ -204,6 +204,36 @@ u8 CreateMonIconNoPersonalityIsEgg(enum Species species, void (*callback)(struct return spriteId; } +u8 CreateTaggedMonIcon(u32 tileTag, u32 paletteTag, enum Species species) +{ + struct SpritePalette palette; + palette.data = gMonIconPaletteTable[gSpeciesInfo[SanitizeSpeciesId(species)].iconPalIndex].data; + palette.tag = paletteTag; + LoadSpritePalette(&palette); + + struct SpriteSheet spriteSheet; + spriteSheet.data = GetMonIconTilesIsEgg(species, 0, FALSE); + spriteSheet.size = 2 * sSpriteImageSizes[sMonIconOamData.shape][sMonIconOamData.size]; + spriteSheet.tag = tileTag; + LoadSpriteSheet(&spriteSheet); + + struct SpriteTemplate spriteTemplate = + { + .tileTag = tileTag, + .paletteTag = paletteTag, + .oam = &sMonIconOamData, + .anims = sMonIconAnims, + .images = NULL, + .affineAnims = sMonIconAffineAnims + }; + + u8 spriteId = CreateSprite(&spriteTemplate, 0, 0, 0); + gSprites[spriteId].animPaused = TRUE; + gSprites[spriteId].animBeginning = FALSE; + UpdateMonIconFrame(&gSprites[spriteId]); + return spriteId; +} + enum Species GetIconSpecies(enum Species species, u32 personality) { species = SanitizeSpeciesId(species); diff --git a/src/script_menu.c b/src/script_menu.c index a022aa072c..76e1bada8e 100644 --- a/src/script_menu.c +++ b/src/script_menu.c @@ -17,6 +17,7 @@ #include "malloc.h" #include "util.h" #include "item_icon.h" +#include "pokemon_icon.h" #include "constants/field_specials.h" #include "constants/items.h" #include "constants/script_menu.h" @@ -65,9 +66,10 @@ static void InitMultichoiceNoWrap(bool8 ignoreBPress, u8 unusedCount, u8 windowI static void MultichoiceDynamicEventDebug_OnInit(struct DynamicListMenuEventArgs *eventArgs); static void MultichoiceDynamicEventDebug_OnSelectionChanged(struct DynamicListMenuEventArgs *eventArgs); static void MultichoiceDynamicEventDebug_OnDestroy(struct DynamicListMenuEventArgs *eventArgs); -static void MultichoiceDynamicEventShowItem_OnInit(struct DynamicListMenuEventArgs *eventArgs); +static void MultichoiceDynamicEventShowSprite_OnInit(struct DynamicListMenuEventArgs *eventArgs); static void MultichoiceDynamicEventShowItem_OnSelectionChanged(struct DynamicListMenuEventArgs *eventArgs); -static void MultichoiceDynamicEventShowItem_OnDestroy(struct DynamicListMenuEventArgs *eventArgs); +static void MultichoiceDynamicEventShowPkmn_OnSelectionChanged(struct DynamicListMenuEventArgs *eventArgs); +static void MultichoiceDynamicEventShowSprite_OnDestroy(struct DynamicListMenuEventArgs *eventArgs); static const struct DynamicListMenuEventCollection sDynamicListMenuEventCollections[] = { @@ -79,9 +81,15 @@ static const struct DynamicListMenuEventCollection sDynamicListMenuEventCollecti }, [DYN_MULTICHOICE_CB_SHOW_ITEM] = { - .OnInit = MultichoiceDynamicEventShowItem_OnInit, + .OnInit = MultichoiceDynamicEventShowSprite_OnInit, .OnSelectionChanged = MultichoiceDynamicEventShowItem_OnSelectionChanged, - .OnDestroy = MultichoiceDynamicEventShowItem_OnDestroy + .OnDestroy = MultichoiceDynamicEventShowSprite_OnDestroy + }, + [DYN_MULTICHOICE_CB_SHOW_PKMN] = + { + .OnInit = MultichoiceDynamicEventShowSprite_OnInit, + .OnSelectionChanged = MultichoiceDynamicEventShowPkmn_OnSelectionChanged, + .OnDestroy = MultichoiceDynamicEventShowSprite_OnDestroy } }; @@ -156,10 +164,10 @@ static void MultichoiceDynamicEventDebug_OnDestroy(struct DynamicListMenuEventAr } #define sAuxWindowId sDynamicMenuEventScratchPad[0] -#define sItemSpriteId sDynamicMenuEventScratchPad[1] -#define TAG_CB_ITEM_ICON 3000 +#define sSpriteId sDynamicMenuEventScratchPad[1] +#define TAG_CB_SPRITE_ICON 3000 -static void MultichoiceDynamicEventShowItem_OnInit(struct DynamicListMenuEventArgs *eventArgs) +static void MultichoiceDynamicEventShowSprite_OnInit(struct DynamicListMenuEventArgs *eventArgs) { struct WindowTemplate *template = &gWindows[eventArgs->windowId].window; u32 baseBlock = template->baseBlock + template->width * template->height; @@ -169,44 +177,60 @@ static void MultichoiceDynamicEventShowItem_OnInit(struct DynamicListMenuEventAr FillWindowPixelBuffer(auxWindowId, 0x11); CopyWindowToVram(auxWindowId, COPYWIN_FULL); sAuxWindowId = auxWindowId; - sItemSpriteId = MAX_SPRITES; + sSpriteId = MAX_SPRITES; +} + +static void FreeSpriteIfUsed(void) +{ + if (sSpriteId != MAX_SPRITES) + { + FreeSpriteTilesByTag(TAG_CB_SPRITE_ICON); + FreeSpritePaletteByTag(TAG_CB_SPRITE_ICON); + DestroySprite(&gSprites[sSpriteId]); + } +} + +static void ChangeSpriteOnSelection(struct DynamicListMenuEventArgs *eventArgs, u32 x, u32 y) +{ + struct WindowTemplate *template = &gWindows[eventArgs->windowId].window; + x += template->tilemapLeft * 8 + template->width * 8; + y += template->tilemapTop * 8; + + gSprites[sSpriteId].oam.priority = 0; + gSprites[sSpriteId].x = x; + gSprites[sSpriteId].y = y; } static void MultichoiceDynamicEventShowItem_OnSelectionChanged(struct DynamicListMenuEventArgs *eventArgs) { - struct WindowTemplate *template = &gWindows[eventArgs->windowId].window; - u32 x = template->tilemapLeft * 8 + template->width * 8 + 36; - u32 y = template->tilemapTop * 8 + 20; - - if (sItemSpriteId != MAX_SPRITES) - { - FreeSpriteTilesByTag(TAG_CB_ITEM_ICON); - FreeSpritePaletteByTag(TAG_CB_ITEM_ICON); - DestroySprite(&gSprites[sItemSpriteId]); - } - - sItemSpriteId = AddItemIconSprite(TAG_CB_ITEM_ICON, TAG_CB_ITEM_ICON, eventArgs->selectedItem); - gSprites[sItemSpriteId].oam.priority = 0; - gSprites[sItemSpriteId].x = x; - gSprites[sItemSpriteId].y = y; + FreeSpriteIfUsed(); + sSpriteId = AddItemIconSprite(TAG_CB_SPRITE_ICON, TAG_CB_SPRITE_ICON, eventArgs->selectedItem); + ChangeSpriteOnSelection(eventArgs, 36, 20); } -static void MultichoiceDynamicEventShowItem_OnDestroy(struct DynamicListMenuEventArgs *eventArgs) +static void MultichoiceDynamicEventShowPkmn_OnSelectionChanged(struct DynamicListMenuEventArgs *eventArgs) +{ + FreeSpriteIfUsed(); + sSpriteId = CreateTaggedMonIcon(TAG_CB_SPRITE_ICON, TAG_CB_SPRITE_ICON, eventArgs->selectedItem); + ChangeSpriteOnSelection(eventArgs, 32, 14); +} + +static void MultichoiceDynamicEventShowSprite_OnDestroy(struct DynamicListMenuEventArgs *eventArgs) { ClearStdWindowAndFrame(sAuxWindowId, TRUE); RemoveWindow(sAuxWindowId); - if (sItemSpriteId != MAX_SPRITES) + if (sSpriteId != MAX_SPRITES) { - FreeSpriteTilesByTag(TAG_CB_ITEM_ICON); - FreeSpritePaletteByTag(TAG_CB_ITEM_ICON); - DestroySprite(&gSprites[sItemSpriteId]); + FreeSpriteTilesByTag(TAG_CB_SPRITE_ICON); + FreeSpritePaletteByTag(TAG_CB_SPRITE_ICON); + DestroySprite(&gSprites[sSpriteId]); } } #undef sAuxWindowId -#undef sItemSpriteId -#undef TAG_CB_ITEM_ICON +#undef sSpriteId +#undef TAG_CB_SPRITE_ICON static void FreeListMenuItems(struct ListMenuItem *items, u32 count) {