Paper Mario DX
Paper Mario (N64) modding
 
Loading...
Searching...
No Matches
fire_shell.c
Go to the documentation of this file.
1#include "battle/battle.h"
2#include "battle/action_cmd.h"
3
4#define NAMESPACE action_command_fire_shell
5
6extern s32 actionCmdTableFireShell[];
7
8// indices into ActionCommandStatus::hudElements for this action command
9enum {
13};
14
15// how much to add to the meter per input
16#define METER_FILL_TICK 950
17
18s32 N(DrainRateTable)[] = { 0, 25, 50, 75, 75 };
19
20#define GET_DRAIN_RATE(pct) PCT_TO_TABLE_RATE(N(DrainRateTable), pct)
21
22// threshold meter values; not used for anything
23// these correspond to values provided via SetupMashMeter
24s32 N(BasicThresholds)[] = { 40, 70, 99, 200 };
25s32 N(SuperThresholds)[] = { 35, 60, 80, 99, 200 };
26s32 N(UltraThresholds)[] = { 35, 35, 60, 80, 99, 200 };
27
28API_CALLABLE(N(init)) {
30 BattleStatus* battleStatus = &gBattleStatus;
31 HudElemID hid;
32
33 battleStatus->maxActionQuality = 100;
35 battleStatus->actionResult = ACTION_RESULT_NONE;
36
37 if (battleStatus->actionCommandMode == AC_MODE_NOT_LEARNED) {
38 battleStatus->actionQuality = 0;
39 return ApiStatus_DONE2;
40 }
42
44 acs->showHud = TRUE;
45 acs->hudPrepareTime = 30;
46 acs->state = AC_STATE_INIT;
47 acs->wrongButtonPressed = FALSE;
48 acs->meterFillLevel = 0;
49 acs->meterFillWidth = 0;
50 acs->isMeterFilled = FALSE;
51 battleStatus->actionQuality = 0;
52 acs->hudPosX = -48;
53 acs->hudPosY = 80;
54
56 acs->hudElemIDs[HIDX_STICK] = hid;
60
62 acs->hudElemIDs[HIDX_METER] = hid;
63 hud_element_set_render_pos(hid, acs->hudPosX, acs->hudPosY + 28);
66
68 acs->hudElemIDs[HIDX_100_PCT] = hid;
69 hud_element_set_render_pos(hid, acs->hudPosX, acs->hudPosY + 28);
72
73 return ApiStatus_DONE2;
74}
75
76API_CALLABLE(N(start)) {
78 BattleStatus* battleStatus = &gBattleStatus;
79 Bytecode* args = script->ptrReadPos;
80
81 if (battleStatus->actionCommandMode == AC_MODE_NOT_LEARNED) {
82 battleStatus->actionQuality = 0;
83 return ApiStatus_DONE2;
84 }
85
87
88 acs->prepareTime = evt_get_variable(script, *args++);
89 acs->duration = evt_get_variable(script, *args++);
90 acs->difficulty = evt_get_variable(script, *args++);
92 acs->statusChance = evt_get_variable(script, *args++); // unused
93
94 acs->wrongButtonPressed = FALSE;
95 acs->meterFillLevel = 0;
96 acs->meterFillWidth = 0;
97 battleStatus->actionQuality = 0;
98 battleStatus->actionResult = ACTION_RESULT_NONE;
99 battleStatus->maxActionQuality = acs->mashMeterCutoffs[(acs->mashMeterNumIntervals - 1)];
100 battleStatus->flags1 &= ~BS_FLAGS1_FREE_ACTION_COMMAND;
101 acs->state = AC_STATE_START;
102
104
105 return ApiStatus_DONE2;
106}
107
108
109void N(update)(void) {
111 BattleStatus* battleStatus = &gBattleStatus;
112 Actor* partner = battleStatus->partnerActor;
113 HudElemID hid;
114 s32 cutoff;
115
116 switch (acs->state) {
117 case AC_STATE_INIT:
119
120 hid = acs->hudElemIDs[HIDX_STICK];
121 hud_element_set_alpha(hid, 255);
122 if (acs->showHud) {
124 }
125
126 hid = acs->hudElemIDs[HIDX_METER];
127 hud_element_set_alpha(hid, 255);
128 if (acs->showHud) {
130 }
131
132 acs->state = AC_STATE_APPEAR;
133 break;
134 case AC_STATE_APPEAR:
136 acs->hudPosX += 20;
137 if (acs->hudPosX > 50) {
138 acs->hudPosX = 50;
139 }
142 break;
143 case AC_STATE_START:
145 if (acs->prepareTime != 0) {
146 acs->prepareTime--;
147 return;
148 }
150 acs->meterFillLevel = 0;
151 battleStatus->resultTier = 0;
152 acs->fireShell.holdingLeft = FALSE;
153 acs->stateTimer = acs->duration;
155 acs->state = AC_STATE_ACTIVE;
156
157 // fallthrough
158 case AC_STATE_ACTIVE:
160
161 // meter can drain if it hasn't been fully filled
162 if (!acs->isMeterFilled) {
163 cutoff = acs->mashMeterCutoffs[acs->mashMeterNumIntervals];
164 acs->meterFillLevel -= GET_DRAIN_RATE(acs->meterFillLevel / cutoff);
165 if (acs->meterFillLevel < 0) {
166 acs->meterFillLevel = 0;
167 }
168 }
169
170 // check for meter-filling input
171 if (!acs->isMeterFilled) {
172 if (battleStatus->curButtonsDown & BUTTON_STICK_LEFT) {
173 acs->fireShell.holdingLeft = TRUE;
174 }
175
176 if (!(battleStatus->curButtonsDown & BUTTON_STICK_LEFT)) {
177 if (acs->fireShell.holdingLeft != 0) {
178 s32 difficultyPct = battleStatus->actionCmdDifficultyTable[acs->difficulty];
179 acs->meterFillLevel += SCALE_BY_PCT(METER_FILL_TICK, difficultyPct);
180 acs->fireShell.holdingLeft = FALSE;
181 }
182 }
183
184 // right stick inputs actively drain the meter
185 if (battleStatus->curButtonsPressed & BUTTON_STICK_RIGHT) {
186 s32 difficultyPct = battleStatus->actionCmdDifficultyTable[acs->difficulty];
187 acs->meterFillLevel -= SCALE_BY_PCT(METER_FILL_TICK, difficultyPct);
188 }
189 }
190
191 if (acs->meterFillLevel < 0) {
192 acs->meterFillLevel = 0;
193 }
194
195 // handle meter reaching 100%
196 if (acs->meterFillLevel > MAX_MASH_UNITS) {
198 acs->isMeterFilled = TRUE;
199 hid = acs->hudElemIDs[HIDX_100_PCT];
200 hud_element_set_render_pos(hid, acs->hudPosX + 50, acs->hudPosY + 28);
202 }
203
204 battleStatus->actionProgress = acs->meterFillLevel / ONE_PCT_MASH;
206
207 // resultTier is not used by this move; uses actionProgress instead via the move script
208 switch (partner->actorBlueprint->level) {
210 if (battleStatus->actionProgress >= N(BasicThresholds)[battleStatus->resultTier]) {
211 battleStatus->resultTier++;
212 }
213 if (battleStatus->resultTier > 0 && (battleStatus->actionProgress < N(BasicThresholds)[battleStatus->resultTier - 1])) {
214 battleStatus->resultTier--;
215 }
216 break;
218 if (battleStatus->actionProgress >= N(SuperThresholds)[battleStatus->resultTier]) {
219 battleStatus->resultTier++;
220 }
221 if (battleStatus->resultTier > 0 && (battleStatus->actionProgress < N(SuperThresholds)[battleStatus->resultTier - 1])) {
222 battleStatus->resultTier--;
223 }
224 break;
226 if (battleStatus->actionProgress >= N(UltraThresholds)[battleStatus->resultTier]) {
227 battleStatus->resultTier++;
228 }
229 if (battleStatus->resultTier > 0 && (battleStatus->actionProgress < N(UltraThresholds)[battleStatus->resultTier - 1])) {
230 battleStatus->resultTier--;
231 }
232 break;
233 }
234
235 if (acs->stateTimer != 0) {
236 acs->stateTimer--;
237 break;
238 }
239
240 if (acs->meterFillLevel == 0) {
241 battleStatus->actionQuality = AC_QUALITY_FAILED;
242 } else {
243 battleStatus->actionQuality = acs->meterFillLevel / ONE_PCT_MASH;
244 }
245
246 cutoff = acs->mashMeterCutoffs[acs->mashMeterNumIntervals - 1];
247 if (battleStatus->actionQuality > cutoff) {
248 battleStatus->actionResult = ACTION_RESULT_SUCCESS;
249 } else {
251 }
252
253 if (battleStatus->actionQuality == 100) {
254 // only count 100% fill as success for this action command
256 }
257
260 acs->stateTimer = 5;
261 acs->state = AC_STATE_DISPOSE;
262 break;
263 case AC_STATE_DISPOSE:
264 if (acs->stateTimer != 0) {
265 acs->stateTimer--;
266 break;
267 }
269 break;
270 }
271}
272
274
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
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
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
HudScript HES_StickNeutral
#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_StickMashLeft
HudScript HES_100pct
@ AC_MODE_NOT_LEARNED
Definition action_cmd.h:60
#define MAX_MASH_UNITS
Definition action_cmd.h:75
struct ActorBlueprint * actorBlueprint
s32 HudElemID
@ ACTION_COMMAND_FIRE_SHELL
Definition enums.h:3481
@ BUTTON_STICK_LEFT
Definition enums.h:2793
@ BUTTON_STICK_RIGHT
Definition enums.h:2794
@ PARTNER_RANK_NORMAL
Definition enums.h:2018
@ PARTNER_RANK_SUPER
Definition enums.h:2019
@ PARTNER_RANK_ULTRA
Definition enums.h:2020
@ SOUND_LOOP_CHARGE_METER
Definition enums.h:1646
@ ACTION_RESULT_NONE
Definition enums.h:1963
@ ACTION_RESULT_METER_NOT_ENOUGH
Definition enums.h:1965
@ ACTION_RESULT_SUCCESS
Definition enums.h:1968
#define ApiStatus_DONE2
Definition evt.h:118
s32 Bytecode
Definition evt.h:7
#define METER_FILL_TICK
Definition fire_shell.c:16
#define GET_DRAIN_RATE(pct)
Definition fire_shell.c:20
s32 actionCmdTableFireShell[]
Definition action_cmd.c:36
@ HIDX_METER
Definition fire_shell.c:11
@ HIDX_STICK
Definition fire_shell.c:10
@ HIDX_100_PCT
Definition fire_shell.c:12
void N update(void)
Definition fire_shell.c:109
void btl_set_popup_duration(s32 duration)
s32 evt_get_variable(Evt *script, Bytecode var)
Definition evt.c:1689
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.
@ HUD_ELEMENT_FLAG_DISABLED
Definition hud_element.h:72
@ HUD_ELEMENT_FLAG_80
Definition hud_element.h:78
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 POPUP_MSG_OFF
Definition battle.h:270
#define POPUP_MSG_ON
Definition battle.h:269
struct Actor * partnerActor
s32 * actionCmdDifficultyTable
BattleStatus gBattleStatus
Definition battle.c:11
void N init(Npc *bombette)
Definition bombette.c:66