Skip to content

Trashcan puzzle in Vermilion Gym

FrenchOrange edited this page Dec 22, 2023 · 6 revisions

In Generation 2, the gym in Vermilion City no longer has its iconic trashcan puzzle. Here's how to reimplement it.

(The code for this feature was adapted from Polished Crystal.)

Contents

  1. Add the door block
  2. Define new switch flags
  3. Implement puzzle behavior
  4. Edit Gym Guide dialogue

1. Add the door block

First, we'll start by actually creating the door that will prevent the player from reaching Lt.Surge until the puzzle has been solved. For the sake of simplicity, we'll reuse the door tiles from the gate tileset. Edit gfx/tilesets/game_corner.png:

game_corner

Now, in the game_corner blockset, create a new block with two doors along its horizontal axis. Edit maps/VermilionGym.blk:

VermilionGym

2. Define new switch flags

Edit constants/event_flags.asm:

; Kanto story events

...

	const EVENT_TALKED_TO_OAK_IN_KANTO
+	const EVENT_VERMILION_GYM_SWITCH_1
+	const EVENT_VERMILION_GYM_SWITCH_2
	const EVENT_GOT_HP_UP_FROM_VERMILION_GUY

...

-; Unused: next 339 events
+; Unused: next 337 events

Edit ram/wram.asm:

...
wdc5f:: db
wdc60:: db

-	ds 18
+	ds 16

+wVermilionGymTrashCan1:: db
+wVermilionGymTrashCan2:: db

wStepCount:: db
wPoisonStepCount:: db
	ds 2
wHappinessStepCount:: db
	ds 1

3. Implement puzzle behavior

Edit maps/VermilionGym.asm:

Click here to view code
	def_callbacks
+	callback MAPCALLBACK_OBJECTS, .VermilionGymDoorsScript
+	callback MAPCALLBACK_TILES, .VermilionGymDoorsCallback
+
+.VermilionGymDoorsScript:
+	checkevent EVENT_VERMILION_GYM_SWITCH_2
+	iftrue .done
+	checkevent EVENT_VERMILION_GYM_SWITCH_1
+	iffalse .resample
+.resample
+	callasm SampleVermilionGymTrashCans
+.done
+	endcallback
+
+.VermilionGymDoorsCallback:
+	checkevent EVENT_VERMILION_GYM_SWITCH_2
+	iftrue .NoDoors
+	endcallback
+
+.NoDoors:
+	changeblock 4, 4, $01 ; floor
+	endcallback
+
+VermilionGymTrashCanScript:
+	checkevent EVENT_VERMILION_GYM_SWITCH_2
+	iftrue .trash_can
+	callasm CheckVermilionGymTrashCan
+	iftrue .open_lock
+	checkevent EVENT_VERMILION_GYM_SWITCH_1
+	iftrue .reset_switches
+.trash_can
+	jumpstd TrashCanScript
+
+.open_lock
+	opentext
+	writetext VermilionGymFoundSwitchText
+	playsound SFX_PUSH_BUTTON
+	promptbutton
+	checkevent EVENT_VERMILION_GYM_SWITCH_1
+	iftrue .second_switch
+	writetext VermilionGymFoundFirstSwitchText
+	playsound SFX_ENTER_DOOR
+	setevent EVENT_VERMILION_GYM_SWITCH_1
+	waitbutton
+	closetext
+	end
+
+.second_switch
+	writetext VermilionGymFoundSecondSwitchText
+	waitbutton
+	playsound SFX_ENTER_DOOR
+	setevent EVENT_VERMILION_GYM_SWITCH_2
+	changeblock 4, 4, $01 ; floor
+	reloadmappart
+	closetext
+	end
+
+.reset_switches
+	opentext
+	writetext VermilionGymTrashCanText
+	promptbutton
+	writetext VermilionGymResetSwitchesText
+	playsound SFX_WRONG
+	waitbutton
+	closetext
+	callasm SampleVermilionGymTrashCans
+	clearevent EVENT_VERMILION_GYM_SWITCH_1
+	end
+
+SampleVermilionGymTrashCans:
+	ldh a, [rSVBK]
+	push af
+	ld a, BANK(wVermilionGymTrashCan1)
+	ldh [rSVBK], a
+.loop
+	call Random
+	ld e, a
+	swap e
+	and $f
+	jr z, .loop
+	dec a
+	ld [wVermilionGymTrashCan1], a
+	call .GetSecondTrashCan
+	ld [wVermilionGymTrashCan2], a
+	pop af
+	ldh [rSVBK], a
+	ret
+
+.GetSecondTrashCan:
+	ld hl, .AdjacencyTable
+	add a
+	add a
+	ld c, a
+	ld a, e
+	and %11
+	add c
+	ld c, a
+	ld b, 0
+	add hl, bc
+	ld a, [hl]
+	ret
+
+.AdjacencyTable:
+	; left, right, up, down
+	db  1,  1,  5,  5 ;  0 ( 1, 7)
+	db  0,  2,  6,  6 ;  1 ( 3, 7)
+	db  1,  3,  7,  7 ;  2 ( 5, 7)
+	db  2,  4,  8,  8 ;  3 ( 7, 7)
+	db  3,  3,  9,  9 ;  4 ( 9, 7)
+	db  6,  6,  0, 10 ;  5 ( 1, 9)
+	db  5,  7,  1, 11 ;  6 ( 3, 9)
+	db  6,  8,  2, 12 ;  7 ( 5, 9)
+	db  7,  9,  3, 13 ;  8 ( 7, 9)
+	db  8,  8,  4, 14 ;  9 ( 9, 9)
+	db 11, 11,  5,  5 ; 10 ( 1,11)
+	db 10, 12,  6,  6 ; 11 ( 3,11)
+	db 11, 13,  7,  7 ; 12 ( 5,11)
+	db 12, 14,  8,  8 ; 13 ( 7,11)
+	db 13, 13,  9,  9 ; 14 ( 9,11)
+
+CheckVermilionGymTrashCan:
+	ldh a, [rSVBK]
+	push af
+	ld a, BANK(wVermilionGymTrashCan1)
+	ldh [rSVBK], a
+	ld de, EVENT_VERMILION_GYM_SWITCH_1
+	ld b, CHECK_FLAG
+	call EventFlagAction
+	ld a, c
+	and a
+	jr z, .first
+	ld a, [wVermilionGymTrashCan2]
+	call .CheckTrashCan
+	ld a, TRUE
+	jr z, .done
+	dec a ; FALSE
+.done
+	ld [wScriptVar], a
+	pop af
+	ldh [rSVBK], a
+	ret
+
+.first:
+	ld a, [wVermilionGymTrashCan1]
+	call .CheckTrashCan
+	jr z, .yes
+	ld a, [wVermilionGymTrashCan2]
+	call .CheckTrashCan
+	ld a, FALSE
+	jr nz, .done
+	ld a, [wVermilionGymTrashCan1]
+	ld [wVermilionGymTrashCan2], a
+.yes
+	ld a, TRUE
+	jr .done
+
+.CheckTrashCan:
+	ld c, a
+	call GetFacingTileCoord
+	call .ConvertCoordsToTrashCan
+	cp c
+	ret
+
+.ConvertCoordsToTrashCan:
+	ld a, d
+	sub 5
+	srl a
+	ld d, a
+	ld a, e
+	sub 11
+	srl a
+	ld e, a
+	add a
+	add a
+	add e
+	add d
+	dec a
+	dec a
+	dec a
+	dec a
+	dec a
+	dec a
+	ret

...

-VermilionGymTrashCan:
-	jumptext VermilionGymTrashCanText

...

VermilionGymTrashCanText:
	text "Nope! Nothing here"
	line "but trash."
	done

+VermilionGymFoundSwitchText:
+	text "Hey!"
+
+	para "There's a switch"
+	line "under the trash!"
+
+	para "Better press it."
+	done
+
+VermilionGymFoundFirstSwitchText:
+	text "The first electric"
+	line "lock opened!"
+	done
+
+VermilionGymFoundSecondSwitchText:
+	text "The second"
+	line "electric lock"
+	cont "opened!"
+
+	para "The path ahead is"
+	line "clear!"
+	done
+
+VermilionGymResetSwitchesText:
+	text "Hey! The electric"
+	line "locks were reset!"
+	done

The puzzle is now working as it should, though we still have one little thing to take care of.

4. Edit Gym Guide dialogue

Turns out, there is a mention of the trashcan puzzle not being activated. We can't let that one slip through.

Edit maps/VermilionGym.asm once more:

VermilionGymGuideText:
	text "Yo! CHAMP in"
	line "making!"

	para "You lucked out"
	line "this time."

	para "LT.SURGE is very"
	line "cautious. He has"

	para "traps set all over"
	line "the GYM."

-	para "But--he-heh--the"
-	line "traps aren't"
-	cont "active right now."
-
-	para "You'll have no"
-	line "problem getting to"
-	cont "LT.SURGE."

+	para "Why lucky, you may"
+	line "ask? Because you"
+
+	para "can train yourself"
+	line "better that way!"
+
+	para "Make up your mind"
+	line "and take on SURGE!"
	done

Now we're done. Vermilion's gym is back to having a proper puzzle!

Vermilion puzzle in-game

Clone this wiki locally