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
|
INCLUDE "constants.asm"
SECTION "home/joypad.asm", ROM0
ClearJoypad::
xor a
; Pressed this frame (delta)
ldh [hJoyDown], a
; Currently pressed
ldh [hJoyState], a
ret
Joypad::
; Read the joypad register and translate it to something more
; workable for use in-game. There are 8 buttons, so we can use
; one byte to contain all player input.
; Updates:
; hJoypadUp: released this frame (delta)
; hJoypadDown: pressed this frame (delta)
; hJoypadState: currently pressed
; hJoypadSum: pressed so far
ld a, [$d4ab]
and $d0
ret nz
ld a, 1 << 5 ; select direction keys
ldh [rJOYP], a
ldh a, [rJOYP]
ldh a, [rJOYP]
cpl
and $0f
swap a
ld b, a
ld a, 1 << 4 ; select button keys
ldh [rJOYP], a
ldh a, [rJOYP]
ldh a, [rJOYP]
ldh a, [rJOYP]
ldh a, [rJOYP]
ldh a, [rJOYP]
ldh a, [rJOYP]
cpl
and $0f
or b
ld b, a
ld a, (1 << 5 | 1 << 4) ; port reset
ldh [rJOYP], a
ldh a, [hJoypadState]
ld e, a
xor b
ld d, a
and e
ldh [hJoypadUp], a
ld a, d
and b
ldh [hJoypadDown], a
ld c, a
ldh a, [hJoypadSum]
or c
ldh [hJoypadSum], a
ld a, b
ldh [hJoypadState], a
ldh [hJoypadState2], a
; Soft-Reset by holding A+B+SELECT+START
and (A_BUTTON | B_BUTTON | SELECT | START)
cp (A_BUTTON | B_BUTTON | SELECT | START)
jp z, Reset
ret
GetJoypad::
; Update mirror joypad input from hJoypadState (real input)
; hJoyReleased, hJoyDown and hJoyState are synchronized
; copies of their hJoypad* counterparts.
; bit 0 A
; 1 B
; 2 SELECT
; 3 START
; 4 RIGHT
; 5 LEFT
; 6 UP
; 7 DOWN
push af
push hl
push de
ld hl, wJoypadFlags
set 6, [hl] ; mutex
ld hl, hJoypadDown
ld de, hJoyDown
ld a, [hli]
ld [de], a
inc de
ld a, [hli]
ld [de], a
inc de
ld a, [hl]
ld [de], a
ld hl, wJoypadFlags
res 6, [hl]
pop de
pop hl
pop af
ret
JoyTitleScreenInput::
; Check if any of the following conditions
; is met for c frames
; - B, Select and Up keys are pressed in same frame
; - A is pressed
; - START is pressed
;
; Inputs: c - number of frames to check for
; Return: carry set if condition met, else reset
.loop
call DelayFrame
push bc
call GetJoypadDebounced
pop bc
ldh a, [hJoyState]
cp (D_UP | SELECT | B_BUTTON)
jr z, .done
ldh a, [hJoySum]
and (START | A_BUTTON)
jr nz, .done
dec c
jr nz, .loop
and a
ret
.done
scf
ret
GetJoypadDebounced::
; Update hJoySum joypad input from either hJoyDown or
; hJoyState depending on hJoyDebounceSrc.
; hJoyState is only updated every 5 frames and
; the update is delayed by 15 frames after any button
; press.
call GetJoypad
ldh a, [hJoyDebounceSrc]
and a
ldh a, [hJoyDown]
jr z, .joyDownSrc
.joyStateSrc
ldh a, [hJoyState]
.joyDownSrc
ldh [hJoySum], a
ldh a, [hJoyDown]
and a
jr z, .sampleAfterPress
ld a, $0f
ld [wVBlankJoyFrameCounter], a
ret
.sampleAfterPress
ld a, [wVBlankJoyFrameCounter]
and a
jr z, .sampleRegular
xor a
ldh [hJoySum], a
ret
.sampleRegular
ld a, $05
ld [wVBlankJoyFrameCounter], a
ret
TextboxWaitPressAorB_BlinkCursor:
; Show a blinking cursor in the lower right-hand
; corner of a textbox and wait until A or B is
; pressed.
;
; CAUTION: The cursor has to be shown when calling
; this function or no cursor will be shown at all.
; Waiting on button presses is unaffected by this.
ldh a, [hSpriteWidth] ; hTextBoxCursorBlinkInterval is shared with
push af ; hSpriteWidth and hSpriteHeight, so we need
ldh a, [hSpriteHeight] ; to back them up
push af
xor a
ldh [hTextBoxCursorBlinkInterval], a
ld a, $06
ldh [hTextBoxCursorBlinkInterval + 1], a ; initially, $600 iterations
.loop
push hl
coord hl, (TEXTBOX_WIDTH - 2), (TEXTBOX_Y + TEXTBOX_HEIGHT - 1)
call TextboxBlinkCursor
pop hl
call GetJoypadDebounced
ldh a, [hJoySum]
and (A_BUTTON | B_BUTTON)
jr z, .loop
pop af
ldh [hSpriteHeight], a
pop af
ldh [hSpriteWidth], a
ret
ButtonSound::
ld a, [wLinkMode]
cp $03
jr z, .link
call WaitAorB_BlinkCursor
push de
ld de, $5
call PlaySFX
pop de
ret
.link
ld c, $41
jp DelayFrames
WaitAorB_BlinkCursor::
.loop
call BlinkCursor
call GetJoypadDebounced
ldh a, [hJoySum]
and (A_BUTTON | B_BUTTON)
ret nz
call UpdateTime
call UpdateTimeOfDayPalettes
ld a, $01
ldh [hBGMapMode], a
call DelayFrame
jr .loop
BlinkCursor:
; Show a blinking cursor in the lower right-hand
; corner of the screen
; Will toggle between cursor and blank every
; 16 frames.
ldh a, [hVBlankCounter]
and $10
jr z, .cursor_off
ld a, "▼"
jr .save_cursor_state
.cursor_off
ld a, " "
.save_cursor_state
ldcoord_a (SCREEN_WIDTH - 2), (SCREEN_HEIGHT - 1)
ret
TextboxBlinkCursor::
; Show a blinking cursor at the specified position
; that toggles between down arrow and horizontal textbox
; frame tile.
; hl - address of cursor
; hTextBoxCursorBlinkInterval - initial delay between toggling
; subsequent delays will be $6FF
; calls of this function
; CAUTION: if the cursor is not shown initially, even initial
; hTextBoxCursorBlinkInterval values will cause no cursor
; to be shown at all.
ld a, [hl]
ld b, a
ld a, "▼"
cp b
jr nz, .showCursorCountdown
.showTextboxFrameCountdown
ldh a, [hTextBoxCursorBlinkInterval]
dec a
ldh [hTextBoxCursorBlinkInterval], a
ret nz
ldh a, [hTextBoxCursorBlinkInterval + 1]
dec a
ldh [hTextBoxCursorBlinkInterval + 1], a
ret nz
ld a, "─"
ld [hl], a
ld a, $ff
ldh [hTextBoxCursorBlinkInterval], a
ld a, $06
ldh [hTextBoxCursorBlinkInterval + 1], a ; reset to $6FF iterations
ret
.showCursorCountdown
ldh a, [hTextBoxCursorBlinkInterval]
and a
ret z
dec a
ldh [hTextBoxCursorBlinkInterval], a
ret nz
dec a
ldh [hTextBoxCursorBlinkInterval], a
ldh a, [hTextBoxCursorBlinkInterval + 1]
dec a
ldh [hTextBoxCursorBlinkInterval + 1], a
ret nz
ld a, $06
ldh [hTextBoxCursorBlinkInterval + 1], a ; reset to $6FF iterations
ld a, "▼"
ld [hl], a
ret
|