summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRangi <remy.oukaour+rangi42@gmail.com>2018-10-06 18:33:36 -0400
committerRangi <remy.oukaour+rangi42@gmail.com>2018-10-06 18:33:36 -0400
commitd39ec661bccb03f41535229af1e10877722e4206 (patch)
tree3cd477cf5b514799838c1bcf1e64bf21c382da06
parentbfec5276e3e0029d4a0fea7c2a87e51a23ed7e77 (diff)
Add a new Unown puzzle chamber, and some other edits
-rw-r--r--Add-a-new-Unown-puzzle-chamber.md163
-rw-r--r--Add-a-new-tileset.md8
-rw-r--r--Allow-more-than-15-object_events-per-map.md45
-rw-r--r--Allow-more-trainer-parties,-with-individual-DVs,-stat-experience,-and-nicknames.md88
-rw-r--r--Tutorials.md3
-rw-r--r--screenshots/17-object_events.pngbin1839 -> 0 bytes
-rw-r--r--screenshots/gfx-unown_puzzle-relicanth.pngbin0 -> 296 bytes
-rw-r--r--screenshots/relicanth-puzzle.pngbin0 -> 1850 bytes
-rw-r--r--screenshots/relicanth-word.pngbin0 -> 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**:
+
+![gfx/unown_puzzle/relicanth.png](screenshots/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.
+
+![Screenshot](screenshots/
+![Screenshot](screenshots/relicanth-puzzle.png)
+
+
+## 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.
+
+![Screenshot](screenshots/relicanth-word.png)
+
+
+## 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.
![Screenshot](screenshots/museum-tileset.png)
+
+
+## 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:
-
-![Screenshot](screenshots/17-object_events.png)
+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:
![Screenshot](screenshots/enemy-dvs.png)
-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
deleted file mode 100644
index 26d2c07..0000000
--- a/screenshots/17-object_events.png
+++ /dev/null
Binary files differ
diff --git a/screenshots/gfx-unown_puzzle-relicanth.png b/screenshots/gfx-unown_puzzle-relicanth.png
new file mode 100644
index 0000000..bf8c67d
--- /dev/null
+++ b/screenshots/gfx-unown_puzzle-relicanth.png
Binary files differ
diff --git a/screenshots/relicanth-puzzle.png b/screenshots/relicanth-puzzle.png
new file mode 100644
index 0000000..5f7861b
--- /dev/null
+++ b/screenshots/relicanth-puzzle.png
Binary files differ
diff --git a/screenshots/relicanth-word.png b/screenshots/relicanth-word.png
new file mode 100644
index 0000000..0798de2
--- /dev/null
+++ b/screenshots/relicanth-word.png
Binary files differ