diff options
author | Rangi <remy.oukaour+rangi42@gmail.com> | 2019-04-22 20:05:44 -0400 |
---|---|---|
committer | Rangi <remy.oukaour+rangi42@gmail.com> | 2019-04-22 20:05:44 -0400 |
commit | 2b6ffec27df8393f5fe82ee53a3627f99f71ab80 (patch) | |
tree | d7c05e7187f1ad63687f13dc4d7e04c91ca9648f | |
parent | d974ef1e165b9916c01754a68c2f47dd9797fcff (diff) |
Edit the male and female player colors
-rw-r--r-- | Edit-the-male-and-female-player-colors.md | 806 | ||||
-rw-r--r-- | Recolor-the-male-and-female-players.md | 16 | ||||
-rw-r--r-- | Tutorials.md | 2 |
3 files changed, 807 insertions, 17 deletions
diff --git a/Edit-the-male-and-female-player-colors.md b/Edit-the-male-and-female-player-colors.md new file mode 100644 index 0000000..56431d5 --- /dev/null +++ b/Edit-the-male-and-female-player-colors.md @@ -0,0 +1,806 @@ +The male player, Chris, is red, and the female player, Kris, is blue. This affects color palettes in a number of different places, including the introductory naming screen, the trainer card, the overworld sprite, the Town Map sprite, and the Magnet Train cutscene. It can be tricky to find and edit all of these places. + +As an example, we'll be making Chris gold (with a brown overworld sprite) and Kris teal (with a green overworld sprite). + + +## Contents + +1. [Edit the overworld sprite colors](#1-edit-the-overworld-sprite-colors) +2. [Edit the Pokégear colors](#2-edit-the-pokégear-colors) +3. [Define sprite animation constants](#3-define-sprite-animation-constants) +4. [Edit the sprite animation data](#4-edit-the-sprite-animation-data) +5. [Use the edited sprite animation data](#5-use-the-edited-sprite-animation-data) +6. [Sync the Pokégear and overworld palettes](#6-sync-the-pokégear-and-overworld-palettes) +7. [Edit the trainer constants](#7-edit-the-trainer-constants) +8. [Create trainer sprite palettes](#8-create-trainer-sprite-palettes) +9. [Give the catch tutorial Dude his own palette](#9-give-the-catch-tutorial-dude-his-own-palette) +10. [Edit the trainer card colors](#10-edit-the-trainer-card-colors) + + +## 1. Edit the overworld sprite colors + +Let's start with the overworld sprites. They don't need any custom colors, since you already have a small set of colors to choose from: red, blue, green, brown, or pink. (Although [nothing actually *uses* pink](Useful-unused-data-and-routines#pink-overworld-sprite-color), and you can change it to something else by editing [gfx/overworld/npc_sprites.pal](../blob/master/gfx/overworld/npc_sprites.pal). I favor purple, since so many default NPCs could have used it anyway: Eusine, Will, Koga, Janine, the Psychics, the Pokémaniacs...) + +Edit [data/sprites/sprites.asm](../blob/master/data/sprites/sprites.asm): + +```diff + OverworldSprites: + ; entries correspond to SPRITE_* constants +- overworld_sprite ChrisSpriteGFX, 12, WALKING_SPRITE, PAL_OW_RED +- overworld_sprite ChrisBikeSpriteGFX, 12, WALKING_SPRITE, PAL_OW_RED ++ overworld_sprite ChrisSpriteGFX, 12, WALKING_SPRITE, PAL_OW_BROWN ++ overworld_sprite ChrisBikeSpriteGFX, 12, WALKING_SPRITE, PAL_OW_BROWN + ... +- overworld_sprite KrisSpriteGFX, 12, WALKING_SPRITE, PAL_OW_BLUE +- overworld_sprite KrisBikeSpriteGFX, 12, WALKING_SPRITE, PAL_OW_BLUE ++ overworld_sprite KrisSpriteGFX, 12, WALKING_SPRITE, PAL_OW_GREEN ++ overworld_sprite KrisBikeSpriteGFX, 12, WALKING_SPRITE, PAL_OW_GREEN + ... +``` + +This affects the default colors of the sprites for Chris and Kris when some random `object_event` uses them, but it turns out that the *player's* object is initialized elsewhere. + +Edit [engine/overworld/player_object.asm](../blob/master/engine/overworld/player_object.asm): + +```diff + SpawnPlayer: + ld a, -1 + ld [wObjectFollow_Leader], a + ld [wObjectFollow_Follower], a + ld a, $0 + ld hl, PlayerObjectTemplate + call CopyPlayerObjectTemplate + ld b, $0 + call PlayerSpawn_ConvertCoords + ld a, PLAYER_OBJECT + call GetMapObject + ld hl, MAPOBJECT_COLOR + add hl, bc +- ln e, PAL_NPC_RED, OBJECTTYPE_SCRIPT ++ ln e, PAL_NPC_BROWN, OBJECTTYPE_SCRIPT + ld a, [wPlayerSpriteSetupFlags] + bit PLAYERSPRITESETUP_FEMALE_TO_MALE_F, a + jr nz, .ok + ld a, [wPlayerGender] + bit PLAYERGENDER_FEMALE_F, a + jr z, .ok +- ln e, PAL_NPC_BLUE, OBJECTTYPE_SCRIPT ++ ln e, PAL_NPC_GREEN, OBJECTTYPE_SCRIPT + + .ok + ... +``` + +There's also a brief moment after Prof. Oak's introductory speech, when your sprite gets shrunk to overworld size and you appear in your room, which has its own color setup. + +Edit [engine/menus/intro_menu.asm](../blob/master/engine/menus/intro_menu.asm): + +```diff +- ld b, PAL_OW_RED ++ ld b, PAL_OW_BROWN + ld a, [wPlayerGender] + bit PLAYERGENDER_FEMALE_F, a + jr z, .male +- ld b, PAL_OW_BLUE ++ ld b, PAL_OW_GREEN + .male + ld a, b +``` + +Of course, *before* your sprite is shrunk, you see its full-size trainer picture, which will also need color changing; but we'll get to that later. + +One more thing needs editing for the overworld colors. When you trade or battle in the Cable Club, a girl player will appear as a boy for compatibility reasons. + +Edit [maps/Pokecenter2F.asm](../blob/master/maps/Pokecenter2F.asm): + +```diff +- setval (PAL_NPC_RED << 4) ++ setval (PAL_NPC_BROWN << 4) + special SetPlayerPalette +``` + +```diff +- setval (PAL_NPC_BLUE << 4) ++ setval (PAL_NPC_GREEN << 4) + special SetPlayerPalette +``` + +There are *two* instances of `PAL_NPC_RED` and *three* of `PAL_NPC_BLUE`, all of which need editing. + + +## 2. Edit the Pokégear colors + +The Pokégear's card icons, and the cities on the Town Map, change color depending on your gender. + +Edit [gfx/pokegear/pokegear.pal](../blob/master/gfx/pokegear/pokegear.pal): + +```diff + ; city (boy) + RGB 28, 31, 20 +- RGB 31, 15, 00 +- RGB 15, 07, 00 ++ RGB 31, 23, 06 ++ RGB 23, 16, 00 + RGB 00, 00, 00 +``` + +Edit [gfx/pokegear/pokegear_f.pal](../blob/master/gfx/pokegear/pokegear_f.pal): + +```diff + ; city (girl) + RGB 28, 31, 20 +- RGB 10, 18, 31 +- RGB 13, 06, 31 ++ RGB 08, 25, 24 ++ RGB 00, 16, 18 + RGB 00, 00, 00 +``` + +I've made them gold and green respectively for the boy and girl, but these colors are independent of any of the sprite colors, so you can freely choose them. + + +## 3. Define sprite animation constants + +There are various parts of the game which *look* like they're using standard overworld NPC sprites—the Magnet Train ride animation, the Town Map, the naming screen—but actually they're using custom animations. The sprite animation system is somewhat complicated, with layers of abstract data referring to each other, so let's take it step by step. + +Edit [constants/sprite_anim_constants.asm](../blob/master/constants/sprite_anim_constants.asm): + +```diff + ; SpriteAnimSeqData indexes (see data/sprite_anims/sequences.asm) + const_def + const SPRITE_ANIM_INDEX_PARTY_MON ; 00 + ... + const SPRITE_ANIM_INDEX_RED_WALK ; 0a + ... +- const SPRITE_ANIM_INDEX_MAGNET_TRAIN_RED ; 15 ++ const SPRITE_ANIM_INDEX_MAGNET_TRAIN_BROWN ; 15 + ... +- const SPRITE_ANIM_INDEX_BLUE_WALK ; 1e ++ const SPRITE_ANIM_INDEX_GREEN_WALK ; 1e +- const SPRITE_ANIM_INDEX_MAGNET_TRAIN_BLUE ; 1f ++ const SPRITE_ANIM_INDEX_MAGNET_TRAIN_GREEN ; 1f + ... + const SPRITE_ANIM_INDEX_CELEBI ; 2c ++ const SPRITE_ANIM_INDEX_BROWN_WALK +``` + +```diff + ; SpriteAnimFrameData indexes (see data/sprite_anims/framesets.asm) + const_def + const SPRITE_ANIM_FRAMESET_00 ; 00 + ... + const SPRITE_ANIM_FRAMESET_RED_WALK ; 11 + ... +- const SPRITE_ANIM_FRAMESET_MAGNET_TRAIN_RED ; 1b ++ const SPRITE_ANIM_FRAMESET_MAGNET_TRAIN_BROWN ; 1b + ... +- const SPRITE_ANIM_FRAMESET_BLUE_WALK ; 2d ++ const SPRITE_ANIM_FRAMESET_GREEN_WALK ; 2d +- const SPRITE_ANIM_FRAMESET_MAGNET_TRAIN_BLUE ; 2e ++ const SPRITE_ANIM_FRAMESET_MAGNET_TRAIN_GREEN ; 2e + ... + const SPRITE_ANIM_FRAMESET_CELEBI_RIGHT ; 41 ++ const SPRITE_ANIM_FRAMESET_BROWN_WALK +``` + +```diff + ; SpriteAnimOAMData indexes (see data/sprite_anims/oam.asm) + const_def + const SPRITE_ANIM_OAMSET_RED_WALK_1 ; 00 + const SPRITE_ANIM_OAMSET_RED_WALK_2 ; 01 + ... +- const SPRITE_ANIM_OAMSET_MAGNET_TRAIN_RED_1 ; 41 +- const SPRITE_ANIM_OAMSET_MAGNET_TRAIN_RED_2 ; 42 ++ const SPRITE_ANIM_OAMSET_MAGNET_TRAIN_BROWN_1 ; 41 ++ const SPRITE_ANIM_OAMSET_MAGNET_TRAIN_BROWN_2 ; 42 + ... +- const SPRITE_ANIM_OAMSET_BLUE_WALK_1 ; 63 +- const SPRITE_ANIM_OAMSET_BLUE_WALK_2 ; 64 ++ const SPRITE_ANIM_OAMSET_GREEN_WALK_1 ; 63 ++ const SPRITE_ANIM_OAMSET_GREEN_WALK_2 ; 64 +- const SPRITE_ANIM_OAMSET_MAGNET_TRAIN_BLUE_1 ; 65 +- const SPRITE_ANIM_OAMSET_MAGNET_TRAIN_BLUE_2 ; 66 ++ const SPRITE_ANIM_OAMSET_MAGNET_TRAIN_GREEN_1 ; 65 ++ const SPRITE_ANIM_OAMSET_MAGNET_TRAIN_GREEN_2 ; 66 + ... + const SPRITE_ANIM_OAMSET_GAMEFREAK_LOGO_11 ; 8b ++ const SPRITE_ANIM_OAMSET_BROWN_WALK_1 ++ const SPRITE_ANIM_OAMSET_BROWN_WALK_2 +``` + +As we'll see next, the `SpriteAnimSeqData` entries refer to `SpriteAnimFrameData` entries, the `SpriteAnimFrameData` entries refer to `SpriteAnimOAMData` entries, and finally the `SpriteAnimOAMData` declare the actual colors that get used. + +Notice that we simply rename the `BLUE` constants to `GREEN`, but have to add some new ones for `BROWN` instead of renaming everything `RED`. This is because the `BLUE` data was added just for Crystal version, and it's only used for Kris, but the `RED` data has certain uses besides for Chris. + + +## 4. Edit the sprite animation data + +Now we'll edit the data files that correspond to those constants, as implied by the comments above each list. + +Edit [data/sprite_anims/sequences.asm](../blob/master/data/sprite_anims/sequences.asm): + +```diff + SpriteAnimSeqData: + ; entries correspond to SPRITE_ANIM_INDEX_* constants + ; frameset sequence, tile + db SPRITE_ANIM_FRAMESET_PARTY_MON, SPRITE_ANIM_SEQ_PARTY_MON, $00 ; SPRITE_ANIM_INDEX_PARTY_MON + ... +- db SPRITE_ANIM_FRAMESET_MAGNET_TRAIN_RED, SPRITE_ANIM_SEQ_NULL, $00 ; SPRITE_ANIM_INDEX_MAGNET_TRAIN_RED ++ db SPRITE_ANIM_FRAMESET_MAGNET_TRAIN_BROWN, SPRITE_ANIM_SEQ_NULL, $00 ; SPRITE_ANIM_INDEX_MAGNET_TRAIN_BROWN + ... +- db SPRITE_ANIM_FRAMESET_BLUE_WALK, SPRITE_ANIM_SEQ_NULL, $00 ; SPRITE_ANIM_INDEX_BLUE_WALK ++ db SPRITE_ANIM_FRAMESET_GREEN_WALK, SPRITE_ANIM_SEQ_NULL, $00 ; SPRITE_ANIM_INDEX_GREEN_WALK +- db SPRITE_ANIM_FRAMESET_MAGNET_TRAIN_BLUE, SPRITE_ANIM_SEQ_NULL, $00 ; SPRITE_ANIM_INDEX_MAGNET_TRAIN_BLUE ++ db SPRITE_ANIM_FRAMESET_MAGNET_TRAIN_GREEN, SPRITE_ANIM_SEQ_NULL, $00 ; SPRITE_ANIM_INDEX_MAGNET_TRAIN_GREEN + ... + db SPRITE_ANIM_FRAMESET_CELEBI_LEFT, SPRITE_ANIM_SEQ_NULL, $00 ; SPRITE_ANIM_INDEX_CELEBI ++ db SPRITE_ANIM_FRAMESET_BROWN_WALK, SPRITE_ANIM_SEQ_NULL, $00 ; SPRITE_ANIM_INDEX_BROWN_WALK +``` + +Edit [data/sprite_anims/framesets.asm](../blob/master/data/sprite_anims/framesets.asm): + +```diff + SpriteAnimFrameData: + ; entries correspond to SPRITE_ANIM_FRAMESET_* constants + dw .Frameset_00 + ... + dw .Frameset_RedWalk + ... +- dw .Frameset_MagnetTrainRed ++ dw .Frameset_MagnetTrainBrown + ... +- dw .Frameset_BlueWalk +- dw .Frameset_GreenWalk +- dw .Frameset_MagnetTrainBlue +- dw .Frameset_MagnetTrainGreen + ... + dw .Frameset_CelebiRight ++ dw .Frameset_BrownWalk +``` + +```diff +-.Frameset_BlueWalk: +- frame SPRITE_ANIM_OAMSET_BLUE_WALK_1, 8 +- frame SPRITE_ANIM_OAMSET_BLUE_WALK_2, 8 +- frame SPRITE_ANIM_OAMSET_BLUE_WALK_1, 8 +- frame SPRITE_ANIM_OAMSET_BLUE_WALK_2, 8, OAM_X_FLIP ++.Frameset_GreenWalk: ++ frame SPRITE_ANIM_OAMSET_GREEN_WALK_1, 8 ++ frame SPRITE_ANIM_OAMSET_GREEN_WALK_2, 8 ++ frame SPRITE_ANIM_OAMSET_GREEN_WALK_1, 8 ++ frame SPRITE_ANIM_OAMSET_GREEN_WALK_2, 8, OAM_X_FLIP + dorestart + +-.Frameset_MagnetTrainBlue: +- frame SPRITE_ANIM_OAMSET_MAGNET_TRAIN_BLUE_1, 8 +- frame SPRITE_ANIM_OAMSET_MAGNET_TRAIN_BLUE_2, 8 +- frame SPRITE_ANIM_OAMSET_MAGNET_TRAIN_BLUE_1, 8 +- frame SPRITE_ANIM_OAMSET_MAGNET_TRAIN_BLUE_2, 8, OAM_X_FLIP ++.Frameset_MagnetTrainGreen: ++ frame SPRITE_ANIM_OAMSET_MAGNET_TRAIN_GREEN_1, 8 ++ frame SPRITE_ANIM_OAMSET_MAGNET_TRAIN_GREEN_2, 8 ++ frame SPRITE_ANIM_OAMSET_MAGNET_TRAIN_GREEN_1, 8 ++ frame SPRITE_ANIM_OAMSET_MAGNET_TRAIN_GREEN_2, 8, OAM_X_FLIP + dorestart +``` + +```diff +-.Frameset_MagnetTrainRed: +- frame SPRITE_ANIM_OAMSET_MAGNET_TRAIN_RED_1, 8 +- frame SPRITE_ANIM_OAMSET_MAGNET_TRAIN_RED_2, 8 +- frame SPRITE_ANIM_OAMSET_MAGNET_TRAIN_RED_1, 8 +- frame SPRITE_ANIM_OAMSET_MAGNET_TRAIN_RED_2, 8, OAM_X_FLIP ++.Frameset_MagnetTrainBrown: ++ frame SPRITE_ANIM_OAMSET_MAGNET_TRAIN_BROWN_1, 8 ++ frame SPRITE_ANIM_OAMSET_MAGNET_TRAIN_BROWN_2, 8 ++ frame SPRITE_ANIM_OAMSET_MAGNET_TRAIN_BROWN_1, 8 ++ frame SPRITE_ANIM_OAMSET_MAGNET_TRAIN_BROWN_2, 8, OAM_X_FLIP + dorestart +``` + +```diff ++.Frameset_BrownWalk: ++ frame SPRITE_ANIM_OAMSET_BROWN_WALK_1, 8 ++ frame SPRITE_ANIM_OAMSET_BROWN_WALK_2, 8 ++ frame SPRITE_ANIM_OAMSET_BROWN_WALK_1, 8 ++ frame SPRITE_ANIM_OAMSET_BROWN_WALK_2, 8, OAM_X_FLIP ++ dorestart +``` + +And edit [data/sprite_anims/oam.asm](../blob/master/data/sprite_anims/oam.asm): + +```diff + SpriteAnimOAMData: + ; entries correspond to SPRITE_ANIM_OAMSET_* constants + ; vtile offset, data pointer + dbw $00, .OAMData_RedWalk ; SPRITE_ANIM_OAMSET_RED_WALK_1 + dbw $04, .OAMData_RedWalk ; SPRITE_ANIM_OAMSET_RED_WALK_2 + ... +- dbw $00, .OAMData_MagnetTrainRed ; SPRITE_ANIM_OAMSET_MAGNET_TRAIN_RED_1 +- dbw $04, .OAMData_MagnetTrainRed ; SPRITE_ANIM_OAMSET_MAGNET_TRAIN_RED_2 ++ dbw $00, .OAMData_MagnetTrainBrown ; SPRITE_ANIM_OAMSET_MAGNET_TRAIN_BROWN_1 ++ dbw $04, .OAMData_MagnetTrainBrown ; SPRITE_ANIM_OAMSET_MAGNET_TRAIN_BROWN_2 + ... +- dbw $00, .OAMData_BlueWalk ; SPRITE_ANIM_OAMSET_BLUE_WALK_1 +- dbw $04, .OAMData_BlueWalk ; SPRITE_ANIM_OAMSET_BLUE_WALK_2 ++ dbw $00, .OAMData_GreenWalk ; SPRITE_ANIM_OAMSET_GREEN_WALK_1 ++ dbw $04, .OAMData_GreenWalk ; SPRITE_ANIM_OAMSET_GREEN_WALK_2 +- dbw $00, .OAMData_MagnetTrainBlue ; SPRITE_ANIM_OAMSET_MAGNET_TRAIN_BLUE_1 +- dbw $04, .OAMData_MagnetTrainBlue ; SPRITE_ANIM_OAMSET_MAGNET_TRAIN_BLUE_2 ++ dbw $00, .OAMData_MagnetTrainGreen ; SPRITE_ANIM_OAMSET_MAGNET_TRAIN_GREEN_1 ++ dbw $04, .OAMData_MagnetTrainGreen ; SPRITE_ANIM_OAMSET_MAGNET_TRAIN_GREEN_2 + ... + dbw $00, .OAMData_GameFreakLogo4_11 ; SPRITE_ANIM_OAMSET_GAMEFREAK_LOGO_11 ++ dbw $00, .OAMData_BrownWalk ; SPRITE_ANIM_OAMSET_BROWN_WALK_1 ++ dbw $04, .OAMData_BrownWalk ; SPRITE_ANIM_OAMSET_BROWN_WALK_2 +``` + +```diff +-.OAMData_BlueWalk: ++.OAMData_GreenWalk: + db 4 +- dsprite -1, 0, -1, 0, $00, PAL_OW_BLUE +- dsprite -1, 0, 0, 0, $01, PAL_OW_BLUE +- dsprite 0, 0, -1, 0, $02, PAL_OW_BLUE +- dsprite 0, 0, 0, 0, $03, PAL_OW_BLUE ++ dsprite -1, 0, -1, 0, $00, PAL_OW_GREEN ++ dsprite -1, 0, 0, 0, $01, PAL_OW_GREEN ++ dsprite 0, 0, -1, 0, $02, PAL_OW_GREEN ++ dsprite 0, 0, 0, 0, $03, PAL_OW_GREEN + +-.OAMData_MagnetTrainBlue: ++.OAMData_MagnetTrainGreen: + db 4 +- dsprite -1, 0, -1, 0, $00, PAL_OW_BLUE | PRIORITY +- dsprite -1, 0, 0, 0, $01, PAL_OW_BLUE | PRIORITY +- dsprite 0, 0, -1, 0, $02, PAL_OW_BLUE | PRIORITY +- dsprite 0, 0, 0, 0, $03, PAL_OW_BLUE | PRIORITY ++ dsprite -1, 0, -1, 0, $00, PAL_OW_GREEN | PRIORITY ++ dsprite -1, 0, 0, 0, $01, PAL_OW_GREEN | PRIORITY ++ dsprite 0, 0, -1, 0, $02, PAL_OW_GREEN | PRIORITY ++ dsprite 0, 0, 0, 0, $03, PAL_OW_GREEN | PRIORITY +``` + +```diff ++.OAMData_BrownWalk: ++ db 4 ++ dsprite -1, 0, -1, 0, $00, PAL_OW_BROWN ++ dsprite -1, 0, 0, 0, $01, PAL_OW_BROWN ++ dsprite 0, 0, -1, 0, $02, PAL_OW_BROWN ++ dsprite 0, 0, 0, 0, $03, PAL_OW_BROWN ++ ++.OAMData_MagnetTrainBrown: ++ db 4 ++ dsprite -1, 0, -1, 0, $00, PAL_OW_BROWN | PRIORITY ++ dsprite -1, 0, 0, 0, $01, PAL_OW_BROWN | PRIORITY ++ dsprite 0, 0, -1, 0, $02, PAL_OW_BROWN | PRIORITY ++ dsprite 0, 0, 0, 0, $03, PAL_OW_BROWN | PRIORITY +``` + +Most of those changes were just renaming labels to avoid confusion. The only part that has a real effect on the game is the final part where the colors change. + + +## 5. Use the edited sprite animation data + +This will mostly be changing `RED` to `BROWN` and `BLUE` to `GREEN`, now that we have the appropriate data definitions for it. + +Edit [engine/events/magnet_train.asm](../blob/master/engine/events/magnet_train.asm): + +```diff + .InitPlayerSpriteAnim: + ld d, 10 * 8 + 5 + ld a, [wMagnetTrainPlayerSpriteInitX] + ld e, a +- ld b, SPRITE_ANIM_INDEX_MAGNET_TRAIN_RED ++ ld b, SPRITE_ANIM_INDEX_MAGNET_TRAIN_BROWN + ldh a, [rSVBK] + push af + ld a, BANK(wPlayerGender) + ldh [rSVBK], a + ld a, [wPlayerGender] + bit PLAYERGENDER_FEMALE_F, a + jr z, .got_gender +- ld b, SPRITE_ANIM_INDEX_MAGNET_TRAIN_BLUE ++ ld b, SPRITE_ANIM_INDEX_MAGNET_TRAIN_GREEN +``` + +Edit [engine/pokegear/pokegear.asm](../blob/master/engine/pokegear/pokegear.asm): + +```diff + PokegearMap_InitPlayerIcon: + push af + depixel 0, 0 +- ld b, SPRITE_ANIM_INDEX_RED_WALK ++ ld b, SPRITE_ANIM_INDEX_BROWN_WALK + ld a, [wPlayerGender] + bit PLAYERGENDER_FEMALE_F, a + jr z, .got_gender +- ld b, SPRITE_ANIM_INDEX_BLUE_WALK ++ ld b, SPRITE_ANIM_INDEX_GREEN_WALK + .got_gender + ... +``` + +```diff + Pokedex_GetArea: + ... + .ShowPlayerLoop: + ... + push bc +- ld c, PAL_OW_RED ++ ld c, PAL_OW_BROWN + ld a, [wPlayerGender] + bit PLAYERGENDER_FEMALE_F, a + jr z, .male +- inc c ; PAL_OW_BLUE ++ ld c, PAL_OW_GREEN + .male + ld a, c + ld [hli], a ; attributes + pop bc + jr .ShowPlayerLoop +``` + +```diff + TownMapPlayerIcon: + ; Draw the player icon at town map location in a + ... + ; Animation/palette + depixel 0, 0 +- ld b, SPRITE_ANIM_INDEX_RED_WALK ; Male ++ ld b, SPRITE_ANIM_INDEX_BROWN_WALK ; Male + ld a, [wPlayerGender] + bit PLAYERGENDER_FEMALE_F, a + jr z, .got_gender +- ld b, SPRITE_ANIM_INDEX_BLUE_WALK ; Female ++ ld b, SPRITE_ANIM_INDEX_GREEN_WALK ; Female + .got_gender + ... +``` + +Edit [engine/menus/naming_screen.asm](../blob/master/engine/menus/naming_screen.asm): + +```diff + .LoadSprite: + ... + ld b, SPRITE_ANIM_INDEX_RED_WALK ++ ld a, d ++ cp HIGH(ChrisSpriteGFX) ++ jr nz, .not_chris ++ ld a, e ++ cp LOW(ChrisSpriteGFX) ++ jr nz, .not_chris ++ ld b, SPRITE_ANIM_INDEX_BROWN_WALK ++ jr .not_kris ++.not_chris + ld a, d + cp HIGH(KrisSpriteGFX) + jr nz, .not_kris + ld a, e + cp LOW(KrisSpriteGFX) + jr nz, .not_kris +- ld b, SPRITE_ANIM_INDEX_BLUE_WALK ++ ld b, SPRITE_ANIM_INDEX_GREEN_WALK + .not_kris + ld a, b + depixel 4, 4, 4, 0 + call _InitSpriteAnimStruct + ret +``` + +Notice how the naming screen does not simply change `SPRITE_ANIM_INDEX_RED_WALK` to `SPRITE_ANIM_INDEX_BROWN_WALK`; it only does so if the current sprite is using `ChrisSpriteGFX`. That's because the default `SPRITE_ANIM_INDEX_RED_WALK` also gets used for naming other things, including your rival, your Pokémon, and Bill's PC boxes. + + +## 6. Sync the Pokégear and overworld palettes + +The previous step should make the Town Map use the correct colors, but there's actually one more thing to do for it. The colors available within the party menu and Pokégear aren't the same as the ones for the overworld. By default, they didn't have to be; all the party Pokémon icons are red, and the Town Map icons can only be red or blue. But it's more convenient to have all the overworld colors available, and it won't break anything to do so. + +Edit [gfx/stats/party_menu_ob.pal](../blob/master/gfx/stats/party_menu_ob.pal): + +```diff + RGB 27, 31, 27 + RGB 31, 19, 10 +- RGB 31, 07, 04 ++ RGB 31, 07, 01 + RGB 00, 00, 00 + + RGB 27, 31, 27 + RGB 31, 19, 10 +- RGB 10, 14, 20 ++ RGB 10, 09, 31 + RGB 00, 00, 00 + + RGB 27, 31, 27 + RGB 31, 19, 10 +- RGB 31, 07, 04 ++ RGB 07, 23, 03 + RGB 00, 00, 00 + + RGB 27, 31, 27 + RGB 31, 19, 10 +- RGB 31, 07, 04 ++ RGB 15, 10, 03 + RGB 00, 00, 00 + + RGB 27, 31, 27 + RGB 31, 19, 10 +- RGB 31, 07, 04 ++ RGB 30, 10, 06 + RGB 00, 00, 00 + + ... +``` + +These are the same red, blue, green, brown, and pink colors as in [gfx/overworld/npc_sprites.pal](../blob/master/gfx/overworld/npc_sprites.pal). So if you edit anything in one file, make the same edit in the other. + + +## 7. Edit the trainer constants + +We're finally getting to edit the "trainer sprite" colors. Of course, the players Chris and Kris don't really have trainer data defined, but they use the same color table as trainers for their intro sprites, Trainer Cards, and battle back sprites. + +Edit [constants/trainer_constants.asm](../blob/master/constants/trainer_constants.asm): + +```diff + ; trainer class ids + ; `trainerclass` indexes are for: + ; - TrainerClassNames (see data/trainers/class_names.asm) + ; - TrainerClassAttributes (see data/trainers/attributes.asm) + ; - TrainerClassDVs (see data/trainers/dvs.asm) + ; - TrainerGroups (see data/trainers/party_pointers.asm) + ; - TrainerEncounterMusic (see data/trainers/encounter_music.asm) + ; - TrainerPicPointers (see data/trainers/pic_pointers.asm) + ; - TrainerPalettes (see data/trainers/palettes.asm) + ; - BTTrainerClassSprites (see data/trainers/sprites.asm) + ; - BTTrainerClassGenders (see data/trainers/genders.asm) + ; trainer constants are Trainers indexes, for the sub-tables of TrainerGroups (see data/trainers/parties.asm) + enum_start + CHRIS EQU __enum__ + trainerclass TRAINER_NONE ; 0 + const PHONECONTACT_MOM + const PHONECONTACT_BIKESHOP + const PHONECONTACT_BILL + const PHONECONTACT_ELM + const PHONECONTACT_BUENA + +-KRIS EQU __enum__ + trainerclass FALKNER ; 1 + const FALKNER1 + + ... + + trainerclass MYSTICALMAN ; 43 + const EUSINE + ++KRIS EQU __enum__ + NUM_TRAINER_CLASSES EQU __enum__ +``` + +`CHRIS` corresponds to the unusable `TRAINER_NONE`, which is fine. But `KRIS` was actually just an alias for `FALKNER`—they use the exact same sprite color. Here we've moved `KRIS` to be after the very last trainer class. Just like `CHRIS`, she won't need any trainer data except a color palette, which we'll do next. + + +## 8. Create trainer sprite palettes + +Create **gfx/player/chris.pal**: + +```diff ++ RGB 30, 21, 14 ++ RGB 22, 15, 00 +``` + +And create **gfx/player/kris/pal**: + +```diff ++ RGB 30, 22, 17 ++ RGB 00, 18, 15 +``` + +Then edit [data/trainers/palettes.asm](../blob/master/data/trainers/palettes.asm): + +```diff + TrainerPalettes: + ; entries correspond to trainer classes + + ; Each .gbcpal is generated from the corresponding .png, and + ; only the middle two colors are included, not black or white. + +-PlayerPalette: ; Chris uses the same colors as Cal +-INCBIN "gfx/trainers/cal.gbcpal", middle_colors ++PlayerPalette: ++INCLUDE "gfx/player/chris.pal" ++ +-KrisPalette: ; Kris shares Falkner's palette + INCBIN "gfx/trainers/falkner.gbcpal", middle_colors + ... ++DudePalette: + INCBIN "gfx/trainers/cal.gbcpal", middle_colors + ... + INCBIN "gfx/trainers/mysticalman.gbcpal", middle_colors ++ ++KrisPalette: ++INCLUDE "gfx/player/kris.pal" +``` + +Previously, Chris was using the same colors as Cal (the boy player lookalike whom you battle in Viridian City's Trainer House); and Kris was literally using Falkner's palette (which makes sense, given that `KRIS` and `FALKNER` were equivalent). Now they both have their own independent palettes. + +Notice how they `INCLUDE` .pal files, not `INCBIN` .gbcpal files. That's because the .gbcpal files are automatically generated from trainer sprites' .png files, whereas we manually created the players' palettes. + +Remember, Chris (the boy player) has to be the first entry, and Kris (the girl player) has to be the last. The `ChrisPalette` and `KrisPalette` labels are sometimes used to directly access their palettes, but sometimes the game relies on their index order. So if you add any new trainer classes, make sure they stay in order. + +Also note the new `DudePalette` label. Before editing the trainer card, let's see how that gets used. + + +## 9. Give the catch tutorial Dude his own palette + +When the Dude on Route 29 shows you how to catch Pokémon, his back sprite shares the same color as the player (red for a boy, blue for a girl), even though his overworld sprite is always red. Now that we're changing the player colors, it would be nice if the Dude has a consistent color of his own. + +Edit [engine/gfx/color.asm](../blob/master/engine/gfx/color.asm): + +```diff + GetPlayerOrMonPalettePointer: + and a + jp nz, GetMonNormalOrShinyPalettePointer + ld a, [wPlayerSpriteSetupFlags] + bit PLAYERSPRITESETUP_FEMALE_TO_MALE_F, a + jr nz, .male ++ ld a, [wBattleType] ++ cp BATTLETYPE_TUTORIAL ++ jr z, .dude + ld a, [wPlayerGender] + and a + jr z, .male + ld hl, KrisPalette + ret + + .male + ld hl, PlayerPalette + ret ++ ++.dude ++ ld hl, DudePalette ++ ret +``` + +I placed the `DudePalette` label so that he shares Cal's palette, since that's what he used originally, but you can put that label anywhere. It doesn't even have to be among the trainer colors. If your catch tutorial NPC needs a custom color, just define it with two `RGB` macros, the same as chris.pal and kris.pal, and `INCLUDE` it with the `DudePalette` label after the `GetPlayerOrMonPalettePointer` routine. + +Anyway, it's time for the last colors to change: the trainer card. + + +## 10. Edit the trainer card colors + +The trainer card "cheats" a little bit. The Game Boy Color hardware only allows eight palettes at a time for BG tiles, as we can see with [BGB](http://bgb.bircd.org/)'s VRAM viewer: + + + +But the trainer card wants ten: one for the player's sprite, one for the border, and eight unique Gym Leader faces. So what the game designers did is pick two pairs of those to share palettes. We already saw how Kris and Falkner used the exact same palette, and in fact, the trainer card used that palette for Clair's face too, even though her trainer sprite is a different shade of blue. + + + +But now that Kris is her own shade of green, we'll have to rethink this design. In the example below, I chose to make Falkner and Clair share a palette, and Chuck and Pryce share a palette. Depending on how your Gym Leaders look, you may have a better choice available. + +Edit [engine/gfx/cgb_layouts.asm](../blob/master/engine/gfx/cgb_layouts.asm): + +```diff + _CGB_TrainerCard: + ld de, wBGPals1 + xor a ; CHRIS + call GetTrainerPalettePointer + call LoadPalette_White_Col1_Col2_Black +- ld a, FALKNER ; KRIS ++ ld a, KRIS + call GetTrainerPalettePointer + call LoadPalette_White_Col1_Col2_Black + ld a, BUGSY + call GetTrainerPalettePointer + call LoadPalette_White_Col1_Col2_Black + ld a, WHITNEY + call GetTrainerPalettePointer + call LoadPalette_White_Col1_Col2_Black + ld a, MORTY + call GetTrainerPalettePointer + call LoadPalette_White_Col1_Col2_Black +- ld a, CHUCK ++ ld a, FALKNER ; CLAIR + call GetTrainerPalettePointer + call LoadPalette_White_Col1_Col2_Black + ld a, JASMINE + call GetTrainerPalettePointer + call LoadPalette_White_Col1_Col2_Black +- ld a, PRYCE ++ ld a, PRYCE ; CHUCK + call GetTrainerPalettePointer + call LoadPalette_White_Col1_Col2_Black + ld a, PREDEFPAL_CGB_BADGE + call GetPredefPal + call LoadHLPaletteIntoDE + + ; fill screen with opposite-gender palette for the card border + hlcoord 0, 0, wAttrMap + ld bc, SCREEN_WIDTH * SCREEN_HEIGHT + ld a, [wPlayerGender] + and a + ld a, $1 ; kris + jr z, .got_gender + ld a, $0 ; chris + .got_gender + call ByteFill + ; fill trainer sprite area with same-gender palette + hlcoord 14, 1, wAttrMap + lb bc, 7, 5 + ld a, [wPlayerGender] + and a + ld a, $0 ; chris + jr z, .got_gender2 + ld a, $1 ; kris + .got_gender2 + call FillBoxCGB +- ; top-right corner still uses the border's palette +- hlcoord 18, 1, wAttrMap +- ld [hl], $1 + hlcoord 2, 11, wAttrMap + lb bc, 2, 4 +- ld a, $1 ; falkner ++ ld a, $5 ; falkner + call FillBoxCGB + hlcoord 6, 11, wAttrMap + lb bc, 2, 4 + ld a, $2 ; bugsy + call FillBoxCGB + hlcoord 10, 11, wAttrMap + lb bc, 2, 4 + ld a, $3 ; whitney + call FillBoxCGB + hlcoord 14, 11, wAttrMap + lb bc, 2, 4 + ld a, $4 ; morty + call FillBoxCGB + hlcoord 2, 14, wAttrMap + lb bc, 2, 4 +- ld a, $5 ; chuck ++ ld a, $7 ; chuck + call FillBoxCGB + hlcoord 6, 14, wAttrMap + lb bc, 2, 4 + ld a, $6 ; jasmine + call FillBoxCGB + hlcoord 10, 14, wAttrMap + lb bc, 2, 4 + ld a, $7 ; pryce + call FillBoxCGB +- ; clair uses kris's palette +- ld a, [wPlayerGender] +- and a +- push af +- jr z, .got_gender3 + hlcoord 14, 14, wAttrMap + lb bc, 2, 4 +- ld a, $1 ++ ld a, $5 ; clair + call FillBoxCGB +-.got_gender3 +- pop af +- ld c, $0 +- jr nz, .got_gender4 +- inc c +-.got_gender4 +- ld a, c ++ ; top-right corner still uses the border's palette + hlcoord 18, 1, wAttrMap ++ ld a, [wPlayerGender] ++ and a ++ ld a, $1 ; kris ++ jr z, .got_gender3 ++ ld a, $0 ; chris ++.got_gender3 + ld [hl], a + call ApplyAttrMap + call ApplyPals + ld a, $1 + ldh [hCGBPalUpdate], a + ret +``` + +Basically this routine has two stages: it loads eight trainers' palettes with `GetTrainerPalettePointer` and `LoadPalette_White_Col1_Col2_Black`, and then it applies those palettes to rectangular areas of the 20x18 screen with `FillBoxCGB`. It happens to always load both the boy and girl palettes, using one for the player's sprite and the other for the card border, but you can always change that logic if you want a different border color. Just remember that only eight palettes in total can be used. + +Anyway, with that, we're all done. Every player-related aspect of the game is recolored for both the boy and girl options. + + diff --git a/Recolor-the-male-and-female-players.md b/Recolor-the-male-and-female-players.md deleted file mode 100644 index e50ded7..0000000 --- a/Recolor-the-male-and-female-players.md +++ /dev/null @@ -1,16 +0,0 @@ -The male player, Chris, is red, and the female player, Kris, is blue. This affects color palettes in a number of different places, including the introductory naming screen, the trainer card, the overworld sprite, the Town Map sprite, and the Magnet Train cutscene. - -Here, we'll be making Chris gold/brown and Kris teal/green. - - -## TOC - - -TODO - - - - - - - diff --git a/Tutorials.md b/Tutorials.md index 2d91584..54dba64 100644 --- a/Tutorials.md +++ b/Tutorials.md @@ -55,7 +55,7 @@ Tutorials may use diff syntax to show edits: - [Town Map](Edit-the-Town-Map) - [Battle HUD](Edit-the-battle-HUD) (*TODO*) -- [Male and female player colors](Recolor-the-male-and-female-players) (*TODO*) +- [Male and female player colors](Edit-the-male-and-female-player-colors) ## Upgrades to existing features |