Trashcan puzzle in Vermilion Gym - pret/pokecrystal GitHub Wiki
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.)
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:
Now, in the game_corner
blockset, create a new block with two doors along its horizontal axis. Edit maps/VermilionGym.blk:
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
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
+ 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.
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!