summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRemy Oukaour <remy.oukaour@gmail.com>2018-01-26 20:44:48 -0500
committerRemy Oukaour <remy.oukaour@gmail.com>2018-01-26 20:44:48 -0500
commit2c6525e6d5fdb2aecb71220a319ae570f16143d4 (patch)
tree070cc5df9084bc94acf196e5fc9bdd656273e4aa
parentade9a9738089c67289dfb3f63cff69fe8b9ab201 (diff)
Tutorial: Allow map tiles to appear above sprites
-rw-r--r--Allow-map-tiles-to-appear-above-sprites.md209
-rw-r--r--Make-Overhead-Tiles.md102
-rw-r--r--Tutorials.md1
-rw-r--r--screenshots/tile-priority.pngbin0 -> 1461 bytes
4 files changed, 210 insertions, 102 deletions
diff --git a/Allow-map-tiles-to-appear-above-sprites.md b/Allow-map-tiles-to-appear-above-sprites.md
new file mode 100644
index 0000000..094d01e
--- /dev/null
+++ b/Allow-map-tiles-to-appear-above-sprites.md
@@ -0,0 +1,209 @@
+Usually on overworld maps, sprites go on top of tiles. But there are exceptions: grass tiles overlap you as you walk, and the popup signs with location names (made of tiles) appear above all the NPC sprites.
+
+It's possible to allow *any* tile in a tileset to appear above sprites by extending the palette system. They key is in [constants/hardware_constants.asm](../blob/master/constants/hardware_constants.asm):
+
+```asm
+; BG Map attribute flags
+PALETTE_MASK EQU %111
+VRAM_BANK_1 EQU 1 << OAM_TILE_BANK ; $08
+OBP_NUM EQU 1 << OAM_OBP_NUM ; $10
+X_FLIP EQU 1 << OAM_X_FLIP ; $20
+Y_FLIP EQU 1 << OAM_Y_FLIP ; $40
+PRIORITY EQU 1 << OAM_PRIORITY ; $80
+```
+
+Every tile on the screen has an attribute byte. The lowest three bits define the color, which is why there's only room for eight colors (from `PAL_BG_GRAY`, 0, to `PAL_BG_TEXT`, 7). The other bits control other properties. In particular, the high bit controls **tile priority**. So if the [gfx/tilesets/\*\_palette\_map.asm](../blob/master/gfx/tilesets/) files could define tiles' priority as well as color, you could make any tile have priority over sprites.
+
+
+## 1. Define `PAL_BG_PRIORITY_*` constants
+
+Edit [constants/tileset_constants.asm](../blob/master/constants/tileset_constants.asm):
+
+```diff
+; bg palette values (see gfx/tilesets/*_palette_map.asm)
+; TilesetBGPalette indexes (see gfx/tilesets/bg_tiles.pal)
+ const_def
+ const PAL_BG_GRAY ; 0
+ const PAL_BG_RED ; 1
+ const PAL_BG_GREEN ; 2
+ const PAL_BG_WATER ; 3
+ const PAL_BG_YELLOW ; 4
+ const PAL_BG_BROWN ; 5
+ const PAL_BG_ROOF ; 6
+ const PAL_BG_TEXT ; 7
+
++const_value set $80
++ const PAL_BG_PRIORITY_GRAY ; 80
++ const PAL_BG_PRIORITY_RED ; 81
++ const PAL_BG_PRIORITY_GREEN ; 82
++ const PAL_BG_PRIORITY_WATER ; 83
++ const PAL_BG_PRIORITY_YELLOW ; 84
++ const PAL_BG_PRIORITY_BROWN ; 85
++ const PAL_BG_PRIORITY_ROOF ; 86
++ const PAL_BG_PRIORITY_TEXT ; 87
+```
+
+(The exact `PAL_BG_PRIORITY_` names are important: [Polished Map](https://github.com/Rangi42/polished-map) supports them when editing maps and tilesets, if you check Options→Tile Priority.)
+
+But we can't just start using colors like `PRIORITY_RED` in the tilesets' palette_map.asm files. The `tilepal` macro packs two tile color definitions into each byte, using four bits per tile: three for the color (`PALETTE_MASK`), one for the bank (`VRAM_BANK_1`). So we need to add space for the new priority data.
+
+
+## 2. Use one byte per color for tileset palettes
+
+Edit [gfx/tilesets/palette_maps.asm](../blob/master/gfx/tilesets/palette_maps.asm):
+
+```diff
+tilepal: MACRO
+; used in gfx/tilesets/*_palette_map.asm
+; vram bank, pals
+x = \1 << OAM_TILE_BANK
+-rept (_NARG +- 1) / 2
++rept _NARG +- 1
+- dn (x | PAL_BG_\3), (x | PAL_BG_\2)
++ db (x | PAL_BG_\2)
+- shift
+ shift
+endr
+ENDM
+```
+
+Now the tileset palette data will take up twice as much space—one byte per tile instead of half a byte—so it won't fit in its ROM bank. Edit [main.asm](../blob/master/main.asm):
+
+```diff
+-SECTION "bank13", ROMX
++SECTION "Tileset Palettes", ROMX
+
+INCLUDE "engine/map_palettes.asm"
+INCLUDE "gfx/tilesets/palette_maps.asm"
++
++
++SECTION "bank13", ROMX
++
+INCLUDE "data/collision_permissions.asm"
+INCLUDE "engine/routines/emptyallsrambanks.asm"
+INCLUDE "engine/routines/savemenu_copytilemapatonce.asm"
+INCLUDE "engine/routines/checksave.asm"
+INCLUDE "data/maps/scenes.asm"
+INCLUDE "engine/routines/loadmappart.asm"
+INCLUDE "engine/routines/phonering_copytilemapatonce.asm"
+```
+
+
+
+## 3. Fix the skipped space in palette_map.asm files
+
+The [gfx/tilesets/\*\_palette\_map.asm](../blob/master/gfx/tilesets/) define tile palettes in order: first for tiles $00 to $5F, then for tiles $80 to $DF. Tiles $60 to $7F are skipped because those IDs are used for font graphics. But the skipping is done with a count of bytes, not of colors, so we need to double the counts.
+
+Edit each \_palette\_map.asm file:
+
+```diff
+-rept 16
++rept 32
+ db $ff
+endr
+```
+
+
+## 3. Correctly read the extended palette data
+
+Edit [engine/map_palettes.asm](../blob/master/engine/map_palettes.asm):
+
+```diff
+SwapTextboxPalettes:: ; 4c000
+ hlcoord 0, 0
+ decoord 0, 0, AttrMap
+ ld b, SCREEN_HEIGHT
+.loop
+ push bc
+ ld c, SCREEN_WIDTH
++ call GetBGMapTilePalettes
+-.innerloop
+- ld a, [hl]
+- push hl
+- srl a
+- jr c, .UpperNybble
+- ld hl, TilesetPalettes
+- add [hl]
+- ld l, a
+- ld a, [TilesetPalettes + 1]
+- adc $0
+- ld h, a
+- ld a, [hl]
+- and $f
+- jr .next
+-
+-.UpperNybble:
+- ld hl, TilesetPalettes
+- add [hl]
+- ld l, a
+- ld a, [TilesetPalettes + 1]
+- adc $0
+- ld h, a
+- ld a, [hl]
+- swap a
+- and $f
+-
+-.next
+- pop hl
+- ld [de], a
+- res 7, [hl]
+- inc hl
+- inc de
+- dec c
+- jr nz, .innerloop
+ pop bc
+ dec b
+ jr nz, .loop
+ ret
+
+ScrollBGMapPalettes:: ; 4c03f
+ ld hl, BGMapBuffer
+ ld de, BGMapPalBuffer
++ ; fallthrough
++GetBGMapTilePalettes:
+.loop
+ ld a, [hl]
+ push hl
+- srl a
+- jr c, .UpperNybble
+-
+-; .LowerNybble
+ ld hl, TilesetPalettes
+ add [hl]
+ ld l, a
+ ld a, [TilesetPalettes + 1]
+ adc $0
+ ld h, a
+ ld a, [hl]
+- and $f
+- jr .next
+-
+-.UpperNybble:
+- ld hl, TilesetPalettes
+- add [hl]
+- ld l, a
+- ld a, [TilesetPalettes + 1]
+- adc $0
+- ld h, a
+- ld a, [hl]
+- swap a
+- and $f
+-
+-.next
+ pop hl
+ ld [de], a
+ res 7, [hl]
+ inc hl
+ inc de
+ dec c
+ jr nz, .loop
+ ret
+```
+
+Notice how `SwapTextboxPalettes` now reuses the loop it shares with `ScrollBGMapPalettes`, and then the whole decision of which nybble to read is no longer necessary because the whole byte defines one tile's attributes.
+
+Anyway—at this point you are done!
+
+![Screenshot](screenshots/tile-priority.png)
+
+Now when you edit a palette_map.asm file, you can use the names `PRIORITY_GRAY`, `PRIORITY_BROWN`, etc., and the corresponding tile will appear above any NPC. *However*, the lightest hue (that's white when you're editing the monochrome tileset PNG) will be transparent. That's how tall grass works: you see only the parts of the player sprite that overlap "white" pixels (actually light green, using the standard outdoor color palette). So design your overhead tiles carefully.
diff --git a/Make-Overhead-Tiles.md b/Make-Overhead-Tiles.md
deleted file mode 100644
index 569d40b..0000000
--- a/Make-Overhead-Tiles.md
+++ /dev/null
@@ -1,102 +0,0 @@
-Step 1: Add these definitions to constants/tilemap_constants.asm:
-
- const_value SET $80
- const PAL_BG_PRIORITY_GRAY ; 80
- const PAL_BG_PRIORITY_RED ; 81
- const PAL_BG_PRIORITY_GREEN ; 82
- const PAL_BG_PRIORITY_WATER ; 83
- const PAL_BG_PRIORITY_YELLOW ; 84
- const PAL_BG_PRIORITY_BROWN ; 85
- const PAL_BG_PRIORITY_ROOF ; 86
- const PAL_BG_PRIORITY_TEXT ; 87
-
-Step 2: Edit macros/pals.asm.
-
-Replace this:
-
- tilepal: MACRO
- ; vram bank, pals
- x = \1 << 3
- rept (_NARG +- 1) / 2
- dn (x | PAL_BG_\3), (x | PAL_BG_\2)
- shift
- shift
- endr
- endm
-
-with this:
-
- tilepal: MACRO
- ; vram bank, pals
- x = \1 << 3
- rept _NARG +- 1
- db (x | PAL_BG_\2)
- shift
- endr
- endm
-
-Now the tileset palette data will take up twice as much space—one byte per tile instead of half a byte—but you'll be able to use, for example, PRIORITY_GRAY instead of GRAY to define an overhead tile.
-
-Step 3: Edit main.asm's SwapTextboxPalettes and ScrollBGMapPalettes.
-
-These two routines read the tileset palette data, so they have to be updated to understand the new one-byte-per-tile format. While we're at it, we can also factor out a large chunk of identical code from both of them into its own subroutine.
-
-Replace all of this:
-
- SwapTextboxPalettes:: ; 4c000
- hlcoord 0, 0
- decoord 0, 0, AttrMap
- ...
- ret
-
- ScrollBGMapPalettes:: ; 4c03f
- ld hl, BGMapBuffer
- ld de, BGMapPalBuffer
- ...
- ret
-
-With this:
-
- SwapTextboxPalettes:: ; 4c000
- hlcoord 0, 0
- decoord 0, 0, AttrMap
- ld b, SCREEN_HEIGHT
- .loop
- push bc
- ld c, SCREEN_WIDTH
- call GetBGMapTilePalettes
- pop bc
- dec b
- jr nz, .loop
- ret
-
- ScrollBGMapPalettes:: ; 4c03f
- ld hl, BGMapBuffer
- ld de, BGMapPalBuffer
- ; don't call GetBGMapTilePalettes and ret, just fallthrough
-
- GetBGMapTilePalettes:
- .loop
- ld a, [hl]
- push hl
- ld hl, TilesetPalettes
- add [hl]
- ld l, a
- ld a, [TilesetPalettes + 1]
- adc $0
- ld h, a
- ld a, [hl]
- pop hl
- ld [de], a
- res 7, [hl]
- inc hl
- inc de
- dec c
- jr nz, .loop
- ret
-
-(Notice how the common code has been moved into GetBGMapTilePalettes, and then the whole decision of which nybble to read is no longer necessary because the whole byte is needed.)
-
-Anyway—at this point you are done! Now when you edit a palette_map.asm file, you can use the names PRIORITY_GRAY, PRIORITY_BROWN, etc instead of just GRAY, BROWN, etc, and the tile will appear above any NPC. However, the lightest hue (that is, white when you're editing the monochrome tileset graphic) will be transparent. That's how tall grass works: you see only the parts of the player sprite that overlap "white" pixels (actually light green, using the standard outdoor color palette.) You'll notice in the Magnet Train example above, I designed the overhead tracks to use only the three darker hues.
-
-(See original thread this tutorial comes from [here](https://hax.iimarckus.org/topic/7268/).) \ No newline at end of file
diff --git a/Tutorials.md b/Tutorials.md
index d8a23c4..0e31d64 100644
--- a/Tutorials.md
+++ b/Tutorials.md
@@ -5,6 +5,7 @@
**Upgrades to existing features:**
- [Remove the 25% failure chance for AI status moves](Remove-the-25%25-failure-chance-for-AI-status-moves)
+- [Allow map tiles to appear above sprites](Allow-map-tiles-to-appear-above-sprites)
**Features from later generations:**
diff --git a/screenshots/tile-priority.png b/screenshots/tile-priority.png
new file mode 100644
index 0000000..3470437
--- /dev/null
+++ b/screenshots/tile-priority.png
Binary files differ