Skip to content

Customizable Pokédex Color

Grate Oracle Lewot edited this page Jan 29, 2024 · 10 revisions

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.

Contents

  1. Create a new WRAM byte
  2. Create color constants
  3. Add the Color option
  4. Making the Pokédex load the color
  5. Closing

1. Create a new WRAM Byte

Edit ram/wram.asm:

 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
 wRegisteredItem:: db

To start we create a WRAM byte. wLastDexMode has room after it and is also used by engine\pokedex\pokedex.asm.

2. Create color constants

Now we need some constants that'll be used to figure out which color is selected. Edit constants\wram_constants.asm:

 ; wCurDexMode::
	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
+       const DEXCOLOR_GRAY
+	const DEXCOLOR_MEWTWO

 ; wMonType::
	const_def
	const PARTYMON   ; 0
	const OTPARTYMON ; 1
	const BOXMON     ; 2
	const TEMPMON    ; 3
	const WILDMON    ; 4

3. Add the Color option

Edit engine\pokedex\pokedex.asm.

 ; 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.

 .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.

 Pokedex_InitOptionScreen:
	xor a
	ldh [hBGMapMode], a
	call ClearSprites
	call Pokedex_DrawOptionScreenBG
	call Pokedex_InitArrowCursor
-	; point cursor to the current dex mode (modes == menu item indexes)
-	ld a, [wCurDexMode]
	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.

 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.

 .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
	jp Pokedex_IncrementDexPointer

Here is the actual color option screen code, that should be placed after Pokedex_UnownModeUpdateCursorGfx. It's a modified version of Pokedex_InitOptionScreen that will also remember the cursor's location on the screen.

 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 Pokédex in the options menu. We had to change it from .Modes 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, 14, 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
	hlcoord 3, 11
	ld de, .Gray
	call Pokedex_PlaceString
	hlcoord 3, 12
	ld de, .Mewtwo
	jp Pokedex_PlaceString

 .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
	
 .Gray
	db "GRAY   ", $4f, -1	
	
 .Mewtwo
	db "MEWTWO ", $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, 10
	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 ; Cyan
	dwcoord 2,  11 ; Gray
	dwcoord 2,  12 ; Mewtwo
	
 .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
	dw .MenuAction_Gray
	dw .MenuAction_Mewtwo
	
 .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
	jr .ChangeColor	
	
 .MenuAction_Gray
	ld b, DEXCOLOR_GRAY
	jr .ChangeColor	

 .MenuAction_Mewtwo
	ld b, DEXCOLOR_MEWTWO
	
 .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. It's 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 it's 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.

 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   "<PK><MN> are listed by"
	next "evolution type.@"

 .OldMode:
	db   "<PK><MN> are listed by"
	next "official type.@"

 .ABCMode:
	db   "<PK><MN> 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 description for our new Pokédex menu option.

4. Making the Pokédex load the color

Now that everything's set up on the Pokédex side, we need it to actually load the correct color. Doing some digging reveals that what we need is located in 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:

 _CGB_Pokedex:
	ld de, wBGPals1
-	ld a, PREDEFPAL_POKEDEX
+	call CheckPokedexColor
	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
	...

+CheckPokedexColor:
+	ld a, [wCurPokedexColor]
+	cp DEXCOLOR_BLUE
+	jr nz, .Purple
+	ld a, PREDEFPAL_TRADE_TUBE
+	ret
+
+.Purple
+	cp DEXCOLOR_PURPLE
+	jr nz, .Brown
+	ld a, PREDEFPAL_RB_PURPLEMON
+	ret
+
+.Brown
+	cp DEXCOLOR_BROWN
+	jr nz, .Green
+	ld a, PREDEFPAL_RB_BROWNMON
+	ret
+
+.Green
+	cp DEXCOLOR_GREEN
+	jr nz, .Pink
+	ld a, PREDEFPAL_RB_GREENMON
+	ret
+
+.Pink
+	cp DEXCOLOR_PINK
+	jr nz, .Yellow
+	ld a, PREDEFPAL_RB_PINKMON
+	ret
+
+.Yellow
+	cp DEXCOLOR_YELLOW
+	jr nz, .Cyan
+	ld a, PREDEFPAL_RB_YELLOWMON
+	ret
+
+.Cyan
+	cp DEXCOLOR_CYAN
+	jr nz, .Gray
+	ld a, PREDEFPAL_RB_CYANMON
+	ret
+
+.Gray
+	cp DEXCOLOR_GRAY
+	jr nz, .Mewtwo
+	ld a, PREDEFPAL_CGB_BADGE
+	ret
+
+.Mewtwo
+	cp DEXCOLOR_MEWTWO
+	jr nz, .Red
+	ld a, PREDEFPAL_DIPLOMA
+	ret
+
+.Red
+	ld a, PREDEFPAL_POKEDEX
+	ret

 PokedexQuestionMarkPalette:
 INCLUDE "gfx/pokedex/question_mark.pal"

...

_CGB_PokedexUnownMode:
	ld de, wBGPals1
-	ld a, PREDEFPAL_POKEDEX
+	call CheckPokedexColor

...

_CGB_PokedexSearchOption:
	ld de, wBGPals1
-	ld a, PREDEFPAL_POKEDEX
+	call CheckPokedexColor
...

We replaced the inital load of PREDEFPAL_POKEDEX with CheckPokedexColor that finds the correct color and sets it. Do this for the other two mentioned locations and you're done.

5. Closing

Screenshot

The palettes I used were the unused palettes of the original Pokémon sprites in Red/Blue, but you can use any palette you like. This also has freed up some space on the options screen to allow for other Pokédex modes in addition to what's already there!

TODO: Cursor color

Clone this wiki locally