Paper Mario DX
Paper Mario (N64) modding
 
Loading...
Searching...
No Matches
mega_shock.c
Go to the documentation of this file.
1#include "common.h"
2
3
4#include "audio/public.h"
5#include "battle/action_cmd.h"
6
7#define NAMESPACE action_command_mega_shock
8
9extern s32 actionCmdTableMegaShock[];
10
11// indices into ActionCommandStatus::hudElements for this action command
12enum {
17};
18
19// how much to add to the meter per input
20#define METER_FILL_TICK 780
21
22s32 N(DrainRateTable)[] = { 0, 25, 50, 75, 75 };
23
24#define GET_DRAIN_RATE(pct) PCT_TO_TABLE_RATE(N(DrainRateTable), pct)
25
26API_CALLABLE(N(init)) {
27 BattleStatus* battleStatus = &gBattleStatus;
29 HudElemID hid;
30
31 battleStatus->maxActionQuality = 5;
33 if (battleStatus->actionCommandMode == AC_MODE_NOT_LEARNED) {
34 battleStatus->actionQuality = 0;
35 return ApiStatus_DONE2;
36 }
37
39
41 acs->state = AC_STATE_INIT;
42 acs->hudPrepareTime = 30;
43 acs->wrongButtonPressed = FALSE;
44 acs->meterFillLevel = 0;
45 acs->meterFillWidth = 0;
46 acs->isMeterFilled = FALSE;
47 acs->hudPosX = -48;
48 acs->hudPosY = 80;
49
51 acs->hudElemIDs[HIDX_A_BUTTON] = hid;
55
57 acs->hudElemIDs[HIDX_B_BUTTON] = hid;
61
63 acs->hudElemIDs[HIDX_METER] = hid;
64 hud_element_set_render_pos(hid, acs->hudPosX, acs->hudPosY + 28);
67
69 acs->hudElemIDs[HIDX_100_PCT] = hid;
70 hud_element_set_render_pos(hid, acs->hudPosX, acs->hudPosY + 28);
73
74 return ApiStatus_DONE2;
75}
76
77API_CALLABLE(N(start)) {
79 BattleStatus* battleStatus = &gBattleStatus;
80 Bytecode* args = script->ptrReadPos;
81
82 if (battleStatus->actionCommandMode == AC_MODE_NOT_LEARNED) {
83 battleStatus->actionQuality = 0;
84 return ApiStatus_DONE2;
85 }
86
88
89 acs->prepareTime = evt_get_variable(script, *args++);
90 acs->duration = evt_get_variable(script, *args++);
91 acs->difficulty = evt_get_variable(script, *args++);
93 acs->statusChance = evt_get_variable(script, *args++); // average chance for enemies to be affected
94
95 acs->wrongButtonPressed = FALSE;
96 acs->meterFillLevel = 0;
97 acs->meterFillWidth = 0;
98 battleStatus->actionQuality = 0;
99 battleStatus->actionResult = ACTION_RESULT_FAIL;
100 acs->state = AC_STATE_START;
101 battleStatus->flags1 &= ~BS_FLAGS1_FREE_ACTION_COMMAND;
102
104
105 return ApiStatus_DONE2;
106}
107
108void N(update)(void) {
110 BattleStatus* battleStatus = &gBattleStatus;
111 HudElemID hid;
112 s32 cutoff;
113 s32 buttonsPushed;
114 s32 buttonsAB;
115 s32 bufferPos;
116 s32 i;
117
118 switch (acs->state) {
119 case AC_STATE_INIT:
121
122 hid = acs->hudElemIDs[HIDX_A_BUTTON];
123 if (acs->showHud) {
125 }
126 hud_element_set_alpha(hid, 255);
127
128 hid = acs->hudElemIDs[HIDX_B_BUTTON];
129 if (acs->showHud) {
131 }
132 hud_element_set_alpha(hid, 255);
133
134 hid = acs->hudElemIDs[HIDX_METER];
135 hud_element_set_alpha(hid, 255);
136 if (acs->showHud) {
138 }
139
140 acs->state = AC_STATE_APPEAR;
141 break;
142 case AC_STATE_APPEAR:
144 if (acs->hudPrepareTime != 0) {
145 acs->hudPrepareTime--;
146 break;
147 }
148
149 acs->hudPosX += 20;
150 if (acs->hudPosX > 50) {
151 acs->hudPosX = 50;
152 }
153
157 break;
158 case AC_STATE_START:
160 if (acs->prepareTime != 0) {
161 acs->prepareTime--;
162 break;
163 }
166 acs->meterFillLevel = 0;
167 acs->any.unk_5C = 0;
168 acs->stateTimer = acs->duration;
170 acs->state = AC_STATE_ACTIVE;
171
172 // fallthrough
173 case AC_STATE_ACTIVE:
175
176 // meter can drain if it hasn't been fully filled
177 if (!acs->isMeterFilled) {
178 if (acs->statusChance != 0) {
179 cutoff = acs->mashMeterCutoffs[acs->mashMeterNumIntervals];
180 acs->meterFillLevel -= GET_DRAIN_RATE(acs->meterFillLevel / cutoff);
181 if (acs->meterFillLevel < 0) {
182 acs->meterFillLevel = 0;
183 }
184 } else {
185 acs->meterFillLevel -= 10;
186 if (acs->meterFillLevel < 0) {
187 acs->meterFillLevel = 0;
188 }
189 }
190 }
191
192 // step back two frames in the input buffer
193 bufferPos = battleStatus->inputBufferPos;
194 bufferPos -= 2;
195 if (bufferPos < 0) {
196 bufferPos += ARRAY_COUNT(battleStatus->pushInputBuffer);
197 }
198
199 buttonsPushed = 0;
200
201 // get combined input during the last two frames
202 for (i = 1; i >= 0; i--) {
203 if (bufferPos >= ARRAY_COUNT(battleStatus->pushInputBuffer)) {
204 bufferPos -= ARRAY_COUNT(battleStatus->pushInputBuffer);
205 }
206 buttonsPushed |= battleStatus->pushInputBuffer[bufferPos];
207 bufferPos++;
208 }
209
210 buttonsAB = BUTTON_A | BUTTON_B;
211 if ((buttonsPushed & buttonsAB) == buttonsAB) {
212 if (acs->statusChance != 0) {
213 s32 amt;
214
215 amt = SCALE_BY_PCT(METER_FILL_TICK, acs->statusChance);
216 amt = SCALE_BY_PCT(amt, battleStatus->actionCmdDifficultyTable[acs->difficulty]);
217
218 // Perplexing reuse of buttonsPushed here, but it fixes register allocation. Likely another
219 // subexpression from above can be put into a variable and reused instead.
220 //
221 // TODO: Find a way to avoid reusing buttonsPushed.
222 buttonsPushed = amt;
223
224 acs->meterFillLevel += buttonsPushed;
225 } else {
227
228 if (acs->meterFillLevel >= 5 * ONE_PCT_MASH) {
229 acs->meterFillLevel = 5 * ONE_PCT_MASH;
230 }
231 }
232
233 // step back two frames in the input buffer
234 bufferPos = battleStatus->inputBufferPos;
235 bufferPos -= 2;
236 if (bufferPos < 0) {
237 bufferPos += ARRAY_COUNT(battleStatus->pushInputBuffer);
238 }
239
240 // clear buffer to be ready for the next input
241 for (i = 1; i >= 0; i--) {
242 if (bufferPos >= ARRAY_COUNT(battleStatus->pushInputBuffer)) {
243 bufferPos -= ARRAY_COUNT(battleStatus->pushInputBuffer);
244 }
245 battleStatus->pushInputBuffer[bufferPos] = 0;
246 bufferPos++;
247 }
248 }
249
250 if (acs->meterFillLevel > MAX_MASH_UNITS) {
252 acs->isMeterFilled = TRUE;
253 hid = acs->hudElemIDs[HIDX_100_PCT];
254 hud_element_set_render_pos(hid, acs->hudPosX + 50, acs->hudPosY + 28);
256 }
257
258 battleStatus->actionProgress = acs->meterFillLevel / ONE_PCT_MASH;
260
261 if (acs->stateTimer != 0) {
262 acs->stateTimer--;
263 break;
264 }
265
266 // Again, reusing buttonsPushed specifically for reg-alloc. See above.
267 //
268 // TODO: Find a way to avoid reusing buttonsPushed.
269 buttonsPushed = acs->meterFillLevel;
270 if (acs->statusChance == 0) {
271 buttonsPushed = 0;
272 }
273
274 if (buttonsPushed == 0) {
275 battleStatus->actionQuality = AC_QUALITY_FAILED;
276 } else {
277 battleStatus->actionQuality = buttonsPushed / ONE_PCT_MASH;
278 }
279
280 // a good result is filling the meter over halfway to the second-highest interval
281 cutoff = acs->mashMeterCutoffs[acs->mashMeterNumIntervals - 1];
282 if (battleStatus->actionProgress <= cutoff / 2) {
284 } else {
285 battleStatus->actionResult = ACTION_RESULT_SUCCESS;
286 }
287
288 if (battleStatus->actionQuality == 100) {
289 // only count 100% fill as success for this action command
291 }
292
295 acs->stateTimer = 5;
296 acs->state = AC_STATE_DISPOSE;
297 break;
298 case AC_STATE_DISPOSE:
299 if (acs->statusChance == 0) {
301 if (acs->meterFillLevel < 0) {
302 acs->meterFillLevel = 0;
303 }
304 }
305
306 if (acs->stateTimer != 0) {
307 acs->stateTimer--;
308 break;
309 }
311 break;
312 }
313}
314
315void N(draw)(void) {
317 s32 hudX, hudY;
318 HudElemID hid;
319
322
323 hid = acs->hudElemIDs[HIDX_METER];
325 hud_element_get_render_pos(hid, &hudX, &hudY);
326
327 if (!acs->isMeterFilled) {
329 } else {
331 }
332
334}
335
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_MEGA_SHOCK
Definition enums.h:3489
@ BUTTON_A
Definition enums.h:2790
@ BUTTON_B
Definition enums.h:2789
@ SOUND_LOOP_CHARGE_METER
Definition enums.h:1646
@ 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 mega_shock.c:20
#define GET_DRAIN_RATE(pct)
Definition mega_shock.c:24
@ HIDX_METER
Definition mega_shock.c:14
@ HIDX_A_BUTTON
Definition mega_shock.c:13
@ HIDX_B_BUTTON
Definition mega_shock.c:15
@ HIDX_100_PCT
Definition mega_shock.c:16
void N free(void)
Definition mega_shock.c:336
s32 actionCmdTableMegaShock[]
Definition action_cmd.c:44
void N update(void)
Definition mega_shock.c:108
void N draw(void)
Definition mega_shock.c:315
void sfx_stop_sound(s32 soundID)
Definition sfx.c:507
void sfx_adjust_env_sound_params(s32 soundID, u8 volume, u8 pan, s16 pitchShift)
Definition sfx.c:492
void sfx_play_sound_with_params(s32 soundID, u8 volume, u8 pan, s16 pitchShift)
Definition sfx.c:458
#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