Paper Mario DX
Paper Mario (N64) modding
 
Loading...
Searching...
No Matches
spook.c
Go to the documentation of this file.
1#include "common.h"
2#include "audio/public.h"
3#include "battle/action_cmd.h"
4
5#define NAMESPACE action_command_spook
6
7extern s32 actionCmdTableSpook[];
8
9// indices into ActionCommandStatus::hudElements for this action command
10enum {
14};
15
16// how much to add to the meter per input
17#define METER_FILL_TICK 850
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 = 100;
30 battleStatus->actionResult = ACTION_RESULT_NONE;
31 if (battleStatus->actionCommandMode == AC_MODE_NOT_LEARNED) {
32 battleStatus->actionQuality = 0;
33 return ApiStatus_DONE2;
34 }
37 acs->showHud = TRUE;
38 acs->hudPrepareTime = 30;
39 acs->state = AC_STATE_INIT;
40 acs->wrongButtonPressed = FALSE;
41 acs->meterFillLevel = 0;
42 acs->meterFillWidth = 0;
43 acs->isMeterFilled = FALSE;
44 battleStatus->actionQuality = 0;
45 battleStatus->actionProgress = 0;
46 acs->hudPosX = -48;
47 acs->hudPosY = 80;
48
50 acs->hudElemIDs[HIDX_STICK] = hid;
54
56 acs->hudElemIDs[HIDX_METER] = hid;
57 hud_element_set_render_pos(hid, acs->hudPosX, acs->hudPosY + 28);
60
62 acs->hudElemIDs[HIDX_100_PCT] = hid;
63 hud_element_set_render_pos(hid, acs->hudPosX, acs->hudPosY + 28);
66
67 return ApiStatus_DONE2;
68}
69
70API_CALLABLE(N(start)) {
72 BattleStatus* battleStatus = &gBattleStatus;
73 Bytecode* args = script->ptrReadPos;
74
75 if (battleStatus->actionCommandMode == AC_MODE_NOT_LEARNED) {
76 battleStatus->actionQuality = 0;
77 return ApiStatus_DONE2;
78 }
79
81
82 acs->prepareTime = evt_get_variable(script, *args++);
83 acs->duration = evt_get_variable(script, *args++);
84 acs->difficulty = evt_get_variable(script, *args++);
86 acs->statusChance = evt_get_variable(script, *args++); // average chance for enemies to be affected
87
88 acs->wrongButtonPressed = FALSE;
89 acs->meterFillLevel = 0;
90 acs->meterFillWidth = 0;
91 battleStatus->actionQuality = 0;
92 battleStatus->actionResult = ACTION_RESULT_NONE;
93 battleStatus->maxActionQuality = acs->mashMeterCutoffs[(acs->mashMeterNumIntervals - 1)];
94 battleStatus->flags1 &= ~BS_FLAGS1_FREE_ACTION_COMMAND;
95 acs->state = AC_STATE_START;
96
98
99 return ApiStatus_DONE2;
100}
101
102
103void N(update)(void) {
105 BattleStatus* battleStatus = &gBattleStatus;
106 HudElemID hid;
107 s32 cutoff;
108 s32 fillLevel;
109
110 switch (acs->state) {
111 case AC_STATE_INIT:
113
114 hid = acs->hudElemIDs[HIDX_STICK];
115 hud_element_set_alpha(hid, 255);
116 if (acs->showHud) {
118 }
119
120 hid = acs->hudElemIDs[HIDX_METER];
121 hud_element_set_alpha(hid, 255);
122 if (acs->showHud) {
124 }
125
126 acs->state = AC_STATE_APPEAR;
127 break;
128 case AC_STATE_APPEAR:
130 acs->hudPosX += 20;
131 if (acs->hudPosX > 50) {
132 acs->hudPosX = 50;
133 }
136 break;
137 case AC_STATE_START:
139 if (acs->prepareTime != 0) {
140 acs->prepareTime--;
141 return;
142 }
144 acs->meterFillLevel = 0;
145 battleStatus->actionProgress = 0;
146 acs->spook.holdingLeft = FALSE;
147 acs->stateTimer = acs->duration;
149 acs->state = AC_STATE_ACTIVE;
150
151 // fallthrough
152 case AC_STATE_ACTIVE:
154
155 // meter can drain if it hasn't been fully filled
156 if (!acs->isMeterFilled) {
157 if (acs->statusChance != 0) {
158 cutoff = acs->mashMeterCutoffs[acs->mashMeterNumIntervals];
159 acs->meterFillLevel -= GET_DRAIN_RATE(acs->meterFillLevel / cutoff);
160 if (acs->meterFillLevel < 0) {
161 acs->meterFillLevel = 0;
162 }
163 } else {
164 acs->meterFillLevel -= 10;
165 if (acs->meterFillLevel < 0) {
166 acs->meterFillLevel = 0;
167 }
168 }
169 }
170
171 // check for meter-filling input
172 if (!acs->isMeterFilled) {
173 if (acs->statusChance != 0) {
174
175 if (battleStatus->curButtonsDown & BUTTON_STICK_LEFT) {
176 acs->spook.holdingLeft = TRUE;
177 }
178
179 if (!(battleStatus->curButtonsDown & BUTTON_STICK_LEFT) && acs->spook.holdingLeft) {
180 s32 a = battleStatus->actionCmdDifficultyTable[acs->difficulty];
181 s32 b = METER_FILL_TICK * acs->statusChance;
182 // divide by 100 for each percent-based multiplier
183 acs->meterFillLevel += (a * b) / (100 * 100);
184 acs->spook.holdingLeft = FALSE;
185 }
186
187 if (battleStatus->curButtonsPressed & BUTTON_STICK_RIGHT) {
188 s32 a = battleStatus->actionCmdDifficultyTable[acs->difficulty];
189 s32 b = METER_FILL_TICK * acs->statusChance;
190 // divide by 100 for each percent-based multiplier
191 acs->meterFillLevel -= (a * b) / (100 * 100);
192 }
193 } else {
194 if (battleStatus->curButtonsDown & BUTTON_STICK_LEFT) {
195 acs->spook.holdingLeft = TRUE;
196 }
197
198 if (!(battleStatus->curButtonsDown & BUTTON_STICK_LEFT) && acs->spook.holdingLeft) {
200 if (acs->meterFillLevel >= 5 * ONE_PCT_MASH) {
201 acs->meterFillLevel = 5 * ONE_PCT_MASH;
202 }
203 acs->spook.holdingLeft = FALSE;
204 }
205
206 if (battleStatus->curButtonsPressed & BUTTON_STICK_RIGHT) {
208 }
209 }
210 }
211
212 if (acs->meterFillLevel < 0) {
213 acs->meterFillLevel = 0;
214 }
215
216 // handle meter reaching 100%
217 if (acs->meterFillLevel > MAX_MASH_UNITS) {
219 acs->isMeterFilled = TRUE;
220 hid = acs->hudElemIDs[HIDX_100_PCT];
221 hud_element_set_render_pos(hid, acs->hudPosX + 50, acs->hudPosY + 28);
223 }
224
225 battleStatus->actionProgress = acs->meterFillLevel / ONE_PCT_MASH;
227
228 if (acs->stateTimer != 0) {
229 acs->stateTimer--;
230 break;
231 }
232
233 fillLevel = acs->meterFillLevel;
234 if (acs->statusChance == 0) {
235 fillLevel = 0;
236 }
237
238 if (fillLevel == 0) {
239 battleStatus->actionQuality = AC_QUALITY_FAILED;
240 } else {
241 battleStatus->actionQuality = fillLevel / ONE_PCT_MASH;
242
243 }
244
245 cutoff = acs->mashMeterCutoffs[acs->mashMeterNumIntervals - 1];
246 if (battleStatus->actionQuality > cutoff) {
247 battleStatus->actionResult = ACTION_RESULT_SUCCESS;
248 } else {
250 }
251
252 if (battleStatus->actionQuality == 100) {
253 // only count 100% fill as success for this action command
255 }
256
259 acs->stateTimer = 5;
260 acs->state = AC_STATE_DISPOSE;
261 break;
262 case AC_STATE_DISPOSE:
263 if (acs->statusChance == 0) {
265 if (acs->meterFillLevel < 0) {
266 acs->meterFillLevel = 0;
267 }
268 }
269
270 if (acs->stateTimer != 0) {
271 acs->stateTimer--;
272 break;
273 }
275 break;
276 }
277}
278
280
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
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
s32 HudElemID
@ ACTION_COMMAND_SPOOK
Definition enums.h:3493
@ BUTTON_STICK_LEFT
Definition enums.h:2793
@ BUTTON_STICK_RIGHT
Definition enums.h:2794
@ 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
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 METER_FILL_TICK
Definition spook.c:17
#define GET_DRAIN_RATE(pct)
Definition spook.c:21
@ HIDX_METER
Definition spook.c:12
@ HIDX_STICK
Definition spook.c:11
@ HIDX_100_PCT
Definition spook.c:13
void N update(void)
Definition spook.c:103
s32 actionCmdTableSpook[]
Definition action_cmd.c:48
#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