summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Option-to-show-shiny-colors-in-Pokédex.md175
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 @@
+![Screenshot](https://i.imgur.com/4wZmDUu.png)
+
+(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
+```