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 setval 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 setval UNOWNPUZZLE_RELICANTH special UnownPuzzle closetext iftrue .PuzzleComplete end .PuzzleComplete ... ``` And it will work the way you expect. ![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 setval 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 setval 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 The wall-opening routines are defined in [engine/events/unown_walls.asm](../blob/master/engine/events/unown_walls.asm). Each wall has a routine that sets the corresponding `WALL_OPENED` event if certain conditions are met: - `HoOhChamber`: Called when you enter the chamber. Checks if Ho-Oh is the first Pokémon in the party. - `OmanyteChamber`: Called when you enter the chamber. Checks if a Water Stone is in the Pack or held by a Pokémon in the party. - `SpecialAerodactylChamber`: Called when you use Flash. Checks if you are in the Aerodactyl chamber. - `SpecialKabutoChamber`: Called when you use an Escape Rope. Checks if you are in the Kabuto chamber. `HoOhChamber` and `OmanyteChamber` are called by `scene_script`s in their respective chamber scripts in [maps/\*.asm](../tree/master/maps/); `SpecialAerodactylChamber` `SpecialKabutoChamber` are called by the `OWFlash` and `EscapeRopeFunction` routines in [engine/events/overworld.asm](../blob/master/engine/events/overworld.asm), respectively. The word "WHIRL" implies that you should use Whirlpool. So, edit [engine/events/unown_walls.asm](../blob/master/engine/events/unown_walls.asm) to define a new `SpecialRelicanthChamber` routine that checks if you are in the Relicanth chamber map, and sets `EVENT_WALL_OPENED_IN_RELICANTH_CHAMBER` if so. Then edit [engine/events/overworld.asm](../blob/master/engine/events/overworld.asm) so that `WhirlpoolFunction` calls `SpecialRelicanthChamber` the way that `EscapeRopeFunction` calls `SpecialKabutoChamber`. (You will, of course, also need to edit [constants/event_flags.asm](../blob/master/event_flags.asm) to define `EVENT_WALL_OPENED_IN_RELICANTH_CHAMBER`, not to mention creating the Relicanth chamber map in the first place.) I won't go into the details of how to do this, since you probably don't want exactly this condition, and the existing four routines are sufficient to show the general pattern. Anyway, once that's done, you can use Whirlpool in the Relicanth chamber to open the wall.