shithub: pokecrystal

Download patch

ref: a999787cb84e8363509ad72d92be8f1fc8b7d321
parent: 1e5c95d8d42d5cf4e13afd204a3d6e18e5c030bb
author: Rangi <remy.oukaour+rangi42@gmail.com>
date: Sun Feb 17 08:18:38 EST 2019

Update documentation:

- Apply more edits from #595
- Move music ID behavior from the wiki to docs
- Move assembly programming links from docs to the wiki
- Describe why the TM item gaps exist

--- a/FAQ.md
+++ b/FAQ.md
@@ -71,7 +71,7 @@
 
 ## How do I write new features?
 
-There are a number of special-purpose scripting languages, as described in [docs](docs/). For more general features, you'll need to code directly in assembly language. See [docs/assembly_programming.md](docs/assembly_programming.md). Some of the [tutorials][tutorials] may also be helpful.
+There are a number of special-purpose scripting languages, as described in [docs](docs/). For more general features, you'll need to code directly in [assembly language][asm]. Some of the [tutorials][tutorials] for specific features may also be helpful.
 
 
 ## I need more help!
@@ -83,3 +83,4 @@
 [polished-map]: https://github.com/Rangi42/polished-map
 [crowdmap]: https://github.com/yenatch/crowdmap/
 [tutorials]: https://github.com/pret/pokecrystal/wiki/Tutorials
+[asm]: https://github.com/pret/pokecrystal/wiki/Assembly-programming
--- a/docs/assembly_programming.md
+++ /dev/null
@@ -1,25 +1,0 @@
-# Assembly Programming
-
-- [**RGBDS documentation**][rgbds-doc]: Includes information on the RGBDS tools and the assembly language syntax.
-   - [**GBZ80 instructions**][gbz80-instructions]: List of CPU instructions and their effects.
-   - [**RGBASM features**][rgbasm-features]: How to use the assembler features: constants, labels, sections, macros, etc.
-   - [**RGBLINK features**][rgblink-features]: How to use the linker, including the [pokecrystal.link](/pokecrystal.link) linkerscript.
-- [**ASMSchool**][asmschool]: A gameboy assembly tutorial.
-- [**GB ASM Tutorial**][gb-asm-tutorial]: A newer but still in-progress asm tutorial.
-- [**Pan Docs**][pan-docs]: Everything You Always Wanted To Know About GAMEBOY (but were afraid to ask).
-- [**GameBoy Programming Manual**][gb-manual]: The official GameBoy programming and hardware manual by Nintendo.
-- [**GameBoy Opcode Summary**][gb-opcodes]: Describes the opcodes of GameBoy assembly language.
-- [**GameBoy Memory Map**][gb-memory-map]: Describes the GameBoy Color address space.
-- [**awesome-gbdev**][awesome-gbdev]: A curated list of Game Boy development resources such as tools, docs, emulators, related projects and open-source ROMs.
-
-[rgbds-doc]: https://rednex.github.io/rgbds/
-[rgbasm-features]: https://rednex.github.io/rgbds/rgbasm.5.html
-[rgblink-features]: https://rednex.github.io/rgbds/rgblink.5.html
-[gbz80-instructions]: https://rednex.github.io/rgbds/gbz80.7.html
-[asmschool]: http://gameboy.mongenel.com/asmschool.html
-[gb-asm-tutorial]: https://eldred.fr/gb-asm-tutorial/
-[pan-docs]: http://bgb.bircd.org/pandocs.htm
-[gb-manual]: https://ia801906.us.archive.org/19/items/GameBoyProgManVer1.1/GameBoyProgManVer1.1.pdf
-[gb-opcodes]: http://www.devrs.com/gb/files/opcodes.html
-[gb-memory-map]: http://gameboy.mongenel.com/dmg/asmmemmap.html
-[awesome-gbdev]: https://github.com/avivace/awesome-gbdev
--- a/docs/bugs_and_glitches.md
+++ b/docs/bugs_and_glitches.md
@@ -10,7 +10,9 @@
 +add green + lines
 ```
 
+Some fixes are mentioned as breaking compatibility with link battles. This can be avoided by writing more complicated fixes that only apply if the value at `[wLinkMode]` is not `LINK_COLOSSEUM`. That's how Crystal itself fixed two bugs in Gold and Silver regarding the moves [Reflect and Light Screen](#reflect-and-light-screen-can-make-special-defense-wrap-around-above-1024) and [Present](#present-damage-is-incorrect-in-link-battles).
 
+
 ## Contents
 
 - [Thick Club and Light Ball can make (Special) Attack wrap around above 1024](#thick-club-and-light-ball-can-make-special-attack-wrap-around-above-1024)
@@ -898,10 +900,10 @@
  	call Random
  	cp 5 percent
  	jr c, .CheckMagikarpArea
- ; Try again if length >= 1616 mm (i.e. if LOW(length) >= 3 inches)
+ ; Try again if length >= 1616 mm (i.e. if LOW(length) >= 4 inches)
  	ld a, [wMagikarpLength + 1]
--	cp LOW(1616) ; should be "cp 3", since 1616 mm = 5'3", but LOW(1616) = 80
-+	cp 3
+-	cp LOW(1616) ; should be "cp 4", since 1616 mm = 5'4", but LOW(1616) = 80
++	cp 4
  	jr nc, .GenerateDVs
 
  ; 20% chance of skipping this check
@@ -908,14 +910,16 @@
  	call Random
  	cp 20 percent - 1
  	jr c, .CheckMagikarpArea
- ; Try again if length >= 1600 mm (i.e. if LOW(length) >= 2 inches)
+ ; Try again if length >= 1600 mm (i.e. if LOW(length) >= 3 inches)
  	ld a, [wMagikarpLength + 1]
--	cp LOW(1600) ; should be "cp 2", since 1600 mm = 5'2", but LOW(1600) = 64
-+	cp 2
+-	cp LOW(1600) ; should be "cp 3", since 1600 mm = 5'3", but LOW(1600) = 64
++	cp 3
  	jr nc, .GenerateDVs
 ```
 
+**Better fix:** Rewrite the whole system to use millimeters instead of feet and inches, since they have better precision (1 in = 25.4 mm); and only convert from metric to imperial units for display purposes (or don't, of course). 
 
+
 ## Magikarp lengths can be miscalculated
 
 **Fix:** Edit `CalcMagikarpLength.BCLessThanDE` in [engine/events/magikarp.asm](/engine/events/magikarp.asm):
@@ -1205,11 +1209,11 @@
 
 This is a mistake with the “`…`” tile in [gfx/battle/hp_exp_bar_border.png](/gfx/battle/hp_exp_bar_border.png):
 
-![image](/docs/images/hp_exp_bar_border.png)
+![image](/gfx/battle/hp_exp_bar_border.png)
 
 **Fix:** Lower the ellipsis by two pixels:
 
-![image](/docs/images/hp_exp_bar_border_fix.png)
+![image](/docs/images/hp_exp_bar_border.png)
 
 
 ## Two tiles in the `port` tileset are drawn incorrectly
@@ -1216,11 +1220,11 @@
 
 This is a mistake with the left-hand warp carpet corner tiles in [gfx/tilesets/port.png](/gfx/tilesets/port.png):
 
-![image](/docs/images/port.png)
+![image](/gfx/tilesets/port.png)
 
 **Fix:** Adjust them to match the right-hand corner tiles:
 
-![image](/docs/images/port_fix.png)
+![image](/docs/images/port.png)
 
 
 ## `LoadMetatiles` wraps around past 128 blocks
--- a/docs/design_flaws.md
+++ b/docs/design_flaws.md
@@ -8,6 +8,7 @@
 - [Pic banks are offset by `PICS_FIX`](#pic-banks-are-offset-by-pics_fix)
 - [`PokemonPicPointers` and `UnownPicPointers` are assumed to start at the same address](#pokemonpicpointers-and-unownpicpointers-are-assumed-to-start-at-the-same-address)
 - [Footprints are split into top and bottom halves](#footprints-are-split-into-top-and-bottom-halves)
+- [Music IDs $64 and $80 or above have special behavior](#music-ids-64-and-80-or-above-have-special-behavior)
 - [`ITEM_C3` and `ITEM_DC` break up the continuous sequence of TM items](#item_c3-and-item_dc-break-up-the-continuous-sequence-of-tm-items)
 - [Pokédex entry banks are derived from their species IDs](#pokédex-entry-banks-are-derived-from-their-species-ids)
 - [Identical sine wave code and data is repeated five times](#identical-sine-wave-code-and-data-is-repeated-five-times)
@@ -73,7 +74,7 @@
 	db BANK("Pics 24") ; BANK("Pics 1") + 23
 ```
 
-**Fix:** Use `dba` instead of `dba_pic`, delete `FixPicBank`, and remove all four calls to `FixPicBank`.
+**Fix:** Delete `FixPicBank` and remove all four calls to `FixPicBank` in [engine/gfx/load_pics.asm](/engine/gfx/load_pics.asm). Then use `dba` instead of `dba_pic` everywhere.
 
 
 ## `PokemonPicPointers` and `UnownPicPointers` are assumed to start at the same address
@@ -148,9 +149,9 @@
 
 **Fix:**
 
-Don't enforce `org $4000` in pokecrystal.link.
+Don't enforce `org $4000` in [pokecrystal.link](/pokecrystal.link).
 
-Modify `GetFrontpicPointer`:
+Edit `GetFrontpicPointer`:
 
 ```diff
  	ld a, [wCurPartySpecies]
@@ -269,7 +270,7 @@
 ...
 ```
 
-Modify `Pokedex_LoadAnyFootprint`:
+Edit `Pokedex_LoadAnyFootprint`:
 
 ```diff
 -	push hl
@@ -294,6 +295,132 @@
 ```
 
 
+## Music IDs $64 and $80 or above have special behavior
+
+If a map's music ID in [data/maps/maps.asm](/master/data/maps/maps.asm) is $64 (the value of `MUSIC_MAHOGANY_MART` or `MUSIC_SUICUNE_BATTLE`) it will play either `MUSIC_ROCKET_HIDEOUT` or `MUSIC_CHERRYGROVE_CITY`. Moreover, if a map's music ID is $80 or above (the value of `RADIO_TOWER_MUSIC`) it might play `MUSIC_ROCKET_OVERTURE` or something else.
+
+This is caused by `GetMapMusic` in [home/map.asm](/master/home/map.asm):
+
+```asm
+GetMapMusic::
+	push hl
+	push bc
+	ld de, MAP_MUSIC
+	call GetMapField
+	ld a, c
+	cp MUSIC_MAHOGANY_MART
+	jr z, .mahoganymart
+	bit RADIO_TOWER_MUSIC_F, c
+	jr nz, .radiotower
+	farcall Function8b342
+	ld e, c
+	ld d, 0
+.done
+	pop bc
+	pop hl
+	ret
+
+.radiotower
+	ld a, [wStatusFlags2]
+	bit STATUSFLAGS2_ROCKETS_IN_RADIO_TOWER_F, a
+	jr z, .clearedradiotower
+	ld de, MUSIC_ROCKET_OVERTURE
+	jr .done
+
+.clearedradiotower
+	; the rest of the byte
+	ld a, c
+	and RADIO_TOWER_MUSIC - 1
+	ld e, a
+	ld d, 0
+	jr .done
+
+.mahoganymart
+	ld a, [wStatusFlags2]
+	bit STATUSFLAGS2_ROCKETS_IN_MAHOGANY_F, a
+	jr z, .clearedmahogany
+	ld de, MUSIC_ROCKET_HIDEOUT
+	jr .done
+
+.clearedmahogany
+	ld de, MUSIC_CHERRYGROVE_CITY
+	jr .done
+```
+
+**Fix:**
+
+Replace `RADIO_TOWER_MUSIC | MUSIC_GOLDENROD_CITY` with `MUSIC_RADIO_TOWER` in [data/maps/maps.asm](/master/data/maps/maps.asm).
+
+Redefine the special music constants in [constants/music_constants.asm](/master/constants/music_constants.asm):
+
+```diff
+-; GetMapMusic picks music for this value (see home/map.asm)
+-MUSIC_MAHOGANY_MART EQU $64
++; GetMapMusic picks music for these values (see home/map.asm)
++MUSIC_MAHOGANY_MART EQU $fc
++MUSIC_RADIO_TOWER   EQU $fd
+
+ ; ExitPokegearRadio_HandleMusic uses these values
+ RESTART_MAP_MUSIC EQU $fe
+ ENTER_MAP_MUSIC   EQU $ff
+-
+-; GetMapMusic picks music for this bit flag
+-RADIO_TOWER_MUSIC_F EQU 7
+-RADIO_TOWER_MUSIC EQU 1 << RADIO_TOWER_MUSIC_F
+```
+
+And then edit `GetMapMusic`:
+
+```diff
+ GetMapMusic::
+ 	push hl
+ 	push bc
+ 	ld de, MAP_MUSIC
+ 	call GetMapField
+ 	ld a, c
+ 	cp MUSIC_MAHOGANY_MART
+ 	jr z, .mahoganymart
+-	bit RADIO_TOWER_MUSIC_F, c
+-	jr nz, .radiotower
++	cp MUSIC_RADIO_TOWER
++	jr z, .radiotower
+ 	farcall Function8b342
+ 	ld e, c
+ 	ld d, 0
+ .done
+ 	pop bc
+ 	pop hl
+ 	ret
+
+ .radiotower
+ 	ld a, [wStatusFlags2]
+ 	bit STATUSFLAGS2_ROCKETS_IN_RADIO_TOWER_F, a
+ 	jr z, .clearedradiotower
+ 	ld de, MUSIC_ROCKET_OVERTURE
+ 	jr .done
+
+ .clearedradiotower
+-	; the rest of the byte
+-	ld a, c
+-	and RADIO_TOWER_MUSIC - 1
+-	ld e, a
+-	ld d, 0
++	ld de, MUSIC_GOLDENROD_CITY
+ 	jr .done
+
+ .mahoganymart
+ 	ld a, [wStatusFlags2]
+ 	bit STATUSFLAGS2_ROCKETS_IN_MAHOGANY_F, a
+ 	jr z, .clearedmahogany
+ 	ld de, MUSIC_ROCKET_HIDEOUT
+ 	jr .done
+
+ .clearedmahogany
+ 	ld de, MUSIC_CHERRYGROVE_CITY
+ 	jr .done
+```
+
+
 ## `ITEM_C3` and `ITEM_DC` break up the continuous sequence of TM items
 
 [constants/item_constants.asm](/constants/item_constants.asm) defined the 50 TMs in order with `add_tm`, but `ITEM_C3` and `ITEM_DC` break up that sequence.
@@ -352,11 +479,39 @@
 	ret
 ```
 
+> There was originally a good reason for these two gaps!
+>
+> Pokémon traded from RBY to GSC have their catch rate interpreted as their new held item. This was planned early on in development, so some items were given indexes corresponding to appropriate Gen 1 catch rates:
+>
+> - $03 = 3: `BRIGHTPOWDER` is for Articuno, Zapdos, Moltres, and Mewtwo
+> - $1E = 30: `LUCKY_PUNCH` is for Chansey
+> - $23 = 35: `METAL_POWDER` is for Ditto
+> - $3C = 60: `SILVER_LEAF` is for 10 Pokémon
+> - $4B = 75: `GOLD_LEAF` is for 13 Pokémon
+> - $96 = 150: `MYSTERYBERRY` is for Clefairy
+> - $AA = 170: `POLKADOT_BOW` is for Jigglypuff
+> - $B4 = 180: `BRICK_PIECE` is for Machop
+>
+> Yellow was also being developed then, and it did the reverse, altering some catch rates to correspond to appropriate Gen 2 items:
+>
+> - Starter Pikachu's catch rate became 163 = $A3 for `LIGHT_BALL`
+> - Wild Kadabra's catch rate became 96 = $60 for `TWISTEDSPOON`
+> - Wild Dragonair's catch rate became 27 = $1B for `PROTEIN`
+> - Wild Dragonite's catch rate became 9 = $09 for `ANTIDOTE`
+>
+> Most catch rates were left as gaps in the item list, and transformed into held items via the `TimeCapsule_CatchRateItems` table in [data/items/catch_rate_items.asm](/data/items/catch_rate_items.asm). For example, the 52 Pokémon with catch rate 45 would hold the gap `ITEM_2D`, except that gets transformed into Bitter Berry.
+>
+> But a few Pokémon end up with weird items. Abra has a catch rate of 200, or $C8; and Krabby, Horsea, Goldeen, and Staryu have a catch rate of 225, or $E1. Those indexes correspond to the items TM09 Psych Up and TM33 Ice Punch, which seem like random choices—because they are.
+>
+> The TMs and HMs span from indexes $BF to $F9. However, as we can see in [pokegold-spaceworld](https://github.com/pret/pokegold-spaceworld/blob/master/constants/item_constants.asm), they *originally* spanned $C4 to $FF. For some reason they were shifted down by 5 during development.
+>
+> Before the index shift, the gap `ITEM_C3` would have been at index $C8, and `ITEM_DC` at $E1. In other words, they would have neatly corresponded to the catch rates for Abra, Krabby, Horsea, Goldeen, and Staryu! Then those Pokémon would have held Berries instead of random TMs.
+
 **Fix:**
 
 Move `ITEM_C3` and `ITEM_DC` above all the TMs in every table of item data.
 
-Modify engine/items/items.asm:
+Edit [engine/items/items.asm](/engine/items/items.asm):
 
 ```diff
  GetTMHMNumber::
@@ -489,7 +644,7 @@
 	db BANK("Pokedex Entries 193-251")
 ```
 
-**Fix:** Use `dba` instead of `dw` in `PokedexDataPointerTable`, and modify the code that accesses it to match.
+**Fix:** Use `dba` instead of `dw` in `PokedexDataPointerTable`. Then edit [home.asm](/home.asm) to contain a single copy of the `PokedexDataPointerTable` lookup code, updated to work with 3-byte `dba` entries and get the bank from the first entry byte. Delete the three separate lookup routines and use the new one (placed in [home.asm](/home.asm) so it can be called from any bank.)
 
 
 ## Identical sine wave code and data is repeated five times
binary files a/docs/images/hp_exp_bar_border.png b/docs/images/hp_exp_bar_border.png differ
binary files a/docs/images/hp_exp_bar_border_fix.png /dev/null differ
binary files a/docs/images/port.png b/docs/images/port.png differ
binary files a/docs/images/port_fix.png /dev/null differ
--- a/engine/battle/core.asm
+++ b/engine/battle/core.asm
@@ -6164,9 +6164,9 @@
 	call Random
 	cp 5 percent
 	jr c, .CheckMagikarpArea
-; Try again if length >= 1616 mm (i.e. if LOW(length) >= 3 inches)
+; Try again if length >= 1616 mm (i.e. if LOW(length) >= 4 inches)
 	ld a, [wMagikarpLength + 1]
-	cp LOW(1616) ; should be "cp 3", since 1616 mm = 5'3", but LOW(1616) = 80
+	cp LOW(1616) ; should be "cp 4", since 1616 mm = 5'4", but LOW(1616) = 80
 	jr nc, .GenerateDVs
 
 ; 20% chance of skipping this check
@@ -6173,9 +6173,9 @@
 	call Random
 	cp 20 percent - 1
 	jr c, .CheckMagikarpArea
-; Try again if length >= 1600 mm (i.e. if LOW(length) >= 2 inches)
+; Try again if length >= 1600 mm (i.e. if LOW(length) >= 3 inches)
 	ld a, [wMagikarpLength + 1]
-	cp LOW(1600) ; should be "cp 2", since 1600 mm = 5'2", but LOW(1600) = 64
+	cp LOW(1600) ; should be "cp 3", since 1600 mm = 5'3", but LOW(1600) = 64
 	jr nc, .GenerateDVs
 
 .CheckMagikarpArea: