diff options
author | Rangi <remy.oukaour+rangi42@gmail.com> | 2019-01-19 21:57:05 -0500 |
---|---|---|
committer | Rangi <remy.oukaour+rangi42@gmail.com> | 2019-01-19 21:57:05 -0500 |
commit | 711b7c443255ec196cd8b727268d45de01e3a709 (patch) | |
tree | ddee1212b3c0d4541f34a635de45b843920611ff | |
parent | 8b6c56ddc6aa2f9f2a3817d4af638c202060fbd1 (diff) |
Use G/S SGB palettes for maps
-rw-r--r-- | Tutorials.md | 4 | ||||
-rw-r--r-- | Use-GS-SGB-palettes-for-maps.md | 280 | ||||
-rw-r--r-- | screenshots/crystal-cgb-overworld.png | bin | 0 -> 7994 bytes | |||
-rw-r--r-- | screenshots/crystal-gbc-only.png | bin | 0 -> 1315 bytes | |||
-rw-r--r-- | screenshots/gold-dmg-overworld.png | bin | 0 -> 4357 bytes | |||
-rw-r--r-- | screenshots/gold-sgb-battle.png | bin | 0 -> 8293 bytes | |||
-rw-r--r-- | screenshots/gold-sgb-overworld.png | bin | 0 -> 8614 bytes | |||
-rw-r--r-- | screenshots/sgb-map-palettes.png | bin | 0 -> 4405 bytes |
8 files changed, 282 insertions, 2 deletions
diff --git a/Tutorials.md b/Tutorials.md index e5e9c2a..80c92fd 100644 --- a/Tutorials.md +++ b/Tutorials.md @@ -60,7 +60,7 @@ Tutorials may use diff syntax to show edits: - [Remove the 25% failure chance for AI status moves](Remove-the-25%25-failure-chance-for-AI-status-moves) - [Remove the redundant move grammar table](Remove-the-redundant-move-grammar-table) -**Features from later generations:** +**Features from different generations:** - [Physical/Special split](Physical-Special-split) - [Replace stat experience with EVs](Replace-stat-experience-with-EVs) @@ -73,6 +73,7 @@ Tutorials may use diff syntax to show edits: - [Rock Climb](Rock-Climb) - [Dive](Dive) - [Puddles that splash when you walk](Puddles-that-splash-when-you-walk) +- [Use G/S SGB palettes for maps](Use-GS-SGB-palettes-for-maps) **To do:** *(feel free to contribute one of these!)* @@ -93,7 +94,6 @@ Tutorials may use diff syntax to show edits: - Colored party menu icons (overworld or battle sprite colors) - Option to show shiny colors in Pokédex - Automatic rain/sun/sandstorm on certain maps -- SGB-style colors for overworld maps and sprites - Implement dynamic overhead+underfoot bridges - Sideways stairs, with step types for diagonal movement and collisions to trigger it - Pan the camera for cutscenes by making the player invisible diff --git a/Use-GS-SGB-palettes-for-maps.md b/Use-GS-SGB-palettes-for-maps.md new file mode 100644 index 0000000..3ef83d2 --- /dev/null +++ b/Use-GS-SGB-palettes-for-maps.md @@ -0,0 +1,280 @@ +The Super Game Boy (SGB) was an adapter that let you play Game Boy games on a SNES, taking advantage of the console's hardware to add more colors than a Game Boy (DMG), but fewer than a Game Boy Color (CGB). Pokémon Gold and Silver supported all three systems, but Crystal was GBC-only. However, it has leftover unused code from G/S for SGB colors. This tutorial will apply the SGB colors to overworld maps, giving them a "retro" look. + + +## TOC + + +## 1. Comparison of DMG, SGB, and CGB colors + +A **palette** consists of four shades: white, light, dark, and black. + +The DMG (from the Game Boy's internal codename "Dot Matrix Game") was monochrome; its games had no concept of color, and the display hardware itself was a greenish monochrome. However, it supported three shade assignments at once: BGP for background tiles, and OBP0 and OBP1 for objects (aka sprites). G/S were designed to look good even with these limitations. + + + +The SGB supported four different palettes at once, and was backwards-compatible with DMG shade assignments. G/S, like Yellow, took advantage of this to give each city its own colors, as well as unique colors for different interfaces like the Pokédex, slot machines, and so on. + + + + + +The CGB supported sixteen palettes: eight usable by background tiles, and eight by objects. + + + +It also doubled the amount of video RAM, which Crystal needed for its extra graphics (like improved maps and in-battle sprite animations). That's why Crystal couldn't have supported the DMG or SGB: + + + +Despite only supporting the CGB, Crystal still has leftover SGB palette data from G/S. The [gfx/sgb/predef.pal](../blob/master/gfx/sgb/predef.pal) table defines most of the individual palettes, which were selectively loaded with the `GetPredefPal` routine in [engine/gfx/color.asm](../blob/master/engine/gfx/color.asm) and applied to regions of the screen by `LoadSGBLayout` in [engine/gfx/sgb_layouts.asm](../blob/master/engine/gfx/sgb_layouts.asm). (Since the SGB used an SNES and TV screen to display the game, that data was sent in "packets" from the Game Boy to the SNES for processing.) + +With that background knowledge, we can apply some SGB palettes to Crystal. It won't literally be playable on a Super Game Boy, but it will look like one. (At least the overworld maps will.) + + +## 2. Load SGB palettes for overworld maps + +Edit [engine/gfx/cgb_layouts.asm](../blob/master/engine/gfx/cgb_layouts.asm): + +```diff + _CGB_MapPals: +- call LoadMapPals ++; Get SGB palette ++ call LoadSGBLayout.GetMapPalsIndex ++ call GetPredefPal ++ ld de, wBGPals1 ++; Copy 7 BG palettes ++ ld b, 7 ++.bg_loop ++ call .LoadHLBGPaletteIntoDE ++ dec b ++ jr nz, .bg_loop ++; Copy PAL_BG_TEXT and 6 OB palettes ++ ld b, 7 ++.ob_loop ++ call .LoadHLOBPaletteIntoDE ++ dec b ++ jr nz, .ob_loop ++; Copy PAL_OW_TREE and PAL_OW_ROCK ++ call .LoadHLBGPaletteIntoDE ++ call .LoadHLBGPaletteIntoDE + ld a, SCGB_MAPPALS + ld [wSGBPredef], a + ret ++ ++.LoadHLBGPaletteIntoDE: ++; morn/day: shades 0, 1, 2, 3 -> 0, 1, 2, 3 ++; nite: shades 0, 1, 2, 3 -> 1, 2, 2, 3 ++ push hl ++ ld a, [wTimeOfDayPal] ++ cp NITE_F ++ jr c, .bg_morn_day ++ inc hl ++ inc hl ++ call .LoadHLColorIntoDE ++ call .LoadHLColorIntoDE ++ dec hl ++ dec hl ++ call .LoadHLColorIntoDE ++ call .LoadHLColorIntoDE ++.bg_done ++ pop hl ++ ret ++ ++.bg_morn_day ++ call LoadHLPaletteIntoDE ++ jr .bg_done ++ ++.LoadHLOBPaletteIntoDE: ++; shades 0, 1, 2, 3 -> 0, 0, 1, 3 ++ push hl ++ call .LoadHLColorIntoDE ++ dec hl ++ dec hl ++ call .LoadHLColorIntoDE ++ call .LoadHLColorIntoDE ++ inc hl ++ inc hl ++ call .LoadHLColorIntoDE ++ pop hl ++ ret ++ ++.LoadHLColorIntoDE: ++ ldh a, [rSVBK] ++ push af ++ ld a, BANK(wBGPals1) ++ ldh [rSVBK], a ++rept PAL_COLOR_SIZE ++ ld a, [hli] ++ ld [de], a ++ inc de ++endr ++ pop af ++ ldh [rSVBK], a ++ ret +``` + +The `LoadMapPals` routine in [engine/gfx/color.asm](../blob/master/engine/gfx/color.asm) was responsible for loading the palettes from [gfx/tilesets/bg_tiles.pal](../blob/master/gfx/tilesets/bg_tiles.pal) and [gfx/overworld/npc_sprites.pal](../blob/master/gfx/overworld/npc_sprites.pal) based on the environment and time of day. (Crystal also made it call `LoadSpecialMapPalette` in [engine/tilesets/tileset_palettes.asm](../blob/master/engine/tilesets/tileset_palettes.asm) to load new unique palettes like [gfx/tilesets/ice_path.pal](../blob/master/gfx/tilesets/ice_path.pal).) + +Anyway, we've replaced all of that with a call to `LoadSGBLayout.GetMapPalsIndex` in [engine/gfx/sgb_layouts.asm](../blob/master/engine/gfx/sgb_layouts.asm), which gets a single palette from [gfx/sgb/predef.pal](../blob/master/gfx/sgb/predef.pal) based on the environment and time of day. The rest of the code is applying the colors for that one palette to all sixteen CGB palettes, giving different shade assignments to background tiles and to objects. + + +## 3. Make water, flower, and cave entrance tiles look like SGB + +Edit [engine/tilesets/tileset_anims.asm](../blob/master/engine/tilesets/tileset_anims.asm): + +```diff + AnimateFlowerTile: + ; No parameters. + + ; Save sp in bc (see WriteTile). + ld hl, sp+0 + ld b, h + ld c, l + + ; Alternate tile graphic every other frame + ld a, [wTileAnimationTimer] + and %10 +- +-; CGB has different color mappings for flowers. +- ld e, a +- ldh a, [hCGB] +- and 1 +- add e +- + swap a + ld e, a + ld d, 0 + ld hl, FlowerTileFrames + add hl, de + ld sp, hl + + ld hl, vTiles2 tile $03 + + jp WriteTile + + FlowerTileFrames: + INCBIN "gfx/tilesets/flower/dmg_1.2bpp" + INCBIN "gfx/tilesets/flower/cgb_1.2bpp" + INCBIN "gfx/tilesets/flower/dmg_2.2bpp" + INCBIN "gfx/tilesets/flower/cgb_2.2bpp" +``` + +As you can see in the screenshots in [step 1](???), the waving flowers have different shading. + +```diff + AnimateWaterPalette: + ; Transition between color values 0-2 for color 0 in palette 3. + + ; No palette changes on DMG. +- ldh a, [hCGB] +- and a +- ret z +- +-; We don't want to mess with non-standard palettes. +- ldh a, [rBGP] ; BGP +- cp %11100100 +- ret nz +- +-; Only update on even frames. +- ld a, [wTileAnimationTimer] +- ld l, a +- and 1 ; odd +- ret nz +- +-; Ready for BGPD input... +- +- ld a, (1 << rBGPI_AUTO_INCREMENT) palette PAL_BG_WATER +- ldh [rBGPI], a +- +- ldh a, [rSVBK] +- push af +- ld a, BANK(wBGPals1) +- ldh [rSVBK], a +- +-; Update color 0 in order 0 1 2 1 +- ld a, l +- and %110 ; frames 0 2 4 6 +- jr z, .color0 +- cp %100 ; frame 4 +- jr z, .color2 +- +-.color1 +- ld hl, wBGPals1 palette PAL_BG_WATER color 1 +- ld a, [hli] +- ldh [rBGPD], a +- ld a, [hli] +- ldh [rBGPD], a +- jr .end +- +-.color0 +- ld hl, wBGPals1 palette PAL_BG_WATER color 0 +- ld a, [hli] +- ldh [rBGPD], a +- ld a, [hli] +- ldh [rBGPD], a +- jr .end +- +-.color2 +- ld hl, wBGPals1 palette PAL_BG_WATER color 2 +- ld a, [hli] +- ldh [rBGPD], a +- ld a, [hli] +- ldh [rBGPD], a +- +-.end +- pop af +- ldh [rSVBK], a + ret +``` + +CGB animated the "white" shade of `PAL_BG_WATER`, cycling it between the white, light, and dark shades. This was arguably a design flaw: it prevents that palette from being used for general-purpose blue things, and when it cycles to the dark shade, water ends up looking like solid dark blue. Here we've fixed the problem. + +```diff + FlickeringCaveEntrancePalette: + ; No palette changes on DMG. +- ldh a, [hCGB] +- and a +- ret z +-; We don't want to mess with non-standard palettes. +- ldh a, [rBGP] +- cp %11100100 +- ret nz +-; We only want to be here if we're in a dark cave. +- ld a, [wTimeOfDayPalset] +- cp %11111111 ; 3,3,3,3 +- ret nz +- +- ldh a, [rSVBK] +- push af +- ld a, BANK(wBGPals1) +- ldh [rSVBK], a +-; Ready for BGPD input... +- ld a, (1 << rBGPI_AUTO_INCREMENT) palette PAL_BG_YELLOW +- ldh [rBGPI], a +- ldh a, [hVBlankCounter] +- and %10 +- jr nz, .bit1set +- ld hl, wBGPals1 palette PAL_BG_YELLOW +- jr .okay +- +-.bit1set +- ld hl, wBGPals1 palette PAL_BG_YELLOW color 1 +- +-.okay +- ld a, [hli] +- ldh [rBGPD], a +- ld a, [hli] +- ldh [rBGPD], a +- +- pop af +- ldh [rSVBK], a + ret +``` + +CGB also animated `PAL_BG_YELLOW` inside of dark caves, giving their entrances a flickering look. This would not have been possible on the SGB, since every tile used the same BGP palette. For a more accurate retro look, we've disabled it. + +That's all it takes to make the overworld maps look like an SGB game: + + + +Adapting more SGB palettes—the Pokédex, slot machines, Pokégear, trainer card, and so on—is left as an exercise for the reader. ;) diff --git a/screenshots/crystal-cgb-overworld.png b/screenshots/crystal-cgb-overworld.png Binary files differnew file mode 100644 index 0000000..8c32e71 --- /dev/null +++ b/screenshots/crystal-cgb-overworld.png diff --git a/screenshots/crystal-gbc-only.png b/screenshots/crystal-gbc-only.png Binary files differnew file mode 100644 index 0000000..80a2dfd --- /dev/null +++ b/screenshots/crystal-gbc-only.png diff --git a/screenshots/gold-dmg-overworld.png b/screenshots/gold-dmg-overworld.png Binary files differnew file mode 100644 index 0000000..8503f55 --- /dev/null +++ b/screenshots/gold-dmg-overworld.png diff --git a/screenshots/gold-sgb-battle.png b/screenshots/gold-sgb-battle.png Binary files differnew file mode 100644 index 0000000..8f279b0 --- /dev/null +++ b/screenshots/gold-sgb-battle.png diff --git a/screenshots/gold-sgb-overworld.png b/screenshots/gold-sgb-overworld.png Binary files differnew file mode 100644 index 0000000..22b1067 --- /dev/null +++ b/screenshots/gold-sgb-overworld.png diff --git a/screenshots/sgb-map-palettes.png b/screenshots/sgb-map-palettes.png Binary files differnew file mode 100644 index 0000000..1b2d2d0 --- /dev/null +++ b/screenshots/sgb-map-palettes.png |