dex-Color.md" Last-Modified: Sat, 21 Mar 2026 21:57:04 GMT Expires: Tue, 18 Mar 2036 21:57:04 GMT ETag: "1acc3760e9e8e29419d1a1e5ca1971cc296a8723" Ever wanted the color of your Pokédex to be something besides red? This is rather simple to implement in pokecrystal. All that's needed is a WRAM byte, and reworking some already existing code. ## 1. Create a WRAM Byte Edit [wram.asm](../blob/master/wram.asm): ```diff wPokegearFlags:: ; bit 0: map ; bit 1: radio ; bit 2: phone ; bit 3: expn ; bit 7: on/off db wRadioTuningKnob:: db wLastDexMode:: db - ds 1 +wCurPokedexColor:: db ; current dex color wWhichRegisteredItem:: db ; d95b wRegisteredItem:: db ; d95c ``` To start we create a wram byte. `wLastDexMode` has room after it and is also used by [engine\pokedex\pokedex.asm](../blob/master/engine/pokedex/pokedex.asm). ## 2. Create Constants Edit [constants\wram_constants.asm](../blob/master/constants/wram_constants.asm). ```diff ; wCurDexMode:: ; c7d4 const_def const DEXMODE_NEW const DEXMODE_OLD const DEXMODE_ABC const DEXMODE_UNOWN +; wPokedexColor + const_def + const DEXCOLOR_RED + const DEXCOLOR_BLUE + const DEXCOLOR_PURPLE + const DEXCOLOR_BROWN + const DEXCOLOR_GREEN + const DEXCOLOR_PINK + const DEXCOLOR_YELLOW + const DEXCOLOR_CYAN ; wMonType:: ; cf5f const_def const PARTYMON ; 0 const OTPARTYMON ; 1 const BOXMON ; 2 const TEMPMON ; 3 const WILDMON ; 4 ``` Now we need some constants that'll be used to figure out which color is seleceted. ## 3. Add the Color Option Edit [engine\pokedex\pokedex.asm](../blob/master/engine/pokedex/pokedex.asm). ```diff ; Pokedex_RunJumptable.Jumptable indexes const_def const DEXSTATE_MAIN_SCR const DEXSTATE_UPDATE_MAIN_SCR const DEXSTATE_DEX_ENTRY_SCR const DEXSTATE_UPDATE_DEX_ENTRY_SCR const DEXSTATE_REINIT_DEX_ENTRY_SCR const DEXSTATE_SEARCH_SCR const DEXSTATE_UPDATE_SEARCH_SCR const DEXSTATE_OPTION_SCR const DEXSTATE_UPDATE_OPTION_SCR const DEXSTATE_SEARCH_RESULTS_SCR const DEXSTATE_UPDATE_SEARCH_RESULTS_SCR const DEXSTATE_UNOWN_MODE const DEXSTATE_UPDATE_UNOWN_MODE + const DEXSTATE_COLOR_OPTION + const DEXSTATE_UPDATE_COLOR_OPTION const DEXSTATE_EXIT ``` First is to create the `const` DEXSTATEs that'll be used to determine the Color options screen. ```diff .Jumptable: ; entries correspond to DEXSTATE_* constants dw Pokedex_InitMainScreen dw Pokedex_UpdateMainScreen dw Pokedex_InitDexEntryScreen dw Pokedex_UpdateDexEntryScreen dw Pokedex_ReinitDexEntryScreen dw Pokedex_InitSearchScreen dw Pokedex_UpdateSearchScreen dw Pokedex_InitOptionScreen dw Pokedex_UpdateOptionScreen dw Pokedex_InitSearchResultsScreen dw Pokedex_UpdateSearchResultsScreen dw Pokedex_InitUnownMode dw Pokedex_UpdateUnownMode + dw Pokedex_InitColorOption + dw Pokedex_UpdateColorOption dw Pokedex_Exit ``` And to create the jumptable data for those screens. ```diff Pokedex_InitOptionScreen: xor a ldh [hBGMapMode], a call ClearSprites call Pokedex_DrawOptionScreenBG call Pokedex_InitArrowCursor - ld a, [wCurDexMode] ; Index of the topmost visible item in a scrolling menu ??? ld [wDexArrowCursorPosIndex], a call Pokedex_DisplayModeDescription call WaitBGMap ld a, SCGB_POKEDEX_SEARCH_OPTION call Pokedex_GetSGBLayout call Pokedex_IncrementDexPointer ret ``` This is to make sure the options menu starts at the top of the screen whenever the player enters it. Otherwise it'd begin at the second option. ```diff Pokedex_UpdateOptionScreen: ... .NoUnownModeArrowCursorData: - db D_UP | D_DOWN, 3 - dwcoord 2, 4 ; NEW - dwcoord 2, 6 ; OLD - dwcoord 2, 8 ; ABC + db D_UP | D_DOWN, 4 + dwcoord 2, 3 ; NEW + dwcoord 2, 4 ; OLD + dwcoord 2, 5 ; ABC + dwcoord 2, 6 ; COLOR .ArrowCursorData: - db D_UP | D_DOWN, 4 - dwcoord 2, 4 ; NEW - dwcoord 2, 6 ; OLD - dwcoord 2, 8 ; ABC - dwcoord 2, 10 ; UNOWN + db D_UP | D_DOWN, 5 + dwcoord 2, 3 ; NEW + dwcoord 2, 4 ; OLD + dwcoord 2, 5 ; ABC + dwcoord 2, 6 ; COLOR + dwcoord 2, 7 ; UNOWN ``` Here we're adding the color option to the cursor jumptable. You may notice that the `dwcoord` are changed as well. This is because in order to fit an extra option on the screen, along with a description of said option, we need to remove the space between each option. ```diff .MenuActionJumptable: dw .MenuAction_NewMode dw .MenuAction_OldMode dw .MenuAction_ABCMode + dw .MenuAction_ColorOption dw .MenuAction_UnownMode ... +.MenuAction_ColorOption + call Pokedex_BlackOutBG + ld a, DEXSTATE_COLOR_OPTION + ld [wJumptableIndex], a + ret .MenuAction_UnownMode: call Pokedex_BlackOutBG ld a, DEXSTATE_UNOWN_MODE ld [wJumptableIndex], a ret ``` Adding the Color option to the `.MenuActionJumptable`. As you can see, the menu action is a copy of the Unown Dex action, but it takes us to the color option instead. ``` Pokedex_InitColorOption: xor a ldh [hBGMapMode], a call ClearSprites call Pokedex_DrawColorScreenBG call Pokedex_InitArrowCursor ld a, [wCurPokedexColor] ld [wDexArrowCursorPosIndex], a call WaitBGMap ld a, SCGB_POKEDEX_SEARCH_OPTION call Pokedex_GetSGBLayout call Pokedex_IncrementDexPointer ret ``` Here is the actual color option screen code, that should be placed after `Pokedex_UnownModeUpdateCursorGfx` Its a modified `Pokedex_InitOptionScreen` that will also remember cursor's location on the screen. ```diff Pokedex_DrawOptionScreenBG: call Pokedex_FillBackgroundColor2 hlcoord 0, 2 lb bc, 8, 18 call Pokedex_PlaceBorder hlcoord 0, 12 lb bc, 4, 18 call Pokedex_PlaceBorder hlcoord 0, 1 ld de, .Title call Pokedex_PlaceString - hlcoord 3, 4 - ld de, .Modes - call PlaceString + hlcoord 3, 3 + ld de, .NewMode + call PlaceString + hlcoord 3, 4 + ld de, .OldMode + call PlaceString + hlcoord 3, 5 + ld de, .AtoZMode + call PlaceString + hlcoord 3, 6 + ld de, .Color + call PlaceString ld a, [wUnlockedUnownMode] and a ret z - hlcoord 3, 10 + hlcoord 3, 7 ld de, .UnownMode call PlaceString ret .Title: db $3b, " OPTION ", $3c, -1 -.Modes: - db "NEW #DEX MODE" - next "OLD #DEX MODE" - next "A to Z MODE" - db "@" - +.NewMode: + db "NEW #DEX MODE@" + +.OldMode: + db "OLD #DEX MODE@" + +.AtoZMode: + db "A to Z MODE@" + +.Color: + db "#DEX COLOR@" + .UnownMode: db "UNOWN MODE@" ``` This is where we add the text displayed by the dex in the options menu. We had to change it from `.Mode` since it would force there to be a space between each line of the options, this way we guarantee that each line will be uniform. ``` Pokedex_DrawColorScreenBG: call Pokedex_FillBackgroundColor2 hlcoord 0, 2 lb bc, 8, 18 call Pokedex_PlaceBorder hlcoord 0, 1 ld de, .Title call Pokedex_PlaceString hlcoord 3, 3 ld de, .Red call Pokedex_PlaceString hlcoord 3, 4 ld de, .Blue call Pokedex_PlaceString hlcoord 3, 5 ld de, .Purple call Pokedex_PlaceString hlcoord 3, 6 ld de, .Brown call Pokedex_PlaceString hlcoord 3, 7 ld de, .Green call Pokedex_PlaceString hlcoord 3, 8 ld de, .Pink call Pokedex_PlaceString hlcoord 3, 9 ld de, .Yellow call Pokedex_PlaceString hlcoord 3, 10 ld de, .Cyan call Pokedex_PlaceString ret .Title: db $3b, " COLORS ", $3c, -1 .Red db "RED ", $4f, -1 .Blue db "BLUE ", $4f, -1 .Purple db "PURPLE ", $4f, -1 .Brown db "BROWN ", $4f, -1 .Green db "GREEN ", $4f, -1 .Pink db "PINK ", $4f, -1 .Yellow db "YELLOW ", $4f, -1 .Cyan db "CYAN ", $4f, -1 Pokedex_UpdateColorOption: ld de, .ArrowCursorData call Pokedex_MoveArrowCursor ld hl, hJoyPressed ld a, [hl] and SELECT | B_BUTTON jr nz, .return_to_main_screen ld a, [hl] and A_BUTTON jr nz, .do_menu_action ret .ArrowCursorData: db D_UP | D_DOWN, 8 dwcoord 2, 3 ; Red dwcoord 2, 4 ; Blue dwcoord 2, 5 ; Purple dwcoord 2, 6 ; Brown dwcoord 2, 7 ; Green dwcoord 2, 8 ; Pink dwcoord 2, 9 ; Yellow dwcoord 2, 10 ; Gray .do_menu_action ld a, [wDexArrowCursorPosIndex] ld hl, .MenuActionJumptable call Pokedex_LoadPointer jp hl .return_to_main_screen call Pokedex_BlackOutBG ld a, DEXSTATE_MAIN_SCR ld [wJumptableIndex], a ret .MenuActionJumptable: dw .MenuAction_Red dw .MenuAction_Blue dw .MenuAction_Purple dw .MenuAction_Brown dw .MenuAction_Green dw .MenuAction_Pink dw .MenuAction_Yellow dw .MenuAction_Cyan .MenuAction_Red ld b, DEXCOLOR_RED jr .ChangeColor .MenuAction_Blue ld b, DEXCOLOR_BLUE jr .ChangeColor .MenuAction_Purple ld b, DEXCOLOR_PURPLE jr .ChangeColor .MenuAction_Brown ld b, DEXCOLOR_BROWN jr .ChangeColor .MenuAction_Green ld b, DEXCOLOR_GREEN jr .ChangeColor .MenuAction_Pink ld b, DEXCOLOR_PINK jr .ChangeColor .MenuAction_Yellow ld b, DEXCOLOR_YELLOW jr .ChangeColor .MenuAction_Cyan ld b, DEXCOLOR_CYAN .ChangeColor: ld a, [wCurPokedexColor] cp b jr z, .skip_changing_color ld a, b ld [wCurPokedexColor], a .skip_changing_color call Pokedex_BlackOutBG ld a, DEXSTATE_COLOR_OPTION ld [wJumptableIndex], a ret ``` This should be placed immediately after `.UnownMode`. This is the bread and butter of the color options screen. So let's break it down into its parts: `Pokedex_DrawColorScreenBG` Is actually what creates the color option screen. Its a copy of the already used `Pokedex_DrawOptionScreenBG`, just adjusted to what we need. `Pokedex_UpdateColorOption` is similarly a copy of `Pokedex_UpdateOptionScreen`, but modified to remove the extra window at the bottom, since the colors don't really need descriptions. Also it uses the same button actions as that screen. This is optional, but the reason we've added the Pokéball symbol beside each color option is because that is the only use of the lighter color in the palette, and will give the player an additional idea of what the color will look like on a whole, without having to completely leave the menu. Now the `.MenuActionJumptable` is a copy of the same one used by the options screen to update the Pokédex mode its in, but modified in a way that it loads `wCurPokedexColor` we created earilier with one of the corresponding palettes and then updates the screen so to apply the color. ```diff Pokedex_DisplayModeDescription: xor a ldh [hBGMapMode], a hlcoord 0, 12 lb bc, 4, 18 call Pokedex_PlaceBorder ld a, [wDexArrowCursorPosIndex] ld hl, .Modes call Pokedex_LoadPointer ld e, l ld d, h hlcoord 1, 14 call PlaceString ld a, $1 ldh [hBGMapMode], a ret .Modes: dw .NewMode dw .OldMode dw .ABCMode + dw .Color dw .UnownMode .NewMode: db " are listed by" next "evolution type.@" .OldMode: db " are listed by" next "official type.@" .ABCMode: db " are listed" next "alphabetically.@" +.Color + db "Change the color" + next "of the border.@" .UnownMode: db "UNOWN are listed" next "in catching order.@" ``` And finally this adds a desctription. ## 4. Making the Pokédex load the color Now that everything's set up on the Pokédex side, we it to actually load the correct color. Do some digging reveals that what we need is located in: [engine\gfx\cgb_layouts.asm](../blob/master/engine/gfx/cgb_layouts.asm). Searching the file for the default Pokédex color (`PREDEFPAL_POKEDEX`) will show it in `_CGB_Pokedex`, `_CGB_PokedexSearchOption`, and `_CGB_PokedexUnownMode`. ```diff _CGB_Pokedex: ld de, wBGPals1 - ld a, PREDEFPAL_POKEDEX + ld a, [wCurPokedexColor] + cp DEXCOLOR_BLUE + jr nz, .Purple + ld a, PREDEFPAL_TRADE_TUBE + jr .setColor +.Purple + cp DEXCOLOR_PURPLE + jr nz, .Brown + ld a, PREDEFPAL_RB_PURPLEMON + jr .setColor +.Brown + cp DEXCOLOR_BROWN + jr nz, .Green + ld a, PREDEFPAL_RB_BROWNMON + jr .setColor +.Green + cp DEXCOLOR_GREEN + jr nz, .Pink + ld a, PREDEFPAL_RB_GREENMON + jr .setColor +.Pink + cp DEXCOLOR_PINK + jr nz, .Yellow + ld a, PREDEFPAL_RB_PINKMON + jr .setColor +.Yellow + cp DEXCOLOR_YELLOW + jr nz, .Cyan + ld a, PREDEFPAL_RB_YELLOWMON + jr .setColor +.Cyan + cp DEXCOLOR_CYAN + jr nz, .Red + ld a, PREDEFPAL_RB_CYANMON + jr .setColor +.Red + ld a, PREDEFPAL_POKEDEX +.setColor 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 ``` We replaced the inital load of `PREDEFPAL_POKEDEX` with a chain comparison that finds the correct color and sets it. Do this for the other two mentioned locations and your done. ## 5. Closing ![Screenshot](https://i.imgur.com/dpYJ0QG.png) The palettes I used were the unused palettes of the original Pokémon sprites in Red/Blue, but you can use