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 }