Paper Mario DX
Paper Mario (N64) modding
 
Loading...
Searching...
No Matches
hurricane.c
Go to the documentation of this file.
1#include "common.h"
2#include "battle/action_cmd.h"
3
4#define NAMESPACE action_command_hurricane
5
6extern s32 actionCmdTableHurricane[];
7
8// indices into ActionCommandStatus::hudElements for this action command
9enum {
14};
15
16// how much to add to the meter per input
17#define METER_FILL_TICK 650
18
19s32 N(DrainRateTable)[] = { 0, 25, 50, 75, 75 };
20
21#define GET_DRAIN_RATE(pct) PCT_TO_TABLE_RATE(N(DrainRateTable), pct)
22
23API_CALLABLE(N(init)) {
25 BattleStatus* battleStatus = &gBattleStatus;
26 HudElemID hid;
27
28 battleStatus->maxActionQuality = 5;
30 if (battleStatus->actionCommandMode == AC_MODE_NOT_LEARNED) {
31 battleStatus->actionQuality = 0;
32 return ApiStatus_DONE2;
33 }
34
36
38 acs->hudPrepareTime = 30;
39 acs->hudPosX = -48;
40 acs->state = AC_STATE_INIT;
41 acs->wrongButtonPressed = FALSE;
42 acs->meterFillLevel = 0;
43 acs->meterFillWidth = 0;
44 acs->isMeterFilled = FALSE;
45 acs->hudPosY = 80;
46
48 acs->hudElemIDs[HIDX_A_BUTTON] = hid;
52
54 acs->hudElemIDs[HIDX_B_BUTTON] = hid;
58
60 acs->hudElemIDs[HIDX_METER] = hid;
61 hud_element_set_render_pos(hid, acs->hudPosX, acs->hudPosY + 28);
64
66 acs->hudElemIDs[HIDX_100_PCT] = hid;
67 hud_element_set_render_pos(hid, acs->hudPosX, acs->hudPosY + 28);
70
71 return ApiStatus_DONE2;
72}
73
74API_CALLABLE(N(start)) {
76 BattleStatus* battleStatus = &gBattleStatus;
77 Bytecode* args = script->ptrReadPos;
78
79 if (battleStatus->actionCommandMode == AC_MODE_NOT_LEARNED) {
80 battleStatus->actionQuality = 0;
81 return ApiStatus_DONE2;
82 }
83
85
86 acs->prepareTime = evt_get_variable(script, *args++);
87 acs->duration = evt_get_variable(script, *args++);
88 acs->difficulty = evt_get_variable(script, *args++);
90 acs->statusChance = evt_get_variable(script, *args++); // average chance for enemies to be affected
91
92 acs->wrongButtonPressed = FALSE;
93 acs->meterFillLevel = 0;
94 acs->meterFillWidth = 0;
95 battleStatus->actionQuality = 0;
96 battleStatus->actionResult = ACTION_RESULT_FAIL;
97 acs->state = AC_STATE_START;
98 battleStatus->flags1 &= ~BS_FLAGS1_FREE_ACTION_COMMAND;
99
101
102 return ApiStatus_DONE2;
103}
104
105void N(update)(void) {
107 BattleStatus* battleStatus = &gBattleStatus;
108 HudElemID hid;
109 s32 cutoff;
110 s32 buttonsPushed;
111 s32 buttonsAB;
112 s32 bufferPos;
113 s32 i;
114
115 switch (acs->state) {
116 case AC_STATE_INIT:
118
119 hid = acs->hudElemIDs[HIDX_A_BUTTON];
120 if (acs->showHud) {
122 }
123 hud_element_set_alpha(hid, 255);
124
125 hid = acs->hudElemIDs[HIDX_B_BUTTON];
126 if (acs->showHud) {
128 }
129 hud_element_set_alpha(hid, 255);
130
131 hid = acs->hudElemIDs[HIDX_METER];
132 hud_element_set_alpha(hid, 255);
133 if (acs->showHud) {
135 }
136
137 acs->state = AC_STATE_APPEAR;
138 break;
139 case AC_STATE_APPEAR:
141 if (acs->hudPrepareTime != 0) {
142 acs->hudPrepareTime--;
143 break;
144 }
145
146 acs->hudPosX += 20;
147 if (acs->hudPosX > 50) {
148 acs->hudPosX = 50;
149 }
150
154 break;
155 case AC_STATE_START:
157 if (acs->prepareTime != 0) {
158 acs->prepareTime--;
159 break;
160 }
163 acs->meterFillLevel = 0;
164 acs->any.unk_5C = 0;
165 acs->stateTimer = acs->duration;
166 acs->state = AC_STATE_ACTIVE;
167
168 // fallthrough
169 case AC_STATE_ACTIVE:
171
172 // meter can drain if it hasn't been fully filled
173 if (!acs->isMeterFilled) {
174 if (acs->statusChance != 0) {
175 cutoff = acs->mashMeterCutoffs[acs->mashMeterNumIntervals];
176 acs->meterFillLevel -= GET_DRAIN_RATE(acs->meterFillLevel / cutoff);
177 if (acs->meterFillLevel < 0) {
178 acs->meterFillLevel = 0;
179 }
180 } else {
181 acs->meterFillLevel -= 10;
182 if (acs->meterFillLevel < 0) {
183 acs->meterFillLevel = 0;
184 }
185 }
186 }
187
188 // step back two frames in the input buffer
189 bufferPos = battleStatus->inputBufferPos;
190 bufferPos -= 2;
191 if (bufferPos < 0) {
192 bufferPos += ARRAY_COUNT(battleStatus->pushInputBuffer);
193 }
194
195 buttonsPushed = 0;
196
197 // get combined input during the last two frames
198 for (i = 1; i >= 0; i--) {
199 if (bufferPos >= ARRAY_COUNT(battleStatus->pushInputBuffer)) {
200 bufferPos -= ARRAY_COUNT(battleStatus->pushInputBuffer);
201 }
202 buttonsPushed |= battleStatus->pushInputBuffer[bufferPos];
203 bufferPos++;
204 }
205
206 buttonsAB = BUTTON_A | BUTTON_B;
207 if ((buttonsPushed & buttonsAB) == buttonsAB) {
208 if (acs->statusChance != 0) {
209 s32 amt;
210
211 amt = SCALE_BY_PCT(METER_FILL_TICK, acs->statusChance);
212 amt = SCALE_BY_PCT(amt, battleStatus->actionCmdDifficultyTable[acs->difficulty]);
213
214 // Perplexing reuse of buttonsPushed here, but it fixes register allocation. Likely another
215 // subexpression from above can be put into a variable and reused instead.
216 //
217 // TODO: Find a way to avoid reusing buttonsPushed.
218 buttonsPushed = amt;
219
220 acs->meterFillLevel += buttonsPushed;
221 } else {
223
224 if (acs->meterFillLevel >= 5 * ONE_PCT_MASH) {
225 acs->meterFillLevel = 5 * ONE_PCT_MASH;
226 }
227 }
228
229 // step back two frames in the input buffer
230 bufferPos = battleStatus->inputBufferPos;
231 bufferPos -= 2;
232 if (bufferPos < 0) {
233 bufferPos += ARRAY_COUNT(battleStatus->pushInputBuffer);
234 }
235
236 // clear buffer to be ready for the next input
237 for (i = 1; i >= 0; i--) {
238 if (bufferPos >= ARRAY_COUNT(battleStatus->pushInputBuffer)) {
239 bufferPos -= ARRAY_COUNT(battleStatus->pushInputBuffer);
240 }
241 battleStatus->pushInputBuffer[bufferPos] = 0;
242 bufferPos++;
243 }
244 }
245
246 // handle meter reaching 100%
247 if (acs->meterFillLevel > MAX_MASH_UNITS) {
249 acs->isMeterFilled = TRUE;
250 hid = acs->hudElemIDs[HIDX_100_PCT];
251 hud_element_set_render_pos(hid, acs->hudPosX + 50, acs->hudPosY + 28);
253 }
254
255 battleStatus->actionProgress = acs->meterFillLevel / ONE_PCT_MASH;
256
257 if (acs->stateTimer != 0) {
258 acs->stateTimer--;
259 break;
260 }
261
262 // Again, reusing buttonsPushed specifically for reg-alloc. See above.
263 //
264 // TODO: Find a way to avoid reusing buttonsPushed.
265 buttonsPushed = acs->meterFillLevel;
266 if (acs->statusChance == 0) {
267 buttonsPushed = 0;
268 }
269
270 if (buttonsPushed == 0) {
271 battleStatus->actionQuality = AC_QUALITY_FAILED;
272 } else {
273 battleStatus->actionQuality = buttonsPushed / ONE_PCT_MASH;
274 }
275
276 // a good result is filling the meter over halfway to the second-highest interval
277 cutoff = acs->mashMeterCutoffs[acs->mashMeterNumIntervals - 1];
278 if (battleStatus->actionProgress <= cutoff / 2) {
280 } else {
281 battleStatus->actionResult = ACTION_RESULT_SUCCESS;
282 }
283
284 if (battleStatus->actionQuality == 100) {
285 // only count 100% fill as success for this action command
287 }
288
290 acs->stateTimer = 5;
291 acs->state = AC_STATE_DISPOSE;
292 break;
293 case AC_STATE_DISPOSE:
294 if (acs->statusChance == 0) {
296 if (acs->meterFillLevel < 0) {
297 acs->meterFillLevel = 0;
298 }
299 }
300
301 if (acs->stateTimer != 0) {
302 acs->stateTimer--;
303 break;
304 }
306 break;
307 }
308}
309
310void N(draw)(void) {
312 s32 hudX, hudY;
313 HudElemID hid;
314
317
318 hid = acs->hudElemIDs[HIDX_METER];
320 hud_element_get_render_pos(hid, &hudX, &hudY);
321
322 if (!acs->isMeterFilled) {
324 } else {
326 }
327
329}
330
BSS ActionCommandStatus gActionCommandStatus
Definition action_cmd.c:91
void draw_mash_meter_multicolor(s32 posX, s32 posY, s32 fillValue)
Definition action_cmd.c:226
void action_command_free(void)
Definition action_cmd.c:446
void increment_action_command_attempt_count(void)
Definition action_cmd.c:641
s32 adjust_action_command_difficulty(s32 difficultyLevel)
Definition action_cmd.c:101
void draw_mash_meter_blink(s32 posX, s32 posY, s32 fillValue)
Definition action_cmd.c:246
void increment_action_command_success_count(void)
Definition action_cmd.c:655
void action_command_init_status(void)
Definition action_cmd.c:256
HudScript HES_MashBButton1
HudScript HES_BButton
#define AC_QUALITY_FAILED
Definition action_cmd.h:66
HudScript HES_AButton
HudElemID hudElemIDs[16]
Definition action_cmd.h:83
@ AC_STATE_APPEAR
Definition action_cmd.h:35
@ AC_STATE_DISPOSE
Definition action_cmd.h:38
@ AC_STATE_INIT
Definition action_cmd.h:34
@ AC_STATE_ACTIVE
Definition action_cmd.h:37
@ AC_STATE_START
Definition action_cmd.h:36
#define ONE_PCT_MASH
Definition action_cmd.h:69
#define SCALE_BY_PCT(x, pct)
Definition action_cmd.h:77
HudScript HES_BlueMeter
HudScript HES_MashAButton
HudScript HES_100pct
@ AC_MODE_NOT_LEARNED
Definition action_cmd.h:60
#define MAX_MASH_UNITS
Definition action_cmd.h:75
s32 HudElemID
@ ACTION_COMMAND_HURRICANE
Definition enums.h:3492
@ BUTTON_A
Definition enums.h:2790
@ BUTTON_B
Definition enums.h:2789
@ ACTION_RESULT_SUCCESS
Definition enums.h:1968
@ ACTION_RESULT_METER_BELOW_HALF
Definition enums.h:1964
@ ACTION_RESULT_FAIL
Definition enums.h:1967
#define ApiStatus_DONE2
Definition evt.h:118
s32 Bytecode
Definition evt.h:7
void btl_set_popup_duration(s32 duration)
s32 evt_get_variable(Evt *script, Bytecode var)
Definition evt.c:1689
void hud_element_get_render_pos(s32 id, s32 *x, s32 *y)
void hud_element_set_alpha(s32 id, s32 opacity)
void hud_element_set_script(s32 id, HudScript *anim)
void hud_element_set_render_depth(s32 id, s32 z)
void hud_element_set_render_pos(s32 id, s32 x, s32 y)
s32 hud_element_create(HudScript *anim)
Creates a new HUD element and returns its ID.
void hud_element_set_flags(s32 id, s32 flags)
Turns on the given flags.
void hud_element_clear_flags(s32 id, s32 flags)
Turns off the given flags.
void hud_element_draw_clipped(s32 id)
void hud_element_free(s32 id)
@ HUD_ELEMENT_FLAG_DISABLED
Definition hud_element.h:72
@ HUD_ELEMENT_FLAG_80
Definition hud_element.h:78
#define METER_FILL_TICK
Definition hurricane.c:17
#define GET_DRAIN_RATE(pct)
Definition hurricane.c:21
@ HIDX_METER
Definition hurricane.c:11
@ HIDX_A_BUTTON
Definition hurricane.c:10
@ HIDX_B_BUTTON
Definition hurricane.c:12
@ HIDX_100_PCT
Definition hurricane.c:13
s32 actionCmdTableHurricane[]
Definition action_cmd.c:47
void N free(void)
Definition hurricane.c:331
void N update(void)
Definition hurricane.c:105
void N draw(void)
Definition hurricane.c:310
#define ARRAY_COUNT(arr)
Definition macros.h:40
#define POPUP_MSG_OFF
Definition battle.h:270
#define POPUP_MSG_ON
Definition battle.h:269
s32 * actionCmdDifficultyTable
s32 pushInputBuffer[64]
BattleStatus gBattleStatus
Definition battle.c:11
void N init(Npc *bombette)
Definition bombette.c:66