diff options
-rw-r--r-- | Option-to-show-shiny-colors-in-Pokédex.md | 175 |
1 files changed, 175 insertions, 0 deletions
diff --git a/Option-to-show-shiny-colors-in-Pokédex.md b/Option-to-show-shiny-colors-in-Pokédex.md new file mode 100644 index 0000000..b03297c --- /dev/null +++ b/Option-to-show-shiny-colors-in-Pokédex.md @@ -0,0 +1,175 @@ + + +(The code for this feature was adapted from Crystal Clear.) + +This implementation requires at least one WRAM byte. We'll also be using a single bit in order to handle the current status, leaving 7 more free for potential future features. + +Fortunately, there is space for this in the existing Pokédex struct. For posterity's sake, we'll also clean up the related 1.1 differences. You can quickly find these two spots in [wram.asm](../blob/master/wram.asm) by searching for `_CRYSTAL11` in your editor of choice. + +Edit [wram.asm](../blob/master/wram.asm): + +```diff + +wBackupDexListingCursor:: db +wBackupDexListingPage:: db +wDexCurLocation:: db +-if DEF(_CRYSTAL11) +wPokedexStatus:: db ++wPokedexShinyToggle:: ++; bit 0: set if displaying shiny palettes ++ db +wPokedexDataEnd:: +-else +-wPokedexDataEnd:: ds 1 +-endc +- ds 2 ++ ds 1 + +NEXTU ; c6d0 + +``` + +Since we removed the 1.1 differences in the first section, we'll want to do the same here. + +Edit [wram.asm](../blob/master/wram.asm): + +```diff + +NEXTU ; cf64 +; pokedex +wPrevDexEntryJumptableIndex:: db +-if DEF(_CRYSTAL11) +wPrevDexEntryBackup:: db +-else +-wPrevDexEntryBackup:: +-wPokedexStatus:: db +-endc + +NEXTU ; cf64 + +``` + +Now that we've got a byte, we need to locate where the engine loads the selected Pokémon palette. Inspecting [engine/pokedex/pokedex.asm](../blob/master/engine/pokedex/pokedex.asm) reveals the `SCGB_POKEDEX` constant, so we'll need to modify the cooresponding CGB layout. + +Within `_CGB_Pokedex`, we can see that is uses the function `GetMonPalettePointer`, in [engine/gfx/color.asm](../blob/master/engine/gfx/color.asm). Simply put, this function returns the pointer of a corresponding Pokémon palette in register `hl`, based on the species value in register `a`. + +The way that palette data is aligned within Pokémon Crystal is convenient. Each Pokémon's default palette is 4 bytes, and the next 4 bytes after are the shiny palette. + +With this in mind, the following implementation should be easier to understand. Whenever `_CGB_Pokedex` is called, the default palette is always loaded. Then, we check bit 0 of `wPokedexShinyToggle`, and if it's _not_ set (`jr z`), we jump ahead to loading the palette at `hl`. But if it _is_ set, we'll increment the value at `hl` 4 times, which will put us at the shiny palette! + +Edit `_CGB_Pokedex` in [engine/gfx/cgb_layouts.asm](../blob/master/engine/gfx/cgb_layouts.asm): + +```diff + +_CGB_Pokedex: + ld de, wBGPals1 + ld a, PREDEFPAL_POKEDEX + call GetPredefPal + call LoadHLPaletteIntoDE ; dex interface palette + ld a, [wCurPartySpecies] + cp $ff + jr nz, .is_pokemon + ld hl, .PokedexQuestionMarkPalette + call LoadHLPaletteIntoDE ; green question mark palette + jr .got_palette + +.is_pokemon + call GetMonPalettePointer ++ ld a, [wPokedexShinyToggle] ++ bit 0, a ++ jr z, .not_shiny ++ inc hl ++ inc hl ++ inc hl ++ inc hl ++.not_shiny + call LoadPalette_White_Col1_Col2_Black ; mon palette +.got_palette + +``` + +Now we have a WRAM byte, and code that uses it. All that's left is a way to set and clear the bit we're using. + +The quickest method is to take advantage of the fact that within the Pokédex, the `SELECT` button is unused when viewing a Pokédex entry. We can see that the joypad handling for this screen is in `Pokedex_UpdateDexEntryScreen`. We'll want to add the `SELECT` button handling first. + +Edit `Pokedex_UpdateDexEntryScreen` in [engine/pokedex/pokedex.asm](../blob/master/engine/pokedex/pokedex.asm): + +```diff + +Pokedex_UpdateDexEntryScreen: + ld de, DexEntryScreen_ArrowCursorData + call Pokedex_MoveArrowCursor + ld hl, hJoyPressed + ld a, [hl] + and B_BUTTON + jr nz, .return_to_prev_screen + ld a, [hl] + and A_BUTTON + jr nz, .do_menu_action ++ ld a, [hl] ++ and SELECT ++ jr nz, .toggle_shininess + call Pokedex_NextOrPreviousDexEntry + ret nc + call Pokedex_IncrementDexPointer + ret + +``` + +Then, at the end of the function, we'll add some code. First, we want to toggle the setting. So we check the `wPokedexShinyToggle` bit, and if it's not set, we'll set it and update the palettes. Otherwise if it's set, we'll clear the bit before updating the palettes. + +Edit `Pokedex_UpdateDexEntryScreen` in [engine/pokedex/pokedex.asm](../blob/master/engine/pokedex/pokedex.asm): + +```diff + +.max_volume + call MaxVolume + ld a, [wPrevDexEntryJumptableIndex] + ld [wJumptableIndex], a + ret + ++.toggle_shininess ++; toggle the current shininess setting ++ ld hl, wPokedexShinyToggle ++ bit 0, [hl] ++ jr z, .set ++ ; already set, so clear it ++ res 0, [hl] ++ jr .update_palettes ++.set ; bit is not set, so set it ++ set 0, [hl] ++.update_palettes ++; refresh palettes ++ ld a, SCGB_POKEDEX ++ call Pokedex_GetSGBLayout ++; play sound based on setting ++ ld de, SFX_BUMP ++ ld a, [wPokedexShinyToggle] ++ bit 0, a ++ jr z, .got_sound ++ ld de, SFX_SHINE ++.got_sound ++ call PlaySFX ++ jp WaitSFX + +``` + +While not strictly a requirement, there's some additional code here for some audio feedback when the `SELECT` button is pressed, based on the setting. You're free to use any SFX that you like, or if you want none at all, you can do this: + +```diff + +.update_palettes +; refresh palettes + ld a, SCGB_POKEDEX +- call Pokedex_GetSGBLayout +-; play sound based on setting +- ld de, SFX_BUMP +- ld a, [wPokedexShinyToggle] +- bit 0, a +- jr z, .got_sound +- ld de, SFX_SHINE +-.got_sound +- call PlaySFX +- jp WaitSFX ++ jp Pokedex_GetSGBLayout +``` |