1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
|
HandleMenuInput::
xor a
ld [wPartyMenuAnimMonEnabled], a
HandleMenuInput_::
ldh a, [hDownArrowBlinkCount1]
push af
ldh a, [hDownArrowBlinkCount2]
push af ; save existing values on stack
xor a
ldh [hDownArrowBlinkCount1], a ; blinking down arrow timing value 1
ld a, 6
ldh [hDownArrowBlinkCount2], a ; blinking down arrow timing value 2
.loop1
xor a
ld [wAnimCounter], a ; counter for pokemon shaking animation
call PlaceMenuCursor
call Delay3
.loop2
push hl
ld a, [wPartyMenuAnimMonEnabled]
and a ; is it a pokemon selection menu?
jr z, .getJoypadState
farcall AnimatePartyMon ; shake mini sprite of selected pokemon
.getJoypadState
pop hl
call JoypadLowSensitivity
ldh a, [hJoy5]
and a ; was a key pressed?
jr nz, .keyPressed
push hl
hlcoord 18, 11 ; coordinates of blinking down arrow in some menus
call HandleDownArrowBlinkTiming ; blink down arrow (if any)
pop hl
ld a, [wMenuJoypadPollCount]
dec a
jr z, .giveUpWaiting
jr .loop2
.giveUpWaiting
; if a key wasn't pressed within the specified number of checks
pop af
ldh [hDownArrowBlinkCount2], a
pop af
ldh [hDownArrowBlinkCount1], a ; restore previous values
xor a
ld [wMenuWrappingEnabled], a ; disable menu wrapping
ret
.keyPressed
xor a
ld [wCheckFor180DegreeTurn], a
ldh a, [hJoy5]
ld b, a
bit 6, a ; pressed Up key?
jr z, .checkIfDownPressed
.upPressed
ld a, [wCurrentMenuItem] ; selected menu item
and a ; already at the top of the menu?
jr z, .alreadyAtTop
.notAtTop
dec a
ld [wCurrentMenuItem], a ; move selected menu item up one space
jr .checkOtherKeys
.alreadyAtTop
ld a, [wMenuWrappingEnabled]
and a ; is wrapping around enabled?
jr z, .noWrappingAround
ld a, [wMaxMenuItem]
ld [wCurrentMenuItem], a ; wrap to the bottom of the menu
jr .checkOtherKeys
.checkIfDownPressed
bit 7, a
jr z, .checkOtherKeys
.downPressed
ld a, [wCurrentMenuItem]
inc a
ld c, a
ld a, [wMaxMenuItem]
cp c
jr nc, .notAtBottom
.alreadyAtBottom
ld a, [wMenuWrappingEnabled]
and a ; is wrapping around enabled?
jr z, .noWrappingAround
ld c, $00 ; wrap from bottom to top
.notAtBottom
ld a, c
ld [wCurrentMenuItem], a
.checkOtherKeys
ld a, [wMenuWatchedKeys]
and b ; does the menu care about any of the pressed keys?
jp z, .loop1
.checkIfAButtonOrBButtonPressed
ldh a, [hJoy5]
and A_BUTTON | B_BUTTON
jr z, .skipPlayingSound
.AButtonOrBButtonPressed
push hl
ld hl, wFlags_0xcd60
bit 5, [hl]
pop hl
jr nz, .skipPlayingSound
ld a, SFX_PRESS_AB
call PlaySound
.skipPlayingSound
pop af
ldh [hDownArrowBlinkCount2], a
pop af
ldh [hDownArrowBlinkCount1], a ; restore previous values
xor a
ld [wMenuWrappingEnabled], a ; disable menu wrapping
ldh a, [hJoy5]
ret
.noWrappingAround
ld a, [wMenuWatchMovingOutOfBounds]
and a ; should we return if the user tried to go past the top or bottom?
jr z, .checkOtherKeys
jr .checkIfAButtonOrBButtonPressed
PlaceMenuCursor::
ld a, [wTopMenuItemY]
and a ; is the y coordinate 0?
jr z, .adjustForXCoord
hlcoord 0, 0
ld bc, SCREEN_WIDTH
.topMenuItemLoop
add hl, bc
dec a
jr nz, .topMenuItemLoop
.adjustForXCoord
ld a, [wTopMenuItemX]
ld b, 0
ld c, a
add hl, bc
push hl
ld a, [wLastMenuItem]
and a ; was the previous menu id 0?
jr z, .checkForArrow1
push af
ldh a, [hUILayoutFlags]
bit 1, a ; is the menu double spaced?
jr z, .doubleSpaced1
ld bc, 20
jr .getOldMenuItemScreenPosition
.doubleSpaced1
ld bc, 40
.getOldMenuItemScreenPosition
pop af
.oldMenuItemLoop
add hl, bc
dec a
jr nz, .oldMenuItemLoop
.checkForArrow1
ld a, [hl]
cp "▶" ; was an arrow next to the previously selected menu item?
jr nz, .skipClearingArrow
.clearArrow
ld a, [wTileBehindCursor]
ld [hl], a
.skipClearingArrow
pop hl
ld a, [wCurrentMenuItem]
and a
jr z, .checkForArrow2
push af
ldh a, [hUILayoutFlags]
bit 1, a ; is the menu double spaced?
jr z, .doubleSpaced2
ld bc, 20
jr .getCurrentMenuItemScreenPosition
.doubleSpaced2
ld bc, 40
.getCurrentMenuItemScreenPosition
pop af
.currentMenuItemLoop
add hl, bc
dec a
jr nz, .currentMenuItemLoop
.checkForArrow2
ld a, [hl]
cp "▶" ; has the right arrow already been placed?
jr z, .skipSavingTile ; if so, don't lose the saved tile
ld [wTileBehindCursor], a ; save tile before overwriting with right arrow
.skipSavingTile
ld a, "▶" ; place right arrow
ld [hl], a
ld a, l
ld [wMenuCursorLocation], a
ld a, h
ld [wMenuCursorLocation + 1], a
ld a, [wCurrentMenuItem]
ld [wLastMenuItem], a
ret
; This is used to mark a menu cursor other than the one currently being
; manipulated. In the case of submenus, this is used to show the location of
; the menu cursor in the parent menu. In the case of swapping items in list,
; this is used to mark the item that was first chosen to be swapped.
PlaceUnfilledArrowMenuCursor::
ld b, a
ld a, [wMenuCursorLocation]
ld l, a
ld a, [wMenuCursorLocation + 1]
ld h, a
ld [hl], "▷"
ld a, b
ret
; Replaces the menu cursor with a blank space.
EraseMenuCursor::
ld a, [wMenuCursorLocation]
ld l, a
ld a, [wMenuCursorLocation + 1]
ld h, a
ld [hl], " "
ret
; This toggles a blinking down arrow at hl on and off after a delay has passed.
; This is often called even when no blinking is occurring.
; The reason is that most functions that call this initialize hDownArrowBlinkCount1 to 0.
; The effect is that if the tile at hl is initialized with a down arrow,
; this function will toggle that down arrow on and off, but if the tile isn't
; initialized with a down arrow, this function does nothing.
; That allows this to be called without worrying about if a down arrow should
; be blinking.
HandleDownArrowBlinkTiming::
ld a, [hl]
ld b, a
ld a, "▼"
cp b
jr nz, .downArrowOff
.downArrowOn
ldh a, [hDownArrowBlinkCount1]
dec a
ldh [hDownArrowBlinkCount1], a
ret nz
ldh a, [hDownArrowBlinkCount2]
dec a
ldh [hDownArrowBlinkCount2], a
ret nz
ld a, " "
ld [hl], a
ld a, $ff
ldh [hDownArrowBlinkCount1], a
ld a, $06
ldh [hDownArrowBlinkCount2], a
ret
.downArrowOff
ldh a, [hDownArrowBlinkCount1]
and a
ret z
dec a
ldh [hDownArrowBlinkCount1], a
ret nz
dec a
ldh [hDownArrowBlinkCount1], a
ldh a, [hDownArrowBlinkCount2]
dec a
ldh [hDownArrowBlinkCount2], a
ret nz
ld a, $06
ldh [hDownArrowBlinkCount2], a
ld a, "▼"
ld [hl], a
ret
; The following code either enables or disables the automatic drawing of
; text boxes by DisplayTextID. Both functions cause DisplayTextID to wait
; for a button press after displaying text (unless [wEnteringCableClub] is set).
EnableAutoTextBoxDrawing::
xor a
jr AutoTextBoxDrawingCommon
DisableAutoTextBoxDrawing::
ld a, TRUE
AutoTextBoxDrawingCommon::
ld [wAutoTextBoxDrawingControl], a
xor a
ld [wDoNotWaitForButtonPressAfterDisplayingText], a ; make DisplayTextID wait for button press
ret
PrintText::
; Print text hl at (1, 14).
push hl
ld a, MESSAGE_BOX
ld [wTextBoxID], a
call DisplayTextBoxID
call UpdateSprites
call Delay3
pop hl
PrintText_NoCreatingTextBox::
bccoord 1, 14
jp TextCommandProcessor
|