Paper Mario DX
Paper Mario (N64) modding
Loading...
Searching...
No Matches
input.c
Go to the documentation of this file.
1
#include "common.h"
2
#include "nu/nusys.h"
3
4
OSContPad
ContPadData
;
5
BSS
s16
StickExtremeX
;
6
BSS
s16
StickExtremeY
;
7
BSS
s16
StickRetriggerStateX
;
8
BSS
s16
StickRetriggerStateY
;
9
10
#define STICK_DEADZONE_THRESHOLD 4
11
#define STICK_BUTTON_THRESHOLD 32
12
#define STICK_RELEASE_THRESHOLD 16
13
14
/*
15
* When converting analog stick input into digital direction buttons (BUTTON_STICK_LEFT/RIGHT/UP/DOWN),
16
* small oscillations near the threshold could trigger rapid spurious stick 'button' inputs. This code
17
* prevents such inputs by recording the most recent 'extreme' values of StickX/Y along with the direction
18
* of motion, inward or outward, and then only counting directional reversals from those extremes.
19
*
20
* How it works:
21
* - When the stick crosses the main threshold (|stick| > 32), the corresponding digital stick 'button' is set.
22
* - While held, the code tracks the furthest extreme reached in the 'outward' direction.
23
* - If the stick reverses inward by more than 16 units, it enters a release-check state.
24
* - If the stick then moves outward again by more than 16 units from the inward extreme, the stick button is cleared.
25
* and a new input may be triggered *without* having to fully return the stick to neutral.
26
*/
27
enum
{
28
DIR_OUTWARD
= 0,
// track outward extremes while the stick is pressed past the threshold
29
DIR_INWARD
= 1,
// track inward motion and determine when the stick direction should be released
30
};
31
32
void
reset_input_state
(
void
) {
33
gGameStatusPtr
->
curButtons
[0] = 0;
34
gGameStatusPtr
->
pressedButtons
[0] = 0;
35
gGameStatusPtr
->
heldButtons
[0] = 0;
36
gGameStatusPtr
->
stickX
[0] = 0;
37
gGameStatusPtr
->
stickY
[0] = 0;
38
gGameStatusPtr
->
prevButtons
[0] = 0;
39
gGameStatusPtr
->
holdRepeatInterval
[0] = 4;
40
gGameStatusPtr
->
holdDelayTime
[0] = 15;
41
gGameStatusPtr
->
holdRepeatCounter
= 0;
42
gGameStatusPtr
->
holdDelayCounter
= 0;
43
}
44
45
void
clear_input
(
void
) {
46
reset_input_state
();
47
StickExtremeX
= 0;
48
StickExtremeY
= 0;
49
StickRetriggerStateX
=
DIR_OUTWARD
;
50
StickRetriggerStateY
=
DIR_OUTWARD
;
51
}
52
53
void
update_input
(
void
) {
54
OSContPad
*
contData
= &
ContPadData
;
55
b32
hasInput
=
false
;
56
b32
stickButtonDetected
;
57
s32
buttons
;
58
s16
stickX;
59
s16
stickY;
60
61
if
(
gGameStatusPtr
->
contBitPattern
& 1) {
62
hasInput
=
true
;
63
nuContDataGet
(
contData
, 0);
64
}
65
66
if
(
gGameStatusPtr
->
demoState
!=
DEMO_STATE_NONE
) {
67
if
(
gGameStatusPtr
->
demoState
<
DEMO_STATE_CHANGE_MAP
68
&& (
contData
->button & (
BUTTON_A
|
BUTTON_B
|
BUTTON_Z
|
BUTTON_START
))
69
&&
hasInput
70
) {
71
gGameStatusPtr
->
demoState
=
DEMO_STATE_CHANGE_MAP
;
72
}
73
contData
->button =
gGameStatusPtr
->
demoButtonInput
;
74
contData
->stick_x =
gGameStatusPtr
->
demoStickX
;
75
contData
->stick_y =
gGameStatusPtr
->
demoStickY
;
76
hasInput
=
true
;
77
}
78
79
if
(!
hasInput
) {
80
return
;
81
}
82
83
stickX =
contData
->stick_x;
84
stickY =
contData
->stick_y;
85
if
(stickX > 0) {
86
stickX -=
STICK_DEADZONE_THRESHOLD
;
87
if
(stickX < 0) {
88
stickX = 0;
89
}
90
}
91
if
(stickX < 0) {
92
stickX +=
STICK_DEADZONE_THRESHOLD
;
93
if
(stickX > 0) {
94
stickX = 0;
95
}
96
}
97
98
if
(stickY > 0) {
99
stickY -=
STICK_DEADZONE_THRESHOLD
;
100
if
(stickY < 0) {
101
stickY = 0;
102
}
103
}
104
if
(stickY < 0) {
105
stickY +=
STICK_DEADZONE_THRESHOLD
;
106
if
(stickY > 0) {
107
stickY = 0;
108
}
109
}
110
111
gGameStatusPtr
->
stickX
[0] = stickX;
112
gGameStatusPtr
->
stickY
[0] = stickY;
113
buttons
=
contData
->button;
114
115
// check if stickX is over the 'digital' threshold for a right stick 'button' press
116
stickButtonDetected
=
false
;
117
if
(stickX >
STICK_BUTTON_THRESHOLD
) {
118
stickButtonDetected
=
true
;
119
buttons
|=
BUTTON_STICK_RIGHT
;
120
if
(!(
gGameStatusPtr
->
prevButtons
[0] &
BUTTON_STICK_RIGHT
)) {
121
StickExtremeX
= stickX;
122
}
else
if
(
StickRetriggerStateX
==
DIR_OUTWARD
) {
123
// track largest value during DIR_OUTWARD
124
if
(
StickExtremeX
< stickX) {
125
StickExtremeX
= stickX;
126
}
127
}
else
{
128
// track smallest value during DIR_INWARD
129
if
(
StickExtremeX
> stickX) {
130
StickExtremeX
= stickX;
131
}
132
}
133
}
134
135
// likewise for left stick 'button' (comparisons reversed since we are working with negative values)
136
if
(stickX < -
STICK_BUTTON_THRESHOLD
) {
137
stickButtonDetected
=
true
;
138
buttons
|=
BUTTON_STICK_LEFT
;
139
if
(!(
gGameStatusPtr
->
prevButtons
[0] &
BUTTON_STICK_LEFT
)) {
140
StickExtremeX
= stickX;
141
}
else
if
(
StickRetriggerStateX
==
DIR_OUTWARD
) {
142
if
(
StickExtremeX
> stickX) {
143
StickExtremeX
= stickX;
144
}
145
}
else
{
146
if
(
StickExtremeX
< stickX)
147
{
148
StickExtremeX
= stickX;
149
}
150
}
151
}
152
153
if
(!
stickButtonDetected
) {
154
StickRetriggerStateX
=
DIR_OUTWARD
;
155
StickExtremeX
= stickX;
156
}
157
158
// likewise for up stick 'button'
159
stickButtonDetected
=
false
;
160
if
(stickY >
STICK_BUTTON_THRESHOLD
) {
161
stickButtonDetected
=
true
;
162
buttons
|=
BUTTON_STICK_UP
;
163
if
(!(
gGameStatusPtr
->
prevButtons
[0] &
BUTTON_STICK_UP
)) {
164
StickExtremeY
= stickY;
165
}
else
if
(
StickRetriggerStateY
==
DIR_OUTWARD
) {
166
if
(
StickExtremeY
< stickY) {
167
StickExtremeY
= stickY;
168
}
169
}
else
{
170
if
(
StickExtremeY
> stickY) {
171
StickExtremeY
= stickY;
172
}
173
}
174
}
175
176
// likewise for down stick 'button'
177
if
(stickY < -
STICK_BUTTON_THRESHOLD
) {
178
stickButtonDetected
=
true
;
179
buttons
|=
BUTTON_STICK_DOWN
;
180
if
(!(
gGameStatusPtr
->
prevButtons
[0] &
BUTTON_STICK_DOWN
)) {
181
StickExtremeY
= stickY;
182
}
else
if
(
StickRetriggerStateY
==
DIR_OUTWARD
) {
183
if
(
StickExtremeY
> stickY) {
184
StickExtremeY
= stickY;
185
}
186
}
else
{
187
if
(
StickExtremeY
< stickY) {
188
StickExtremeY
= stickY;
189
}
190
}
191
}
192
193
if
(!
stickButtonDetected
) {
194
StickRetriggerStateY
=
DIR_OUTWARD
;
195
StickExtremeY
= stickY;
196
}
197
198
if
(stickX >
STICK_BUTTON_THRESHOLD
) {
199
// if stick changes direction of motion during a release (from inward back to outward),
200
// clear the old input and reset to DIR_OUTWARD in preparation for a new input. this allows quick
201
// repeated inputs by rocking the stick without having to fully return to neutral between each.
202
if
(
StickRetriggerStateX
==
DIR_INWARD
&& stickX -
StickExtremeX
>
STICK_RELEASE_THRESHOLD
) {
203
buttons
&=
~BUTTON_STICK_RIGHT
;
204
StickRetriggerStateX
=
DIR_OUTWARD
;
205
}
206
// if we ever fall RELEASE_THRESHOLD units below the maximum value recorded, begin DIR_INWARD reversal checks
207
if
(
StickExtremeX
- stickX >
STICK_RELEASE_THRESHOLD
) {
208
StickRetriggerStateX
=
DIR_INWARD
;
209
}
210
}
211
212
if
(stickX < -
STICK_BUTTON_THRESHOLD
) {
213
if
(
StickRetriggerStateX
==
DIR_INWARD
&&
StickExtremeX
- stickX >
STICK_RELEASE_THRESHOLD
) {
214
buttons
&=
~BUTTON_STICK_LEFT
;
215
StickRetriggerStateX
=
DIR_OUTWARD
;
216
}
217
if
(stickX -
StickExtremeX
>
STICK_RELEASE_THRESHOLD
) {
218
StickRetriggerStateX
=
DIR_INWARD
;
219
}
220
}
221
222
if
(stickY >
STICK_BUTTON_THRESHOLD
) {
223
if
(
StickRetriggerStateY
==
DIR_INWARD
&& stickY -
StickExtremeY
>
STICK_RELEASE_THRESHOLD
) {
224
buttons
&=
~BUTTON_STICK_UP
;
225
StickRetriggerStateY
=
DIR_OUTWARD
;
226
}
227
if
(
StickExtremeY
- stickY >
STICK_RELEASE_THRESHOLD
) {
228
StickRetriggerStateY
=
DIR_INWARD
;
229
}
230
}
231
232
if
(stickY < -
STICK_BUTTON_THRESHOLD
) {
233
if
(
StickRetriggerStateY
==
DIR_INWARD
&&
StickExtremeY
- stickY >
STICK_RELEASE_THRESHOLD
) {
234
buttons
&=
~BUTTON_STICK_DOWN
;
235
StickRetriggerStateY
=
DIR_OUTWARD
;
236
}
237
if
(stickY -
StickExtremeY
>
STICK_RELEASE_THRESHOLD
) {
238
StickRetriggerStateY
=
DIR_INWARD
;
239
}
240
}
241
242
gGameStatusPtr
->
curButtons
[0] =
buttons
;
243
gGameStatusPtr
->
pressedButtons
[0] =
gGameStatusPtr
->
curButtons
[0] ^
gGameStatusPtr
->
prevButtons
[0];
244
gGameStatusPtr
->
pressedButtons
[0] &=
gGameStatusPtr
->
curButtons
[0];
245
246
if
(
gGameStatusPtr
->
curButtons
[0] == 0) {
247
gGameStatusPtr
->
heldButtons
[0] = 0;
248
}
else
if
(
gGameStatusPtr
->
prevButtons
[0] !=
gGameStatusPtr
->
curButtons
[0]) {
249
// buttons changed this frame: treat new presses as an immediate "held" pulse
250
gGameStatusPtr
->
heldButtons
[0] =
gGameStatusPtr
->
pressedButtons
[0];
251
gGameStatusPtr
->
holdDelayCounter
=
gGameStatusPtr
->
holdDelayTime
[0];
252
gGameStatusPtr
->
holdRepeatCounter
= -1;
253
}
else
{
254
// no change in buttons and at least one button is still held
255
if
(
gGameStatusPtr
->
holdRepeatCounter
>= 0) {
256
// repeat "held" input pulses at a regular interval
257
gGameStatusPtr
->
holdRepeatCounter
--;
258
if
(
gGameStatusPtr
->
holdRepeatCounter
!= 0) {
259
gGameStatusPtr
->
heldButtons
[0] = 0;
260
}
else
{
261
gGameStatusPtr
->
heldButtons
[0] =
gGameStatusPtr
->
curButtons
[0];
262
gGameStatusPtr
->
holdRepeatCounter
=
gGameStatusPtr
->
holdRepeatInterval
[0];
263
}
264
}
else
{
265
// initial delay before train of "held" pulses begin
266
gGameStatusPtr
->
holdDelayCounter
--;
267
if
(
gGameStatusPtr
->
holdDelayCounter
!= 0) {
268
gGameStatusPtr
->
heldButtons
[0] = 0;
269
}
else
{
270
gGameStatusPtr
->
heldButtons
[0] =
gGameStatusPtr
->
curButtons
[0];
271
gGameStatusPtr
->
holdRepeatCounter
=
gGameStatusPtr
->
holdRepeatInterval
[0];
272
}
273
}
274
}
275
276
gGameStatusPtr
->
prevButtons
[0] =
gGameStatusPtr
->
curButtons
[0];
277
}
PopupMenu_SelectedIndex
BSS s32 PopupMenu_SelectedIndex
Definition
8a860_len_3f30.c:84
GameStatus::stickX
s8 stickX[4]
Definition
common_structs.h:1390
GameStatus::holdRepeatInterval
s16 holdRepeatInterval[4]
Definition
common_structs.h:1393
GameStatus::pressedButtons
u32 pressedButtons[4]
Definition
common_structs.h:1387
GameStatus::holdDelayTime
s16 holdDelayTime[4]
Definition
common_structs.h:1392
GameStatus::curButtons
u32 curButtons[4]
Definition
common_structs.h:1386
GameStatus::stickY
s8 stickY[4]
Definition
common_structs.h:1391
GameStatus::prevButtons
u32 prevButtons[4]
Definition
common_structs.h:1389
GameStatus::demoButtonInput
s16 demoButtonInput
Definition
common_structs.h:1398
b32
s32 b32
Definition
common_structs.h:27
GameStatus::demoStickY
s8 demoStickY
Definition
common_structs.h:1400
GameStatus::holdRepeatCounter
s16 holdRepeatCounter
Definition
common_structs.h:1396
GameStatus::demoState
s8 demoState
Definition
common_structs.h:1403
GameStatus::holdDelayCounter
s16 holdDelayCounter
Definition
common_structs.h:1394
GameStatus::contBitPattern
u8 contBitPattern
Definition
common_structs.h:1405
GameStatus::demoStickX
s8 demoStickX
Definition
common_structs.h:1399
GameStatus::heldButtons
u32 heldButtons[4]
Definition
common_structs.h:1388
BUTTON_A
@ BUTTON_A
Definition
enums.h:2776
BUTTON_START
@ BUTTON_START
Definition
enums.h:2773
BUTTON_STICK_UP
@ BUTTON_STICK_UP
Definition
enums.h:2777
BUTTON_STICK_DOWN
@ BUTTON_STICK_DOWN
Definition
enums.h:2778
BUTTON_STICK_LEFT
@ BUTTON_STICK_LEFT
Definition
enums.h:2779
BUTTON_STICK_RIGHT
@ BUTTON_STICK_RIGHT
Definition
enums.h:2780
BUTTON_B
@ BUTTON_B
Definition
enums.h:2775
BUTTON_Z
@ BUTTON_Z
Definition
enums.h:2774
DEMO_STATE_CHANGE_MAP
@ DEMO_STATE_CHANGE_MAP
Definition
enums.h:3570
DEMO_STATE_NONE
@ DEMO_STATE_NONE
Definition
enums.h:3568
clear_input
void clear_input(void)
Definition
input.c:45
STICK_RELEASE_THRESHOLD
#define STICK_RELEASE_THRESHOLD
Definition
input.c:12
DIR_INWARD
@ DIR_INWARD
Definition
input.c:29
DIR_OUTWARD
@ DIR_OUTWARD
Definition
input.c:28
StickRetriggerStateY
BSS s16 StickRetriggerStateY
Definition
input.c:8
STICK_BUTTON_THRESHOLD
#define STICK_BUTTON_THRESHOLD
Definition
input.c:11
StickRetriggerStateX
BSS s16 StickRetriggerStateX
Definition
input.c:7
reset_input_state
void reset_input_state(void)
Definition
input.c:32
ContPadData
OSContPad ContPadData
Definition
input.c:4
update_input
void update_input(void)
Definition
input.c:53
STICK_DEADZONE_THRESHOLD
#define STICK_DEADZONE_THRESHOLD
Definition
input.c:10
StickExtremeX
BSS s16 StickExtremeX
Definition
input.c:5
StickExtremeY
BSS s16 StickExtremeY
Definition
input.c:6
BSS
#define BSS
Definition
macros.h:6
gGameStatusPtr
GameStatus * gGameStatusPtr
Definition
main_loop.c:31
src
input.c
Generated by
1.10.0