mario_actions_automatic.c (27065B)
1 #include <PR/ultratypes.h> 2 3 #include "sm64.h" 4 #include "behavior_data.h" 5 #include "mario_actions_automatic.h" 6 #include "audio/external.h" 7 #include "area.h" 8 #include "mario.h" 9 #include "mario_step.h" 10 #include "engine/math_util.h" 11 #include "memory.h" 12 #include "engine/graph_node.h" 13 #include "save_file.h" 14 #include "engine/surface_collision.h" 15 #include "interaction.h" 16 #include "camera.h" 17 #include "level_table.h" 18 #include "rumble_init.h" 19 20 #define POLE_NONE 0 21 #define POLE_TOUCHED_FLOOR 1 22 #define POLE_FELL_OFF 2 23 24 #define HANG_NONE 0 25 #define HANG_HIT_CEIL_OR_OOB 1 26 #define HANG_LEFT_CEIL 2 27 28 void add_tree_leaf_particles(struct MarioState *m) { 29 f32 leafHeight; 30 31 if (m->usedObj->behavior == segmented_to_virtual(bhvTree)) { 32 // make leaf effect spawn higher on the Shifting Sand Land palm tree 33 if (gCurrLevelNum == LEVEL_SSL) { 34 leafHeight = 250.0f; 35 } else { 36 leafHeight = 100.0f; 37 } 38 if (m->pos[1] - m->floorHeight > leafHeight) { 39 m->particleFlags |= PARTICLE_LEAF; 40 } 41 } 42 } 43 44 void play_climbing_sounds(struct MarioState *m, s32 b) { 45 s32 isOnTree = (m->usedObj->behavior == segmented_to_virtual(bhvTree)); 46 47 if (b == 1) { 48 if (is_anim_past_frame(m, 1)) { 49 play_sound(isOnTree ? SOUND_ACTION_CLIMB_UP_TREE : SOUND_ACTION_CLIMB_UP_POLE, 50 m->marioObj->header.gfx.cameraToObject); 51 } 52 } else { 53 play_sound(isOnTree ? SOUND_MOVING_SLIDE_DOWN_TREE : SOUND_MOVING_SLIDE_DOWN_POLE, 54 m->marioObj->header.gfx.cameraToObject); 55 } 56 } 57 58 s32 set_pole_position(struct MarioState *m, f32 offsetY) { 59 UNUSED u8 filler[12]; 60 struct Surface *floor; 61 struct Surface *ceil; 62 f32 floorHeight; 63 f32 ceilHeight; 64 s32 collided; 65 s32 result = POLE_NONE; 66 f32 poleTop = m->usedObj->hitboxHeight - 100.0f; 67 struct Object *marioObj = m->marioObj; 68 69 if (marioObj->oMarioPolePos > poleTop) { 70 marioObj->oMarioPolePos = poleTop; 71 } 72 73 m->pos[0] = m->usedObj->oPosX; 74 m->pos[2] = m->usedObj->oPosZ; 75 m->pos[1] = m->usedObj->oPosY + marioObj->oMarioPolePos + offsetY; 76 77 collided = f32_find_wall_collision(&m->pos[0], &m->pos[1], &m->pos[2], 60.0f, 50.0f); 78 collided |= f32_find_wall_collision(&m->pos[0], &m->pos[1], &m->pos[2], 30.0f, 24.0f); 79 80 ceilHeight = vec3f_find_ceil(m->pos, m->pos[1], &ceil); 81 if (m->pos[1] > ceilHeight - 160.0f) { 82 m->pos[1] = ceilHeight - 160.0f; 83 marioObj->oMarioPolePos = m->pos[1] - m->usedObj->oPosY; 84 } 85 86 floorHeight = find_floor(m->pos[0], m->pos[1], m->pos[2], &floor); 87 if (m->pos[1] < floorHeight) { 88 m->pos[1] = floorHeight; 89 set_mario_action(m, ACT_IDLE, 0); 90 result = POLE_TOUCHED_FLOOR; 91 } else if (marioObj->oMarioPolePos < -m->usedObj->hitboxDownOffset) { 92 m->pos[1] = m->usedObj->oPosY - m->usedObj->hitboxDownOffset; 93 set_mario_action(m, ACT_FREEFALL, 0); 94 result = POLE_FELL_OFF; 95 } else if (collided) { 96 if (m->pos[1] > floorHeight + 20.0f) { 97 m->forwardVel = -2.0f; 98 set_mario_action(m, ACT_SOFT_BONK, 0); 99 result = POLE_FELL_OFF; 100 } else { 101 set_mario_action(m, ACT_IDLE, 0); 102 result = POLE_TOUCHED_FLOOR; 103 } 104 } 105 106 vec3f_copy(m->marioObj->header.gfx.pos, m->pos); 107 vec3s_set(m->marioObj->header.gfx.angle, m->usedObj->oMoveAnglePitch, m->faceAngle[1], 108 m->usedObj->oMoveAngleRoll); 109 110 return result; 111 } 112 113 s32 act_holding_pole(struct MarioState *m) { 114 struct Object *marioObj = m->marioObj; 115 116 #ifdef VERSION_JP 117 if (m->input & INPUT_A_PRESSED) { 118 add_tree_leaf_particles(m); 119 m->faceAngle[1] += 0x8000; 120 return set_mario_action(m, ACT_WALL_KICK_AIR, 0); 121 } 122 123 if (m->input & INPUT_Z_PRESSED) { 124 add_tree_leaf_particles(m); 125 m->forwardVel = -2.0f; 126 return set_mario_action(m, ACT_SOFT_BONK, 0); 127 } 128 #else 129 if ((m->input & INPUT_Z_PRESSED) || m->health < 0x100) { 130 add_tree_leaf_particles(m); 131 m->forwardVel = -2.0f; 132 return set_mario_action(m, ACT_SOFT_BONK, 0); 133 } 134 135 if (m->input & INPUT_A_PRESSED) { 136 add_tree_leaf_particles(m); 137 m->faceAngle[1] += 0x8000; 138 return set_mario_action(m, ACT_WALL_KICK_AIR, 0); 139 } 140 #endif 141 142 if (m->controller->stickY > 16.0f) { 143 f32 poleTop = m->usedObj->hitboxHeight - 100.0f; 144 const BehaviorScript *poleBehavior = virtual_to_segmented(0x13, m->usedObj->behavior); 145 146 if (marioObj->oMarioPolePos < poleTop - 0.4f) { 147 return set_mario_action(m, ACT_CLIMBING_POLE, 0); 148 } 149 150 if (poleBehavior != bhvGiantPole && m->controller->stickY > 50.0f) { 151 return set_mario_action(m, ACT_TOP_OF_POLE_TRANSITION, 0); 152 } 153 } 154 155 if (m->controller->stickY < -16.0f) { 156 marioObj->oMarioPoleYawVel -= m->controller->stickY * 2; 157 if (marioObj->oMarioPoleYawVel > 0x1000) { 158 marioObj->oMarioPoleYawVel = 0x1000; 159 } 160 161 m->faceAngle[1] += marioObj->oMarioPoleYawVel; 162 marioObj->oMarioPolePos -= marioObj->oMarioPoleYawVel / 0x100; 163 164 if (m->usedObj->behavior == segmented_to_virtual(bhvTree)) { 165 //! The Shifting Sand Land palm tree check is done climbing up in 166 // add_tree_leaf_particles, but not here, when climbing down. 167 if (m->pos[1] - m->floorHeight > 100.0f) { 168 m->particleFlags |= PARTICLE_LEAF; 169 } 170 } 171 play_climbing_sounds(m, 2); 172 #if ENABLE_RUMBLE 173 reset_rumble_timers(); 174 #endif 175 set_sound_moving_speed(SOUND_BANK_MOVING, marioObj->oMarioPoleYawVel / 0x100 * 2); 176 } else { 177 marioObj->oMarioPoleYawVel = 0; 178 m->faceAngle[1] -= m->controller->stickX * 16.0f; 179 } 180 181 if (set_pole_position(m, 0.0f) == POLE_NONE) { 182 set_mario_animation(m, MARIO_ANIM_IDLE_ON_POLE); 183 } 184 185 return FALSE; 186 } 187 188 s32 act_climbing_pole(struct MarioState *m) { 189 s32 sp24; 190 struct Object *marioObj = m->marioObj; 191 s16 cameraAngle = m->area->camera->yaw; 192 193 #ifndef VERSION_JP 194 if (m->health < 0x100) { 195 add_tree_leaf_particles(m); 196 m->forwardVel = -2.0f; 197 return set_mario_action(m, ACT_SOFT_BONK, 0); 198 } 199 #endif 200 201 if (m->input & INPUT_A_PRESSED) { 202 add_tree_leaf_particles(m); 203 m->faceAngle[1] += 0x8000; 204 return set_mario_action(m, ACT_WALL_KICK_AIR, 0); 205 } 206 207 if (m->controller->stickY < 8.0f) { 208 return set_mario_action(m, ACT_HOLDING_POLE, 0); 209 } 210 211 marioObj->oMarioPolePos += m->controller->stickY / 8.0f; 212 marioObj->oMarioPoleYawVel = 0; 213 m->faceAngle[1] = cameraAngle - approach_s32((s16)(cameraAngle - m->faceAngle[1]), 0, 0x400, 0x400); 214 215 if (set_pole_position(m, 0.0f) == POLE_NONE) { 216 sp24 = m->controller->stickY / 4.0f * 0x10000; 217 set_mario_anim_with_accel(m, MARIO_ANIM_CLIMB_UP_POLE, sp24); 218 add_tree_leaf_particles(m); 219 play_climbing_sounds(m, 1); 220 } 221 222 return FALSE; 223 } 224 225 s32 act_grab_pole_slow(struct MarioState *m) { 226 play_sound_if_no_flag(m, SOUND_MARIO_WHOA, MARIO_MARIO_SOUND_PLAYED); 227 228 if (set_pole_position(m, 0.0f) == POLE_NONE) { 229 set_mario_animation(m, MARIO_ANIM_GRAB_POLE_SHORT); 230 if (is_anim_at_end(m)) { 231 set_mario_action(m, ACT_HOLDING_POLE, 0); 232 } 233 add_tree_leaf_particles(m); 234 } 235 236 return FALSE; 237 } 238 239 s32 act_grab_pole_fast(struct MarioState *m) { 240 struct Object *marioObj = m->marioObj; 241 242 play_sound_if_no_flag(m, SOUND_MARIO_WHOA, MARIO_MARIO_SOUND_PLAYED); 243 m->faceAngle[1] += marioObj->oMarioPoleYawVel; 244 marioObj->oMarioPoleYawVel = marioObj->oMarioPoleYawVel * 8 / 10; 245 246 if (set_pole_position(m, 0.0f) == POLE_NONE) { 247 if (marioObj->oMarioPoleYawVel > 0x800) { 248 set_mario_animation(m, MARIO_ANIM_GRAB_POLE_SWING_PART1); 249 } else { 250 set_mario_animation(m, MARIO_ANIM_GRAB_POLE_SWING_PART2); 251 if (is_anim_at_end(m)) { 252 marioObj->oMarioPoleYawVel = 0; 253 set_mario_action(m, ACT_HOLDING_POLE, 0); 254 } 255 } 256 add_tree_leaf_particles(m); 257 } 258 259 return FALSE; 260 } 261 262 s32 act_top_of_pole_transition(struct MarioState *m) { 263 struct Object *marioObj = m->marioObj; 264 265 marioObj->oMarioPoleYawVel = 0; 266 if (m->actionArg == 0) { 267 set_mario_animation(m, MARIO_ANIM_START_HANDSTAND); 268 if (is_anim_at_end(m)) { 269 return set_mario_action(m, ACT_TOP_OF_POLE, 0); 270 } 271 } else { 272 set_mario_animation(m, MARIO_ANIM_RETURN_FROM_HANDSTAND); 273 if (m->marioObj->header.gfx.animInfo.animFrame == 0) { 274 return set_mario_action(m, ACT_HOLDING_POLE, 0); 275 } 276 } 277 278 set_pole_position(m, return_mario_anim_y_translation(m)); 279 return FALSE; 280 } 281 282 s32 act_top_of_pole(struct MarioState *m) { 283 UNUSED struct Object *marioObj = m->marioObj; 284 285 if (m->input & INPUT_A_PRESSED) { 286 return set_mario_action(m, ACT_TOP_OF_POLE_JUMP, 0); 287 } 288 if (m->controller->stickY < -16.0f) { 289 return set_mario_action(m, ACT_TOP_OF_POLE_TRANSITION, 1); 290 } 291 292 m->faceAngle[1] -= m->controller->stickX * 16.0f; 293 294 set_mario_animation(m, MARIO_ANIM_HANDSTAND_IDLE); 295 set_pole_position(m, return_mario_anim_y_translation(m)); 296 return FALSE; 297 } 298 299 s32 perform_hanging_step(struct MarioState *m, Vec3f nextPos) { 300 UNUSED u8 filler[4]; 301 struct Surface *ceil; 302 struct Surface *floor; 303 f32 ceilHeight; 304 f32 floorHeight; 305 f32 ceilOffset; 306 307 m->wall = resolve_and_return_wall_collisions(nextPos, 50.0f, 50.0f); 308 floorHeight = find_floor(nextPos[0], nextPos[1], nextPos[2], &floor); 309 ceilHeight = vec3f_find_ceil(nextPos, floorHeight, &ceil); 310 311 if (floor == NULL) { 312 return HANG_HIT_CEIL_OR_OOB; 313 } 314 if (ceil == NULL) { 315 return HANG_LEFT_CEIL; 316 } 317 if (ceilHeight - floorHeight <= 160.0f) { 318 return HANG_HIT_CEIL_OR_OOB; 319 } 320 if (ceil->type != SURFACE_HANGABLE) { 321 return HANG_LEFT_CEIL; 322 } 323 324 ceilOffset = ceilHeight - (nextPos[1] + 160.0f); 325 if (ceilOffset < -30.0f) { 326 return HANG_HIT_CEIL_OR_OOB; 327 } 328 if (ceilOffset > 30.0f) { 329 return HANG_LEFT_CEIL; 330 } 331 332 nextPos[1] = m->ceilHeight - 160.0f; 333 vec3f_copy(m->pos, nextPos); 334 335 m->floor = floor; 336 m->floorHeight = floorHeight; 337 m->ceil = ceil; 338 m->ceilHeight = ceilHeight; 339 340 return HANG_NONE; 341 } 342 343 s32 update_hang_moving(struct MarioState *m) { 344 s32 stepResult; 345 Vec3f nextPos; 346 f32 maxSpeed = 4.0f; 347 348 m->forwardVel += 1.0f; 349 if (m->forwardVel > maxSpeed) { 350 m->forwardVel = maxSpeed; 351 } 352 353 m->faceAngle[1] = 354 m->intendedYaw - approach_s32((s16)(m->intendedYaw - m->faceAngle[1]), 0, 0x800, 0x800); 355 356 m->slideYaw = m->faceAngle[1]; 357 m->slideVelX = m->forwardVel * sins(m->faceAngle[1]); 358 m->slideVelZ = m->forwardVel * coss(m->faceAngle[1]); 359 360 m->vel[0] = m->slideVelX; 361 m->vel[1] = 0.0f; 362 m->vel[2] = m->slideVelZ; 363 364 nextPos[0] = m->pos[0] - m->ceil->normal.y * m->vel[0]; 365 nextPos[2] = m->pos[2] - m->ceil->normal.y * m->vel[2]; 366 nextPos[1] = m->pos[1]; 367 368 stepResult = perform_hanging_step(m, nextPos); 369 370 vec3f_copy(m->marioObj->header.gfx.pos, m->pos); 371 vec3s_set(m->marioObj->header.gfx.angle, 0, m->faceAngle[1], 0); 372 return stepResult; 373 } 374 375 void update_hang_stationary(struct MarioState *m) { 376 m->forwardVel = 0.0f; 377 m->slideVelX = 0.0f; 378 m->slideVelZ = 0.0f; 379 380 m->pos[1] = m->ceilHeight - 160.0f; 381 vec3f_copy(m->vel, gVec3fZero); 382 vec3f_copy(m->marioObj->header.gfx.pos, m->pos); 383 } 384 385 s32 act_start_hanging(struct MarioState *m) { 386 #if ENABLE_RUMBLE 387 if (m->actionTimer++ == 0) { 388 queue_rumble_data(5, 80); 389 } 390 #else 391 m->actionTimer++; 392 #endif 393 394 if ((m->input & INPUT_NONZERO_ANALOG) && m->actionTimer >= 31) { 395 return set_mario_action(m, ACT_HANGING, 0); 396 } 397 398 if (!(m->input & INPUT_A_DOWN)) { 399 return set_mario_action(m, ACT_FREEFALL, 0); 400 } 401 402 if (m->input & INPUT_Z_PRESSED) { 403 return set_mario_action(m, ACT_GROUND_POUND, 0); 404 } 405 406 //! Crash if Mario's referenced ceiling is NULL (same for other hanging actions) 407 if (m->ceil->type != SURFACE_HANGABLE) { 408 return set_mario_action(m, ACT_FREEFALL, 0); 409 } 410 411 set_mario_animation(m, MARIO_ANIM_HANG_ON_CEILING); 412 play_sound_if_no_flag(m, SOUND_ACTION_HANGING_STEP, MARIO_ACTION_SOUND_PLAYED); 413 update_hang_stationary(m); 414 415 if (is_anim_at_end(m)) { 416 set_mario_action(m, ACT_HANGING, 0); 417 } 418 419 return FALSE; 420 } 421 422 s32 act_hanging(struct MarioState *m) { 423 if (m->input & INPUT_NONZERO_ANALOG) { 424 return set_mario_action(m, ACT_HANG_MOVING, m->actionArg); 425 } 426 427 if (!(m->input & INPUT_A_DOWN)) { 428 return set_mario_action(m, ACT_FREEFALL, 0); 429 } 430 431 if (m->input & INPUT_Z_PRESSED) { 432 return set_mario_action(m, ACT_GROUND_POUND, 0); 433 } 434 435 if (m->ceil->type != SURFACE_HANGABLE) { 436 return set_mario_action(m, ACT_FREEFALL, 0); 437 } 438 439 if (m->actionArg & 1) { 440 set_mario_animation(m, MARIO_ANIM_HANDSTAND_LEFT); 441 } else { 442 set_mario_animation(m, MARIO_ANIM_HANDSTAND_RIGHT); 443 } 444 445 update_hang_stationary(m); 446 447 return FALSE; 448 } 449 450 s32 act_hang_moving(struct MarioState *m) { 451 if (!(m->input & INPUT_A_DOWN)) { 452 return set_mario_action(m, ACT_FREEFALL, 0); 453 } 454 455 if (m->input & INPUT_Z_PRESSED) { 456 return set_mario_action(m, ACT_GROUND_POUND, 0); 457 } 458 459 if (m->ceil->type != SURFACE_HANGABLE) { 460 return set_mario_action(m, ACT_FREEFALL, 0); 461 } 462 463 if (m->actionArg & 1) { 464 set_mario_animation(m, MARIO_ANIM_MOVE_ON_WIRE_NET_RIGHT); 465 } else { 466 set_mario_animation(m, MARIO_ANIM_MOVE_ON_WIRE_NET_LEFT); 467 } 468 469 if (m->marioObj->header.gfx.animInfo.animFrame == 12) { 470 play_sound(SOUND_ACTION_HANGING_STEP, m->marioObj->header.gfx.cameraToObject); 471 #if ENABLE_RUMBLE 472 queue_rumble_data(1, 30); 473 #endif 474 } 475 476 if (is_anim_past_end(m)) { 477 m->actionArg ^= 1; 478 if (m->input & INPUT_UNKNOWN_5) { 479 return set_mario_action(m, ACT_HANGING, m->actionArg); 480 } 481 } 482 483 if (update_hang_moving(m) == HANG_LEFT_CEIL) { 484 set_mario_action(m, ACT_FREEFALL, 0); 485 } 486 487 return FALSE; 488 } 489 490 s32 let_go_of_ledge(struct MarioState *m) { 491 f32 floorHeight; 492 struct Surface *floor; 493 494 m->vel[1] = 0.0f; 495 m->forwardVel = -8.0f; 496 m->pos[0] -= 60.0f * sins(m->faceAngle[1]); 497 m->pos[2] -= 60.0f * coss(m->faceAngle[1]); 498 499 floorHeight = find_floor(m->pos[0], m->pos[1], m->pos[2], &floor); 500 if (floorHeight < m->pos[1] - 100.0f) { 501 m->pos[1] -= 100.0f; 502 } else { 503 m->pos[1] = floorHeight; 504 } 505 506 return set_mario_action(m, ACT_SOFT_BONK, 0); 507 } 508 509 void climb_up_ledge(struct MarioState *m) { 510 set_mario_animation(m, MARIO_ANIM_IDLE_HEAD_LEFT); 511 m->pos[0] += 14.0f * sins(m->faceAngle[1]); 512 m->pos[2] += 14.0f * coss(m->faceAngle[1]); 513 vec3f_copy(m->marioObj->header.gfx.pos, m->pos); 514 } 515 516 void update_ledge_climb_camera(struct MarioState *m) { 517 f32 sp4; 518 519 if (m->actionTimer < 14) { 520 sp4 = m->actionTimer; 521 } else { 522 sp4 = 14.0f; 523 } 524 m->statusForCamera->pos[0] = m->pos[0] + sp4 * sins(m->faceAngle[1]); 525 m->statusForCamera->pos[2] = m->pos[2] + sp4 * coss(m->faceAngle[1]); 526 m->statusForCamera->pos[1] = m->pos[1]; 527 m->actionTimer++; 528 m->flags |= MARIO_UNKNOWN_25; 529 } 530 531 void update_ledge_climb(struct MarioState *m, s32 animation, u32 endAction) { 532 stop_and_set_height_to_floor(m); 533 534 set_mario_animation(m, animation); 535 if (is_anim_at_end(m)) { 536 set_mario_action(m, endAction, 0); 537 if (endAction == ACT_IDLE) { 538 climb_up_ledge(m); 539 } 540 } 541 } 542 543 s32 act_ledge_grab(struct MarioState *m) { 544 f32 heightAboveFloor; 545 s16 intendedDYaw = m->intendedYaw - m->faceAngle[1]; 546 s32 hasSpaceForMario = (m->ceilHeight - m->floorHeight >= 160.0f); 547 548 if (m->actionTimer < 10) { 549 m->actionTimer++; 550 } 551 552 if (m->floor->normal.y < 0.9063078f) { 553 return let_go_of_ledge(m); 554 } 555 556 if (m->input & (INPUT_Z_PRESSED | INPUT_OFF_FLOOR)) { 557 return let_go_of_ledge(m); 558 } 559 560 if ((m->input & INPUT_A_PRESSED) && hasSpaceForMario) { 561 return set_mario_action(m, ACT_LEDGE_CLIMB_FAST, 0); 562 } 563 564 if (m->input & INPUT_STOMPED) { 565 if (m->marioObj->oInteractStatus & INT_STATUS_MARIO_KNOCKBACK_DMG) { 566 m->hurtCounter += (m->flags & MARIO_CAP_ON_HEAD) ? 12 : 18; 567 } 568 return let_go_of_ledge(m); 569 } 570 if (m->actionTimer == 10 && (m->input & INPUT_NONZERO_ANALOG) 571 #ifdef VERSION_EU 572 // On EU, you can't slow climb up ledges while holding A. 573 && !(m->input & INPUT_A_DOWN) 574 #endif 575 ) { 576 if (intendedDYaw >= -0x4000 && intendedDYaw <= 0x4000) { 577 if (hasSpaceForMario) { 578 return set_mario_action(m, ACT_LEDGE_CLIMB_SLOW_1, 0); 579 } 580 } else { 581 return let_go_of_ledge(m); 582 } 583 } 584 585 heightAboveFloor = m->pos[1] - find_floor_height_relative_polar(m, -0x8000, 30.0f); 586 if (hasSpaceForMario && heightAboveFloor < 100.0f) { 587 return set_mario_action(m, ACT_LEDGE_CLIMB_FAST, 0); 588 } 589 590 if (m->actionArg == 0) { 591 play_sound_if_no_flag(m, SOUND_MARIO_WHOA, MARIO_MARIO_SOUND_PLAYED); 592 } 593 594 stop_and_set_height_to_floor(m); 595 set_mario_animation(m, MARIO_ANIM_IDLE_ON_LEDGE); 596 597 return FALSE; 598 } 599 600 s32 act_ledge_climb_slow(struct MarioState *m) { 601 if (m->input & INPUT_OFF_FLOOR) { 602 return let_go_of_ledge(m); 603 } 604 605 if (m->actionTimer >= 28 606 && (m->input 607 & (INPUT_NONZERO_ANALOG | INPUT_A_PRESSED | INPUT_OFF_FLOOR | INPUT_ABOVE_SLIDE))) { 608 climb_up_ledge(m); 609 return check_common_action_exits(m); 610 } 611 612 if (m->actionTimer == 10) { 613 play_sound_if_no_flag(m, SOUND_MARIO_EEUH, MARIO_MARIO_SOUND_PLAYED); 614 } 615 616 update_ledge_climb(m, MARIO_ANIM_SLOW_LEDGE_GRAB, ACT_IDLE); 617 618 update_ledge_climb_camera(m); 619 if (m->marioObj->header.gfx.animInfo.animFrame == 17) { 620 m->action = ACT_LEDGE_CLIMB_SLOW_2; 621 } 622 623 return FALSE; 624 } 625 626 s32 act_ledge_climb_down(struct MarioState *m) { 627 if (m->input & INPUT_OFF_FLOOR) { 628 return let_go_of_ledge(m); 629 } 630 631 play_sound_if_no_flag(m, SOUND_MARIO_WHOA, MARIO_MARIO_SOUND_PLAYED); 632 633 update_ledge_climb(m, MARIO_ANIM_CLIMB_DOWN_LEDGE, ACT_LEDGE_GRAB); 634 m->actionArg = 1; 635 636 return FALSE; 637 } 638 639 s32 act_ledge_climb_fast(struct MarioState *m) { 640 if (m->input & INPUT_OFF_FLOOR) { 641 return let_go_of_ledge(m); 642 } 643 644 play_sound_if_no_flag(m, SOUND_MARIO_UH2, MARIO_MARIO_SOUND_PLAYED); 645 646 update_ledge_climb(m, MARIO_ANIM_FAST_LEDGE_GRAB, ACT_IDLE); 647 648 if (m->marioObj->header.gfx.animInfo.animFrame == 8) { 649 play_mario_landing_sound(m, SOUND_ACTION_TERRAIN_LANDING); 650 } 651 update_ledge_climb_camera(m); 652 653 return FALSE; 654 } 655 656 s32 act_grabbed(struct MarioState *m) { 657 if (m->marioObj->oInteractStatus & INT_STATUS_MARIO_UNK2) { 658 s32 thrown = (m->marioObj->oInteractStatus & INT_STATUS_MARIO_UNK6) == 0; 659 660 m->faceAngle[1] = m->usedObj->oMoveAngleYaw; 661 vec3f_copy(m->pos, m->marioObj->header.gfx.pos); 662 #if ENABLE_RUMBLE 663 queue_rumble_data(5, 60); 664 #endif 665 666 return set_mario_action(m, (m->forwardVel >= 0.0f) ? ACT_THROWN_FORWARD : ACT_THROWN_BACKWARD, 667 thrown); 668 } 669 670 set_mario_animation(m, MARIO_ANIM_BEING_GRABBED); 671 return FALSE; 672 } 673 674 s32 act_in_cannon(struct MarioState *m) { 675 struct Object *marioObj = m->marioObj; 676 s16 startFacePitch = m->faceAngle[0]; 677 s16 startFaceYaw = m->faceAngle[1]; 678 679 switch (m->actionState) { 680 case 0: 681 m->marioObj->header.gfx.node.flags &= ~GRAPH_RENDER_ACTIVE; 682 m->usedObj->oInteractStatus = INT_STATUS_INTERACTED; 683 684 m->statusForCamera->cameraEvent = CAM_EVENT_CANNON; 685 m->statusForCamera->usedObj = m->usedObj; 686 687 vec3f_set(m->vel, 0.0f, 0.0f, 0.0f); 688 689 m->pos[0] = m->usedObj->oPosX; 690 m->pos[1] = m->usedObj->oPosY + 350.0f; 691 m->pos[2] = m->usedObj->oPosZ; 692 693 m->forwardVel = 0.0f; 694 695 m->actionState = 1; 696 break; 697 698 case 1: 699 if (m->usedObj->oAction == 1) { 700 m->faceAngle[0] = m->usedObj->oMoveAnglePitch; 701 m->faceAngle[1] = m->usedObj->oMoveAngleYaw; 702 703 marioObj->oMarioCannonObjectYaw = m->usedObj->oMoveAngleYaw; 704 marioObj->oMarioCannonInputYaw = 0; 705 706 m->actionState = 2; 707 } 708 break; 709 710 case 2: 711 m->faceAngle[0] -= (s16)(m->controller->stickY * 10.0f); 712 marioObj->oMarioCannonInputYaw -= (s16)(m->controller->stickX * 10.0f); 713 714 if (m->faceAngle[0] > 0x38E3) { 715 m->faceAngle[0] = 0x38E3; 716 } 717 if (m->faceAngle[0] < 0) { 718 m->faceAngle[0] = 0; 719 } 720 721 if (marioObj->oMarioCannonInputYaw > 0x4000) { 722 marioObj->oMarioCannonInputYaw = 0x4000; 723 } 724 if (marioObj->oMarioCannonInputYaw < -0x4000) { 725 marioObj->oMarioCannonInputYaw = -0x4000; 726 } 727 728 m->faceAngle[1] = marioObj->oMarioCannonObjectYaw + marioObj->oMarioCannonInputYaw; 729 if (m->input & INPUT_A_PRESSED) { 730 m->forwardVel = 100.0f * coss(m->faceAngle[0]); 731 732 m->vel[1] = 100.0f * sins(m->faceAngle[0]); 733 734 m->pos[0] += 120.0f * coss(m->faceAngle[0]) * sins(m->faceAngle[1]); 735 m->pos[1] += 120.0f * sins(m->faceAngle[0]); 736 m->pos[2] += 120.0f * coss(m->faceAngle[0]) * coss(m->faceAngle[1]); 737 738 play_sound(SOUND_ACTION_FLYING_FAST, m->marioObj->header.gfx.cameraToObject); 739 play_sound(SOUND_OBJ_POUNDING_CANNON, m->marioObj->header.gfx.cameraToObject); 740 741 m->marioObj->header.gfx.node.flags |= GRAPH_RENDER_ACTIVE; 742 743 set_mario_action(m, ACT_SHOT_FROM_CANNON, 0); 744 #if ENABLE_RUMBLE 745 queue_rumble_data(60, 70); 746 #endif 747 m->usedObj->oAction = 2; 748 return FALSE; 749 } else if (m->faceAngle[0] != startFacePitch || m->faceAngle[1] != startFaceYaw) { 750 play_sound(SOUND_MOVING_AIM_CANNON, m->marioObj->header.gfx.cameraToObject); 751 #if ENABLE_RUMBLE 752 reset_rumble_timers_2(0); 753 #endif 754 } 755 } 756 757 vec3f_copy(m->marioObj->header.gfx.pos, m->pos); 758 vec3s_set(m->marioObj->header.gfx.angle, 0, m->faceAngle[1], 0); 759 set_mario_animation(m, MARIO_ANIM_DIVE); 760 761 return FALSE; 762 } 763 764 s32 act_tornado_twirling(struct MarioState *m) { 765 struct Surface *floor; 766 Vec3f nextPos; 767 f32 sinAngleVel; 768 f32 cosAngleVel; 769 f32 floorHeight; 770 struct Object *marioObj = m->marioObj; 771 struct Object *usedObj = m->usedObj; 772 s16 prevTwirlYaw = m->twirlYaw; 773 774 f32 dx = (m->pos[0] - usedObj->oPosX) * 0.95f; 775 f32 dz = (m->pos[2] - usedObj->oPosZ) * 0.95f; 776 777 if (m->vel[1] < 60.0f) { 778 m->vel[1] += 1.0f; 779 } 780 781 if ((marioObj->oMarioTornadoPosY += m->vel[1]) < 0.0f) { 782 marioObj->oMarioTornadoPosY = 0.0f; 783 } 784 if (marioObj->oMarioTornadoPosY > usedObj->hitboxHeight) { 785 if (m->vel[1] < 20.0f) { 786 m->vel[1] = 20.0f; 787 } 788 return set_mario_action(m, ACT_TWIRLING, 1); 789 } 790 791 if (m->angleVel[1] < 0x3000) { 792 m->angleVel[1] += 0x100; 793 } 794 795 if (marioObj->oMarioTornadoYawVel < 0x1000) { 796 marioObj->oMarioTornadoYawVel += 0x100; 797 } 798 799 m->twirlYaw += m->angleVel[1]; 800 801 sinAngleVel = sins(marioObj->oMarioTornadoYawVel); 802 cosAngleVel = coss(marioObj->oMarioTornadoYawVel); 803 804 nextPos[0] = usedObj->oPosX + dx * cosAngleVel + dz * sinAngleVel; 805 nextPos[2] = usedObj->oPosZ - dx * sinAngleVel + dz * cosAngleVel; 806 nextPos[1] = usedObj->oPosY + marioObj->oMarioTornadoPosY; 807 808 f32_find_wall_collision(&nextPos[0], &nextPos[1], &nextPos[2], 60.0f, 50.0f); 809 810 floorHeight = find_floor(nextPos[0], nextPos[1], nextPos[2], &floor); 811 if (floor != NULL) { 812 m->floor = floor; 813 m->floorHeight = floorHeight; 814 vec3f_copy(m->pos, nextPos); 815 } else { 816 if (nextPos[1] >= m->floorHeight) { 817 m->pos[1] = nextPos[1]; 818 } else { 819 m->pos[1] = m->floorHeight; 820 } 821 } 822 823 m->actionTimer++; 824 825 set_mario_animation(m, (m->actionArg == 0) ? MARIO_ANIM_START_TWIRL : MARIO_ANIM_TWIRL); 826 827 if (is_anim_past_end(m)) { 828 m->actionArg = 1; 829 } 830 831 // Play sound on angle overflow 832 if (prevTwirlYaw > m->twirlYaw) { 833 play_sound(SOUND_ACTION_TWIRL, m->marioObj->header.gfx.cameraToObject); 834 } 835 836 vec3f_copy(m->marioObj->header.gfx.pos, m->pos); 837 vec3s_set(m->marioObj->header.gfx.angle, 0, m->faceAngle[1] + m->twirlYaw, 0); 838 #if ENABLE_RUMBLE 839 reset_rumble_timers(); 840 #endif 841 842 return FALSE; 843 } 844 845 s32 check_common_automatic_cancels(struct MarioState *m) { 846 if (m->pos[1] < m->waterLevel - 100) { 847 return set_water_plunge_action(m); 848 } 849 850 return FALSE; 851 } 852 853 s32 mario_execute_automatic_action(struct MarioState *m) { 854 s32 cancel; 855 856 if (check_common_automatic_cancels(m)) { 857 return TRUE; 858 } 859 860 m->quicksandDepth = 0.0f; 861 862 /* clang-format off */ 863 switch (m->action) { 864 case ACT_HOLDING_POLE: cancel = act_holding_pole(m); break; 865 case ACT_GRAB_POLE_SLOW: cancel = act_grab_pole_slow(m); break; 866 case ACT_GRAB_POLE_FAST: cancel = act_grab_pole_fast(m); break; 867 case ACT_CLIMBING_POLE: cancel = act_climbing_pole(m); break; 868 case ACT_TOP_OF_POLE_TRANSITION: cancel = act_top_of_pole_transition(m); break; 869 case ACT_TOP_OF_POLE: cancel = act_top_of_pole(m); break; 870 case ACT_START_HANGING: cancel = act_start_hanging(m); break; 871 case ACT_HANGING: cancel = act_hanging(m); break; 872 case ACT_HANG_MOVING: cancel = act_hang_moving(m); break; 873 case ACT_LEDGE_GRAB: cancel = act_ledge_grab(m); break; 874 case ACT_LEDGE_CLIMB_SLOW_1: cancel = act_ledge_climb_slow(m); break; 875 case ACT_LEDGE_CLIMB_SLOW_2: cancel = act_ledge_climb_slow(m); break; 876 case ACT_LEDGE_CLIMB_DOWN: cancel = act_ledge_climb_down(m); break; 877 case ACT_LEDGE_CLIMB_FAST: cancel = act_ledge_climb_fast(m); break; 878 case ACT_GRABBED: cancel = act_grabbed(m); break; 879 case ACT_IN_CANNON: cancel = act_in_cannon(m); break; 880 case ACT_TORNADO_TWIRLING: cancel = act_tornado_twirling(m); break; 881 } 882 /* clang-format on */ 883 884 return cancel; 885 }