diff options
-rw-r--r-- | Add-a-new-Unown-puzzle-chamber.md | 163 | ||||
-rw-r--r-- | Add-a-new-tileset.md | 8 | ||||
-rw-r--r-- | Allow-more-than-15-object_events-per-map.md | 45 | ||||
-rw-r--r-- | Allow-more-trainer-parties,-with-individual-DVs,-stat-experience,-and-nicknames.md | 88 | ||||
-rw-r--r-- | Tutorials.md | 3 | ||||
-rw-r--r-- | screenshots/17-object_events.png | bin | 1839 -> 0 bytes | |||
-rw-r--r-- | screenshots/gfx-unown_puzzle-relicanth.png | bin | 0 -> 296 bytes | |||
-rw-r--r-- | screenshots/relicanth-puzzle.png | bin | 0 -> 1850 bytes | |||
-rw-r--r-- | screenshots/relicanth-word.png | bin | 0 -> 1002 bytes |
9 files changed, 186 insertions, 121 deletions
diff --git a/Add-a-new-Unown-puzzle-chamber.md b/Add-a-new-Unown-puzzle-chamber.md new file mode 100644 index 0000000..c39f6ba --- /dev/null +++ b/Add-a-new-Unown-puzzle-chamber.md @@ -0,0 +1,163 @@ +This tutorial is for how to add a new Unown puzzle chamber, including a new sliding panel puzzle, a word on the back wall, and a trigger condition for the back wall to open. As an example, we'll add a chamber for Relicanth. + + +## Contents + +1. [Create a new puzzle](#1-create-a-new-puzzle) +2. [Create a new word wall](#2-create-a-new-word-wall) +3. [Create a condition to open the wall](#3-create-a-condition-to-open-the-wall) + + +## 1. Create a new puzzle + +Create **gfx/unown_puzzle/relicanth.png**: + + + +(This image was drawn by [Neslug](https://www.deviantart.com/neslug/art/GSC-Hoenn-Puzzle-Panels-192327829).) + +Then edit [constants/script_constants.asm](../blob/master/constants/script_constants.asm): + +```diff + ; UnownPuzzle writebyte arguments + ; LoadUnownPuzzlePiecesGFX.LZPointers indexes (see engine/games/unown_puzzle.asm) + const_def + const UNOWNPUZZLE_KABUTO ; 0 + const UNOWNPUZZLE_OMANYTE ; 1 + const UNOWNPUZZLE_AERODACTYL ; 2 + const UNOWNPUZZLE_HO_OH ; 3 ++ const UNOWNPUZZLE_RELICANTH + NUM_UNOWN_PUZZLES EQU const_value +``` + +And edit [engine/games/unown_puzzle.asm](../blob/master/engine/games/unown_puzzle.asm): + +```diff + LoadUnownPuzzlePiecesGFX: + ... + + .LZPointers: + ; entries correspond to UNOWNPUZZLE_* constants + dw KabutoPuzzleLZ + dw OmanytePuzzleLZ + dw AerodactylPuzzleLZ + dw HoOhPuzzleLZ ++ dw RelicanthPuzzleLZ + + UnownPuzzleCursorGFX: + INCBIN "gfx/unown_puzzle/cursor.2bpp" + + UnownPuzzleStartCancelLZ: + INCBIN "gfx/unown_puzzle/start_cancel.2bpp.lz" + + HoOhPuzzleLZ: + INCBIN "gfx/unown_puzzle/hooh.2bpp.lz" + + AerodactylPuzzleLZ: + INCBIN "gfx/unown_puzzle/aerodactyl.2bpp.lz" + + KabutoPuzzleLZ: + INCBIN "gfx/unown_puzzle/kabuto.2bpp.lz" + + OmanytePuzzleLZ: + INCBIN "gfx/unown_puzzle/omanyte.2bpp.lz" ++ ++RelicanthPuzzleLZ: ++INCBIN "gfx/unown_puzzle/relicanth.2bpp.lz" +``` + +Now you can create a map with a script like this: + +``` +RuinsOfAlphRelicanthChamberPuzzle: + refreshscreen + writebyte UNOWNPUZZLE_RELICANTH + special UnownPuzzle + closetext + iftrue .PuzzleComplete + end + +.PuzzleComplete + ... +``` + +And it will work the way you expect. + + + + +## 2. Create a new word wall + +Edit [constants/script_constants.asm](../blob/master/constants/script_constants.asm) again: + +```diff + ; DisplayUnownWords writebyte arguments + ; UnownWalls and MenuHeaders_UnownWalls indexes (see data/events/unown_walls.asm) + const_def + const UNOWNWORDS_ESCAPE ; 0 + const UNOWNWORDS_LIGHT ; 1 + const UNOWNWORDS_WATER ; 2 + const UNOWNWORDS_HO_OH ; 3 ++ const UNOWNWORDS_WHIRL +``` + +Then edit [data/events/unown_walls.asm](../blob/master/data/events/unown_walls.asm): + +```diff + UnownWalls: + ; UNOWNWORDS_ESCAPE + ; db $08, $44, $04, $00, $2e, $08, -1 + unownwall "E", "S", "C", "A", "P", "E" + ; UNOWNWORDS_LIGHT + ; db $26, $20, $0c, $0e, $46, -1 + unownwall "L", "I", "G", "H", "T" + ; UNOWNWORDS_WATER + ; db $4c, $00, $46, $08, $42, -1 + unownwall "W", "A", "T", "E", "R" + ; UNOWNWORDS_HO_OH + ; db $0e, $2c, $64, $2c, $0e, -1 + unownwall "H", "O", "-", "O", "H" ++; UNOWNWORDS_WHIRL ++ unownwall "W", "H", "I", "R", "L" + + MenuHeaders_UnownWalls: + ; UNOWNWORDS_ESCAPE + db MENU_BACKUP_TILES ; flags + menu_coords 3, 4, 16, 9 + ; UNOWNWORDS_LIGHT + db MENU_BACKUP_TILES ; flags + menu_coords 4, 4, 15, 9 + ; UNOWNWORDS_WATER + db MENU_BACKUP_TILES ; flags + menu_coords 4, 4, 15, 9 + ; UNOWNWORDS_HO_OH + db MENU_BACKUP_TILES ; flags + menu_coords 4, 4, 15, 9 ++; UNOWNWORDS_WHIRL ++ db MENU_BACKUP_TILES ; flags ++ menu_coords 4, 4, 15, 9 +``` + +The `unownwall` macro turns capital letters and hyphens into their corresponding Unown letters. The `menu_coords` macro is used here to define the textbox surrounding the word when it appears; note that the word "ESCAPE" has a wider box to fit its six letters. + +Now you can create a map with a script like this: + +``` +RuinsOfAlphRelicanthChamberWallPatternLeft: + opentext + writetext RuinsOfAlphRelicanthChamberWallPatternLeftText + writebyte UNOWNWORDS_WHIRL + special DisplayUnownWords + closetext + end +``` + +And it will work the way you expect. + + + + +## 3. Create a condition to open the wall + +TODO diff --git a/Add-a-new-tileset.md b/Add-a-new-tileset.md index adb223f..fd3d19e 100644 --- a/Add-a-new-tileset.md +++ b/Add-a-new-tileset.md @@ -11,6 +11,7 @@ This tutorial is for how to add a new tileset. As an example, we'll add Pewter M 6. [Define its collision data](#6-define-its-collision-data) 7. [Include the new files in the ROM](#7-include-the-new-files-in-the-rom) 8. [Define its animated tiles](#8-define-its-animated-tiles) +9. [Design a custom palette for it](#9-design-a-custom-palette-for-it) ## 1. Define a tileset constant @@ -244,3 +245,10 @@ Note that you can't animate tiles $80 and above. That's because they exist in VR Anyway, that's it. Now maps can use `TILESET_MUSEUM` like any other tileset.  + + +## 9. Design a custom palette for it + +A few tilesets in pokecrystal have custom palettes. For example, Ice Path uses an entirely different palette from most caves; and Radio Tower uses a subtly different palette that makes `YELLOW` look green and `GREEN` look green-on-blue, so the tops of potted plants look natural against the blue walls. + +TODO: custom palette diff --git a/Allow-more-than-15-object_events-per-map.md b/Allow-more-than-15-object_events-per-map.md index 2f67d9f..0cbf7f4 100644 --- a/Allow-more-than-15-object_events-per-map.md +++ b/Allow-more-than-15-object_events-per-map.md @@ -39,50 +39,7 @@ And edit [wram.asm](../blob/master/wram.asm): wObjectMasks:: ds NUM_OBJECTS ; d81e ``` -That's it! We just added space for maps to define two more `object_event`s. - -We can demonstrate this by editing [maps/GoldenrodCity.asm](../blob/master/maps/GoldenrodCity.asm): - -```diff -- db 15 ; object events -+ db 17 ; object events - object_event 7, 18, SPRITE_POKEFAN_M, SPRITEMOVEDATA_STANDING_UP, 0, 0, -1, -1, 0, OBJECTTYPE_SCRIPT, 0, GoldenrodCityPokefanMScript, EVENT_GOLDENROD_CITY_CIVILIANS - ... - object_event 12, 22, SPRITE_POKEFAN_M, SPRITEMOVEDATA_SPINRANDOM_SLOW, 0, 0, -1, -1, PAL_NPC_RED, OBJECTTYPE_SCRIPT, 0, MoveTutorScript, EVENT_GOLDENROD_CITY_MOVE_TUTOR -+ object_event 17, 12, SPRITE_YOUNGSTER, SPRITEMOVEDATA_STANDING_LEFT, 0, 0, -1, -1, PAL_NPC_RED, OBJECTTYPE_SCRIPT, 0, GoldenrodCityTrainSpotter1Script, EVENT_RESTORED_POWER_TO_KANTO -+ object_event 22, 13, SPRITE_YOUNGSTER, SPRITEMOVEDATA_SPINRANDOM_SLOW, 0, 0, -1, -1, PAL_NPC_BLUE, OBJECTTYPE_SCRIPT, 0, GoldenrodCityTrainSpotter2Script, EVENT_RESTORED_POWER_TO_KANTO -+ -+GoldenrodCityTrainSpotter1Script: -+ jumptextfaceplayer .Text -+ -+.Text: -+ text "The MAGNET TRAIN" -+ line "isn't here, so" -+ cont "we're safe on the" -+ cont "tracks." -+ -+ para "I'm disappointed" -+ line "though… I wanted" -+ cont "to photograph it!" -+ done -+ -+GoldenrodCityTrainSpotter2Script: -+ jumptextfaceplayer .Text -+ -+.Text: -+ text "Trainspotting is" -+ line "a hobby anyone" -+ cont "can get into!" -+ -+ para "I collect train" -+ line "tickets and" -+ cont "timetables!" -+ done -``` - -The new 16th and 17th NPCs will appear: - - +That's it! We just added space for maps to define 17 total `object_event`s. So you could, for example, add two more NPCs to make Goldenrod City feel busier. Let's look at how it works. `wMapObjects` is an array of `map_object` structs, one for each possible object (including the player). You can see what data is stored for each `map_object` in the macro definition in [macros/wram.asm](../blob/master/macros/wram.asm): diff --git a/Allow-more-trainer-parties,-with-individual-DVs,-stat-experience,-and-nicknames.md b/Allow-more-trainer-parties,-with-individual-DVs,-stat-experience,-and-nicknames.md index a35e1bc..7590af1 100644 --- a/Allow-more-trainer-parties,-with-individual-DVs,-stat-experience,-and-nicknames.md +++ b/Allow-more-trainer-parties,-with-individual-DVs,-stat-experience,-and-nicknames.md @@ -439,29 +439,13 @@ Finally, edit [engine/overworld/wildmons.asm](../blob/master/engine/overworld/wi Now you can give nicknames to enemy Pokémon. Be sure to keep the data in order: level, species, nickname, held item, moves. -For example, these are parties for your rival that give him nicknames, held items, and a new Pokémon: +For example, here's a party for your rival that give him nicknames, held items, and a new Pokémon: ``` -Rival1Group: - ; RIVAL1 (1) - db "?@", TRAINERTYPE_NICKNAME | TRAINERTYPE_ITEM - db 3, RATTATA, "RATTATA@", NO_ITEM - db 5, CHIKORITA, "ROOT@", BERRY - db -1 ; end - - ; RIVAL1 (2) - db "?@", TRAINERTYPE_NICKNAME | TRAINERTYPE_ITEM - db 3, RATTATA, "RATTATA@", NO_ITEM - db 5, CYNDAQUIL, "BLAZE@", BERRY - db -1 ; end - - ; RIVAL1 (3) - db "?@", TRAINERTYPE_NICKNAME | TRAINERTYPE_ITEM + db "RIVAL@", TRAINERTYPE_NICKNAME | TRAINERTYPE_ITEM db 3, RATTATA, "RATTATA@", NO_ITEM db 5, TOTODILE, "JAWS@", BERRY db -1 ; end - - ... ``` Which successfully loads in battle: @@ -645,36 +629,20 @@ Now you can give custom DVs to enemy Pokémon. Be sure to keep the data in order DVs are specified as `$AD, $SP`, where *A* = attack, *D* = defense, *S* = speed, and *P* = special, with each one going from $0 to $F (15). -For example, these are parties for your rival that give him custom DVs and held items: +For example, here's a party with custom DVs: ``` -Rival1Group: - ; RIVAL1 (1) - db "?@", TRAINERTYPE_DVS | TRAINERTYPE_ITEM - db 3, RATTATA, PERFECT_DV, PERFECT_DV, NO_ITEM ; top percentage - db 5, CHIKORITA, ATKDEFDV_SHINY, SPDSPCDV_SHINY, BERRY - db -1 ; end - - ; RIVAL1 (2) - db "?@", TRAINERTYPE_DVS | TRAINERTYPE_ITEM - db 3, RATTATA, PERFECT_DV, PERFECT_DV, NO_ITEM ; top percentage - db 5, CYNDAQUIL, ATKDEFDV_SHINY, SPDSPCDV_SHINY, BERRY - db -1 ; end - - ; RIVAL1 (3) - db "?@", TRAINERTYPE_DVS | TRAINERTYPE_ITEM - db 3, RATTATA, PERFECT_DV, PERFECT_DV, NO_ITEM ; top percentage + db "RIVAL@", TRAINERTYPE_DVS | TRAINERTYPE_ITEM + db 3, RATTATA, $87, $77, NO_ITEM db 5, TOTODILE, ATKDEFDV_SHINY, SPDSPCDV_SHINY, BERRY db -1 ; end - - ... ``` Which successfully loads in battle:  -Note that since −1 ($FF) is the end-of-party marker, you can't use $FF for any DVs. That's why `PERFECT_DV` gets turned into $FF, as explained in the comments. It's defined as $11 since you're unlikely to want those specific DVs, but you can use any value for it. If you want to use $00, you should also replace the two `cp PERFECT_DV` lines with `and a` since that's a more efficient way to check for zero. +Note that since −1 ($FF) is the end-of-party marker, you can't use $FF for any DVs. That's why `PERFECT_DV` gets turned into $FF, as explained in the comments. It's defined as $11 since you're unlikely to want those specific DVs, but you can use any value for it. If you want to do `PERFECT_DV EQU $00`, you should also replace the two `cp PERFECT_DV` lines with `and a` since that's a more efficient way to check for zero. ## 4. Add a trainer type flag for stat experience @@ -848,58 +816,26 @@ Now you can give custom stat experience to enemy Pokémon. Be sure to keep the d Stat experience is specified as five *words*, not bytes, because each of the five stats (HP, Attack, Defense, Speed, and Special) has two-byte experience going from $0000 to $FFFF (65,535). -For example, these are parties for your rival that give him custom DVs, stat experience, held items, and moves: +For example, here's a party with custom DVs, stat experience, held items, and moves: ``` -Rival1Group: - ; RIVAL1 (1) - db "?@", TRAINERTYPE_DVS | TRAINERTYPE_STAT_EXP | TRAINERTYPE_ITEM | TRAINERTYPE_MOVES - db 3, RATTATA - db PERFECT_DV, PERFECT_DV ; atk|def, spd|spc - dw PERFECT_STAT_EXP, PERFECT_STAT_EXP, PERFECT_STAT_EXP, PERFECT_STAT_EXP, PERFECT_STAT_EXP ; hp, atk, def, spd, spc - db NO_ITEM - db TACKLE, TAIL_WHIP, BITE, NO_MOVE ; Bite is an egg move - db 5, CHIKORITA - db ATKDEFDV_SHINY, SPDSPCDV_SHINY ; atk|def, spd|spc - dw $0000, $0000, $0000, $0000, $0000 ; hp, atk, def, spd, spc - db BERRY - db TACKLE, GROWL, NO_MOVE, NO_MOVE - db -1 ; end - - ; RIVAL1 (2) - db "?@", TRAINERTYPE_DVS | TRAINERTYPE_STAT_EXP | TRAINERTYPE_ITEM | TRAINERTYPE_MOVES + db "RIVAL@", TRAINERTYPE_DVS | TRAINERTYPE_STAT_EXP | TRAINERTYPE_ITEM | TRAINERTYPE_MOVES db 3, RATTATA - db PERFECT_DV, PERFECT_DV ; atk|def, spd|spc - dw PERFECT_STAT_EXP, PERFECT_STAT_EXP, PERFECT_STAT_EXP, PERFECT_STAT_EXP, PERFECT_STAT_EXP ; hp, atk, def, spd, spc - db NO_ITEM - db TACKLE, TAIL_WHIP, BITE, NO_MOVE ; Bite is an egg move - db 5, CYNDAQUIL - db ATKDEFDV_SHINY, SPDSPCDV_SHINY ; atk|def, spd|spc - dw $0000, $0000, $0000, $0000, $0000 ; hp, atk, def, spd, spc - db BERRY - db TACKLE, LEER, NO_MOVE, NO_MOVE - db -1 ; end - - ; RIVAL1 (3) - db "?@", TRAINERTYPE_DVS | TRAINERTYPE_STAT_EXP | TRAINERTYPE_ITEM | TRAINERTYPE_MOVES - db 3, RATTATA - db PERFECT_DV, PERFECT_DV ; atk|def, spd|spc - dw PERFECT_STAT_EXP, PERFECT_STAT_EXP, PERFECT_STAT_EXP, PERFECT_STAT_EXP, PERFECT_STAT_EXP ; hp, atk, def, spd, spc + db PERFECT_DV, $de ; atk|def, spd|spc + dw $0040, $0060, $0020, $0040, $0000 ; hp, atk, def, spd, spc db NO_ITEM db TACKLE, TAIL_WHIP, BITE, NO_MOVE ; Bite is an egg move db 5, TOTODILE db ATKDEFDV_SHINY, SPDSPCDV_SHINY ; atk|def, spd|spc - dw $0000, $0000, $0000, $0000, $0000 ; hp, atk, def, spd, spc + dw $0000, PERFECT_STAT_EXP, $0000, PERFECT_STAT_EXP, $0000 ; hp, atk, def, spd, spc db BERRY db SCRATCH, LEER, NO_MOVE, NO_MOVE db -1 ; end - - ... ``` Which successfully loads in battle (no screenshot because stat experience isn't visible). -Again, since −1 ($FF) is the end-of-party marker, you can't use stat experience values with $FF in them. That's why `PERFECT_STAT_EXP` gets turned into $FFFF, as explained in the comments. It's defined as $1337 since you're unlikely to want that specific value, but you can use any value for it. If you want to use $0000, you should also replace the `cp LOW(PERFECT_STAT_EXP)` and `cp HIGH(PERFECT_STAT_EXP)` lines with `and a` since that's a more efficient way to check for zero. +Again, since −1 ($FF) is the end-of-party marker, you can't use stat experience values with $FF in them. That's why `PERFECT_STAT_EXP` gets turned into $FFFF, as explained in the comments. It's defined as $1337 since you're unlikely to want that specific value, but you can use any value for it. If you want to do `PERFECT_STAT_EXP EQU $0000`, you should also replace the `cp LOW(PERFECT_STAT_EXP)` and `cp HIGH(PERFECT_STAT_EXP)` lines with `and a` since that's a more efficient way to check for zero. ## 5. Allow trainer data to be stored in multiple banks diff --git a/Tutorials.md b/Tutorials.md index 2875304..b2d258a 100644 --- a/Tutorials.md +++ b/Tutorials.md @@ -28,6 +28,7 @@ Tutorials may use diff syntax to show edits: - [Radio channel](Add-a-new-radio-channel) - [Wild Pokémon slot](Add-a-new-wild-Pokémon-slot) - [Unown form](Add-a-new-Unown-form) +- [Unown puzzle chamber](Add-a-new-Unown-puzzle-chamber) - [Fishing rod](Add-a-new-fishing-rod) - [Battle transition](Add-a-new-battle-transition) @@ -85,7 +86,7 @@ Tutorials may use diff syntax to show edits: - More daily and weekly events - Third trainer card page for Kanto badges - Fourth stats page for caught data -- Colored party menu icons +- Colored party menu icons (overworld or battle sprite colors) - Option to show shiny colors in Pokédex - Add 255 moves, not just 254 - Automatic rain/sun/sandstorm on certain maps diff --git a/screenshots/17-object_events.png b/screenshots/17-object_events.png Binary files differdeleted file mode 100644 index 26d2c07..0000000 --- a/screenshots/17-object_events.png +++ /dev/null diff --git a/screenshots/gfx-unown_puzzle-relicanth.png b/screenshots/gfx-unown_puzzle-relicanth.png Binary files differnew file mode 100644 index 0000000..bf8c67d --- /dev/null +++ b/screenshots/gfx-unown_puzzle-relicanth.png diff --git a/screenshots/relicanth-puzzle.png b/screenshots/relicanth-puzzle.png Binary files differnew file mode 100644 index 0000000..5f7861b --- /dev/null +++ b/screenshots/relicanth-puzzle.png diff --git a/screenshots/relicanth-word.png b/screenshots/relicanth-word.png Binary files differnew file mode 100644 index 0000000..0798de2 --- /dev/null +++ b/screenshots/relicanth-word.png |