Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
MorsGames
GitHub Repository: MorsGames/sm64plus
Path: blob/master/src/game/mario_actions_submerged.c
7858 views
1
#include <PR/ultratypes.h>
2
3
#include "sm64.h"
4
#include "level_update.h"
5
#include "memory.h"
6
#include "engine/math_util.h"
7
#include "area.h"
8
#include "save_file.h"
9
#include "sound_init.h"
10
#include "engine/surface_collision.h"
11
#include "interaction.h"
12
#include "mario.h"
13
#include "mario_step.h"
14
#include "camera.h"
15
#include "audio/external.h"
16
#include "behavior_data.h"
17
#include "level_table.h"
18
#include "rumble_init.h"
19
20
#include "settings.h"
21
22
#define MIN_SWIM_STRENGTH 160
23
#define MIN_SWIM_SPEED 16.0f
24
25
static s16 sWasAtSurface = FALSE;
26
static s16 sSwimStrength = MIN_SWIM_STRENGTH;
27
static s16 sWaterCurrentSpeeds[] = { 28, 12, 8, 4 };
28
29
static s16 sBobTimer;
30
static s16 sBobIncrement;
31
static f32 sBobHeight;
32
33
static void set_swimming_at_surface_particles(struct MarioState *m, u32 particleFlag) {
34
s16 atSurface = m->pos[1] >= m->waterLevel - 130;
35
36
if (atSurface) {
37
m->particleFlags |= particleFlag;
38
if (atSurface ^ sWasAtSurface) {
39
play_sound(SOUND_ACTION_UNKNOWN431, m->marioObj->header.gfx.cameraToObject);
40
}
41
}
42
43
sWasAtSurface = atSurface;
44
}
45
46
static s32 swimming_near_surface(struct MarioState *m) {
47
if (m->flags & MARIO_METAL_CAP) {
48
return FALSE;
49
}
50
51
return (m->waterLevel - 80) - m->pos[1] < 400.0f;
52
}
53
54
static f32 get_buoyancy(struct MarioState *m) {
55
f32 buoyancy = 0.0f;
56
57
if (m->flags & MARIO_METAL_CAP) {
58
if (m->action & ACT_FLAG_INVULNERABLE) {
59
buoyancy = -2.0f;
60
} else {
61
buoyancy = -18.0f;
62
}
63
} else if (swimming_near_surface(m)) {
64
if (configImprovedSwimming) {
65
buoyancy = 2.0f;
66
}
67
else {
68
buoyancy = 1.25f;
69
}
70
} else if (!(m->action & ACT_FLAG_MOVING)) {
71
if (configImprovedSwimming) {
72
buoyancy = -0.5f;
73
}
74
else {
75
buoyancy = -2.0f;
76
}
77
}
78
79
return buoyancy;
80
}
81
82
static u32 perform_water_full_step(struct MarioState *m, Vec3f nextPos) {
83
struct Surface *wall;
84
struct Surface *ceil;
85
struct Surface *floor;
86
f32 ceilHeight;
87
f32 floorHeight;
88
89
wall = resolve_and_return_wall_collisions(nextPos, 10.0f, 110.0f);
90
floorHeight = find_floor(nextPos[0], nextPos[1], nextPos[2], &floor);
91
92
if (configApplyBugFixes > 1)
93
ceilHeight = vec3f_find_ceil(nextPos, nextPos[1], &ceil);
94
else
95
ceilHeight = vec3f_find_ceil(nextPos, floorHeight, &ceil);
96
97
if (floor == NULL) {
98
return WATER_STEP_CANCELLED;
99
}
100
101
if (nextPos[1] >= floorHeight) {
102
if (ceilHeight - nextPos[1] >= 160.0f) {
103
vec3f_copy(m->pos, nextPos);
104
m->floor = floor;
105
m->floorHeight = floorHeight;
106
107
if (wall != NULL) {
108
return WATER_STEP_HIT_WALL;
109
} else {
110
return WATER_STEP_NONE;
111
}
112
}
113
114
if (ceilHeight - floorHeight < 160.0f) {
115
return WATER_STEP_CANCELLED;
116
}
117
118
//! Water ceiling downwarp
119
vec3f_set(m->pos, nextPos[0], ceilHeight - 160.0f, nextPos[2]);
120
m->floor = floor;
121
m->floorHeight = floorHeight;
122
return WATER_STEP_HIT_CEILING;
123
} else {
124
if (ceilHeight - floorHeight < 160.0f) {
125
return WATER_STEP_CANCELLED;
126
}
127
128
vec3f_set(m->pos, nextPos[0], floorHeight, nextPos[2]);
129
m->floor = floor;
130
m->floorHeight = floorHeight;
131
return WATER_STEP_HIT_FLOOR;
132
}
133
}
134
135
static void apply_water_current(struct MarioState *m, Vec3f step) {
136
s32 i;
137
f32 whirlpoolRadius = 2000.0f;
138
139
if (m->floor->type == SURFACE_FLOWING_WATER) {
140
s16 currentAngle = m->floor->force << 8;
141
f32 currentSpeed = sWaterCurrentSpeeds[m->floor->force >> 8];
142
143
step[0] += currentSpeed * sins(currentAngle);
144
step[2] += currentSpeed * coss(currentAngle);
145
}
146
147
for (i = 0; i < 2; i++) {
148
struct Whirlpool *whirlpool = gCurrentArea->whirlpools[i];
149
if (whirlpool != NULL) {
150
f32 strength = 0.0f;
151
152
f32 dx = whirlpool->pos[0] - m->pos[0];
153
f32 dy = whirlpool->pos[1] - m->pos[1];
154
f32 dz = whirlpool->pos[2] - m->pos[2];
155
156
f32 lateralDist = sqrtf(dx * dx + dz * dz);
157
f32 distance = sqrtf(lateralDist * lateralDist + dy * dy);
158
159
s16 pitchToWhirlpool = atan2s(lateralDist, dy);
160
s16 yawToWhirlpool = atan2s(dz, dx);
161
162
yawToWhirlpool -= (s16)(0x2000 * 1000.0f / (distance + 1000.0f));
163
164
if (whirlpool->strength >= 0) {
165
if (gCurrLevelNum == LEVEL_DDD && gCurrAreaIndex == 2) {
166
whirlpoolRadius = 4000.0f;
167
}
168
169
if (distance >= 26.0f && distance < whirlpoolRadius) {
170
strength = whirlpool->strength * (1.0f - distance / whirlpoolRadius);
171
}
172
} else if (distance < 2000.0f) {
173
strength = whirlpool->strength * (1.0f - distance / 2000.0f);
174
}
175
176
step[0] += strength * coss(pitchToWhirlpool) * sins(yawToWhirlpool);
177
step[1] += strength * sins(pitchToWhirlpool);
178
step[2] += strength * coss(pitchToWhirlpool) * coss(yawToWhirlpool);
179
}
180
}
181
}
182
183
static u32 perform_water_step(struct MarioState *m) {
184
UNUSED u32 unused;
185
u32 stepResult;
186
Vec3f nextPos;
187
Vec3f step;
188
struct Object *marioObj = m->marioObj;
189
190
vec3f_copy(step, m->vel);
191
192
if (m->action & ACT_FLAG_SWIMMING) {
193
apply_water_current(m, step);
194
}
195
196
nextPos[0] = m->pos[0] + step[0];
197
nextPos[1] = m->pos[1] + step[1];
198
nextPos[2] = m->pos[2] + step[2];
199
200
if (nextPos[1] > m->waterLevel - 80) {
201
nextPos[1] = m->waterLevel - 80;
202
m->vel[1] = 0.0f;
203
}
204
205
stepResult = perform_water_full_step(m, nextPos);
206
207
vec3f_copy(marioObj->header.gfx.pos, m->pos);
208
vec3s_set(marioObj->header.gfx.angle, -m->faceAngle[0], m->faceAngle[1], m->faceAngle[2]);
209
210
return stepResult;
211
}
212
213
static BAD_RETURN(u32) update_water_pitch(struct MarioState *m) {
214
struct Object *marioObj = m->marioObj;
215
216
if (marioObj->header.gfx.angle[0] > 0) {
217
marioObj->header.gfx.pos[1] +=
218
60.0f * sins(marioObj->header.gfx.angle[0]) * sins(marioObj->header.gfx.angle[0]);
219
}
220
221
if (marioObj->header.gfx.angle[0] < 0) {
222
marioObj->header.gfx.angle[0] = marioObj->header.gfx.angle[0] * 6 / 10;
223
}
224
225
if (marioObj->header.gfx.angle[0] > 0) {
226
marioObj->header.gfx.angle[0] = marioObj->header.gfx.angle[0] * 10 / 8;
227
}
228
}
229
230
static void stationary_slow_down(struct MarioState *m) {
231
f32 buoyancy = get_buoyancy(m);
232
233
m->angleVel[0] = 0;
234
m->angleVel[1] = 0;
235
236
m->forwardVel = approach_f32(m->forwardVel, 0.0f, 1.0f, 1.0f);
237
m->vel[1] = approach_f32(m->vel[1], buoyancy, 2.0f, 1.0f);
238
239
m->faceAngle[0] = approach_s32(m->faceAngle[0], 0, 0x200, 0x200);
240
m->faceAngle[2] = approach_s32(m->faceAngle[2], 0, 0x100, 0x100);
241
242
m->vel[0] = m->forwardVel * coss(m->faceAngle[0]) * sins(m->faceAngle[1]);
243
m->vel[2] = m->forwardVel * coss(m->faceAngle[0]) * coss(m->faceAngle[1]);
244
}
245
246
static void update_swimming_speed(struct MarioState *m, f32 decelThreshold) {
247
f32 buoyancy = get_buoyancy(m);
248
f32 maxSpeed = 28.0f;
249
250
if (m->action & ACT_FLAG_STATIONARY) {
251
m->forwardVel -= 2.0f;
252
}
253
254
if (m->forwardVel < 0.0f) {
255
m->forwardVel = 0.0f;
256
}
257
258
if (m->forwardVel > maxSpeed) {
259
m->forwardVel = maxSpeed;
260
}
261
262
if (m->forwardVel > decelThreshold) {
263
m->forwardVel -= 0.5f;
264
}
265
266
m->vel[0] = m->forwardVel * coss(m->faceAngle[0]) * sins(m->faceAngle[1]);
267
m->vel[1] = m->forwardVel * sins(m->faceAngle[0]) + buoyancy;
268
m->vel[2] = m->forwardVel * coss(m->faceAngle[0]) * coss(m->faceAngle[1]);
269
}
270
271
static void update_swimming_yaw(struct MarioState *m) {
272
s16 targetYawVel = -(s16)(10.0f * m->controller->stickX);
273
274
if (targetYawVel > 0) {
275
if (m->angleVel[1] < 0) {
276
m->angleVel[1] += 0x40;
277
if (m->angleVel[1] > 0x10) {
278
m->angleVel[1] = 0x10;
279
}
280
} else {
281
m->angleVel[1] = approach_s32(m->angleVel[1], targetYawVel, 0x10, 0x20);
282
}
283
} else if (targetYawVel < 0) {
284
if (m->angleVel[1] > 0) {
285
m->angleVel[1] -= 0x40;
286
if (m->angleVel[1] < -0x10) {
287
m->angleVel[1] = -0x10;
288
}
289
} else {
290
m->angleVel[1] = approach_s32(m->angleVel[1], targetYawVel, 0x20, 0x10);
291
}
292
} else {
293
m->angleVel[1] = approach_s32(m->angleVel[1], 0, 0x40, 0x40);
294
}
295
296
m->faceAngle[1] += m->angleVel[1];
297
m->faceAngle[2] = -m->angleVel[1] * 8;
298
}
299
300
static void update_swimming_pitch(struct MarioState *m) {
301
s16 targetPitch = -(s16)(252.0f * m->controller->stickY);
302
303
s16 pitchVel;
304
if (m->faceAngle[0] < 0) {
305
pitchVel = 0x100;
306
} else {
307
pitchVel = 0x200;
308
}
309
310
if (m->faceAngle[0] < targetPitch) {
311
if ((m->faceAngle[0] += pitchVel) > targetPitch) {
312
m->faceAngle[0] = targetPitch;
313
}
314
} else if (m->faceAngle[0] > targetPitch) {
315
if ((m->faceAngle[0] -= pitchVel) < targetPitch) {
316
m->faceAngle[0] = targetPitch;
317
}
318
}
319
}
320
321
static void common_idle_step(struct MarioState *m, s32 animation, s32 arg) {
322
s16 *val = &m->marioBodyState->headAngle[0];
323
324
update_swimming_yaw(m);
325
update_swimming_pitch(m);
326
update_swimming_speed(m, MIN_SWIM_SPEED);
327
perform_water_step(m);
328
update_water_pitch(m);
329
330
if (m->faceAngle[0] > 0) {
331
*val = approach_s32(*val, m->faceAngle[0] / 2, 0x80, 0x200);
332
} else {
333
*val = approach_s32(*val, 0, 0x200, 0x200);
334
}
335
336
if (arg == 0) {
337
set_mario_animation(m, animation);
338
} else {
339
set_mario_anim_with_accel(m, animation, arg);
340
}
341
342
set_swimming_at_surface_particles(m, PARTICLE_IDLE_WATER_WAVE);
343
}
344
345
static s32 act_water_idle(struct MarioState *m) {
346
u32 val = 0x10000;
347
348
if (m->flags & MARIO_METAL_CAP) {
349
return set_mario_action(m, ACT_METAL_WATER_FALLING, 1);
350
}
351
352
if (m->input & INPUT_B_PRESSED) {
353
return set_mario_action(m, ACT_WATER_PUNCH, 0);
354
}
355
356
if (m->input & INPUT_A_PRESSED) {
357
return set_mario_action(m, ACT_BREASTSTROKE, 0);
358
}
359
360
if (m->faceAngle[0] < -0x1000) {
361
val = 0x30000;
362
}
363
364
common_idle_step(m, MARIO_ANIM_WATER_IDLE, val);
365
return FALSE;
366
}
367
368
static s32 act_hold_water_idle(struct MarioState *m) {
369
if (m->flags & MARIO_METAL_CAP) {
370
return set_mario_action(m, ACT_HOLD_METAL_WATER_FALLING, 0);
371
}
372
373
if (m->marioObj->oInteractStatus & INT_STATUS_MARIO_DROP_OBJECT) {
374
return drop_and_set_mario_action(m, ACT_WATER_IDLE, 0);
375
}
376
377
if (m->input & INPUT_B_PRESSED) {
378
return set_mario_action(m, ACT_WATER_THROW, 0);
379
}
380
381
if (m->input & INPUT_A_PRESSED) {
382
return set_mario_action(m, ACT_HOLD_BREASTSTROKE, 0);
383
}
384
385
common_idle_step(m, MARIO_ANIM_WATER_IDLE_WITH_OBJ, 0);
386
return FALSE;
387
}
388
389
static s32 act_water_action_end(struct MarioState *m) {
390
if (m->flags & MARIO_METAL_CAP) {
391
return set_mario_action(m, ACT_METAL_WATER_FALLING, 1);
392
}
393
394
if (m->input & INPUT_B_PRESSED) {
395
return set_mario_action(m, ACT_WATER_PUNCH, 0);
396
}
397
398
if (m->input & INPUT_A_PRESSED) {
399
return set_mario_action(m, ACT_BREASTSTROKE, 0);
400
}
401
402
common_idle_step(m, MARIO_ANIM_WATER_ACTION_END, 0);
403
if (is_anim_at_end(m)) {
404
set_mario_action(m, ACT_WATER_IDLE, 0);
405
}
406
return FALSE;
407
}
408
409
static s32 act_hold_water_action_end(struct MarioState *m) {
410
if (m->flags & MARIO_METAL_CAP) {
411
return set_mario_action(m, ACT_HOLD_METAL_WATER_FALLING, 0);
412
}
413
414
if (m->marioObj->oInteractStatus & INT_STATUS_MARIO_DROP_OBJECT) {
415
return drop_and_set_mario_action(m, ACT_WATER_IDLE, 0);
416
}
417
418
if (m->input & INPUT_B_PRESSED) {
419
return set_mario_action(m, ACT_WATER_THROW, 0);
420
}
421
422
if (m->input & INPUT_A_PRESSED) {
423
return set_mario_action(m, ACT_HOLD_BREASTSTROKE, 0);
424
}
425
426
common_idle_step(
427
m, m->actionArg == 0 ? MARIO_ANIM_WATER_ACTION_END_WITH_OBJ : MARIO_ANIM_STOP_GRAB_OBJ_WATER,
428
0);
429
if (is_anim_at_end(m)) {
430
set_mario_action(m, ACT_HOLD_WATER_IDLE, 0);
431
}
432
return FALSE;
433
}
434
435
static void reset_bob_variables(struct MarioState *m) {
436
sBobTimer = 0;
437
sBobIncrement = 0x800;
438
sBobHeight = m->faceAngle[0] / 256.0f + 20.0f;
439
}
440
441
/**
442
* Controls the bobbing that happens when you swim near the surface.
443
*/
444
static void surface_swim_bob(struct MarioState *m) {
445
if (sBobIncrement != 0 && m->pos[1] > m->waterLevel - 85 && m->faceAngle[0] >= 0) {
446
if ((sBobTimer += sBobIncrement) >= 0) {
447
m->marioObj->header.gfx.pos[1] += sBobHeight * sins(sBobTimer);
448
return;
449
}
450
}
451
452
sBobIncrement = 0;
453
}
454
455
static void common_swimming_step(struct MarioState *m, s16 swimStrength) {
456
s16 floorPitch;
457
UNUSED struct Object *marioObj = m->marioObj;
458
459
update_swimming_yaw(m);
460
update_swimming_pitch(m);
461
update_swimming_speed(m, swimStrength / 10.0f);
462
463
switch (perform_water_step(m)) {
464
case WATER_STEP_HIT_FLOOR:
465
floorPitch = -find_floor_slope(m, -0x8000);
466
if (m->faceAngle[0] < floorPitch) {
467
if (configImprovedSwimming)
468
m->faceAngle[0] = approach_s32(m->faceAngle[0], floorPitch, 0x400, 0x400);
469
else
470
m->faceAngle[0] = floorPitch;
471
}
472
break;
473
474
case WATER_STEP_HIT_CEILING:
475
if (m->faceAngle[0] > -0x3000) {
476
m->faceAngle[0] -= 0x100;
477
}
478
break;
479
480
case WATER_STEP_HIT_WALL:
481
if (m->controller->stickY == 0.0f) {
482
if (m->faceAngle[0] > 0.0f) {
483
m->faceAngle[0] += 0x200;
484
if (m->faceAngle[0] > 0x3F00) {
485
m->faceAngle[0] = 0x3F00;
486
}
487
} else {
488
m->faceAngle[0] -= 0x200;
489
if (m->faceAngle[0] < -0x3F00) {
490
m->faceAngle[0] = -0x3F00;
491
}
492
}
493
}
494
break;
495
}
496
497
update_water_pitch(m);
498
m->marioBodyState->headAngle[0] = approach_s32(m->marioBodyState->headAngle[0], 0, 0x200, 0x200);
499
500
surface_swim_bob(m);
501
set_swimming_at_surface_particles(m, PARTICLE_WAVE_TRAIL);
502
}
503
504
static void play_swimming_noise(struct MarioState *m) {
505
s16 animFrame = m->marioObj->header.gfx.animInfo.animFrame;
506
507
// This must be one line to match on -O2
508
if (animFrame == 0 || animFrame == 12) play_sound(SOUND_ACTION_UNKNOWN434, m->marioObj->header.gfx.cameraToObject);
509
}
510
511
static s32 check_water_jump(struct MarioState *m) {
512
s32 probe = (s32)(m->pos[1] + 1.5f);
513
514
if (m->input & INPUT_A_PRESSED) {
515
if (probe >= m->waterLevel - 80 && m->faceAngle[0] >= 0 && m->controller->stickY < -60.0f) {
516
vec3s_set(m->angleVel, 0, 0, 0);
517
518
if (configImprovedSwimming) {
519
m->vel[1] = 64.0f;
520
}
521
else {
522
m->vel[1] = 62.0f;
523
}
524
525
if (m->heldObj == NULL) {
526
return set_mario_action(m, ACT_WATER_JUMP, 0);
527
} else {
528
return set_mario_action(m, ACT_HOLD_WATER_JUMP, 0);
529
}
530
}
531
}
532
533
return FALSE;
534
}
535
536
static s32 act_breaststroke(struct MarioState *m) {
537
if (m->actionArg == 0) {
538
sSwimStrength = MIN_SWIM_STRENGTH;
539
}
540
541
if (m->flags & MARIO_METAL_CAP) {
542
return set_mario_action(m, ACT_METAL_WATER_FALLING, 1);
543
}
544
545
if (m->input & INPUT_B_PRESSED) {
546
return set_mario_action(m, ACT_WATER_PUNCH, 0);
547
}
548
549
if (++m->actionTimer == 14) {
550
return set_mario_action(m, ACT_FLUTTER_KICK, 0);
551
}
552
553
if (check_water_jump(m)) {
554
return TRUE;
555
}
556
557
if (m->actionTimer < 6) {
558
if (configImprovedSwimming) {
559
m->forwardVel += 1.0f;
560
}
561
else {
562
m->forwardVel += 0.5f;
563
}
564
}
565
566
if (m->actionTimer >= 9) {
567
if (configImprovedSwimming) {
568
m->forwardVel += 3.0f;
569
}
570
else {
571
m->forwardVel += 1.5f;
572
}
573
}
574
575
if (m->actionTimer >= 2) {
576
if (m->actionTimer < 6 && (m->input & INPUT_A_PRESSED)) {
577
m->actionState = 1;
578
}
579
580
if (m->actionTimer == 9 && m->actionState == 1) {
581
set_anim_to_frame(m, 0);
582
m->actionState = 0;
583
m->actionTimer = 1;
584
sSwimStrength = MIN_SWIM_STRENGTH;
585
}
586
}
587
588
if (m->actionTimer == 1) {
589
play_sound(sSwimStrength == MIN_SWIM_STRENGTH ? SOUND_ACTION_SWIM : SOUND_ACTION_SWIM_FAST,
590
m->marioObj->header.gfx.cameraToObject);
591
reset_bob_variables(m);
592
}
593
594
#if ENABLE_RUMBLE
595
if (m->actionTimer < 6) {
596
func_sh_8024CA04();
597
}
598
#endif
599
600
set_mario_animation(m, MARIO_ANIM_SWIM_PART1);
601
common_swimming_step(m, sSwimStrength);
602
603
return FALSE;
604
}
605
606
static s32 act_swimming_end(struct MarioState *m) {
607
if (m->flags & MARIO_METAL_CAP) {
608
return set_mario_action(m, ACT_METAL_WATER_FALLING, 1);
609
}
610
611
if (m->input & INPUT_B_PRESSED) {
612
return set_mario_action(m, ACT_WATER_PUNCH, 0);
613
}
614
615
if (m->actionTimer >= 15) {
616
return set_mario_action(m, ACT_WATER_ACTION_END, 0);
617
}
618
619
if (check_water_jump(m)) {
620
return TRUE;
621
}
622
623
if ((m->input & INPUT_A_DOWN) && m->actionTimer >= 7) {
624
if (m->actionTimer == 7 && sSwimStrength < 280) {
625
sSwimStrength += 10;
626
}
627
return set_mario_action(m, ACT_BREASTSTROKE, 1);
628
}
629
630
if (m->actionTimer >= 7) {
631
sSwimStrength = MIN_SWIM_STRENGTH;
632
}
633
634
m->actionTimer++;
635
636
m->forwardVel -= 0.25f;
637
set_mario_animation(m, MARIO_ANIM_SWIM_PART2);
638
common_swimming_step(m, sSwimStrength);
639
640
return FALSE;
641
}
642
643
static s32 act_flutter_kick(struct MarioState *m) {
644
if (m->flags & MARIO_METAL_CAP) {
645
return set_mario_action(m, ACT_METAL_WATER_FALLING, 1);
646
}
647
648
if (m->input & INPUT_B_PRESSED) {
649
return set_mario_action(m, ACT_WATER_PUNCH, 0);
650
}
651
652
if (!(m->input & INPUT_A_DOWN)) {
653
if (m->actionTimer == 0 && sSwimStrength < 280) {
654
sSwimStrength += 10;
655
}
656
return set_mario_action(m, ACT_SWIMMING_END, 0);
657
}
658
659
m->forwardVel = approach_f32(m->forwardVel, 12.0f, 0.1f, 0.15f);
660
m->actionTimer = 1;
661
sSwimStrength = MIN_SWIM_STRENGTH;
662
663
if (m->forwardVel < 14.0f) {
664
play_swimming_noise(m);
665
set_mario_animation(m, MARIO_ANIM_FLUTTERKICK);
666
}
667
668
common_swimming_step(m, sSwimStrength);
669
return FALSE;
670
}
671
672
static s32 act_hold_breaststroke(struct MarioState *m) {
673
if (m->flags & MARIO_METAL_CAP) {
674
return set_mario_action(m, ACT_HOLD_METAL_WATER_FALLING, 0);
675
}
676
677
if (m->marioObj->oInteractStatus & INT_STATUS_MARIO_DROP_OBJECT) {
678
return drop_and_set_mario_action(m, ACT_WATER_IDLE, 0);
679
}
680
681
if (++m->actionTimer == 17) {
682
return set_mario_action(m, ACT_HOLD_FLUTTER_KICK, 0);
683
}
684
685
if (m->input & INPUT_B_PRESSED) {
686
return set_mario_action(m, ACT_WATER_THROW, 0);
687
}
688
689
if (check_water_jump(m)) {
690
return TRUE;
691
}
692
693
if (m->actionTimer < 6) {
694
m->forwardVel += 0.5f;
695
}
696
697
if (m->actionTimer >= 9) {
698
m->forwardVel += 1.5f;
699
}
700
701
if (m->actionTimer >= 2) {
702
if (m->actionTimer < 6 && (m->input & INPUT_A_PRESSED)) {
703
m->actionState = 1;
704
}
705
706
if (m->actionTimer == 9 && m->actionState == 1) {
707
set_anim_to_frame(m, 0);
708
m->actionState = 0;
709
m->actionTimer = 1;
710
}
711
}
712
713
if (m->actionTimer == 1) {
714
play_sound(SOUND_ACTION_SWIM, m->marioObj->header.gfx.cameraToObject);
715
reset_bob_variables(m);
716
}
717
718
set_mario_animation(m, MARIO_ANIM_SWIM_WITH_OBJ_PART1);
719
common_swimming_step(m, 0x00A0);
720
return FALSE;
721
}
722
723
static s32 act_hold_swimming_end(struct MarioState *m) {
724
if (m->flags & MARIO_METAL_CAP) {
725
return set_mario_action(m, ACT_HOLD_METAL_WATER_FALLING, 0);
726
}
727
728
if (m->marioObj->oInteractStatus & INT_STATUS_MARIO_DROP_OBJECT) {
729
return drop_and_set_mario_action(m, ACT_WATER_IDLE, 0);
730
}
731
732
if (m->actionTimer >= 15) {
733
return set_mario_action(m, ACT_HOLD_WATER_ACTION_END, 0);
734
}
735
736
if (m->input & INPUT_B_PRESSED) {
737
return set_mario_action(m, ACT_WATER_THROW, 0);
738
}
739
740
if (check_water_jump(m)) {
741
return TRUE;
742
}
743
744
if ((m->input & INPUT_A_DOWN) && m->actionTimer >= 7) {
745
return set_mario_action(m, ACT_HOLD_BREASTSTROKE, 0);
746
}
747
748
m->actionTimer++;
749
750
m->forwardVel -= 0.25f;
751
set_mario_animation(m, MARIO_ANIM_SWIM_WITH_OBJ_PART2);
752
common_swimming_step(m, 0x00A0);
753
return FALSE;
754
}
755
756
static s32 act_hold_flutter_kick(struct MarioState *m) {
757
if (m->flags & MARIO_METAL_CAP) {
758
return set_mario_action(m, ACT_HOLD_METAL_WATER_FALLING, 0);
759
}
760
761
if (m->marioObj->oInteractStatus & INT_STATUS_MARIO_DROP_OBJECT) {
762
return drop_and_set_mario_action(m, ACT_WATER_IDLE, 0);
763
}
764
765
if (m->input & INPUT_B_PRESSED) {
766
return set_mario_action(m, ACT_WATER_THROW, 0);
767
}
768
769
if (!(m->input & INPUT_A_DOWN)) {
770
return set_mario_action(m, ACT_HOLD_SWIMMING_END, 0);
771
}
772
773
m->forwardVel = approach_f32(m->forwardVel, 12.0f, 0.1f, 0.15f);
774
if (m->forwardVel < 14.0f) {
775
play_swimming_noise(m);
776
set_mario_animation(m, MARIO_ANIM_FLUTTERKICK_WITH_OBJ);
777
}
778
common_swimming_step(m, 0x00A0);
779
return FALSE;
780
}
781
782
static s32 act_water_shell_swimming(struct MarioState *m) {
783
if (m->marioObj->oInteractStatus & INT_STATUS_MARIO_DROP_OBJECT) {
784
return drop_and_set_mario_action(m, ACT_WATER_IDLE, 0);
785
}
786
787
if (m->input & INPUT_B_PRESSED) {
788
return set_mario_action(m, ACT_WATER_THROW, 0);
789
}
790
791
if (m->actionTimer++ == (configBetterPowerups ? 480 : 240)) {
792
m->heldObj->oInteractStatus = INT_STATUS_STOP_RIDING;
793
m->heldObj = NULL;
794
stop_shell_music();
795
set_mario_action(m, ACT_FLUTTER_KICK, 0);
796
}
797
798
m->forwardVel = approach_f32(m->forwardVel, 30.0f, 2.0f, 1.0f);
799
800
play_swimming_noise(m);
801
set_mario_animation(m, MARIO_ANIM_FLUTTERKICK_WITH_OBJ);
802
common_swimming_step(m, 0x012C);
803
804
return FALSE;
805
}
806
807
static s32 check_water_grab(struct MarioState *m) {
808
//! Heave hos have the grabbable interaction type but are not normally
809
// grabbable. Since water grabbing doesn't check the appropriate input flag,
810
// you can use water grab to pick up heave ho.
811
if (m->marioObj->collidedObjInteractTypes & INTERACT_GRABBABLE) {
812
struct Object *object = mario_get_collided_object(m, INTERACT_GRABBABLE);
813
f32 dx = object->oPosX - m->pos[0];
814
f32 dz = object->oPosZ - m->pos[2];
815
s16 dAngleToObject = atan2s(dz, dx) - m->faceAngle[1];
816
817
if (dAngleToObject >= -0x2AAA && dAngleToObject <= 0x2AAA) {
818
m->usedObj = object;
819
mario_grab_used_object(m);
820
m->marioBodyState->grabPos = GRAB_POS_LIGHT_OBJ;
821
return TRUE;
822
}
823
}
824
825
return FALSE;
826
}
827
828
static s32 act_water_throw(struct MarioState *m) {
829
update_swimming_yaw(m);
830
update_swimming_pitch(m);
831
update_swimming_speed(m, MIN_SWIM_SPEED);
832
perform_water_step(m);
833
update_water_pitch(m);
834
835
set_mario_animation(m, MARIO_ANIM_WATER_THROW_OBJ);
836
play_sound_if_no_flag(m, SOUND_ACTION_SWIM, MARIO_ACTION_SOUND_PLAYED);
837
838
m->marioBodyState->headAngle[0] = approach_s32(m->marioBodyState->headAngle[0], 0, 0x200, 0x200);
839
840
if (m->actionTimer++ == 5) {
841
mario_throw_held_object(m);
842
#if ENABLE_RUMBLE
843
queue_rumble_data(3, 50);
844
#endif
845
}
846
847
if (is_anim_at_end(m)) {
848
set_mario_action(m, ACT_WATER_IDLE, 0);
849
}
850
851
return FALSE;
852
}
853
854
static s32 act_water_punch(struct MarioState *m) {
855
if (m->forwardVel < 7.0f) {
856
m->forwardVel += 1.0f;
857
}
858
859
update_swimming_yaw(m);
860
update_swimming_pitch(m);
861
update_swimming_speed(m, MIN_SWIM_SPEED);
862
perform_water_step(m);
863
update_water_pitch(m);
864
865
m->marioBodyState->headAngle[0] = approach_s32(m->marioBodyState->headAngle[0], 0, 0x200, 0x200);
866
867
play_sound_if_no_flag(m, SOUND_ACTION_SWIM, MARIO_ACTION_SOUND_PLAYED);
868
869
switch (m->actionState) {
870
case 0:
871
set_mario_animation(m, MARIO_ANIM_WATER_GRAB_OBJ_PART1);
872
if (is_anim_at_end(m)) {
873
m->actionState = check_water_grab(m) + 1;
874
}
875
break;
876
877
case 1:
878
set_mario_animation(m, MARIO_ANIM_WATER_GRAB_OBJ_PART2);
879
if (is_anim_at_end(m)) {
880
set_mario_action(m, ACT_WATER_ACTION_END, 0);
881
}
882
break;
883
884
case 2:
885
set_mario_animation(m, MARIO_ANIM_WATER_PICK_UP_OBJ);
886
if (is_anim_at_end(m)) {
887
if (m->heldObj->behavior == segmented_to_virtual(bhvKoopaShellUnderwater)) {
888
play_shell_music();
889
set_mario_action(m, ACT_WATER_SHELL_SWIMMING, 0);
890
} else {
891
set_mario_action(m, ACT_HOLD_WATER_ACTION_END, 1);
892
}
893
}
894
break;
895
}
896
897
return FALSE;
898
}
899
900
static void common_water_knockback_step(struct MarioState *m, s32 animation, u32 endAction, s32 arg3) {
901
stationary_slow_down(m);
902
perform_water_step(m);
903
set_mario_animation(m, animation);
904
905
m->marioBodyState->headAngle[0] = 0;
906
907
if (is_anim_at_end(m)) {
908
if (arg3 > 0) {
909
m->invincTimer = 30;
910
}
911
912
set_mario_action(m, m->health >= 0x100 ? endAction : ACT_WATER_DEATH, 0);
913
}
914
}
915
916
static s32 act_backward_water_kb(struct MarioState *m) {
917
common_water_knockback_step(m, MARIO_ANIM_BACKWARDS_WATER_KB, ACT_WATER_IDLE, m->actionArg);
918
return FALSE;
919
}
920
921
static s32 act_forward_water_kb(struct MarioState *m) {
922
common_water_knockback_step(m, MARIO_ANIM_WATER_FORWARD_KB, ACT_WATER_IDLE, m->actionArg);
923
return FALSE;
924
}
925
926
static s32 act_water_shocked(struct MarioState *m) {
927
play_sound_if_no_flag(m, SOUND_MARIO_WAAAOOOW, MARIO_ACTION_SOUND_PLAYED);
928
play_sound(SOUND_MOVING_SHOCKED, m->marioObj->header.gfx.cameraToObject);
929
set_camera_shake_from_hit(SHAKE_SHOCK);
930
931
if (set_mario_animation(m, MARIO_ANIM_SHOCKED) == 0) {
932
m->actionTimer++;
933
m->flags |= MARIO_METAL_SHOCK;
934
}
935
936
if (m->actionTimer >= 6) {
937
m->invincTimer = 30;
938
set_mario_action(m, m->health < 0x100 ? ACT_WATER_DEATH : ACT_WATER_IDLE, 0);
939
}
940
941
stationary_slow_down(m);
942
perform_water_step(m);
943
m->marioBodyState->headAngle[0] = 0;
944
return FALSE;
945
}
946
947
static s32 act_drowning(struct MarioState *m) {
948
switch (m->actionState) {
949
case 0:
950
set_mario_animation(m, MARIO_ANIM_DROWNING_PART1);
951
m->marioBodyState->eyeState = MARIO_EYES_HALF_CLOSED;
952
if (is_anim_at_end(m)) {
953
m->actionState = 1;
954
}
955
break;
956
957
case 1:
958
set_mario_animation(m, MARIO_ANIM_DROWNING_PART2);
959
m->marioBodyState->eyeState = MARIO_EYES_DEAD;
960
if (m->marioObj->header.gfx.animInfo.animFrame == 30) {
961
level_trigger_warp(m, WARP_OP_DEATH);
962
}
963
break;
964
}
965
966
play_sound_if_no_flag(m, SOUND_MARIO_DROWNING, MARIO_ACTION_SOUND_PLAYED);
967
stationary_slow_down(m);
968
perform_water_step(m);
969
970
return FALSE;
971
}
972
973
static s32 act_water_death(struct MarioState *m) {
974
stationary_slow_down(m);
975
perform_water_step(m);
976
977
m->marioBodyState->eyeState = MARIO_EYES_DEAD;
978
979
set_mario_animation(m, MARIO_ANIM_WATER_DYING);
980
if (set_mario_animation(m, MARIO_ANIM_WATER_DYING) == 35) {
981
level_trigger_warp(m, WARP_OP_DEATH);
982
}
983
984
return FALSE;
985
}
986
987
static s32 act_water_plunge(struct MarioState *m) {
988
u32 stepResult;
989
s32 stateFlags = m->heldObj != NULL;
990
991
f32 endVSpeed;
992
if (swimming_near_surface(m)) {
993
endVSpeed = 0.0f;
994
} else {
995
endVSpeed = -5.0f;
996
}
997
998
if (m->flags & MARIO_METAL_CAP) {
999
stateFlags |= 4;
1000
} else if ((m->prevAction & ACT_FLAG_DIVING) || (m->input & INPUT_A_DOWN)) {
1001
stateFlags |= 2;
1002
}
1003
1004
m->actionTimer++;
1005
1006
stationary_slow_down(m);
1007
1008
stepResult = perform_water_step(m);
1009
1010
if (m->actionState == 0) {
1011
play_sound(SOUND_ACTION_UNKNOWN430, m->marioObj->header.gfx.cameraToObject);
1012
if (m->peakHeight - m->pos[1] > 1150.0f) {
1013
play_sound(SOUND_MARIO_HAHA_2, m->marioObj->header.gfx.cameraToObject);
1014
}
1015
1016
m->particleFlags |= PARTICLE_WATER_SPLASH;
1017
m->actionState = 1;
1018
#if ENABLE_RUMBLE
1019
if (m->prevAction & ACT_FLAG_AIR) {
1020
queue_rumble_data(5, 80);
1021
}
1022
#endif
1023
}
1024
1025
if (stepResult == WATER_STEP_HIT_FLOOR || m->vel[1] >= endVSpeed || m->actionTimer > 20) {
1026
switch (stateFlags) {
1027
case 0:
1028
set_mario_action(m, ACT_WATER_ACTION_END, 0);
1029
break;
1030
case 1:
1031
set_mario_action(m, ACT_HOLD_WATER_ACTION_END, 0);
1032
break;
1033
case 2:
1034
set_mario_action(m, ACT_FLUTTER_KICK, 0);
1035
break;
1036
case 3:
1037
set_mario_action(m, ACT_HOLD_FLUTTER_KICK, 0);
1038
break;
1039
case 4:
1040
set_mario_action(m, ACT_METAL_WATER_FALLING, 0);
1041
break;
1042
case 5:
1043
set_mario_action(m, ACT_HOLD_METAL_WATER_FALLING, 0);
1044
break;
1045
}
1046
sBobIncrement = 0;
1047
}
1048
1049
switch (stateFlags) {
1050
case 0:
1051
set_mario_animation(m, MARIO_ANIM_WATER_ACTION_END);
1052
break;
1053
case 1:
1054
set_mario_animation(m, MARIO_ANIM_WATER_ACTION_END_WITH_OBJ);
1055
break;
1056
case 2:
1057
set_mario_animation(m, MARIO_ANIM_FLUTTERKICK);
1058
break;
1059
case 3:
1060
set_mario_animation(m, MARIO_ANIM_FLUTTERKICK_WITH_OBJ);
1061
break;
1062
case 4:
1063
set_mario_animation(m, MARIO_ANIM_GENERAL_FALL);
1064
break;
1065
case 5:
1066
set_mario_animation(m, MARIO_ANIM_FALL_WITH_LIGHT_OBJ);
1067
break;
1068
}
1069
1070
m->particleFlags |= PARTICLE_PLUNGE_BUBBLE;
1071
return FALSE;
1072
}
1073
1074
static s32 act_caught_in_whirlpool(struct MarioState *m) {
1075
f32 sinAngleChange;
1076
f32 cosAngleChange;
1077
f32 newDistance;
1078
s16 angleChange;
1079
1080
struct Object *marioObj = m->marioObj;
1081
struct Object *whirlpool = m->usedObj;
1082
1083
f32 dx = m->pos[0] - whirlpool->oPosX;
1084
f32 dz = m->pos[2] - whirlpool->oPosZ;
1085
f32 distance = sqrtf(dx * dx + dz * dz);
1086
1087
if ((marioObj->oMarioWhirlpoolPosY += m->vel[1]) < 0.0f) {
1088
marioObj->oMarioWhirlpoolPosY = 0.0f;
1089
if (distance < 16.1f && m->actionTimer++ == 16) {
1090
level_trigger_warp(m, WARP_OP_DEATH);
1091
}
1092
}
1093
1094
if (distance <= 28.0f) {
1095
newDistance = 16.0f;
1096
angleChange = 0x1800;
1097
} else if (distance < 256.0f) {
1098
newDistance = distance - (12.0f - distance / 32.0f);
1099
angleChange = (s16)(0x1C00 - distance * 20.0f);
1100
} else {
1101
newDistance = distance - 4.0f;
1102
angleChange = 0x800;
1103
}
1104
1105
m->vel[1] = -640.0f / (newDistance + 16.0f);
1106
1107
sinAngleChange = sins(angleChange);
1108
cosAngleChange = coss(angleChange);
1109
1110
if (distance < 1.0f) {
1111
dx = newDistance * sins(m->faceAngle[1]);
1112
dz = newDistance * coss(m->faceAngle[1]);
1113
} else {
1114
dx *= newDistance / distance;
1115
dz *= newDistance / distance;
1116
}
1117
1118
m->pos[0] = whirlpool->oPosX + dx * cosAngleChange + dz * sinAngleChange;
1119
m->pos[2] = whirlpool->oPosZ - dx * sinAngleChange + dz * cosAngleChange;
1120
m->pos[1] = whirlpool->oPosY + marioObj->oMarioWhirlpoolPosY;
1121
1122
m->faceAngle[1] = atan2s(dz, dx) + 0x8000;
1123
1124
set_mario_animation(m, MARIO_ANIM_GENERAL_FALL);
1125
vec3f_copy(m->marioObj->header.gfx.pos, m->pos);
1126
vec3s_set(m->marioObj->header.gfx.angle, 0, m->faceAngle[1], 0);
1127
#if ENABLE_RUMBLE
1128
reset_rumble_timers();
1129
#endif
1130
1131
return FALSE;
1132
}
1133
1134
static void play_metal_water_jumping_sound(struct MarioState *m, u32 landing) {
1135
if (!(m->flags & MARIO_ACTION_SOUND_PLAYED)) {
1136
m->particleFlags |= PARTICLE_MIST_CIRCLE;
1137
}
1138
1139
play_sound_if_no_flag(m, landing ? SOUND_ACTION_METAL_LAND_WATER : SOUND_ACTION_METAL_JUMP_WATER,
1140
MARIO_ACTION_SOUND_PLAYED);
1141
}
1142
1143
static void play_metal_water_walking_sound(struct MarioState *m) {
1144
if (is_anim_past_frame(m, 10) || is_anim_past_frame(m, 49)) {
1145
play_sound(SOUND_ACTION_METAL_STEP_WATER, m->marioObj->header.gfx.cameraToObject);
1146
m->particleFlags |= PARTICLE_DUST;
1147
}
1148
}
1149
1150
static void update_metal_water_walking_speed(struct MarioState *m) {
1151
f32 val = m->intendedMag / 1.5f;
1152
1153
if (m->forwardVel <= 0.0f) {
1154
m->forwardVel += 1.1f;
1155
} else if (m->forwardVel <= val) {
1156
m->forwardVel += 1.1f - m->forwardVel / 43.0f;
1157
} else if (m->floor->normal.y >= 0.95f) {
1158
m->forwardVel -= 1.0f;
1159
}
1160
1161
if (m->forwardVel > 32.0f) {
1162
m->forwardVel = 32.0f;
1163
}
1164
1165
m->faceAngle[1] =
1166
m->intendedYaw - approach_s32((s16)(m->intendedYaw - m->faceAngle[1]), 0, 0x800, 0x800);
1167
1168
m->slideVelX = m->forwardVel * sins(m->faceAngle[1]);
1169
m->slideVelZ = m->forwardVel * coss(m->faceAngle[1]);
1170
1171
m->vel[0] = m->slideVelX;
1172
m->vel[1] = 0.0f;
1173
m->vel[2] = m->slideVelZ;
1174
}
1175
1176
static s32 update_metal_water_jump_speed(struct MarioState *m) {
1177
UNUSED f32 nextY = m->pos[1] + m->vel[1];
1178
f32 waterSurface = m->waterLevel - 100;
1179
1180
if (m->vel[1] > 0.0f && m->pos[1] > waterSurface) {
1181
return TRUE;
1182
}
1183
1184
if (m->input & INPUT_NONZERO_ANALOG) {
1185
s16 intendedDYaw = m->intendedYaw - m->faceAngle[1];
1186
m->forwardVel += 0.8f * coss(intendedDYaw);
1187
m->faceAngle[1] += 0x200 * sins(intendedDYaw);
1188
} else {
1189
m->forwardVel = approach_f32(m->forwardVel, 0.0f, 0.25f, 0.25f);
1190
}
1191
1192
if (m->forwardVel > 16.0f) {
1193
m->forwardVel -= 1.0f;
1194
}
1195
1196
if (m->forwardVel < 0.0f) {
1197
m->forwardVel += 2.0f;
1198
}
1199
1200
m->vel[0] = m->slideVelX = m->forwardVel * sins(m->faceAngle[1]);
1201
m->vel[2] = m->slideVelZ = m->forwardVel * coss(m->faceAngle[1]);
1202
return FALSE;
1203
}
1204
1205
static s32 act_metal_water_standing(struct MarioState *m) {
1206
if (!(m->flags & MARIO_METAL_CAP)) {
1207
return set_mario_action(m, ACT_WATER_IDLE, 0);
1208
}
1209
1210
if (m->input & INPUT_A_PRESSED) {
1211
return set_mario_action(m, ACT_METAL_WATER_JUMP, 0);
1212
}
1213
1214
if (m->input & INPUT_NONZERO_ANALOG) {
1215
return set_mario_action(m, ACT_METAL_WATER_WALKING, 0);
1216
}
1217
1218
switch (m->actionState) {
1219
case 0:
1220
set_mario_animation(m, MARIO_ANIM_IDLE_HEAD_LEFT);
1221
break;
1222
case 1:
1223
set_mario_animation(m, MARIO_ANIM_IDLE_HEAD_RIGHT);
1224
break;
1225
case 2:
1226
set_mario_animation(m, MARIO_ANIM_IDLE_HEAD_CENTER);
1227
break;
1228
}
1229
1230
if (is_anim_at_end(m) && ++m->actionState == 3) {
1231
m->actionState = 0;
1232
}
1233
1234
stop_and_set_height_to_floor(m);
1235
if (m->pos[1] >= m->waterLevel - 150) {
1236
m->particleFlags |= PARTICLE_IDLE_WATER_WAVE;
1237
}
1238
1239
return FALSE;
1240
}
1241
1242
static s32 act_hold_metal_water_standing(struct MarioState *m) {
1243
if (m->marioObj->oInteractStatus & INT_STATUS_MARIO_DROP_OBJECT) {
1244
return drop_and_set_mario_action(m, ACT_METAL_WATER_STANDING, 0);
1245
}
1246
1247
if (!(m->flags & MARIO_METAL_CAP)) {
1248
return set_mario_action(m, ACT_HOLD_WATER_IDLE, 0);
1249
}
1250
1251
if (m->input & INPUT_A_PRESSED) {
1252
return set_mario_action(m, ACT_HOLD_METAL_WATER_JUMP, 0);
1253
}
1254
1255
if (m->input & INPUT_NONZERO_ANALOG) {
1256
return set_mario_action(m, ACT_HOLD_METAL_WATER_WALKING, 0);
1257
}
1258
1259
stop_and_set_height_to_floor(m);
1260
set_mario_animation(m, MARIO_ANIM_IDLE_WITH_LIGHT_OBJ);
1261
return FALSE;
1262
}
1263
1264
static s32 act_metal_water_walking(struct MarioState *m) {
1265
s32 val04;
1266
1267
if (!(m->flags & MARIO_METAL_CAP)) {
1268
return set_mario_action(m, ACT_WATER_IDLE, 0);
1269
}
1270
1271
if (m->input & INPUT_FIRST_PERSON) {
1272
return set_mario_action(m, ACT_METAL_WATER_STANDING, 0);
1273
}
1274
1275
if (m->input & INPUT_A_PRESSED) {
1276
return set_mario_action(m, ACT_METAL_WATER_JUMP, 0);
1277
}
1278
1279
if (m->input & INPUT_UNKNOWN_5) {
1280
return set_mario_action(m, ACT_METAL_WATER_STANDING, 0);
1281
}
1282
1283
if ((val04 = (s32)(m->forwardVel / 4.0f * 0x10000)) < 0x1000) {
1284
val04 = 0x1000;
1285
}
1286
1287
set_mario_anim_with_accel(m, MARIO_ANIM_WALKING, val04);
1288
play_metal_water_walking_sound(m);
1289
update_metal_water_walking_speed(m);
1290
1291
switch (perform_ground_step(m)) {
1292
case GROUND_STEP_LEFT_GROUND:
1293
set_mario_action(m, ACT_METAL_WATER_FALLING, 1);
1294
break;
1295
1296
case GROUND_STEP_HIT_WALL:
1297
m->forwardVel = 0.0f;
1298
break;
1299
}
1300
1301
return FALSE;
1302
}
1303
1304
static s32 act_hold_metal_water_walking(struct MarioState *m) {
1305
s32 val04;
1306
1307
if (m->marioObj->oInteractStatus & INT_STATUS_MARIO_DROP_OBJECT) {
1308
return drop_and_set_mario_action(m, ACT_METAL_WATER_WALKING, 0);
1309
}
1310
1311
if (!(m->flags & MARIO_METAL_CAP)) {
1312
return set_mario_action(m, ACT_HOLD_WATER_IDLE, 0);
1313
}
1314
1315
if (m->input & INPUT_A_PRESSED) {
1316
return set_mario_action(m, ACT_HOLD_METAL_WATER_JUMP, 0);
1317
}
1318
1319
if (m->input & INPUT_UNKNOWN_5) {
1320
return set_mario_action(m, ACT_HOLD_METAL_WATER_STANDING, 0);
1321
}
1322
1323
m->intendedMag *= 0.4f;
1324
1325
if ((val04 = (s32)(m->forwardVel / 2.0f * 0x10000)) < 0x1000) {
1326
val04 = 0x1000;
1327
}
1328
1329
set_mario_anim_with_accel(m, MARIO_ANIM_RUN_WITH_LIGHT_OBJ, val04);
1330
play_metal_water_walking_sound(m);
1331
update_metal_water_walking_speed(m);
1332
1333
switch (perform_ground_step(m)) {
1334
case GROUND_STEP_LEFT_GROUND:
1335
set_mario_action(m, ACT_HOLD_METAL_WATER_FALLING, 1);
1336
break;
1337
1338
case GROUND_STEP_HIT_WALL:
1339
m->forwardVel = 0.0f;
1340
break;
1341
}
1342
1343
return FALSE;
1344
}
1345
1346
static s32 act_metal_water_jump(struct MarioState *m) {
1347
if (!(m->flags & MARIO_METAL_CAP)) {
1348
return set_mario_action(m, ACT_WATER_IDLE, 0);
1349
}
1350
1351
if (update_metal_water_jump_speed(m)) {
1352
return set_mario_action(m, ACT_WATER_JUMP, 1);
1353
}
1354
1355
play_metal_water_jumping_sound(m, FALSE);
1356
set_mario_animation(m, MARIO_ANIM_SINGLE_JUMP);
1357
1358
switch (perform_air_step(m, 0)) {
1359
case AIR_STEP_LANDED:
1360
set_mario_action(m, ACT_METAL_WATER_JUMP_LAND, 0);
1361
break;
1362
1363
case AIR_STEP_HIT_WALL:
1364
m->forwardVel = 0.0f;
1365
break;
1366
}
1367
1368
return FALSE;
1369
}
1370
1371
static s32 act_hold_metal_water_jump(struct MarioState *m) {
1372
if (m->marioObj->oInteractStatus & INT_STATUS_MARIO_DROP_OBJECT) {
1373
return drop_and_set_mario_action(m, ACT_METAL_WATER_FALLING, 0);
1374
}
1375
1376
if (!(m->flags & MARIO_METAL_CAP)) {
1377
return set_mario_action(m, ACT_HOLD_WATER_IDLE, 0);
1378
}
1379
1380
if (update_metal_water_jump_speed(m)) {
1381
return set_mario_action(m, ACT_HOLD_WATER_JUMP, 1);
1382
}
1383
1384
play_metal_water_jumping_sound(m, FALSE);
1385
set_mario_animation(m, MARIO_ANIM_JUMP_WITH_LIGHT_OBJ);
1386
1387
switch (perform_air_step(m, 0)) {
1388
case AIR_STEP_LANDED:
1389
set_mario_action(m, ACT_HOLD_METAL_WATER_JUMP_LAND, 0);
1390
break;
1391
1392
case AIR_STEP_HIT_WALL:
1393
m->forwardVel = 0.0f;
1394
break;
1395
}
1396
1397
return FALSE;
1398
}
1399
1400
static s32 act_metal_water_falling(struct MarioState *m) {
1401
if (!(m->flags & MARIO_METAL_CAP)) {
1402
return set_mario_action(m, ACT_WATER_IDLE, 0);
1403
}
1404
1405
if (m->input & INPUT_NONZERO_ANALOG) {
1406
m->faceAngle[1] += 0x400 * sins(m->intendedYaw - m->faceAngle[1]);
1407
}
1408
1409
set_mario_animation(m, m->actionArg == 0 ? MARIO_ANIM_GENERAL_FALL : MARIO_ANIM_FALL_FROM_WATER);
1410
stationary_slow_down(m);
1411
1412
if (perform_water_step(m) & WATER_STEP_HIT_FLOOR) { // hit floor or cancelled
1413
set_mario_action(m, ACT_METAL_WATER_FALL_LAND, 0);
1414
}
1415
1416
return FALSE;
1417
}
1418
1419
static s32 act_hold_metal_water_falling(struct MarioState *m) {
1420
if (m->marioObj->oInteractStatus & INT_STATUS_MARIO_DROP_OBJECT) {
1421
return drop_and_set_mario_action(m, ACT_METAL_WATER_FALLING, 0);
1422
}
1423
1424
if (!(m->flags & MARIO_METAL_CAP)) {
1425
return set_mario_action(m, ACT_HOLD_WATER_IDLE, 0);
1426
}
1427
1428
if (m->input & INPUT_NONZERO_ANALOG) {
1429
m->faceAngle[1] += 0x400 * sins(m->intendedYaw - m->faceAngle[1]);
1430
}
1431
1432
set_mario_animation(m, MARIO_ANIM_FALL_WITH_LIGHT_OBJ);
1433
stationary_slow_down(m);
1434
1435
if (perform_water_step(m) & WATER_STEP_HIT_FLOOR) { // hit floor or cancelled
1436
set_mario_action(m, ACT_HOLD_METAL_WATER_FALL_LAND, 0);
1437
}
1438
1439
return FALSE;
1440
}
1441
1442
static s32 act_metal_water_jump_land(struct MarioState *m) {
1443
play_metal_water_jumping_sound(m, TRUE);
1444
1445
if (!(m->flags & MARIO_METAL_CAP)) {
1446
return set_mario_action(m, ACT_WATER_IDLE, 0);
1447
}
1448
1449
if (m->input & INPUT_NONZERO_ANALOG) {
1450
return set_mario_action(m, ACT_METAL_WATER_WALKING, 0);
1451
}
1452
1453
stop_and_set_height_to_floor(m);
1454
set_mario_animation(m, MARIO_ANIM_LAND_FROM_SINGLE_JUMP);
1455
1456
if (is_anim_at_end(m)) {
1457
return set_mario_action(m, ACT_METAL_WATER_STANDING, 0);
1458
}
1459
1460
return FALSE;
1461
}
1462
1463
static s32 act_hold_metal_water_jump_land(struct MarioState *m) {
1464
play_metal_water_jumping_sound(m, TRUE);
1465
1466
if (m->marioObj->oInteractStatus & INT_STATUS_MARIO_DROP_OBJECT) {
1467
return drop_and_set_mario_action(m, ACT_METAL_WATER_STANDING, 0);
1468
}
1469
1470
if (!(m->flags & MARIO_METAL_CAP)) {
1471
return set_mario_action(m, ACT_HOLD_WATER_IDLE, 0);
1472
}
1473
1474
if (m->input & INPUT_NONZERO_ANALOG) {
1475
return set_mario_action(m, ACT_HOLD_METAL_WATER_WALKING, 0);
1476
}
1477
1478
stop_and_set_height_to_floor(m);
1479
set_mario_animation(m, MARIO_ANIM_JUMP_LAND_WITH_LIGHT_OBJ);
1480
1481
if (is_anim_at_end(m)) {
1482
return set_mario_action(m, ACT_HOLD_METAL_WATER_STANDING, 0);
1483
}
1484
1485
return FALSE;
1486
}
1487
1488
static s32 act_metal_water_fall_land(struct MarioState *m) {
1489
play_metal_water_jumping_sound(m, TRUE);
1490
1491
if (!(m->flags & MARIO_METAL_CAP)) {
1492
return set_mario_action(m, ACT_WATER_IDLE, 0);
1493
}
1494
1495
if (m->input & INPUT_NONZERO_ANALOG) {
1496
return set_mario_action(m, ACT_METAL_WATER_WALKING, 0);
1497
}
1498
1499
stop_and_set_height_to_floor(m);
1500
set_mario_animation(m, MARIO_ANIM_GENERAL_LAND);
1501
1502
if (is_anim_at_end(m)) {
1503
return set_mario_action(m, ACT_METAL_WATER_STANDING, 0);
1504
}
1505
1506
return FALSE;
1507
}
1508
1509
static s32 act_hold_metal_water_fall_land(struct MarioState *m) {
1510
play_metal_water_jumping_sound(m, TRUE);
1511
1512
if (m->marioObj->oInteractStatus & INT_STATUS_MARIO_DROP_OBJECT) {
1513
return drop_and_set_mario_action(m, ACT_METAL_WATER_STANDING, 0);
1514
}
1515
1516
if (!(m->flags & MARIO_METAL_CAP)) {
1517
return set_mario_action(m, ACT_HOLD_WATER_IDLE, 0);
1518
}
1519
1520
if (m->input & INPUT_NONZERO_ANALOG) {
1521
return set_mario_action(m, ACT_HOLD_METAL_WATER_WALKING, 0);
1522
}
1523
1524
stop_and_set_height_to_floor(m);
1525
set_mario_animation(m, MARIO_ANIM_FALL_LAND_WITH_LIGHT_OBJ);
1526
1527
if (is_anim_at_end(m)) {
1528
return set_mario_action(m, ACT_HOLD_METAL_WATER_STANDING, 0);
1529
}
1530
1531
return FALSE;
1532
}
1533
1534
static s32 check_common_submerged_cancels(struct MarioState *m) {
1535
if (m->pos[1] > m->waterLevel - 80) {
1536
if (m->waterLevel - 80 > m->floorHeight) {
1537
m->pos[1] = m->waterLevel - 80;
1538
} else {
1539
//! If you press B to throw the shell, there is a ~5 frame window
1540
// where your held object is the shell, but you are not in the
1541
// water shell swimming action. This allows you to hold the water
1542
// shell on land (used for cloning in DDD).
1543
if (m->action == ACT_WATER_SHELL_SWIMMING && m->heldObj != NULL) {
1544
m->heldObj->oInteractStatus = INT_STATUS_STOP_RIDING;
1545
m->heldObj = NULL;
1546
stop_shell_music();
1547
}
1548
1549
return transition_submerged_to_walking(m);
1550
}
1551
}
1552
1553
if (m->health < 0x100 && !(m->action & (ACT_FLAG_INTANGIBLE | ACT_FLAG_INVULNERABLE))) {
1554
set_mario_action(m, ACT_DROWNING, 0);
1555
}
1556
1557
return FALSE;
1558
}
1559
1560
s32 mario_execute_submerged_action(struct MarioState *m) {
1561
s32 cancel;
1562
1563
if (check_common_submerged_cancels(m)) {
1564
return TRUE;
1565
}
1566
1567
m->quicksandDepth = 0.0f;
1568
1569
m->marioBodyState->headAngle[1] = 0;
1570
m->marioBodyState->headAngle[2] = 0;
1571
1572
/* clang-format off */
1573
switch (m->action) {
1574
case ACT_WATER_IDLE: cancel = act_water_idle(m); break;
1575
case ACT_HOLD_WATER_IDLE: cancel = act_hold_water_idle(m); break;
1576
case ACT_WATER_ACTION_END: cancel = act_water_action_end(m); break;
1577
case ACT_HOLD_WATER_ACTION_END: cancel = act_hold_water_action_end(m); break;
1578
case ACT_DROWNING: cancel = act_drowning(m); break;
1579
case ACT_BACKWARD_WATER_KB: cancel = act_backward_water_kb(m); break;
1580
case ACT_FORWARD_WATER_KB: cancel = act_forward_water_kb(m); break;
1581
case ACT_WATER_DEATH: cancel = act_water_death(m); break;
1582
case ACT_WATER_SHOCKED: cancel = act_water_shocked(m); break;
1583
case ACT_BREASTSTROKE: cancel = act_breaststroke(m); break;
1584
case ACT_SWIMMING_END: cancel = act_swimming_end(m); break;
1585
case ACT_FLUTTER_KICK: cancel = act_flutter_kick(m); break;
1586
case ACT_HOLD_BREASTSTROKE: cancel = act_hold_breaststroke(m); break;
1587
case ACT_HOLD_SWIMMING_END: cancel = act_hold_swimming_end(m); break;
1588
case ACT_HOLD_FLUTTER_KICK: cancel = act_hold_flutter_kick(m); break;
1589
case ACT_WATER_SHELL_SWIMMING: cancel = act_water_shell_swimming(m); break;
1590
case ACT_WATER_THROW: cancel = act_water_throw(m); break;
1591
case ACT_WATER_PUNCH: cancel = act_water_punch(m); break;
1592
case ACT_WATER_PLUNGE: cancel = act_water_plunge(m); break;
1593
case ACT_CAUGHT_IN_WHIRLPOOL: cancel = act_caught_in_whirlpool(m); break;
1594
case ACT_METAL_WATER_STANDING: cancel = act_metal_water_standing(m); break;
1595
case ACT_METAL_WATER_WALKING: cancel = act_metal_water_walking(m); break;
1596
case ACT_METAL_WATER_FALLING: cancel = act_metal_water_falling(m); break;
1597
case ACT_METAL_WATER_FALL_LAND: cancel = act_metal_water_fall_land(m); break;
1598
case ACT_METAL_WATER_JUMP: cancel = act_metal_water_jump(m); break;
1599
case ACT_METAL_WATER_JUMP_LAND: cancel = act_metal_water_jump_land(m); break;
1600
case ACT_HOLD_METAL_WATER_STANDING: cancel = act_hold_metal_water_standing(m); break;
1601
case ACT_HOLD_METAL_WATER_WALKING: cancel = act_hold_metal_water_walking(m); break;
1602
case ACT_HOLD_METAL_WATER_FALLING: cancel = act_hold_metal_water_falling(m); break;
1603
case ACT_HOLD_METAL_WATER_FALL_LAND: cancel = act_hold_metal_water_fall_land(m); break;
1604
case ACT_HOLD_METAL_WATER_JUMP: cancel = act_hold_metal_water_jump(m); break;
1605
case ACT_HOLD_METAL_WATER_JUMP_LAND: cancel = act_hold_metal_water_jump_land(m); break;
1606
}
1607
/* clang-format on */
1608
1609
return cancel;
1610
}
1611
1612