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. ## Contents 1. [Comparison of DMG, SGB, and CGB colors](#1-comparison-of-dmg-sgb-and-cgb-colors) 2. [Load SGB palettes for overworld maps](#2-load-sgb-palettes-for-overworld-maps) 3. [Make water, flower, and cave entrance tiles look like SGB](#3-make-water-flower-and-cave-entrance-tiles-look-like-sgb) ## 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. ![Screenshot](screenshots/gold-dmg-overworld.png) 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. ![Screenshot](screenshots/gold-sgb-overworld.png) As you can see, the SGB also supported decorative borders, since a TV screen had enough space to spare for one. ![Screenshot](screenshots/gold-sgb-battle.png) The CGB supported sixteen palettes: eight usable by background tiles, and eight by objects. ![Screenshot](screenshots/crystal-cgb-overworld.png) 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: ![Screenshot](screenshots/crystal-gbc-only.png) 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](#1-comparison-of-dmg-sgb-and-cgb-colors), 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: ![Screenshot](screenshots/sgb-map-palettes.png) Adapting more SGB palettes—the Pokédex, slot machines, Pokégear, trainer card, and so on—is left as an exercise for the reader. ;) TODO: apply other overworld SGB palettes (heal machine anim, battle transition, poision step, etc)