sm64

A Super Mario 64 decompilation
Log | Files | Refs | README | LICENSE

mario_actions_submerged.c (47167B)


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