Paper Mario DX
Paper Mario (N64) modding
 
Loading...
Searching...
No Matches
power_shock.c
Go to the documentation of this file.
1#include "common.h"
2#include "battle/action_cmd.h"
3
15#define NAMESPACE action_command_power_shock
16
17extern s32 actionCmdTablePowerShock[];
18
19// indices into ActionCommandStatus::hudElements for this action command
20enum {
23 HIDX_RUN_AWAY = 2, // unused
26};
27
28// how much to add to the meter per input
29#define METER_FILL_TICK 850
30
31s32 N(DrainRateTable)[] = { 0, 25, 50, 75, 75 };
32
33#define GET_DRAIN_RATE(pct) (N(DrainRateTable)[((pct) / (ONE_PCT_MASH / 5))])
34
35BSS s32 N(HasStarted);
36
37API_CALLABLE(N(init)) {
39 BattleStatus* battleStatus = &gBattleStatus;
40 HudElemID hid;
41 s32 offsetX;
42
43 battleStatus->maxActionQuality = 100;
45
46 if (battleStatus->actionCommandMode == AC_MODE_NOT_LEARNED) {
47 battleStatus->actionQuality = 0;
48 return ApiStatus_DONE2;
49 }
50
53 acs->state = AC_STATE_INIT;
54 acs->wrongButtonPressed = FALSE;
55 acs->meterFillLevel = 0;
56 acs->meterFillWidth = 0;
57 acs->escapeThreshold = rand_int(100);
58 acs->hudPrepareTime = 30;
59 acs->isMeterFilled = FALSE;
60 acs->thresholdMoveDir = 0;
61 N(HasStarted) = FALSE;
62
63 acs->hudPosX = -48;
64 acs->hudPosY = 80;
65
67 acs->hudElemIDs[HIDX_BUTTON] = hid;
71
73 acs->hudElemIDs[HIDX_METER] = hid;
74 hud_element_set_render_pos(hid, acs->hudPosX, acs->hudPosY + 28);
77
79 acs->hudElemIDs[HIDX_100_PCT] = hid;
80 hud_element_set_render_pos(hid, acs->hudPosX, acs->hudPosY + 28);
83
85 acs->hudElemIDs[HIDX_OK] = hid;
86 hud_element_set_render_pos(hid, acs->hudPosX, acs->hudPosY + 28);
89
90 offsetX = 29 - ((100 - acs->escapeThreshold) * 60) / 100;
91 hud_element_set_render_pos(acs->hudElemIDs[HIDX_100_PCT], acs->hudPosX - offsetX, acs->hudPosY + 17);
92 return ApiStatus_DONE2;
93}
94
95API_CALLABLE(N(start)) {
97 BattleStatus* battleStatus = &gBattleStatus;
98 Bytecode* args = script->ptrReadPos;
99
100 if (battleStatus->actionCommandMode == AC_MODE_NOT_LEARNED) {
101 battleStatus->actionQuality = 0;
102 return ApiStatus_DONE2;
103 }
104
106
107 acs->prepareTime = evt_get_variable(script, *args++);
108 acs->duration = evt_get_variable(script, *args++);
109 acs->difficulty = evt_get_variable(script, *args++);
111 acs->statusChance = evt_get_variable(script, *args++); // chance for enemy to be affected
112
113 acs->wrongButtonPressed = FALSE;
114 acs->meterFillLevel = 0;
115 acs->meterFillWidth = 0;
116 battleStatus->actionQuality = 0;
117 battleStatus->actionResult = ACTION_RESULT_FAIL;
118 acs->state = AC_STATE_START;
119 battleStatus->flags1 &= ~BS_FLAGS1_FREE_ACTION_COMMAND;
120
122
123 return ApiStatus_DONE2;
124}
125
126void N(update)(void) {
128 BattleStatus* battleStatus = &gBattleStatus;
129 HudElemID hid;
130 s32 amt;
131 s32 cutoff;
132 s32 offsetX;
133
134 switch (acs->state) {
135 case AC_STATE_INIT:
137 hid = acs->hudElemIDs[HIDX_BUTTON];
138 if (acs->showHud) {
140 }
141 hud_element_set_alpha(hid, 255);
142 hid = acs->hudElemIDs[HIDX_METER];
143 hud_element_set_alpha(hid, 255);
144 if (acs->showHud) {
146 }
147 hid = acs->hudElemIDs[HIDX_OK];
148 hud_element_set_alpha(hid, 255);
149 if (acs->showHud) {
151 }
152 acs->state = AC_STATE_APPEAR;
153 break;
154 case AC_STATE_APPEAR:
156 if (acs->hudPrepareTime != 0) {
157 acs->hudPrepareTime--;
158 } else {
159 acs->hudPosX += 20;
160 if (acs->hudPosX > 50) {
161 acs->hudPosX = 50;
162 }
165
166 amt = 100 - acs->escapeThreshold;
167 offsetX = 29 - (amt * 60) / 100;
168 hud_element_set_render_pos(acs->hudElemIDs[HIDX_OK], acs->hudPosX - offsetX, acs->hudPosY + 17);
169 }
170 break;
171 case AC_STATE_START:
173 if (acs->prepareTime != 0) {
174 acs->prepareTime--;
175 break;
176 }
178 acs->meterFillLevel = 0;
179 acs->any.unk_5C = 0;
180 N(HasStarted) = TRUE;
181 acs->stateTimer = acs->duration;
183 acs->state = AC_STATE_ACTIVE;
184
185 // fallthrough
186 case AC_STATE_ACTIVE:
188
189 // meter can drain if it hasn't been fully filled
190 if (!acs->isMeterFilled) {
191 if (acs->statusChance != 0) {
192 cutoff = acs->mashMeterCutoffs[acs->mashMeterNumIntervals];
193 acs->meterFillLevel -= GET_DRAIN_RATE(acs->meterFillLevel / cutoff);
194 if (acs->meterFillLevel < 0) {
195 acs->meterFillLevel = 0;
196 }
197 } else {
198 acs->meterFillLevel -= 10;
199 if (acs->meterFillLevel < 0) {
200 acs->meterFillLevel = 0;
201 }
202 }
203 }
204
205 // check for meter-filling input
206 if (battleStatus->curButtonsPressed & BUTTON_A) {
207 if (acs->statusChance != 0) {
208 s32 difficultyPct = battleStatus->actionCmdDifficultyTable[acs->difficulty];
209 amt = SCALE_BY_PCT(SCALE_BY_PCT(METER_FILL_TICK, difficultyPct), acs->statusChance);
210
211 acs->meterFillLevel += amt;
212 } else {
214 if (acs->meterFillLevel >= 5 * ONE_PCT_MASH) {
215 acs->meterFillLevel = 5 * ONE_PCT_MASH;
216 }
217 }
218 }
219
220 // handle meter reaching 100%
221 if (acs->meterFillLevel > MAX_MASH_UNITS) {
223 acs->isMeterFilled = TRUE;
224 hid = acs->hudElemIDs[HIDX_100_PCT];
225 hud_element_set_render_pos(hid, acs->hudPosX + 50, acs->hudPosY + 28);
227 }
228
229 battleStatus->actionProgress = acs->meterFillLevel / ONE_PCT_MASH;
231
232 if (acs->stateTimer != 0) {
233 acs->stateTimer--;
234 break;
235 }
236
237 amt = acs->meterFillLevel;
238 if (acs->statusChance == 0) {
239 amt = 0;
240 }
241
242 battleStatus->actionProgress = amt / ONE_PCT_MASH;
243 if (amt == 0) {
244 battleStatus->actionQuality = AC_QUALITY_FAILED;
245 } else if (battleStatus->actionProgress >= acs->escapeThreshold) {
246 battleStatus->actionQuality = 1;
247 } else {
248 battleStatus->actionQuality = 0;
249 }
250
251 // a good result is filling the meter over halfway to the second-highest interval
252 cutoff = acs->mashMeterCutoffs[acs->mashMeterNumIntervals - 1];
253 if (battleStatus->actionProgress <= cutoff / 2) {
255 } else {
256 battleStatus->actionResult = ACTION_RESULT_SUCCESS;
257 }
258
259 if (battleStatus->actionQuality == 1) {
261 }
262
265 acs->stateTimer = 5;
266 acs->state = AC_STATE_DISPOSE;
267 break;
268 case AC_STATE_DISPOSE:
269 if (acs->statusChance == 0) {
271 if (acs->meterFillLevel < 0) {
272 acs->meterFillLevel = 0;
273 }
274 }
275 if (acs->stateTimer != 0) {
276 acs->stateTimer--;
277 break;
278 }
280 break;
281 }
282
283 // Invisible "run away"-like meter that determines success threshold.
284 // https://www.youtube.com/watch?v=FagUpV0c67s
285 switch (acs->state) {
286 case AC_STATE_APPEAR:
287 case AC_STATE_START:
288 case AC_STATE_ACTIVE:
289 if (acs->thresholdMoveDir == 0) {
290 acs->escapeThreshold += 7;
291 if (acs->escapeThreshold >= 100) {
292 acs->escapeThreshold = 100;
293 acs->thresholdMoveDir = 1;
294 }
295 } else {
296 acs->escapeThreshold -= 7;
297 if (acs->escapeThreshold <= 0) {
298 acs->escapeThreshold = 0;
299 acs->thresholdMoveDir = 0;
300 }
301 }
302 }
303}
304
305void N(draw)(void) {
307 s32 hudX, hudY;
308 HudElemID hid;
309
310 hudX = 60 - (acs->escapeThreshold * 60 / 100);
311 hud_element_set_render_pos(acs->hudElemIDs[HIDX_OK], acs->hudPosX + 31 - hudX, acs->hudPosY + 17);
313
314 hid = acs->hudElemIDs[HIDX_METER];
316 hud_element_get_render_pos(hid, &hudX, &hudY);
317 // Redundant call, but needed to match.
318 hud_element_get_render_pos(hid, &hudX, &hudY);
319
320 if (!N(HasStarted)) {
322 } else if (!acs->isMeterFilled) {
324 } else {
326 }
327 hid = acs->hudElemIDs[HIDX_100_PCT];
329}
330
void draw_mash_meter_blink_with_divisor(s32 posX, s32 posY, s32 fillValue, s32 divisor)
Definition action_cmd.c:251
BSS ActionCommandStatus gActionCommandStatus
Definition action_cmd.c:91
void action_command_free(void)
Definition action_cmd.c:446
void increment_action_command_attempt_count(void)
Definition action_cmd.c:641
void draw_mash_meter_multicolor_with_divisor(s32 posX, s32 posY, s32 fillValue, s32 divisor)
Definition action_cmd.c:231
s32 adjust_action_command_difficulty(s32 difficultyLevel)
Definition action_cmd.c:101
void increment_action_command_success_count(void)
Definition action_cmd.c:655
void action_command_init_status(void)
Definition action_cmd.c:256
#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_RunAwayOK
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
#define rand_int
@ ACTION_COMMAND_POWER_SHOCK
Definition enums.h:3488
@ BUTTON_A
Definition enums.h:2790
@ 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 power_shock.c:29
#define GET_DRAIN_RATE(pct)
Definition power_shock.c:33
void N free(void)
s32 actionCmdTablePowerShock[]
Definition action_cmd.c:43
@ HIDX_RUN_AWAY
Definition power_shock.c:23
@ HIDX_METER
Definition power_shock.c:22
@ HIDX_BUTTON
Definition power_shock.c:21
@ HIDX_OK
Definition power_shock.c:25
@ HIDX_100_PCT
Definition power_shock.c:24
void N update(void)
void N draw(void)
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 BSS
Definition macros.h:7
#define POPUP_MSG_OFF
Definition battle.h:270
#define POPUP_MSG_ON
Definition battle.h:269
s32 * actionCmdDifficultyTable
BattleStatus gBattleStatus
Definition battle.c:11
void N init(Npc *bombette)
Definition bombette.c:66