Add a new Unown puzzle chamber - pret/pokecrystal GitHub Wiki

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
  2. Create a new word 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

(This image was drawn by Neslug.)

Then edit constants/script_constants.asm:

 ; 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:

 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

2. Create a new word wall

Edit constants/script_constants.asm again:

 ; 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:

 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

3. Create a condition to open the wall

The wall-opening routines are defined in 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_scripts in their respective chamber scripts in maps/*.asm; SpecialAerodactylChamber SpecialKabutoChamber are called by the OWFlash and EscapeRopeFunction routines in engine/events/overworld.asm, respectively.

The word "WHIRL" implies that you should use Whirlpool. So, edit 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 so that WhirlpoolFunction calls SpecialRelicanthChamber the way that EscapeRopeFunction calls SpecialKabutoChamber. (You will, of course, also need to edit constants/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.