camera.c (403427B)
1 #include <ultra64.h> 2 3 #define INCLUDED_FROM_CAMERA_C 4 5 #include "prevent_bss_reordering.h" 6 #include "sm64.h" 7 #include "camera.h" 8 #include "seq_ids.h" 9 #include "dialog_ids.h" 10 #include "audio/external.h" 11 #include "mario_misc.h" 12 #include "game_init.h" 13 #include "hud.h" 14 #include "engine/math_util.h" 15 #include "area.h" 16 #include "engine/surface_collision.h" 17 #include "engine/behavior_script.h" 18 #include "level_update.h" 19 #include "ingame_menu.h" 20 #include "mario_actions_cutscene.h" 21 #include "save_file.h" 22 #include "object_helpers.h" 23 #include "print.h" 24 #include "spawn_sound.h" 25 #include "behavior_actions.h" 26 #include "behavior_data.h" 27 #include "object_list_processor.h" 28 #include "paintings.h" 29 #include "engine/graph_node.h" 30 #include "level_table.h" 31 32 #define CBUTTON_MASK (U_CBUTTONS | D_CBUTTONS | L_CBUTTONS | R_CBUTTONS) 33 34 /** 35 * @file camera.c 36 * Implements the camera system, including C-button input, camera modes, camera triggers, and cutscenes. 37 * 38 * When working with the camera, you should be familiar with sm64's coordinate system. 39 * Relative to the camera, the coordinate system follows the right hand rule: 40 * +X points right. 41 * +Y points up. 42 * +Z points out of the screen. 43 * 44 * You should also be familiar with Euler angles: 'pitch', 'yaw', and 'roll'. 45 * pitch: rotation about the X-axis, measured from +Y. 46 * Unlike yaw and roll, pitch is bounded in +-0x4000 (90 degrees). 47 * Pitch is 0 when the camera points parallel to the xz-plane (+Y points straight up). 48 * 49 * yaw: rotation about the Y-axis, measured from (absolute) +Z. 50 * Positive yaw rotates clockwise, towards +X. 51 * 52 * roll: rotation about the Z-axis, measured from the camera's right direction. 53 * Unfortunately, it's weird: For some reason, roll is flipped. Positive roll makes the camera 54 * rotate counterclockwise, which means the WORLD rotates clockwise. Luckily roll is rarely 55 * used. 56 * 57 * Remember the right hand rule: make a thumbs-up with your right hand, stick your thumb in the 58 * +direction (except for roll), and the angle follows the rotation of your curled fingers. 59 * 60 * Illustrations: 61 * Following the right hand rule, each hidden axis's positive direction points out of the screen. 62 * 63 * YZ-Plane (pitch) XZ-Plane (yaw) XY-Plane (roll -- Note flipped) 64 * +Y -Z +Y 65 * ^ ^ (into the ^ 66 * --|-- | screen) |<- 67 * +pitch / | \ -pitch | | \ -roll 68 * v | v | | | 69 * +Z <------O------> -Z -X <------O------> +X -X <------O------> +X 70 * | ^ | ^ | | 71 * | \ | / | / +roll 72 * | -yaw --|-- +yaw |<- 73 * v v v 74 * -Y +Z -Y 75 * 76 */ 77 78 // BSS 79 /** 80 * Stores Lakitu's position from the last frame, used for transitioning in next_lakitu_state() 81 */ 82 Vec3f sOldPosition; 83 /** 84 * Stores Lakitu's focus from the last frame, used for transitioning in next_lakitu_state() 85 */ 86 Vec3f sOldFocus; 87 /** 88 * Global array of PlayerCameraState. 89 * L is real. 90 */ 91 struct PlayerCameraState gPlayerCameraState[2]; 92 /** 93 * Direction controlled by player 2, moves the focus during the credits. 94 */ 95 Vec3f sPlayer2FocusOffset; 96 /** 97 * The pitch used for the credits easter egg. 98 */ 99 s16 sCreditsPlayer2Pitch; 100 /** 101 * The yaw used for the credits easter egg. 102 */ 103 s16 sCreditsPlayer2Yaw; 104 /** 105 * Used to decide when to zoom out in the pause menu. 106 */ 107 u8 sFramesPaused; 108 109 extern struct CameraFOVStatus sFOVState; 110 extern struct TransitionInfo sModeTransition; 111 extern struct PlayerGeometry sMarioGeometry; 112 extern s16 unusedFreeRoamWallYaw; 113 extern s16 sAvoidYawVel; 114 extern s16 sCameraYawAfterDoorCutscene; 115 extern s16 unusedSplinePitch; 116 extern s16 unusedSplineYaw; 117 extern struct HandheldShakePoint sHandheldShakeSpline[4]; 118 extern s16 sHandheldShakeMag; 119 extern f32 sHandheldShakeTimer; 120 extern f32 sHandheldShakeInc; 121 extern s16 sHandheldShakePitch; 122 extern s16 sHandheldShakeYaw; 123 extern s16 sHandheldShakeRoll; 124 extern u32 unused8033B30C; 125 extern u32 unused8033B310; 126 extern s16 sSelectionFlags; 127 extern s16 unused8033B316; 128 extern s16 s2ndRotateFlags; 129 extern s16 unused8033B31A; 130 extern s16 sCameraSoundFlags; 131 extern u16 sCButtonsPressed; 132 extern s16 sCutsceneDialogID; 133 extern struct LakituState gLakituState; 134 extern s16 unused8033B3E8; 135 extern s16 sAreaYaw; 136 extern s16 sAreaYawChange; 137 extern s16 sLakituDist; 138 extern s16 sLakituPitch; 139 extern f32 sZoomAmount; 140 extern s16 sCSideButtonYaw; 141 extern s16 sBehindMarioSoundTimer; 142 extern f32 sZeroZoomDist; 143 extern s16 sCUpCameraPitch; 144 extern s16 sModeOffsetYaw; 145 extern s16 sSpiralStairsYawOffset; 146 extern s16 s8DirModeBaseYaw; 147 extern s16 s8DirModeYawOffset; 148 extern f32 sPanDistance; 149 extern f32 sCannonYOffset; 150 extern struct ModeTransitionInfo sModeInfo; 151 extern Vec3f sCastleEntranceOffset; 152 extern u32 sParTrackIndex; 153 extern struct ParallelTrackingPoint *sParTrackPath; 154 extern struct CameraStoredInfo sParTrackTransOff; 155 extern struct CameraStoredInfo sCameraStoreCUp; 156 extern struct CameraStoredInfo sCameraStoreCutscene; 157 extern s16 gCameraMovementFlags; 158 extern s16 sStatusFlags; 159 extern struct CutsceneSplinePoint sCurCreditsSplinePos[32]; 160 extern struct CutsceneSplinePoint sCurCreditsSplineFocus[32]; 161 extern s16 sCutsceneSplineSegment; 162 extern f32 sCutsceneSplineSegmentProgress; 163 extern s16 unused8033B6E8; 164 extern s16 sCutsceneShot; 165 extern s16 gCutsceneTimer; 166 extern struct CutsceneVariable sCutsceneVars[10]; 167 extern s32 gObjCutsceneDone; 168 extern u32 gCutsceneObjSpawn; 169 extern struct Camera *gCamera; 170 171 /** 172 * Lakitu's position and focus. 173 * @see LakituState 174 */ 175 struct LakituState gLakituState; 176 struct CameraFOVStatus sFOVState; 177 struct TransitionInfo sModeTransition; 178 struct PlayerGeometry sMarioGeometry; 179 struct Camera *gCamera; 180 s16 unusedFreeRoamWallYaw; 181 s16 sAvoidYawVel; 182 s16 sCameraYawAfterDoorCutscene; 183 /** 184 * The current spline that controls the camera's position during the credits. 185 */ 186 struct CutsceneSplinePoint sCurCreditsSplinePos[32]; 187 188 /** 189 * The current spline that controls the camera's focus during the credits. 190 */ 191 struct CutsceneSplinePoint sCurCreditsSplineFocus[32]; 192 193 s16 unusedSplinePitch; 194 s16 unusedSplineYaw; 195 196 /** 197 * The progress (from 0 to 1) through the current spline segment. 198 * When it becomes >= 1, 1.0 is subtracted from it and sCutsceneSplineSegment is increased. 199 */ 200 f32 sCutsceneSplineSegmentProgress; 201 202 /** 203 * The current segment of the CutsceneSplinePoint[] being used. 204 */ 205 s16 sCutsceneSplineSegment; 206 s16 unused8033B6E8; 207 208 // Shaky Hand-held Camera effect variables 209 struct HandheldShakePoint sHandheldShakeSpline[4]; 210 s16 sHandheldShakeMag; 211 f32 sHandheldShakeTimer; 212 f32 sHandheldShakeInc; 213 s16 sHandheldShakePitch; 214 s16 sHandheldShakeYaw; 215 s16 sHandheldShakeRoll; 216 217 /** 218 * Controls which object to spawn in the intro and ending cutscenes. 219 */ 220 u32 gCutsceneObjSpawn; 221 /** 222 * Controls when an object-based cutscene should end. It's only used in the star spawn cutscenes, but 223 * Yoshi also toggles this. 224 */ 225 s32 gObjCutsceneDone; 226 227 u32 unused8033B30C; 228 u32 unused8033B310; 229 230 /** 231 * Determines which R-Trigger mode is selected in the pause menu. 232 */ 233 s16 sSelectionFlags; 234 235 /** 236 * Flags that determine what movements the camera should start / do this frame. 237 */ 238 s16 gCameraMovementFlags; 239 s16 unused8033B316; 240 241 /** 242 * Flags that change how modes operate and how Lakitu moves. 243 * The most commonly used flag is CAM_FLAG_SMOOTH_MOVEMENT, which makes Lakitu fly to the next position, 244 * instead of warping. 245 */ 246 s16 sStatusFlags; 247 /** 248 * Flags that determine whether the player has already rotated left or right. Used in radial mode to 249 * determine whether to rotate all the way, or just to 60 degrees. 250 */ 251 s16 s2ndRotateFlags; 252 s16 unused8033B31A; 253 /** 254 * Flags that control buzzes and sounds that play, mostly for C-button input. 255 */ 256 s16 sCameraSoundFlags; 257 /** 258 * Stores what C-Buttons are pressed this frame. 259 */ 260 u16 sCButtonsPressed; 261 /** 262 * A copy of gDialogID, the dialog displayed during the cutscene. 263 */ 264 s16 sCutsceneDialogID; 265 /** 266 * The currently playing shot in the cutscene. 267 */ 268 s16 sCutsceneShot; 269 /** 270 * The current frame of the cutscene shot. 271 */ 272 s16 gCutsceneTimer; 273 s16 unused8033B3E8; 274 #if defined(VERSION_EU) || defined(VERSION_SH) || defined(VERSION_CN) 275 s16 unused8033B3E82; 276 #endif 277 /** 278 * The angle of the direction vector from the area's center to Mario's position. 279 */ 280 s16 sAreaYaw; 281 282 /** 283 * How much sAreaYaw changed when Mario moved. 284 */ 285 s16 sAreaYawChange; 286 287 /** 288 * Lakitu's distance from Mario in C-Down mode 289 */ 290 s16 sLakituDist; 291 292 /** 293 * How much Lakitu looks down in C-Down mode 294 */ 295 s16 sLakituPitch; 296 297 /** 298 * The amount of distance left to zoom out 299 */ 300 f32 sZoomAmount; 301 302 s16 sCSideButtonYaw; 303 304 /** 305 * Sound timer used to space out sounds in behind Mario mode 306 */ 307 s16 sBehindMarioSoundTimer; 308 309 /** 310 * Virtually unused aside being set to 0 and compared with gCameraZoomDist (which is never < 0) 311 */ 312 f32 sZeroZoomDist; 313 314 /** 315 * The camera's pitch in C-Up mode. Mainly controls Mario's head rotation. 316 */ 317 s16 sCUpCameraPitch; 318 /** 319 * The current mode's yaw, which gets added to the camera's yaw. 320 */ 321 s16 sModeOffsetYaw; 322 323 /** 324 * Stores Mario's yaw around the stairs, relative to the camera's position. 325 * 326 * Used in update_spiral_stairs_camera() 327 */ 328 s16 sSpiralStairsYawOffset; 329 330 /** 331 * The constant offset to 8-direction mode's yaw. 332 */ 333 s16 s8DirModeBaseYaw; 334 /** 335 * Player-controlled yaw offset in 8-direction mode, a multiple of 45 degrees. 336 */ 337 s16 s8DirModeYawOffset; 338 339 /** 340 * The distance that the camera will look ahead of Mario in the direction Mario is facing. 341 */ 342 f32 sPanDistance; 343 344 /** 345 * When Mario gets in the cannon, it is pointing straight up and rotates down. 346 * This is used to make the camera start up and rotate down, like the cannon. 347 */ 348 f32 sCannonYOffset; 349 /** 350 * These structs are used by the cutscenes. Most of the fields are unused, and some (all?) of the used 351 * ones have multiple uses. 352 * Check the cutscene_start functions for documentation on the cvars used by a specific cutscene. 353 */ 354 struct CutsceneVariable sCutsceneVars[10]; 355 struct ModeTransitionInfo sModeInfo; 356 /** 357 * Offset added to sFixedModeBasePosition when Mario is inside, near the castle lobby entrance 358 */ 359 Vec3f sCastleEntranceOffset; 360 361 /** 362 * The index into the current parallel tracking path 363 */ 364 u32 sParTrackIndex; 365 366 /** 367 * The current list of ParallelTrackingPoints used in update_parallel_tracking_camera() 368 */ 369 struct ParallelTrackingPoint *sParTrackPath; 370 371 /** 372 * On the first frame after the camera changes to a different parallel tracking path, this stores the 373 * displacement between the camera's calculated new position and its previous positions 374 * 375 * This transition offset is then used to smoothly interpolate the camera's position between the two 376 * paths 377 */ 378 struct CameraStoredInfo sParTrackTransOff; 379 380 /** 381 * The information stored when C-Up is active, used to update Lakitu's rotation when exiting C-Up 382 */ 383 struct CameraStoredInfo sCameraStoreCUp; 384 385 /** 386 * The information stored during cutscenes 387 */ 388 struct CameraStoredInfo sCameraStoreCutscene; 389 390 // first iteration of data 391 u32 unused8032CFC0 = 0; 392 struct Object *gCutsceneFocus = NULL; 393 394 u32 unused8032CFC8 = 0; 395 u32 unused8032CFCC = 0; 396 397 /** 398 * The information of a second focus camera used by some objects 399 */ 400 struct Object *gSecondCameraFocus = NULL; 401 402 /** 403 * How fast the camera's yaw should approach the next yaw. 404 */ 405 s16 sYawSpeed = 0x400; 406 s32 gCurrLevelArea = 0; 407 u32 gPrevLevel = 0; 408 409 f32 unused8032CFE0 = 1000.0f; 410 f32 unused8032CFE4 = 800.0f; 411 u32 unused8032CFE8 = 0; 412 f32 gCameraZoomDist = 800.0f; 413 414 /** 415 * A cutscene that plays when the player interacts with an object 416 */ 417 u8 sObjectCutscene = 0; 418 419 /** 420 * The ID of the cutscene that ended. It's set to 0 if no cutscene ended less than 8 frames ago. 421 * 422 * It is only used to prevent the same cutscene from playing twice before 8 frames have passed. 423 */ 424 u8 gRecentCutscene = 0; 425 426 /** 427 * A timer that increments for 8 frames when a cutscene ends. 428 * When it reaches 8, it sets gRecentCutscene to 0. 429 */ 430 u8 sFramesSinceCutsceneEnded = 0; 431 /** 432 * Mario's response to a dialog. 433 * 0 = No response yet 434 * 1 = Yes 435 * 2 = No 436 * 3 = Dialog doesn't have a response 437 */ 438 u8 sCutsceneDialogResponse = DIALOG_RESPONSE_NONE; 439 struct PlayerCameraState *sMarioCamState = &gPlayerCameraState[0]; 440 struct PlayerCameraState *sLuigiCamState = &gPlayerCameraState[1]; 441 u32 unused8032D008 = 0; 442 Vec3f sFixedModeBasePosition = { 646.0f, 143.0f, -1513.0f }; 443 Vec3f sUnusedModeBasePosition_2 = { 646.0f, 143.0f, -1513.0f }; 444 Vec3f sUnusedModeBasePosition_3 = { 646.0f, 143.0f, -1513.0f }; 445 Vec3f sUnusedModeBasePosition_4 = { 646.0f, 143.0f, -1513.0f }; 446 Vec3f sUnusedModeBasePosition_5 = { 646.0f, 143.0f, -1513.0f }; 447 448 s32 update_radial_camera(struct Camera *c, Vec3f, Vec3f); 449 s32 update_outward_radial_camera(struct Camera *c, Vec3f, Vec3f); 450 s32 update_behind_mario_camera(struct Camera *c, Vec3f, Vec3f); 451 s32 update_mario_camera(struct Camera *c, Vec3f, Vec3f); 452 s32 unused_update_mode_5_camera(struct Camera *c, Vec3f, Vec3f); 453 s32 update_c_up(struct Camera *c, Vec3f, Vec3f); 454 s32 nop_update_water_camera(struct Camera *c, Vec3f, Vec3f); 455 s32 update_slide_or_0f_camera(struct Camera *c, Vec3f, Vec3f); 456 s32 update_in_cannon(struct Camera *c, Vec3f, Vec3f); 457 s32 update_boss_fight_camera(struct Camera *c, Vec3f, Vec3f); 458 s32 update_parallel_tracking_camera(struct Camera *c, Vec3f, Vec3f); 459 s32 update_fixed_camera(struct Camera *c, Vec3f, Vec3f); 460 s32 update_8_directions_camera(struct Camera *c, Vec3f, Vec3f); 461 s32 update_slide_or_0f_camera(struct Camera *c, Vec3f, Vec3f); 462 s32 update_spiral_stairs_camera(struct Camera *c, Vec3f, Vec3f); 463 464 typedef s32 (*CameraTransition)(struct Camera *c, Vec3f, Vec3f); 465 CameraTransition sModeTransitions[] = { 466 NULL, 467 update_radial_camera, 468 update_outward_radial_camera, 469 update_behind_mario_camera, 470 update_mario_camera, 471 unused_update_mode_5_camera, 472 update_c_up, 473 update_mario_camera, 474 nop_update_water_camera, 475 update_slide_or_0f_camera, 476 update_in_cannon, 477 update_boss_fight_camera, 478 update_parallel_tracking_camera, 479 update_fixed_camera, 480 update_8_directions_camera, 481 update_slide_or_0f_camera, 482 update_mario_camera, 483 update_spiral_stairs_camera 484 }; 485 486 // Move these two tables to another include file? 487 extern u8 sDanceCutsceneIndexTable[][4]; 488 extern u8 sZoomOutAreaMasks[]; 489 490 /** 491 * Starts a camera shake triggered by an interaction 492 */ 493 void set_camera_shake_from_hit(s16 shake) { 494 switch (shake) { 495 // Makes the camera stop for a bit 496 case SHAKE_ATTACK: 497 gLakituState.focHSpeed = 0; 498 gLakituState.posHSpeed = 0; 499 break; 500 501 case SHAKE_FALL_DAMAGE: 502 set_camera_pitch_shake(0x60, 0x3, 0x8000); 503 set_camera_roll_shake(0x60, 0x3, 0x8000); 504 break; 505 506 case SHAKE_GROUND_POUND: 507 set_camera_pitch_shake(0x60, 0xC, 0x8000); 508 break; 509 510 case SHAKE_SMALL_DAMAGE: 511 if (sMarioCamState->action & (ACT_FLAG_SWIMMING | ACT_FLAG_METAL_WATER)) { 512 set_camera_yaw_shake(0x200, 0x10, 0x1000); 513 set_camera_roll_shake(0x400, 0x20, 0x1000); 514 set_fov_shake(0x100, 0x30, 0x8000); 515 } else { 516 set_camera_yaw_shake(0x80, 0x8, 0x4000); 517 set_camera_roll_shake(0x80, 0x8, 0x4000); 518 set_fov_shake(0x100, 0x30, 0x8000); 519 } 520 521 gLakituState.focHSpeed = 0; 522 gLakituState.posHSpeed = 0; 523 break; 524 525 case SHAKE_MED_DAMAGE: 526 if (sMarioCamState->action & (ACT_FLAG_SWIMMING | ACT_FLAG_METAL_WATER)) { 527 set_camera_yaw_shake(0x400, 0x20, 0x1000); 528 set_camera_roll_shake(0x600, 0x30, 0x1000); 529 set_fov_shake(0x180, 0x40, 0x8000); 530 } else { 531 set_camera_yaw_shake(0x100, 0x10, 0x4000); 532 set_camera_roll_shake(0x100, 0x10, 0x4000); 533 set_fov_shake(0x180, 0x40, 0x8000); 534 } 535 536 gLakituState.focHSpeed = 0; 537 gLakituState.posHSpeed = 0; 538 break; 539 540 case SHAKE_LARGE_DAMAGE: 541 if (sMarioCamState->action & (ACT_FLAG_SWIMMING | ACT_FLAG_METAL_WATER)) { 542 set_camera_yaw_shake(0x600, 0x30, 0x1000); 543 set_camera_roll_shake(0x800, 0x40, 0x1000); 544 set_fov_shake(0x200, 0x50, 0x8000); 545 } else { 546 set_camera_yaw_shake(0x180, 0x20, 0x4000); 547 set_camera_roll_shake(0x200, 0x20, 0x4000); 548 set_fov_shake(0x200, 0x50, 0x8000); 549 } 550 551 gLakituState.focHSpeed = 0; 552 gLakituState.posHSpeed = 0; 553 break; 554 555 case SHAKE_HIT_FROM_BELOW: 556 gLakituState.focHSpeed = 0.07; 557 gLakituState.posHSpeed = 0.07; 558 break; 559 560 case SHAKE_SHOCK: 561 set_camera_pitch_shake(random_float() * 64.f, 0x8, 0x8000); 562 set_camera_yaw_shake(random_float() * 64.f, 0x8, 0x8000); 563 break; 564 } 565 } 566 567 /** 568 * Start a shake from the environment 569 */ 570 void set_environmental_camera_shake(s16 shake) { 571 switch (shake) { 572 case SHAKE_ENV_EXPLOSION: 573 set_camera_pitch_shake(0x60, 0x8, 0x4000); 574 break; 575 576 case SHAKE_ENV_BOWSER_THROW_BOUNCE: 577 set_camera_pitch_shake(0xC0, 0x8, 0x4000); 578 break; 579 580 case SHAKE_ENV_BOWSER_JUMP: 581 set_camera_pitch_shake(0x100, 0x8, 0x3000); 582 break; 583 584 case SHAKE_ENV_UNUSED_6: 585 set_camera_roll_shake(0x80, 0x10, 0x3000); 586 break; 587 588 case SHAKE_ENV_UNUSED_7: 589 set_camera_pitch_shake(0x20, 0x8, 0x8000); 590 break; 591 592 case SHAKE_ENV_PYRAMID_EXPLODE: 593 set_camera_pitch_shake(0x40, 0x8, 0x8000); 594 break; 595 596 case SHAKE_ENV_JRB_SHIP_DRAIN: 597 set_camera_pitch_shake(0x20, 0x8, 0x8000); 598 set_camera_roll_shake(0x400, 0x10, 0x100); 599 break; 600 601 case SHAKE_ENV_FALLING_BITS_PLAT: 602 set_camera_pitch_shake(0x40, 0x2, 0x8000); 603 break; 604 605 case SHAKE_ENV_UNUSED_5: 606 set_camera_yaw_shake(-0x200, 0x80, 0x200); 607 break; 608 } 609 } 610 611 /** 612 * Starts a camera shake, but scales the amplitude by the point's distance from the camera 613 */ 614 void set_camera_shake_from_point(s16 shake, f32 posX, f32 posY, f32 posZ) { 615 switch (shake) { 616 case SHAKE_POS_BOWLING_BALL: 617 set_pitch_shake_from_point(0x28, 0x8, 0x4000, 2000.f, posX, posY, posZ); 618 break; 619 620 case SHAKE_POS_SMALL: 621 set_pitch_shake_from_point(0x80, 0x8, 0x4000, 4000.f, posX, posY, posZ); 622 set_fov_shake_from_point_preset(SHAKE_FOV_SMALL, posX, posY, posZ); 623 break; 624 625 case SHAKE_POS_MEDIUM: 626 set_pitch_shake_from_point(0xC0, 0x8, 0x4000, 6000.f, posX, posY, posZ); 627 set_fov_shake_from_point_preset(SHAKE_FOV_MEDIUM, posX, posY, posZ); 628 break; 629 630 case SHAKE_POS_LARGE: 631 set_pitch_shake_from_point(0x100, 0x8, 0x3000, 8000.f, posX, posY, posZ); 632 set_fov_shake_from_point_preset(SHAKE_FOV_LARGE, posX, posY, posZ); 633 break; 634 } 635 } 636 637 /** 638 * Start a camera shake from an environmental source, but only shake the camera's pitch. 639 */ 640 void unused_set_camera_pitch_shake_env(s16 shake) { 641 switch (shake) { 642 case SHAKE_ENV_EXPLOSION: 643 set_camera_pitch_shake(0x60, 0x8, 0x4000); 644 break; 645 646 case SHAKE_ENV_BOWSER_THROW_BOUNCE: 647 set_camera_pitch_shake(0xC0, 0x8, 0x4000); 648 break; 649 650 case SHAKE_ENV_BOWSER_JUMP: 651 set_camera_pitch_shake(0x100, 0x8, 0x3000); 652 break; 653 } 654 } 655 656 /** 657 * Calculates Mario's distance to the floor, or the water level if it is above the floor. Then: 658 * `posOff` is set to the distance multiplied by posMul and bounded to [-posBound, posBound] 659 * `focOff` is set to the distance multiplied by focMul and bounded to [-focBound, focBound] 660 * 661 * Notes: 662 * posMul is always 1.0f, focMul is always 0.9f 663 * both ranges are always 200.f 664 * Since focMul is 0.9, `focOff` is closer to the floor than `posOff` 665 * posOff and focOff are sometimes the same address, which just ignores the pos calculation 666 *! Doesn't return anything, but required to match on -O2 667 */ 668 BAD_RETURN(f32) calc_y_to_curr_floor(f32 *posOff, f32 posMul, f32 posBound, f32 *focOff, f32 focMul, f32 focBound) { 669 f32 floorHeight = sMarioGeometry.currFloorHeight; 670 f32 waterHeight; 671 UNUSED u8 filler[4]; 672 673 if (!(sMarioCamState->action & ACT_FLAG_METAL_WATER)) { 674 //! @bug this should use sMarioGeometry.waterHeight 675 if (floorHeight < (waterHeight = find_water_level(sMarioCamState->pos[0], sMarioCamState->pos[2]))) { 676 floorHeight = waterHeight; 677 } 678 } 679 680 if (sMarioCamState->action & ACT_FLAG_ON_POLE) { 681 if (sMarioGeometry.currFloorHeight >= gMarioStates[0].usedObj->oPosY && sMarioCamState->pos[1] 682 < 0.7f * gMarioStates[0].usedObj->hitboxHeight + gMarioStates[0].usedObj->oPosY) { 683 posBound = 1200; 684 } 685 } 686 687 *posOff = (floorHeight - sMarioCamState->pos[1]) * posMul; 688 689 if (*posOff > posBound) { 690 *posOff = posBound; 691 } 692 693 if (*posOff < -posBound) { 694 *posOff = -posBound; 695 } 696 697 *focOff = (floorHeight - sMarioCamState->pos[1]) * focMul; 698 699 if (*focOff > focBound) { 700 *focOff = focBound; 701 } 702 703 if (*focOff < -focBound) { 704 *focOff = -focBound; 705 } 706 } 707 708 void focus_on_mario(Vec3f focus, Vec3f pos, f32 posYOff, f32 focYOff, f32 dist, s16 pitch, s16 yaw) { 709 Vec3f marioPos; 710 711 marioPos[0] = sMarioCamState->pos[0]; 712 marioPos[1] = sMarioCamState->pos[1] + posYOff; 713 marioPos[2] = sMarioCamState->pos[2]; 714 715 vec3f_set_dist_and_angle(marioPos, pos, dist, pitch + sLakituPitch, yaw); 716 717 focus[0] = sMarioCamState->pos[0]; 718 focus[1] = sMarioCamState->pos[1] + focYOff; 719 focus[2] = sMarioCamState->pos[2]; 720 } 721 722 static UNUSED void set_pos_to_mario(Vec3f foc, Vec3f pos, f32 yOff, f32 focYOff, f32 dist, s16 pitch, s16 yaw) { 723 Vec3f marioPos; 724 f32 posDist; 725 f32 focDist; 726 727 s16 posPitch; 728 s16 posYaw; 729 s16 focPitch; 730 s16 focYaw; 731 732 vec3f_copy(marioPos, sMarioCamState->pos); 733 marioPos[1] += yOff; 734 735 vec3f_set_dist_and_angle(marioPos, pos, dist, pitch + sLakituPitch, yaw); 736 vec3f_get_dist_and_angle(pos, sMarioCamState->pos, &posDist, &posPitch, &posYaw); 737 738 //! Useless get and set 739 vec3f_get_dist_and_angle(pos, foc, &focDist, &focPitch, &focYaw); 740 vec3f_set_dist_and_angle(pos, foc, focDist, focPitch, focYaw); 741 742 foc[1] = sMarioCamState->pos[1] + focYOff; 743 } 744 745 /** 746 * Set the camera's y coordinate to goalHeight, respecting floors and ceilings in the way 747 */ 748 void set_camera_height(struct Camera *c, f32 goalHeight) { 749 struct Surface *surface; 750 f32 marioFloorHeight; 751 f32 marioCeilHeight; 752 f32 camFloorHeight; 753 UNUSED u8 filler[8]; 754 UNUSED s16 action = sMarioCamState->action; 755 f32 baseOff = 125.f; 756 f32 camCeilHeight = find_ceil(c->pos[0], gLakituState.goalPos[1] - 50.f, c->pos[2], &surface); 757 758 if (sMarioCamState->action & ACT_FLAG_HANGING) { 759 marioCeilHeight = sMarioGeometry.currCeilHeight; 760 marioFloorHeight = sMarioGeometry.currFloorHeight; 761 762 if (marioFloorHeight < marioCeilHeight - 400.f) { 763 marioFloorHeight = marioCeilHeight - 400.f; 764 } 765 766 goalHeight = marioFloorHeight + (marioCeilHeight - marioFloorHeight) * 0.4f; 767 768 if (sMarioCamState->pos[1] - 400 > goalHeight) { 769 goalHeight = sMarioCamState->pos[1] - 400; 770 } 771 772 approach_camera_height(c, goalHeight, 5.f); 773 } else { 774 camFloorHeight = find_floor(c->pos[0], c->pos[1] + 100.f, c->pos[2], &surface) + baseOff; 775 marioFloorHeight = baseOff + sMarioGeometry.currFloorHeight; 776 777 if (camFloorHeight < marioFloorHeight) { 778 camFloorHeight = marioFloorHeight; 779 } 780 if (goalHeight < camFloorHeight) { 781 goalHeight = camFloorHeight; 782 c->pos[1] = goalHeight; 783 } 784 // Warp camera to goalHeight if further than 1000 and Mario is stuck in the ground 785 if (sMarioCamState->action == ACT_BUTT_STUCK_IN_GROUND || 786 sMarioCamState->action == ACT_HEAD_STUCK_IN_GROUND || 787 sMarioCamState->action == ACT_FEET_STUCK_IN_GROUND) { 788 if (ABS(c->pos[1] - goalHeight) > 1000.f) { 789 c->pos[1] = goalHeight; 790 } 791 } 792 approach_camera_height(c, goalHeight, 20.f); 793 if (camCeilHeight != CELL_HEIGHT_LIMIT) { 794 camCeilHeight -= baseOff; 795 if ((c->pos[1] > camCeilHeight && sMarioGeometry.currFloorHeight + baseOff < camCeilHeight) 796 || (sMarioGeometry.currCeilHeight != CELL_HEIGHT_LIMIT 797 && sMarioGeometry.currCeilHeight > camCeilHeight && c->pos[1] > camCeilHeight)) { 798 c->pos[1] = camCeilHeight; 799 } 800 } 801 } 802 } 803 804 /** 805 * Pitch the camera down when the camera is facing down a slope 806 */ 807 s16 look_down_slopes(s16 camYaw) { 808 struct Surface *floor; 809 f32 floorDY; 810 // Default pitch 811 s16 pitch = 0x05B0; 812 // x and z offsets towards the camera 813 f32 xOff = sMarioCamState->pos[0] + sins(camYaw) * 40.f; 814 f32 zOff = sMarioCamState->pos[2] + coss(camYaw) * 40.f; 815 816 floorDY = find_floor(xOff, sMarioCamState->pos[1], zOff, &floor) - sMarioCamState->pos[1]; 817 818 if (floor != NULL) { 819 if (floor->type != SURFACE_WALL_MISC && floorDY > 0) { 820 if (floor->normal.z == 0.f && floorDY < 100.f) { 821 pitch = 0x05B0; 822 } else { 823 // Add the slope's angle of declination to the pitch 824 pitch += atan2s(40.f, floorDY); 825 } 826 } 827 } 828 829 return pitch; 830 } 831 832 /** 833 * Look ahead to the left or right in the direction the player is facing 834 * The calculation for pan[0] could be simplified to: 835 * yaw = -yaw; 836 * pan[0] = sins(sMarioCamState->faceAngle[1] + yaw) * sins(0xC00) * dist; 837 * Perhaps, early in development, the pan used to be calculated for both the x and z directions 838 * 839 * Since this function only affects the camera's focus, Mario's movement direction isn't affected. 840 */ 841 void pan_ahead_of_player(struct Camera *c) { 842 f32 dist; 843 s16 pitch; 844 s16 yaw; 845 Vec3f pan = { 0, 0, 0 }; 846 847 // Get distance and angle from camera to Mario. 848 vec3f_get_dist_and_angle(c->pos, sMarioCamState->pos, &dist, &pitch, &yaw); 849 850 // The camera will pan ahead up to about 30% of the camera's distance to Mario. 851 pan[2] = sins(0xC00) * dist; 852 853 rotate_in_xz(pan, pan, sMarioCamState->faceAngle[1]); 854 // rotate in the opposite direction 855 yaw = -yaw; 856 rotate_in_xz(pan, pan, yaw); 857 // Only pan left or right 858 pan[2] = 0.f; 859 860 // If Mario is long jumping, or on a flag pole (but not at the top), then pan in the opposite direction 861 if (sMarioCamState->action == ACT_LONG_JUMP || 862 (sMarioCamState->action != ACT_TOP_OF_POLE && (sMarioCamState->action & ACT_FLAG_ON_POLE))) { 863 pan[0] = -pan[0]; 864 } 865 866 // Slowly make the actual pan, sPanDistance, approach the calculated pan 867 // If Mario is sleeping, then don't pan 868 if (sStatusFlags & CAM_FLAG_SLEEPING) { 869 approach_f32_asymptotic_bool(&sPanDistance, 0.f, 0.025f); 870 } else { 871 approach_f32_asymptotic_bool(&sPanDistance, pan[0], 0.025f); 872 } 873 874 // Now apply the pan. It's a dir vector to the left or right, rotated by the camera's yaw to Mario 875 pan[0] = sPanDistance; 876 yaw = -yaw; 877 rotate_in_xz(pan, pan, yaw); 878 vec3f_add(c->focus, pan); 879 } 880 881 s16 find_in_bounds_yaw_wdw_bob_thi(Vec3f pos, Vec3f origin, s16 yaw) { 882 switch (gCurrLevelArea) { 883 case AREA_WDW_MAIN: 884 yaw = clamp_positions_and_find_yaw(pos, origin, 4508.f, -3739.f, 4508.f, -3739.f); 885 break; 886 case AREA_BOB: 887 yaw = clamp_positions_and_find_yaw(pos, origin, 8000.f, -8000.f, 7050.f, -8000.f); 888 break; 889 case AREA_THI_HUGE: 890 yaw = clamp_positions_and_find_yaw(pos, origin, 8192.f, -8192.f, 8192.f, -8192.f); 891 break; 892 case AREA_THI_TINY: 893 yaw = clamp_positions_and_find_yaw(pos, origin, 2458.f, -2458.f, 2458.f, -2458.f); 894 break; 895 } 896 return yaw; 897 } 898 899 /** 900 * Rotates the camera around the area's center point. 901 */ 902 s32 update_radial_camera(struct Camera *c, Vec3f focus, Vec3f pos) { 903 f32 cenDistX = sMarioCamState->pos[0] - c->areaCenX; 904 f32 cenDistZ = sMarioCamState->pos[2] - c->areaCenZ; 905 s16 camYaw = atan2s(cenDistZ, cenDistX) + sModeOffsetYaw; 906 s16 pitch = look_down_slopes(camYaw); 907 UNUSED u8 filler1[4]; 908 f32 posY; 909 f32 focusY; 910 UNUSED u8 filler2[8]; 911 f32 yOff = 125.f; 912 f32 baseDist = 1000.f; 913 914 sAreaYaw = camYaw - sModeOffsetYaw; 915 calc_y_to_curr_floor(&posY, 1.f, 200.f, &focusY, 0.9f, 200.f); 916 focus_on_mario(focus, pos, posY + yOff, focusY + yOff, sLakituDist + baseDist, pitch, camYaw); 917 camYaw = find_in_bounds_yaw_wdw_bob_thi(pos, focus, camYaw); 918 919 return camYaw; 920 } 921 922 /** 923 * Update the camera during 8 directional mode 924 */ 925 s32 update_8_directions_camera(struct Camera *c, Vec3f focus, Vec3f pos) { 926 UNUSED f32 cenDistX = sMarioCamState->pos[0] - c->areaCenX; 927 UNUSED f32 cenDistZ = sMarioCamState->pos[2] - c->areaCenZ; 928 s16 camYaw = s8DirModeBaseYaw + s8DirModeYawOffset; 929 s16 pitch = look_down_slopes(camYaw); 930 f32 posY; 931 f32 focusY; 932 UNUSED u8 filler[12]; 933 f32 yOff = 125.f; 934 f32 baseDist = 1000.f; 935 936 sAreaYaw = camYaw; 937 calc_y_to_curr_floor(&posY, 1.f, 200.f, &focusY, 0.9f, 200.f); 938 focus_on_mario(focus, pos, posY + yOff, focusY + yOff, sLakituDist + baseDist, pitch, camYaw); 939 pan_ahead_of_player(c); 940 if (gCurrLevelArea == AREA_DDD_SUB) { 941 camYaw = clamp_positions_and_find_yaw(pos, focus, 6839.f, 995.f, 5994.f, -3945.f); 942 } 943 944 return camYaw; 945 } 946 947 /** 948 * Moves the camera for the radial and outward radial camera modes. 949 * 950 * If sModeOffsetYaw is 0, the camera points directly at the area center point. 951 */ 952 void radial_camera_move(struct Camera *c) { 953 s16 maxAreaYaw = DEGREES(60); 954 s16 minAreaYaw = DEGREES(-60); 955 s16 rotateSpeed = 0x1000; 956 s16 avoidYaw; 957 s32 avoidStatus; 958 UNUSED s16 unused1 = 0; 959 UNUSED s32 unused2 = 0; 960 f32 areaDistX = sMarioCamState->pos[0] - c->areaCenX; 961 f32 areaDistZ = sMarioCamState->pos[2] - c->areaCenZ; 962 UNUSED u8 filler[4]; 963 964 // How much the camera's yaw changed 965 s16 yawOffset = calculate_yaw(sMarioCamState->pos, c->pos) - atan2s(areaDistZ, areaDistX); 966 967 if (yawOffset > maxAreaYaw) { 968 yawOffset = maxAreaYaw; 969 } 970 if (yawOffset < minAreaYaw) { 971 yawOffset = minAreaYaw; 972 } 973 974 // Check if Mario stepped on a surface that rotates the camera. For example, when Mario enters the 975 // gate in BoB, the camera turns right to face up the hill path 976 if (!(gCameraMovementFlags & CAM_MOVE_ROTATE)) { 977 if (sMarioGeometry.currFloorType == SURFACE_CAMERA_MIDDLE 978 && sMarioGeometry.prevFloorType != SURFACE_CAMERA_MIDDLE) { 979 gCameraMovementFlags |= (CAM_MOVE_RETURN_TO_MIDDLE | CAM_MOVE_ENTERED_ROTATE_SURFACE); 980 } 981 if (sMarioGeometry.currFloorType == SURFACE_CAMERA_ROTATE_RIGHT 982 && sMarioGeometry.prevFloorType != SURFACE_CAMERA_ROTATE_RIGHT) { 983 gCameraMovementFlags |= (CAM_MOVE_ROTATE_RIGHT | CAM_MOVE_ENTERED_ROTATE_SURFACE); 984 } 985 if (sMarioGeometry.currFloorType == SURFACE_CAMERA_ROTATE_LEFT 986 && sMarioGeometry.prevFloorType != SURFACE_CAMERA_ROTATE_LEFT) { 987 gCameraMovementFlags |= (CAM_MOVE_ROTATE_LEFT | CAM_MOVE_ENTERED_ROTATE_SURFACE); 988 } 989 } 990 991 if (gCameraMovementFlags & CAM_MOVE_ENTERED_ROTATE_SURFACE) { 992 rotateSpeed = 0x200; 993 } 994 995 if (c->mode == CAMERA_MODE_OUTWARD_RADIAL) { 996 areaDistX = -areaDistX; 997 areaDistZ = -areaDistZ; 998 } 999 1000 // Avoid obstructing walls 1001 avoidStatus = rotate_camera_around_walls(c, c->pos, &avoidYaw, 0x400); 1002 if (avoidStatus == 3) { 1003 if (avoidYaw - atan2s(areaDistZ, areaDistX) + DEGREES(90) < 0) { 1004 avoidYaw += DEGREES(180); 1005 } 1006 1007 // We want to change sModeOffsetYaw so that the player is no longer obstructed by the wall. 1008 // So, we make avoidYaw relative to the yaw around the area center 1009 avoidYaw -= atan2s(areaDistZ, areaDistX); 1010 1011 // Bound avoid yaw to radial mode constraints 1012 if (avoidYaw > DEGREES(105)) { 1013 avoidYaw = DEGREES(105); 1014 } 1015 if (avoidYaw < DEGREES(-105)) { 1016 avoidYaw = DEGREES(-105); 1017 } 1018 } 1019 1020 if (gCameraMovementFlags & CAM_MOVE_RETURN_TO_MIDDLE) { 1021 if (camera_approach_s16_symmetric_bool(&sModeOffsetYaw, 0, rotateSpeed) == 0) { 1022 gCameraMovementFlags &= ~CAM_MOVE_RETURN_TO_MIDDLE; 1023 } 1024 } else { 1025 // Prevent the player from rotating into obstructing walls 1026 if ((gCameraMovementFlags & CAM_MOVE_ROTATE_RIGHT) && avoidStatus == 3 1027 && avoidYaw + 0x10 < sModeOffsetYaw) { 1028 sModeOffsetYaw = avoidYaw; 1029 gCameraMovementFlags &= ~(CAM_MOVE_ROTATE_RIGHT | CAM_MOVE_ENTERED_ROTATE_SURFACE); 1030 } 1031 if ((gCameraMovementFlags & CAM_MOVE_ROTATE_LEFT) && avoidStatus == 3 1032 && avoidYaw - 0x10 > sModeOffsetYaw) { 1033 sModeOffsetYaw = avoidYaw; 1034 gCameraMovementFlags &= ~(CAM_MOVE_ROTATE_LEFT | CAM_MOVE_ENTERED_ROTATE_SURFACE); 1035 } 1036 1037 // If it's the first time rotating, just rotate to +-60 degrees 1038 if (!(s2ndRotateFlags & CAM_MOVE_ROTATE_RIGHT) && (gCameraMovementFlags & CAM_MOVE_ROTATE_RIGHT) 1039 && camera_approach_s16_symmetric_bool(&sModeOffsetYaw, maxAreaYaw, rotateSpeed) == 0) { 1040 gCameraMovementFlags &= ~(CAM_MOVE_ROTATE_RIGHT | CAM_MOVE_ENTERED_ROTATE_SURFACE); 1041 } 1042 if (!(s2ndRotateFlags & CAM_MOVE_ROTATE_LEFT) && (gCameraMovementFlags & CAM_MOVE_ROTATE_LEFT) 1043 && camera_approach_s16_symmetric_bool(&sModeOffsetYaw, minAreaYaw, rotateSpeed) == 0) { 1044 gCameraMovementFlags &= ~(CAM_MOVE_ROTATE_LEFT | CAM_MOVE_ENTERED_ROTATE_SURFACE); 1045 } 1046 1047 // If it's the second time rotating, rotate all the way to +-105 degrees. 1048 if ((s2ndRotateFlags & CAM_MOVE_ROTATE_RIGHT) && (gCameraMovementFlags & CAM_MOVE_ROTATE_RIGHT) 1049 && camera_approach_s16_symmetric_bool(&sModeOffsetYaw, DEGREES(105), rotateSpeed) == 0) { 1050 gCameraMovementFlags &= ~(CAM_MOVE_ROTATE_RIGHT | CAM_MOVE_ENTERED_ROTATE_SURFACE); 1051 s2ndRotateFlags &= ~CAM_MOVE_ROTATE_RIGHT; 1052 } 1053 if ((s2ndRotateFlags & CAM_MOVE_ROTATE_LEFT) && (gCameraMovementFlags & CAM_MOVE_ROTATE_LEFT) 1054 && camera_approach_s16_symmetric_bool(&sModeOffsetYaw, DEGREES(-105), rotateSpeed) == 0) { 1055 gCameraMovementFlags &= ~(CAM_MOVE_ROTATE_LEFT | CAM_MOVE_ENTERED_ROTATE_SURFACE); 1056 s2ndRotateFlags &= ~CAM_MOVE_ROTATE_LEFT; 1057 } 1058 } 1059 if (!(gCameraMovementFlags & CAM_MOVE_ROTATE)) { 1060 // If not rotating, rotate away from walls obscuring Mario from view 1061 if (avoidStatus == 3) { 1062 approach_s16_asymptotic_bool(&sModeOffsetYaw, avoidYaw, 10); 1063 } else { 1064 if (c->mode == CAMERA_MODE_RADIAL) { 1065 // sModeOffsetYaw only updates when Mario is moving 1066 rotateSpeed = gMarioStates[0].forwardVel / 32.f * 128.f; 1067 camera_approach_s16_symmetric_bool(&sModeOffsetYaw, yawOffset, rotateSpeed); 1068 } 1069 if (c->mode == CAMERA_MODE_OUTWARD_RADIAL) { 1070 sModeOffsetYaw = offset_yaw_outward_radial(c, atan2s(areaDistZ, areaDistX)); 1071 } 1072 } 1073 } 1074 1075 // Bound sModeOffsetYaw within (-120, 120) degrees 1076 if (sModeOffsetYaw > 0x5554) { 1077 sModeOffsetYaw = 0x5554; 1078 } 1079 if (sModeOffsetYaw < -0x5554) { 1080 sModeOffsetYaw = -0x5554; 1081 } 1082 } 1083 1084 /** 1085 * Moves Lakitu from zoomed in to zoomed out and vice versa. 1086 * When C-Down mode is not active, sLakituDist and sLakituPitch decrease to 0. 1087 */ 1088 void lakitu_zoom(f32 rangeDist, s16 rangePitch) { 1089 if (sLakituDist < 0) { 1090 if ((sLakituDist += 30) > 0) { 1091 sLakituDist = 0; 1092 } 1093 } else if (rangeDist < sLakituDist) { 1094 if ((sLakituDist -= 30) < rangeDist) { 1095 sLakituDist = rangeDist; 1096 } 1097 } else if (gCameraMovementFlags & CAM_MOVE_ZOOMED_OUT) { 1098 if ((sLakituDist += 30) > rangeDist) { 1099 sLakituDist = rangeDist; 1100 } 1101 } else { 1102 if ((sLakituDist -= 30) < 0) { 1103 sLakituDist = 0; 1104 } 1105 } 1106 1107 if (gCurrLevelArea == AREA_SSL_PYRAMID && gCamera->mode == CAMERA_MODE_OUTWARD_RADIAL) { 1108 rangePitch /= 2; 1109 } 1110 1111 if (gCameraMovementFlags & CAM_MOVE_ZOOMED_OUT) { 1112 if ((sLakituPitch += rangePitch / 13) > rangePitch) { 1113 sLakituPitch = rangePitch; 1114 } 1115 } else { 1116 if ((sLakituPitch -= rangePitch / 13) < 0) { 1117 sLakituPitch = 0; 1118 } 1119 } 1120 } 1121 1122 void radial_camera_input_default(struct Camera *c) { 1123 radial_camera_input(c, 0.f); 1124 } 1125 1126 /** 1127 * Makes Lakitu cam's yaw match the angle turned towards in C-Up mode, and makes Lakitu slowly fly back 1128 * to the distance he was at before C-Up 1129 */ 1130 void update_yaw_and_dist_from_c_up(UNUSED struct Camera *c) { 1131 f32 dist = 1000.f; 1132 1133 sModeOffsetYaw = sModeInfo.transitionStart.yaw - sAreaYaw; 1134 sLakituDist = sModeInfo.transitionStart.dist - dist; 1135 // No longer in C-Up 1136 gCameraMovementFlags &= ~CAM_MOVING_INTO_MODE; 1137 } 1138 1139 /** 1140 * Handles input and updates for the radial camera mode 1141 */ 1142 void mode_radial_camera(struct Camera *c) { 1143 Vec3f pos; 1144 UNUSED u8 filler1[8]; 1145 s16 oldAreaYaw = sAreaYaw; 1146 UNUSED u8 filler2[4]; 1147 1148 if (gCameraMovementFlags & CAM_MOVING_INTO_MODE) { 1149 update_yaw_and_dist_from_c_up(c); 1150 } 1151 1152 radial_camera_input_default(c); 1153 radial_camera_move(c); 1154 1155 if (c->mode == CAMERA_MODE_RADIAL) { 1156 lakitu_zoom(400.f, 0x900); 1157 } 1158 c->nextYaw = update_radial_camera(c, c->focus, pos); 1159 c->pos[0] = pos[0]; 1160 c->pos[2] = pos[2]; 1161 sAreaYawChange = sAreaYaw - oldAreaYaw; 1162 if (sMarioCamState->action == ACT_RIDING_HOOT) { 1163 pos[1] += 500.f; 1164 } 1165 set_camera_height(c, pos[1]); 1166 pan_ahead_of_player(c); 1167 } 1168 1169 /** 1170 * A mode that only has 8 camera angles, 45 degrees apart 1171 */ 1172 void mode_8_directions_camera(struct Camera *c) { 1173 Vec3f pos; 1174 UNUSED u8 filler[8]; 1175 s16 oldAreaYaw = sAreaYaw; 1176 1177 radial_camera_input(c, 0.f); 1178 1179 if (gPlayer1Controller->buttonPressed & R_CBUTTONS) { 1180 s8DirModeYawOffset += DEGREES(45); 1181 play_sound_cbutton_side(); 1182 } 1183 if (gPlayer1Controller->buttonPressed & L_CBUTTONS) { 1184 s8DirModeYawOffset -= DEGREES(45); 1185 play_sound_cbutton_side(); 1186 } 1187 1188 lakitu_zoom(400.f, 0x900); 1189 c->nextYaw = update_8_directions_camera(c, c->focus, pos); 1190 c->pos[0] = pos[0]; 1191 c->pos[2] = pos[2]; 1192 sAreaYawChange = sAreaYaw - oldAreaYaw; 1193 set_camera_height(c, pos[1]); 1194 } 1195 1196 /** 1197 * Updates the camera in outward radial mode. 1198 * sModeOffsetYaw is calculated in radial_camera_move, which calls offset_yaw_outward_radial 1199 */ 1200 s32 update_outward_radial_camera(struct Camera *c, Vec3f focus, Vec3f pos) { 1201 f32 xDistFocToMario = sMarioCamState->pos[0] - c->areaCenX; 1202 f32 zDistFocToMario = sMarioCamState->pos[2] - c->areaCenZ; 1203 s16 camYaw = atan2s(zDistFocToMario, xDistFocToMario) + sModeOffsetYaw + DEGREES(180); 1204 s16 pitch = look_down_slopes(camYaw); 1205 f32 baseDist = 1000.f; 1206 // A base offset of 125.f is ~= Mario's eye height 1207 f32 yOff = 125.f; 1208 f32 posY; 1209 f32 focusY; 1210 1211 sAreaYaw = camYaw - sModeOffsetYaw - DEGREES(180); 1212 calc_y_to_curr_floor(&posY, 1.f, 200.f, &focusY, 0.9f, 200.f); 1213 focus_on_mario(focus, pos, posY + yOff, focusY + yOff, sLakituDist + baseDist, pitch, camYaw); 1214 1215 return camYaw; 1216 } 1217 1218 /** 1219 * Input and updates for the outward radial mode. 1220 */ 1221 void mode_outward_radial_camera(struct Camera *c) { 1222 Vec3f pos; 1223 s16 oldAreaYaw = sAreaYaw; 1224 1225 if (gCameraMovementFlags & CAM_MOVING_INTO_MODE) { 1226 update_yaw_and_dist_from_c_up(c); 1227 } 1228 radial_camera_input_default(c); 1229 radial_camera_move(c); 1230 lakitu_zoom(400.f, 0x900); 1231 c->nextYaw = update_outward_radial_camera(c, c->focus, pos); 1232 c->pos[0] = pos[0]; 1233 c->pos[2] = pos[2]; 1234 sAreaYawChange = sAreaYaw - oldAreaYaw; 1235 if (sMarioCamState->action == ACT_RIDING_HOOT) { 1236 pos[1] += 500.f; 1237 } 1238 set_camera_height(c, pos[1]); 1239 pan_ahead_of_player(c); 1240 } 1241 1242 /** 1243 * Move the camera in parallel tracking mode 1244 * 1245 * Uses the line between the next two points in sParTrackPath 1246 * The camera can move forward/back and side to side, but it will face perpendicular to that line 1247 * 1248 * Although, annoyingly, it's not truly parallel, the function returns the yaw from the camera to Mario, 1249 * so Mario will run slightly towards the camera. 1250 */ 1251 s32 update_parallel_tracking_camera(struct Camera *c, Vec3f focus, Vec3f pos) { 1252 Vec3f path[2]; 1253 Vec3f parMidPoint; 1254 Vec3f marioOffset; 1255 Vec3f camOffset; 1256 /// Adjusts the focus to look where Mario is facing. Unused since marioOffset is copied to focus 1257 Vec3f focOffset; 1258 s16 pathPitch; 1259 s16 pathYaw; 1260 UNUSED u8 filler[4]; 1261 f32 distThresh; 1262 f32 zoom; 1263 f32 camParDist; 1264 UNUSED u8 filler2[8]; 1265 f32 pathLength; 1266 UNUSED u8 filler3[8]; 1267 UNUSED f32 unusedScale = 0.5f; 1268 f32 parScale = 0.5f; 1269 f32 marioFloorDist; 1270 Vec3f marioPos; 1271 UNUSED u8 filler4[12]; 1272 UNUSED Vec3f unused; 1273 Vec3s pathAngle; 1274 // Variables for changing to the next/prev path in the list 1275 Vec3f oldPos; 1276 Vec3f prevPathPos; 1277 Vec3f nextPathPos; 1278 f32 distToNext; 1279 f32 distToPrev; 1280 s16 prevPitch; 1281 s16 nextPitch; 1282 s16 prevYaw; 1283 s16 nextYaw; 1284 1285 unused[0] = 0.f; 1286 unused[1] = 0.f; 1287 unused[2] = 0.f; 1288 1289 // Store camera pos, for changing between paths 1290 vec3f_copy(oldPos, pos); 1291 1292 vec3f_copy(path[0], sParTrackPath[sParTrackIndex].pos); 1293 vec3f_copy(path[1], sParTrackPath[sParTrackIndex + 1].pos); 1294 1295 distThresh = sParTrackPath[sParTrackIndex].distThresh; 1296 zoom = sParTrackPath[sParTrackIndex].zoom; 1297 calc_y_to_curr_floor(&marioFloorDist, 1.f, 200.f, &marioFloorDist, 0.9f, 200.f); 1298 1299 marioPos[0] = sMarioCamState->pos[0]; 1300 // Mario's y pos + ~Mario's height + Mario's height above the floor 1301 marioPos[1] = sMarioCamState->pos[1] + 150.f + marioFloorDist; 1302 marioPos[2] = sMarioCamState->pos[2]; 1303 1304 // Calculate middle of the path (parScale is 0.5f) 1305 parMidPoint[0] = path[0][0] + (path[1][0] - path[0][0]) * parScale; 1306 parMidPoint[1] = path[0][1] + (path[1][1] - path[0][1]) * parScale; 1307 parMidPoint[2] = path[0][2] + (path[1][2] - path[0][2]) * parScale; 1308 1309 // Get direction of path 1310 vec3f_get_dist_and_angle(path[0], path[1], &pathLength, &pathPitch, &pathYaw); 1311 1312 marioOffset[0] = marioPos[0] - parMidPoint[0]; 1313 marioOffset[1] = marioPos[1] - parMidPoint[1]; 1314 marioOffset[2] = marioPos[2] - parMidPoint[2]; 1315 1316 // Make marioOffset point from the midpoint -> the start of the path 1317 // Rotating by -yaw then -pitch moves the hor dist from the midpoint into marioOffset's z coordinate 1318 // marioOffset[0] = the (perpendicular) horizontal distance from the path 1319 // marioOffset[1] = the vertical distance from the path 1320 // marioOffset[2] = the (parallel) horizontal distance from the path's midpoint 1321 pathYaw = -pathYaw; 1322 rotate_in_xz(marioOffset, marioOffset, pathYaw); 1323 pathYaw = -pathYaw; 1324 pathPitch = -pathPitch; 1325 rotate_in_yz(marioOffset, marioOffset, pathPitch); 1326 pathPitch = -pathPitch; 1327 vec3f_copy(focOffset, marioOffset); 1328 1329 // OK 1330 focOffset[0] = -focOffset[0] * 0.f; 1331 focOffset[1] = focOffset[1] * 0.f; 1332 1333 // Repeat above calcs with camOffset 1334 camOffset[0] = pos[0] - parMidPoint[0]; 1335 camOffset[1] = pos[1] - parMidPoint[1]; 1336 camOffset[2] = pos[2] - parMidPoint[2]; 1337 pathYaw = -pathYaw; 1338 rotate_in_xz(camOffset, camOffset, pathYaw); 1339 pathYaw = -pathYaw; 1340 pathPitch = -pathPitch; 1341 rotate_in_yz(camOffset, camOffset, pathPitch); 1342 pathPitch = -pathPitch; 1343 1344 // If Mario is distThresh units away from the camera along the path, move the camera 1345 //! When distThresh != 0, it causes Mario to move slightly towards the camera when running sideways 1346 //! Set each ParallelTrackingPoint's distThresh to 0 to make Mario truly run parallel to the path 1347 if (marioOffset[2] > camOffset[2]) { 1348 if (marioOffset[2] - camOffset[2] > distThresh) { 1349 camOffset[2] = marioOffset[2] - distThresh; 1350 } 1351 } else { 1352 if (marioOffset[2] - camOffset[2] < -distThresh) { 1353 camOffset[2] = marioOffset[2] + distThresh; 1354 } 1355 } 1356 1357 // If zoom != 0.0, the camera will move zoom% closer to Mario 1358 marioOffset[0] = -marioOffset[0] * zoom; 1359 marioOffset[1] = marioOffset[1] * zoom; 1360 marioOffset[2] = camOffset[2]; 1361 1362 //! Does nothing because focOffset[0] is always 0 1363 focOffset[0] *= 0.3f; 1364 //! Does nothing because focOffset[1] is always 0 1365 focOffset[1] *= 0.3f; 1366 1367 pathAngle[0] = pathPitch; 1368 pathAngle[1] = pathYaw; //! No effect 1369 1370 // make marioOffset[2] == distance from the start of the path 1371 marioOffset[2] = pathLength / 2 - marioOffset[2]; 1372 1373 pathAngle[1] = pathYaw + DEGREES(180); 1374 pathAngle[2] = 0; 1375 1376 // Rotate the offset in the direction of the path again 1377 offset_rotated(pos, path[0], marioOffset, pathAngle); 1378 vec3f_get_dist_and_angle(path[0], c->pos, &camParDist, &pathPitch, &pathYaw); 1379 1380 // Adjust the focus. Does nothing, focus is set to Mario at the end 1381 focOffset[2] = pathLength / 2 - focOffset[2]; 1382 offset_rotated(c->focus, path[0], focOffset, pathAngle); 1383 1384 // Changing paths, update the stored position offset 1385 if (sStatusFlags & CAM_FLAG_CHANGED_PARTRACK_INDEX) { 1386 sStatusFlags &= ~CAM_FLAG_CHANGED_PARTRACK_INDEX; 1387 sParTrackTransOff.pos[0] = oldPos[0] - c->pos[0]; 1388 sParTrackTransOff.pos[1] = oldPos[1] - c->pos[1]; 1389 sParTrackTransOff.pos[2] = oldPos[2] - c->pos[2]; 1390 } 1391 // Slowly transition to the next path 1392 approach_f32_asymptotic_bool(&sParTrackTransOff.pos[0], 0.f, 0.025f); 1393 approach_f32_asymptotic_bool(&sParTrackTransOff.pos[1], 0.f, 0.025f); 1394 approach_f32_asymptotic_bool(&sParTrackTransOff.pos[2], 0.f, 0.025f); 1395 vec3f_add(c->pos, sParTrackTransOff.pos); 1396 1397 // Check if the camera should go to the next path 1398 if (sParTrackPath[sParTrackIndex + 1].startOfPath != 0) { 1399 // get Mario's distance to the next path 1400 calculate_angles(sParTrackPath[sParTrackIndex + 1].pos, sParTrackPath[sParTrackIndex + 2].pos, &nextPitch, &nextYaw); 1401 vec3f_set_dist_and_angle(sParTrackPath[sParTrackIndex + 1].pos, nextPathPos, 400.f, nextPitch, nextYaw); 1402 distToPrev = calc_abs_dist(marioPos, nextPathPos); 1403 1404 // get Mario's distance to the previous path 1405 calculate_angles(sParTrackPath[sParTrackIndex + 1].pos, sParTrackPath[sParTrackIndex].pos, &prevPitch, &prevYaw); 1406 vec3f_set_dist_and_angle(sParTrackPath[sParTrackIndex + 1].pos, prevPathPos, 400.f, prevPitch, prevYaw); 1407 distToNext = calc_abs_dist(marioPos, prevPathPos); 1408 if (distToPrev < distToNext) { 1409 sParTrackIndex++; 1410 sStatusFlags |= CAM_FLAG_CHANGED_PARTRACK_INDEX; 1411 } 1412 } 1413 1414 // Check if the camera should go to the previous path 1415 if (sParTrackIndex != 0) { 1416 // get Mario's distance to the next path 1417 calculate_angles((*(sParTrackPath + sParTrackIndex)).pos, (*(sParTrackPath + sParTrackIndex + 1)).pos, &nextPitch, &nextYaw); 1418 vec3f_set_dist_and_angle(sParTrackPath[sParTrackIndex].pos, nextPathPos, 700.f, nextPitch, nextYaw); 1419 distToPrev = calc_abs_dist(marioPos, nextPathPos); 1420 1421 // get Mario's distance to the previous path 1422 calculate_angles((*(sParTrackPath + sParTrackIndex)).pos, (*(sParTrackPath + sParTrackIndex - 1)).pos, &prevPitch, &prevYaw); 1423 vec3f_set_dist_and_angle(sParTrackPath[sParTrackIndex].pos, prevPathPos, 700.f, prevPitch, prevYaw); 1424 distToNext = calc_abs_dist(marioPos, prevPathPos); 1425 if (distToPrev > distToNext) { 1426 sParTrackIndex--; 1427 sStatusFlags |= CAM_FLAG_CHANGED_PARTRACK_INDEX; 1428 } 1429 } 1430 1431 // Update the camera focus and return the camera's yaw 1432 vec3f_copy(focus, marioPos); 1433 vec3f_get_dist_and_angle(focus, pos, &camParDist, &pathPitch, &pathYaw); 1434 return pathYaw; 1435 } 1436 1437 /** 1438 * Updates the camera during fixed mode. 1439 */ 1440 s32 update_fixed_camera(struct Camera *c, Vec3f focus, UNUSED Vec3f pos) { 1441 f32 focusFloorOff; 1442 f32 goalHeight; 1443 f32 ceilHeight; 1444 f32 heightOffset; 1445 f32 distCamToFocus; 1446 UNUSED u8 filler2[8]; 1447 f32 scaleToMario = 0.5f; 1448 s16 pitch; 1449 s16 yaw; 1450 Vec3s faceAngle; 1451 struct Surface *ceiling; 1452 Vec3f basePos; 1453 UNUSED u8 filler[12]; 1454 1455 play_camera_buzz_if_c_sideways(); 1456 1457 // Don't move closer to Mario in these areas 1458 switch (gCurrLevelArea) { 1459 case AREA_RR: 1460 scaleToMario = 0.f; 1461 heightOffset = 0.f; 1462 break; 1463 1464 case AREA_CASTLE_LOBBY: 1465 scaleToMario = 0.3f; 1466 heightOffset = 0.f; 1467 break; 1468 1469 case AREA_BBH: 1470 scaleToMario = 0.f; 1471 heightOffset = 0.f; 1472 break; 1473 } 1474 1475 handle_c_button_movement(c); 1476 play_camera_buzz_if_cdown(); 1477 1478 calc_y_to_curr_floor(&focusFloorOff, 1.f, 200.f, &focusFloorOff, 0.9f, 200.f); 1479 vec3f_copy(focus, sMarioCamState->pos); 1480 focus[1] += focusFloorOff + 125.f; 1481 vec3f_get_dist_and_angle(focus, c->pos, &distCamToFocus, &faceAngle[0], &faceAngle[1]); 1482 faceAngle[2] = 0; 1483 1484 vec3f_copy(basePos, sFixedModeBasePosition); 1485 vec3f_add(basePos, sCastleEntranceOffset); 1486 1487 if (sMarioGeometry.currFloorType != SURFACE_DEATH_PLANE 1488 && sMarioGeometry.currFloorHeight != FLOOR_LOWER_LIMIT) { 1489 goalHeight = sMarioGeometry.currFloorHeight + basePos[1] + heightOffset; 1490 } else { 1491 goalHeight = gLakituState.goalPos[1]; 1492 } 1493 1494 if (300 > distCamToFocus) { 1495 goalHeight += 300 - distCamToFocus; 1496 } 1497 1498 ceilHeight = find_ceil(c->pos[0], goalHeight - 100.f, c->pos[2], &ceiling); 1499 if (ceilHeight != CELL_HEIGHT_LIMIT) { 1500 if (goalHeight > (ceilHeight -= 125.f)) { 1501 goalHeight = ceilHeight; 1502 } 1503 } 1504 1505 if (sStatusFlags & CAM_FLAG_SMOOTH_MOVEMENT) { 1506 camera_approach_f32_symmetric_bool(&c->pos[1], goalHeight, 15.f); 1507 } else { 1508 if (goalHeight < sMarioCamState->pos[1] - 500.f) { 1509 goalHeight = sMarioCamState->pos[1] - 500.f; 1510 } 1511 c->pos[1] = goalHeight; 1512 } 1513 1514 c->pos[0] = basePos[0] + (sMarioCamState->pos[0] - basePos[0]) * scaleToMario; 1515 c->pos[2] = basePos[2] + (sMarioCamState->pos[2] - basePos[2]) * scaleToMario; 1516 1517 if (scaleToMario != 0.f) { 1518 vec3f_get_dist_and_angle(c->focus, c->pos, &distCamToFocus, &pitch, &yaw); 1519 if (distCamToFocus > 1000.f) { 1520 distCamToFocus = 1000.f; 1521 vec3f_set_dist_and_angle(c->focus, c->pos, distCamToFocus, pitch, yaw); 1522 } 1523 } 1524 1525 return faceAngle[1]; 1526 } 1527 1528 /** 1529 * Updates the camera during a boss fight 1530 */ 1531 s32 update_boss_fight_camera(struct Camera *c, Vec3f focus, Vec3f pos) { 1532 struct Object *o; 1533 UNUSED u8 filler2[12]; 1534 f32 focusDistance; 1535 UNUSED u8 filler3[4]; 1536 // Floor normal values 1537 f32 nx; 1538 f32 ny; 1539 f32 nz; 1540 /// Floor originOffset 1541 f32 oo; 1542 UNUSED u8 filler4[4]; 1543 UNUSED s16 unused; 1544 s16 yaw; 1545 s16 heldState; 1546 struct Surface *floor; 1547 UNUSED u8 filler[20]; 1548 Vec3f secondFocus; 1549 Vec3f holdFocOffset = { 0.f, -150.f, -125.f }; 1550 1551 handle_c_button_movement(c); 1552 1553 // Start camera shakes if bowser jumps or gets thrown. 1554 if (sMarioCamState->cameraEvent == CAM_EVENT_BOWSER_JUMP) { 1555 set_environmental_camera_shake(SHAKE_ENV_BOWSER_JUMP); 1556 sMarioCamState->cameraEvent = 0; 1557 } 1558 if (sMarioCamState->cameraEvent == CAM_EVENT_BOWSER_THROW_BOUNCE) { 1559 set_environmental_camera_shake(SHAKE_ENV_BOWSER_THROW_BOUNCE); 1560 sMarioCamState->cameraEvent = 0; 1561 } 1562 1563 yaw = sModeOffsetYaw + DEGREES(45); 1564 // Get boss's position and whether Mario is holding it. 1565 if ((o = gSecondCameraFocus) != NULL) { 1566 object_pos_to_vec3f(secondFocus, o); 1567 heldState = o->oHeldState; 1568 } else { 1569 // If no boss is there, just rotate around the area's center point. 1570 secondFocus[0] = c->areaCenX; 1571 secondFocus[1] = sMarioCamState->pos[1]; 1572 secondFocus[2] = c->areaCenZ; 1573 heldState = 0; 1574 } 1575 1576 focusDistance = calc_abs_dist(sMarioCamState->pos, secondFocus) * 1.6f; 1577 if (focusDistance < 800.f) { 1578 focusDistance = 800.f; 1579 } 1580 if (focusDistance > 5000.f) { 1581 focusDistance = 5000.f; 1582 } 1583 1584 // If holding the boss, add a slight offset to secondFocus so that the spinning is more pronounced. 1585 if (heldState == 1) { 1586 offset_rotated(secondFocus, sMarioCamState->pos, holdFocOffset, sMarioCamState->faceAngle); 1587 } 1588 1589 // Set the camera focus to the average of Mario and secondFocus 1590 focus[0] = (sMarioCamState->pos[0] + secondFocus[0]) / 2.f; 1591 focus[1] = (sMarioCamState->pos[1] + secondFocus[1]) / 2.f + 125.f; 1592 focus[2] = (sMarioCamState->pos[2] + secondFocus[2]) / 2.f; 1593 1594 // Calculate the camera's position as an offset from the focus 1595 // When C-Down is not active, this 1596 vec3f_set_dist_and_angle(focus, pos, focusDistance, 0x1000, yaw); 1597 // Find the floor of the arena 1598 pos[1] = find_floor(c->areaCenX, CELL_HEIGHT_LIMIT, c->areaCenZ, &floor); 1599 if (floor != NULL) { 1600 nx = floor->normal.x; 1601 ny = floor->normal.y; 1602 nz = floor->normal.z; 1603 oo = floor->originOffset; 1604 pos[1] = 300.f - (nx * pos[0] + nz * pos[2] + oo) / ny; 1605 switch (gCurrLevelArea) { 1606 case AREA_BOB: 1607 pos[1] += 125.f; 1608 //! fall through, makes the BoB boss fight camera move up twice as high as it should 1609 case AREA_WF: 1610 pos[1] += 125.f; 1611 } 1612 } 1613 1614 //! Must be same line to match on -O2 1615 // Prevent the camera from going to the ground in the outside boss fight 1616 if (gCurrLevelNum == LEVEL_BBH) { pos[1] = 2047.f; } 1617 1618 // Rotate from C-Button input 1619 if (sCSideButtonYaw < 0) { 1620 sModeOffsetYaw += 0x200; 1621 if ((sCSideButtonYaw += 0x100) > 0) { 1622 sCSideButtonYaw = 0; 1623 } 1624 } 1625 if (sCSideButtonYaw > 0) { 1626 sModeOffsetYaw -= 0x200; 1627 if ((sCSideButtonYaw -= 0x100) < 0) { 1628 sCSideButtonYaw = 0; 1629 } 1630 } 1631 1632 focus[1] = (sMarioCamState->pos[1] + secondFocus[1]) / 2.f + 100.f; 1633 if (heldState == 1) { 1634 focus[1] += 300.f * sins((gMarioStates[0].angleVel[1] > 0.f) ? gMarioStates[0].angleVel[1] 1635 : -gMarioStates[0].angleVel[1]); 1636 } 1637 1638 //! Unnecessary conditional, focusDistance is already bounded to 800 1639 if (focusDistance < 400.f) { 1640 focusDistance = 400.f; 1641 } 1642 1643 // Set C-Down distance and pitch. 1644 // C-Down will essentially double the distance from the center. 1645 // sLakituPitch approaches 33.75 degrees. 1646 lakitu_zoom(focusDistance, 0x1800); 1647 1648 // Move the camera position back as sLakituDist and sLakituPitch increase. 1649 // This doesn't zoom out of bounds because pos is set above each frame. 1650 // The constant 0x1000 doubles the pitch from the center when sLakituPitch is 0 1651 // When Lakitu is fully zoomed out, the pitch comes to 0x3800, or 78.75 degrees, up from the focus. 1652 vec3f_set_dist_and_angle(pos, pos, sLakituDist, sLakituPitch + 0x1000, yaw); 1653 1654 return yaw; 1655 } 1656 1657 // 2nd iteration of data 1658 s16 unused8032D0A8[] = { 14, 1, 2, 4 }; 1659 s16 unused8032D0B0[] = { 16, 9, 17, 0 }; 1660 1661 /** 1662 * Maps cutscene to numbers in [0,4]. Used in determine_dance_cutscene() with sDanceCutsceneIndexTable. 1663 * 1664 * Only the first 5 entries are used. Perhaps the last 5 were bools used to indicate whether the star 1665 * type exits the course or not. 1666 */ 1667 u8 sDanceCutsceneTable[] = { 1668 CUTSCENE_DANCE_FLY_AWAY, CUTSCENE_DANCE_ROTATE, CUTSCENE_DANCE_CLOSEUP, CUTSCENE_KEY_DANCE, CUTSCENE_DANCE_DEFAULT, 1669 FALSE, FALSE, FALSE, FALSE, TRUE, 1670 }; 1671 1672 /** 1673 * Perhaps used by different dance cutscenes. 1674 */ 1675 struct UnusedDanceInfo { 1676 Vec3f point; 1677 f32 distTarget; 1678 f32 distMultiplier; 1679 }; 1680 1681 struct UnusedDanceInfo unusedDanceInfo1 = { 1682 { -3026.0f, 912.0f, -2148.0f }, 600.0f, 0.3f 1683 }; 1684 1685 u32 unusedDanceType = 0; 1686 1687 struct UnusedDanceInfo unusedDanceInfo2 = { 1688 { -4676.0f, 917.0f, -3802.0f }, 600.0f, 0.3f 1689 }; 1690 1691 /** 1692 * Table that dictates camera movement in bookend room. 1693 * Due to only the X being varied in the table, this only moves along the X axis linearly. 1694 * Third entry is seemingly unused. 1695 */ 1696 struct ParallelTrackingPoint sBBHLibraryParTrackPath[] = { 1697 { 1, { -929.0f, 1619.0f, -1490.0f }, 50.0f, 0.0f }, 1698 { 0, { -2118.0f, 1619.0f, -1490.0f }, 50.0f, 0.0f }, 1699 { 0, { 0.0f, 0.0f, 0.0f }, 0.0f, 0.0f }, 1700 }; 1701 1702 s32 unused_update_mode_5_camera(UNUSED struct Camera *c, UNUSED Vec3f focus, UNUSED Vec3f pos) { 1703 #ifdef AVOID_UB 1704 return 0; 1705 #endif 1706 } 1707 1708 UNUSED static void stub_camera_1(UNUSED s32 unused) { 1709 } 1710 1711 void mode_boss_fight_camera(struct Camera *c) { 1712 c->nextYaw = update_boss_fight_camera(c, c->focus, c->pos); 1713 } 1714 1715 /** 1716 * Parallel tracking mode, the camera faces perpendicular to a line defined by sParTrackPath 1717 * 1718 * @see update_parallel_tracking_camera 1719 */ 1720 void mode_parallel_tracking_camera(struct Camera *c) { 1721 s16 dummy; 1722 1723 radial_camera_input(c, 0.f); 1724 set_fov_function(CAM_FOV_DEFAULT); 1725 c->nextYaw = update_parallel_tracking_camera(c, c->focus, c->pos); 1726 camera_approach_s16_symmetric_bool(&dummy, 0, 0x0400); 1727 } 1728 1729 /** 1730 * Fixed camera mode, the camera rotates around a point and looks and zooms toward Mario. 1731 */ 1732 void mode_fixed_camera(struct Camera *c) { 1733 UNUSED u8 filler[8]; 1734 1735 if (gCurrLevelNum == LEVEL_BBH) { 1736 set_fov_function(CAM_FOV_BBH); 1737 } else { 1738 set_fov_function(CAM_FOV_APP_45); 1739 } 1740 c->nextYaw = update_fixed_camera(c, c->focus, c->pos); 1741 c->yaw = c->nextYaw; 1742 pan_ahead_of_player(c); 1743 vec3f_set(sCastleEntranceOffset, 0.f, 0.f, 0.f); 1744 } 1745 1746 /** 1747 * Updates the camera in BEHIND_MARIO mode. 1748 * 1749 * The C-Buttons rotate the camera 90 degrees left/right and 67.5 degrees up/down. 1750 */ 1751 s32 update_behind_mario_camera(struct Camera *c, Vec3f focus, Vec3f pos) { 1752 UNUSED u8 filler1[12]; 1753 f32 dist; 1754 UNUSED u8 filler2[4]; 1755 s16 absPitch; 1756 s16 pitch; 1757 s16 yaw; 1758 s16 goalPitch = -sMarioCamState->faceAngle[0]; 1759 s16 marioYaw = sMarioCamState->faceAngle[1] + DEGREES(180); 1760 s16 goalYawOff = 0; 1761 s16 yawSpeed; 1762 s16 pitchInc = 32; 1763 UNUSED u8 filler3[12]; 1764 f32 maxDist = 800.f; 1765 f32 focYOff = 125.f; 1766 1767 // Zoom in when Mario R_TRIG mode is active 1768 if (sSelectionFlags & CAM_MODE_MARIO_ACTIVE) { 1769 maxDist = 350.f; 1770 focYOff = 120.f; 1771 } 1772 if (!(sMarioCamState->action & (ACT_FLAG_SWIMMING | ACT_FLAG_METAL_WATER))) { 1773 pitchInc = 128; 1774 } 1775 1776 // Focus on Mario 1777 vec3f_copy(focus, sMarioCamState->pos); 1778 c->focus[1] += focYOff; 1779 //! @bug unnecessary 1780 dist = calc_abs_dist(focus, pos); 1781 //! @bug unnecessary 1782 pitch = calculate_pitch(focus, pos); 1783 vec3f_get_dist_and_angle(focus, pos, &dist, &pitch, &yaw); 1784 if (dist > maxDist) { 1785 dist = maxDist; 1786 } 1787 if ((absPitch = pitch) < 0) { 1788 absPitch = -absPitch; 1789 } 1790 1791 // Determine the yaw speed based on absPitch. A higher absPitch (further away from looking straight) 1792 // translates to a slower speed 1793 // Note: Pitch is always within +- 90 degrees or +-0x4000, and 0x4000 / 0x200 = 32 1794 yawSpeed = 32 - absPitch / 0x200; 1795 if (yawSpeed < 1) { 1796 yawSpeed = 1; 1797 } 1798 if (yawSpeed > 32) { 1799 yawSpeed = 32; 1800 } 1801 1802 if (sCSideButtonYaw != 0) { 1803 camera_approach_s16_symmetric_bool(&sCSideButtonYaw, 0, 1); 1804 yawSpeed = 8; 1805 } 1806 if (sBehindMarioSoundTimer != 0) { 1807 goalPitch = 0; 1808 camera_approach_s16_symmetric_bool(&sBehindMarioSoundTimer, 0, 1); 1809 pitchInc = 0x800; 1810 } 1811 1812 if (sBehindMarioSoundTimer == 28) { 1813 if (sCSideButtonYaw < 5 || sCSideButtonYaw > 28) { 1814 play_sound_cbutton_up(); 1815 } 1816 } 1817 if (sCSideButtonYaw == 28) { 1818 if (sBehindMarioSoundTimer < 5 || sBehindMarioSoundTimer > 28) { 1819 play_sound_cbutton_up(); 1820 } 1821 } 1822 1823 // C-Button input. Note: Camera rotates in the opposite direction of the button (airplane controls) 1824 //! @bug C-Right and C-Up take precedence due to the way input is handled here 1825 1826 // Rotate right 1827 if (sCButtonsPressed & L_CBUTTONS) { 1828 if (gPlayer1Controller->buttonPressed & L_CBUTTONS) { 1829 play_sound_cbutton_side(); 1830 } 1831 if (dist < maxDist) { 1832 camera_approach_f32_symmetric_bool(&dist, maxDist, 5.f); 1833 } 1834 goalYawOff = -0x3FF8; 1835 sCSideButtonYaw = 30; 1836 yawSpeed = 2; 1837 } 1838 // Rotate left 1839 if (sCButtonsPressed & R_CBUTTONS) { 1840 if (gPlayer1Controller->buttonPressed & R_CBUTTONS) { 1841 play_sound_cbutton_side(); 1842 } 1843 if (dist < maxDist) { 1844 camera_approach_f32_symmetric_bool(&dist, maxDist, 5.f); 1845 } 1846 goalYawOff = 0x3FF8; 1847 sCSideButtonYaw = 30; 1848 yawSpeed = 2; 1849 } 1850 // Rotate up 1851 if (sCButtonsPressed & D_CBUTTONS) { 1852 if (gPlayer1Controller->buttonPressed & (U_CBUTTONS | D_CBUTTONS)) { 1853 play_sound_cbutton_side(); 1854 } 1855 if (dist < maxDist) { 1856 camera_approach_f32_symmetric_bool(&dist, maxDist, 5.f); 1857 } 1858 goalPitch = -0x3000; 1859 sBehindMarioSoundTimer = 30; 1860 pitchInc = 0x800; 1861 } 1862 // Rotate down 1863 if (sCButtonsPressed & U_CBUTTONS) { 1864 if (gPlayer1Controller->buttonPressed & (U_CBUTTONS | D_CBUTTONS)) { 1865 play_sound_cbutton_side(); 1866 } 1867 if (dist < maxDist) { 1868 camera_approach_f32_symmetric_bool(&dist, maxDist, 5.f); 1869 } 1870 goalPitch = 0x3000; 1871 sBehindMarioSoundTimer = 30; 1872 pitchInc = 0x800; 1873 } 1874 1875 approach_s16_asymptotic_bool(&yaw, marioYaw + goalYawOff, yawSpeed); 1876 camera_approach_s16_symmetric_bool(&pitch, goalPitch, pitchInc); 1877 if (dist < 300.f) { 1878 dist = 300.f; 1879 } 1880 vec3f_set_dist_and_angle(focus, pos, dist, pitch, yaw); 1881 if (gCurrLevelArea == AREA_WDW_MAIN) { 1882 yaw = clamp_positions_and_find_yaw(pos, focus, 4508.f, -3739.f, 4508.f, -3739.f); 1883 } 1884 if (gCurrLevelArea == AREA_THI_HUGE) { 1885 yaw = clamp_positions_and_find_yaw(pos, focus, 8192.f, -8192.f, 8192.f, -8192.f); 1886 } 1887 if (gCurrLevelArea == AREA_THI_TINY) { 1888 yaw = clamp_positions_and_find_yaw(pos, focus, 2458.f, -2458.f, 2458.f, -2458.f); 1889 } 1890 1891 return yaw; 1892 } 1893 1894 /** 1895 * "Behind Mario" mode: used when Mario is flying, on the water's surface, or shot from a cannon 1896 */ 1897 s32 mode_behind_mario(struct Camera *c) { 1898 struct MarioState *marioState = &gMarioStates[0]; 1899 struct Surface *floor; 1900 Vec3f newPos; 1901 //! @bug oldPos is unused, see resolve_geometry_collisions 1902 Vec3f oldPos; 1903 f32 waterHeight; 1904 f32 floorHeight; 1905 f32 distCamToFocus; 1906 s16 camPitch; 1907 s16 camYaw; 1908 s16 yaw; 1909 1910 vec3f_copy(oldPos, c->pos); 1911 gCameraMovementFlags &= ~CAM_MOVING_INTO_MODE; 1912 vec3f_copy(newPos, c->pos); 1913 yaw = update_behind_mario_camera(c, c->focus, newPos); 1914 c->pos[0] = newPos[0]; 1915 c->pos[2] = newPos[2]; 1916 1917 // Keep the camera above the water surface if swimming 1918 if (c->mode == CAMERA_MODE_WATER_SURFACE) { 1919 floorHeight = find_floor(c->pos[0], c->pos[1], c->pos[2], &floor); 1920 newPos[1] = marioState->waterLevel + 120; 1921 if (newPos[1] < (floorHeight += 120.f)) { 1922 newPos[1] = floorHeight; 1923 } 1924 } 1925 approach_camera_height(c, newPos[1], 50.f); 1926 waterHeight = find_water_level(c->pos[0], c->pos[2]) + 100.f; 1927 if (c->pos[1] <= waterHeight) { 1928 gCameraMovementFlags |= CAM_MOVE_SUBMERGED; 1929 } else { 1930 gCameraMovementFlags &= ~CAM_MOVE_SUBMERGED; 1931 } 1932 1933 resolve_geometry_collisions(c->pos, oldPos); 1934 // Prevent camera getting too far away 1935 vec3f_get_dist_and_angle(c->focus, c->pos, &distCamToFocus, &camPitch, &camYaw); 1936 if (distCamToFocus > 800.f) { 1937 distCamToFocus = 800.f; 1938 vec3f_set_dist_and_angle(c->focus, c->pos, distCamToFocus, camPitch, camYaw); 1939 } 1940 pan_ahead_of_player(c); 1941 1942 return yaw; 1943 } 1944 1945 /** 1946 * Update the camera in slide and hoot mode. 1947 * 1948 * In slide mode, keep the camera 800 units from Mario 1949 */ 1950 s16 update_slide_camera(struct Camera *c) { 1951 struct Surface *floor; 1952 f32 floorHeight; 1953 Vec3f pos; 1954 f32 distCamToFocus; 1955 f32 maxCamDist; 1956 f32 pitchScale; 1957 s16 camPitch; 1958 s16 camYaw; 1959 UNUSED struct MarioState *marioState = &gMarioStates[0]; 1960 s16 goalPitch = 0x1555; 1961 s16 goalYaw = sMarioCamState->faceAngle[1] + DEGREES(180); 1962 1963 // Zoom in when inside the CCM shortcut 1964 if (sStatusFlags & CAM_FLAG_CCM_SLIDE_SHORTCUT) { 1965 sLakituDist = approach_f32(sLakituDist, -600.f, 20.f, 20.f); 1966 } else { 1967 sLakituDist = approach_f32(sLakituDist, 0.f, 20.f, 20.f); 1968 } 1969 1970 // No C-Button input in this mode, notify the player with a buzzer 1971 play_camera_buzz_if_cbutton(); 1972 1973 // Focus on Mario 1974 vec3f_copy(c->focus, sMarioCamState->pos); 1975 c->focus[1] += 50.f; 1976 1977 vec3f_get_dist_and_angle(c->focus, c->pos, &distCamToFocus, &camPitch, &camYaw); 1978 maxCamDist = 800.f; 1979 1980 // In hoot mode, zoom further out and rotate faster 1981 if (sMarioCamState->action == ACT_RIDING_HOOT) { 1982 maxCamDist = 1000.f; 1983 goalPitch = 0x2800; 1984 camera_approach_s16_symmetric_bool(&camYaw, goalYaw, 0x100); 1985 } else { 1986 camera_approach_s16_symmetric_bool(&camYaw, goalYaw, 0x80); 1987 } 1988 camera_approach_s16_symmetric_bool(&camPitch, goalPitch, 0x100); 1989 1990 // Hoot mode 1991 if (sMarioCamState->action != ACT_RIDING_HOOT && sMarioGeometry.currFloorType == SURFACE_DEATH_PLANE) { 1992 vec3f_set_dist_and_angle(c->focus, pos, maxCamDist + sLakituDist, camPitch, camYaw); 1993 c->pos[0] = pos[0]; 1994 c->pos[2] = pos[2]; 1995 camera_approach_f32_symmetric_bool(&c->pos[1], c->focus[1], 30.f); 1996 vec3f_get_dist_and_angle(c->pos, c->focus, &distCamToFocus, &camPitch, &camYaw); 1997 pitchScale = (distCamToFocus - maxCamDist + sLakituDist) / 10000.f; 1998 if (pitchScale > 1.f) { 1999 pitchScale = 1.f; 2000 } 2001 camPitch += 0x1000 * pitchScale; 2002 vec3f_set_dist_and_angle(c->pos, c->focus, distCamToFocus, camPitch, camYaw); 2003 2004 // Slide mode 2005 } else { 2006 vec3f_set_dist_and_angle(c->focus, c->pos, maxCamDist + sLakituDist, camPitch, camYaw); 2007 sStatusFlags |= CAM_FLAG_BLOCK_SMOOTH_MOVEMENT; 2008 2009 // Stay above the slide floor 2010 floorHeight = find_floor(c->pos[0], c->pos[1] + 200.f, c->pos[2], &floor) + 125.f; 2011 if (c->pos[1] < floorHeight) { 2012 c->pos[1] = floorHeight; 2013 } 2014 // Stay closer than maxCamDist 2015 vec3f_get_dist_and_angle(c->focus, c->pos, &distCamToFocus, &camPitch, &camYaw); 2016 if (distCamToFocus > maxCamDist + sLakituDist) { 2017 distCamToFocus = maxCamDist + sLakituDist; 2018 vec3f_set_dist_and_angle(c->focus, c->pos, distCamToFocus, camPitch, camYaw); 2019 } 2020 } 2021 2022 camYaw = calculate_yaw(c->focus, c->pos); 2023 return camYaw; 2024 } 2025 2026 void mode_behind_mario_camera(struct Camera *c) { 2027 c->nextYaw = mode_behind_mario(c); 2028 } 2029 2030 s32 nop_update_water_camera(UNUSED struct Camera *c, UNUSED Vec3f focus, UNUSED Vec3f pos) { 2031 #ifdef AVOID_UB 2032 return 0; 2033 #endif 2034 } 2035 2036 /** 2037 * Exactly the same as BEHIND_MARIO 2038 */ 2039 void mode_water_surface_camera(struct Camera *c) { 2040 c->nextYaw = mode_behind_mario(c); 2041 } 2042 2043 /** 2044 * Used in sModeTransitions for CLOSE and FREE_ROAM mode 2045 */ 2046 s32 update_mario_camera(UNUSED struct Camera *c, Vec3f focus, Vec3f pos) { 2047 s16 yaw = sMarioCamState->faceAngle[1] + sModeOffsetYaw + DEGREES(180); 2048 focus_on_mario(focus, pos, 125.f, 125.f, gCameraZoomDist, 0x05B0, yaw); 2049 2050 return sMarioCamState->faceAngle[1]; 2051 } 2052 2053 /** 2054 * Update the camera in default, close, and free roam mode 2055 * 2056 * The camera moves behind Mario, and can rotate all the way around 2057 */ 2058 s16 update_default_camera(struct Camera *c) { 2059 Vec3f tempPos; 2060 Vec3f cPos; 2061 UNUSED u8 filler1[12]; 2062 struct Surface *marioFloor; 2063 struct Surface *cFloor; 2064 struct Surface *tempFloor; 2065 struct Surface *ceil; 2066 f32 camFloorHeight; 2067 f32 tempFloorHeight; 2068 f32 marioFloorHeight; 2069 UNUSED u8 filler2[4]; 2070 f32 dist; 2071 f32 zoomDist; 2072 f32 waterHeight; 2073 f32 gasHeight; 2074 s16 avoidYaw; 2075 s16 pitch; 2076 s16 yaw; 2077 s16 yawGoal = sMarioCamState->faceAngle[1] + DEGREES(180); 2078 f32 posHeight; 2079 f32 focHeight; 2080 f32 distFromWater; 2081 s16 tempPitch; 2082 s16 tempYaw; 2083 f32 xzDist; 2084 UNUSED u8 filler3[4]; 2085 s16 nextYawVel; 2086 s16 yawVel = 0; 2087 f32 scale; 2088 s32 avoidStatus = 0; 2089 s32 closeToMario = 0; 2090 f32 ceilHeight = find_ceil(gLakituState.goalPos[0], 2091 gLakituState.goalPos[1], 2092 gLakituState.goalPos[2], &ceil); 2093 s16 yawDir; 2094 2095 handle_c_button_movement(c); 2096 vec3f_get_dist_and_angle(sMarioCamState->pos, c->pos, &dist, &pitch, &yaw); 2097 2098 // If C-Down is active, determine what distance the camera should be from Mario 2099 if (gCameraMovementFlags & CAM_MOVE_ZOOMED_OUT) { 2100 //! In Mario mode, the camera is zoomed out further than in Lakitu mode (1400 vs 1200) 2101 if (set_cam_angle(0) == CAM_ANGLE_MARIO) { 2102 zoomDist = gCameraZoomDist + 1050; 2103 } else { 2104 zoomDist = gCameraZoomDist + 400; 2105 } 2106 } else { 2107 zoomDist = gCameraZoomDist; 2108 } 2109 2110 if (sMarioCamState->action & ACT_FLAG_HANGING || 2111 sMarioCamState->action == ACT_RIDING_HOOT) { 2112 zoomDist *= 0.8f; 2113 set_handheld_shake(HAND_CAM_SHAKE_HANG_OWL); 2114 } 2115 2116 // If not zooming out, only allow dist to decrease 2117 if (sZoomAmount == 0.f) { 2118 if (dist > zoomDist) { 2119 if ((dist -= 50.f) < zoomDist) { 2120 dist = zoomDist; 2121 } 2122 } 2123 } else { 2124 if ((sZoomAmount -= 30.f) < 0.f) { 2125 sZoomAmount = 0.f; 2126 } 2127 if (dist > zoomDist) { 2128 if ((dist -= 30.f) < zoomDist) { 2129 dist = zoomDist; 2130 } 2131 } 2132 if (dist < zoomDist) { 2133 if ((dist += 30.f) > zoomDist) { 2134 dist = zoomDist; 2135 } 2136 } 2137 } 2138 2139 // Determine how fast to rotate the camera 2140 if (sCSideButtonYaw == 0) { 2141 if (c->mode == CAMERA_MODE_FREE_ROAM) { 2142 nextYawVel = 0xC0; 2143 } else { 2144 nextYawVel = 0x100; 2145 } 2146 if ((gPlayer1Controller->stickX != 0.f || gPlayer1Controller->stickY != 0.f) != 0) { 2147 nextYawVel = 0x20; 2148 } 2149 } else { 2150 if (sCSideButtonYaw < 0) { 2151 yaw += 0x200; 2152 } 2153 if (sCSideButtonYaw > 0) { 2154 yaw -= 0x200; 2155 } 2156 camera_approach_s16_symmetric_bool(&sCSideButtonYaw, 0, 0x100); 2157 nextYawVel = 0; 2158 } 2159 sYawSpeed = 0x400; 2160 xzDist = calc_hor_dist(sMarioCamState->pos, c->pos); 2161 2162 if (sStatusFlags & CAM_FLAG_BEHIND_MARIO_POST_DOOR) { 2163 if (xzDist >= 250) { 2164 sStatusFlags &= ~CAM_FLAG_BEHIND_MARIO_POST_DOOR; 2165 } 2166 if (ABS((sMarioCamState->faceAngle[1] - yaw) / 2) < 0x1800) { 2167 sStatusFlags &= ~CAM_FLAG_BEHIND_MARIO_POST_DOOR; 2168 yaw = sCameraYawAfterDoorCutscene + DEGREES(180); 2169 dist = 800.f; 2170 sStatusFlags |= CAM_FLAG_BLOCK_SMOOTH_MOVEMENT; 2171 } 2172 } else if (xzDist < 250) { 2173 // Turn rapidly if very close to Mario 2174 c->pos[0] += (250 - xzDist) * sins(yaw); 2175 c->pos[2] += (250 - xzDist) * coss(yaw); 2176 if (sCSideButtonYaw == 0) { 2177 nextYawVel = 0x1000; 2178 sYawSpeed = 0; 2179 vec3f_get_dist_and_angle(sMarioCamState->pos, c->pos, &dist, &pitch, &yaw); 2180 } 2181 closeToMario |= 1; 2182 } 2183 2184 if (-16 < gPlayer1Controller->stickY) { 2185 c->yaw = yaw; 2186 } 2187 2188 calc_y_to_curr_floor(&posHeight, 1, 200, &focHeight, 0.9f, 200); 2189 vec3f_copy(cPos, c->pos); 2190 avoidStatus = rotate_camera_around_walls(c, cPos, &avoidYaw, 0x600); 2191 // If a wall is blocking the view of Mario, then rotate in the calculated direction 2192 if (avoidStatus == 3) { 2193 unusedFreeRoamWallYaw = avoidYaw; 2194 sAvoidYawVel = yaw; 2195 sStatusFlags |= CAM_FLAG_COLLIDED_WITH_WALL; 2196 //! Does nothing 2197 vec3f_get_dist_and_angle(sMarioCamState->pos, cPos, &xzDist, &tempPitch, &tempYaw); 2198 // Rotate to avoid the wall 2199 approach_s16_asymptotic_bool(&yaw, avoidYaw, 10); 2200 //! Does nothing 2201 vec3f_set_dist_and_angle(sMarioCamState->pos, cPos, xzDist, tempPitch, tempYaw); 2202 sAvoidYawVel = (sAvoidYawVel - yaw) / 0x100; 2203 } else { 2204 if (gMarioStates[0].forwardVel == 0.f) { 2205 if (sStatusFlags & CAM_FLAG_COLLIDED_WITH_WALL) { 2206 if ((yawGoal - yaw) / 0x100 >= 0) { 2207 yawDir = -1; 2208 } else { 2209 yawDir = 1; 2210 } 2211 if ((sAvoidYawVel > 0 && yawDir > 0) || (sAvoidYawVel < 0 && yawDir < 0)) { 2212 yawVel = nextYawVel; 2213 } 2214 } else { 2215 yawVel = nextYawVel; 2216 } 2217 } else { 2218 if (nextYawVel == 0x1000) { 2219 yawVel = nextYawVel; 2220 } 2221 sStatusFlags &= ~CAM_FLAG_COLLIDED_WITH_WALL; 2222 } 2223 2224 // If a wall is near the camera, turn twice as fast 2225 if (avoidStatus != 0) { 2226 yawVel += yawVel; 2227 } 2228 // ...Unless the camera already rotated from being close to Mario 2229 if ((closeToMario & 1) && avoidStatus != 0) { 2230 yawVel = 0; 2231 } 2232 if (yawVel != 0 && get_dialog_id() == DIALOG_NONE) { 2233 camera_approach_s16_symmetric_bool(&yaw, yawGoal, yawVel); 2234 } 2235 } 2236 2237 // Only zoom out if not obstructed by walls and Lakitu hasn't collided with any 2238 if (avoidStatus == 0 && !(sStatusFlags & CAM_FLAG_COLLIDED_WITH_WALL)) { 2239 approach_f32_asymptotic_bool(&dist, zoomDist - 100.f, 0.05f); 2240 } 2241 vec3f_set_dist_and_angle(sMarioCamState->pos, cPos, dist, pitch, yaw); 2242 cPos[1] += posHeight + 125.f; 2243 2244 // Move the camera away from walls and set the collision flag 2245 if (collide_with_walls(cPos, 10.f, 80.f) != 0) { 2246 sStatusFlags |= CAM_FLAG_COLLIDED_WITH_WALL; 2247 } 2248 2249 c->focus[0] = sMarioCamState->pos[0]; 2250 c->focus[1] = sMarioCamState->pos[1] + 125.f + focHeight; 2251 c->focus[2] = sMarioCamState->pos[2]; 2252 2253 marioFloorHeight = 125.f + sMarioGeometry.currFloorHeight; 2254 marioFloor = sMarioGeometry.currFloor; 2255 camFloorHeight = find_floor(cPos[0], cPos[1] + 50.f, cPos[2], &cFloor) + 125.f; 2256 for (scale = 0.1f; scale < 1.f; scale += 0.2f) { 2257 scale_along_line(tempPos, cPos, sMarioCamState->pos, scale); 2258 tempFloorHeight = find_floor(tempPos[0], tempPos[1], tempPos[2], &tempFloor) + 125.f; 2259 if (tempFloor != NULL && tempFloorHeight > marioFloorHeight) { 2260 marioFloorHeight = tempFloorHeight; 2261 marioFloor = tempFloor; 2262 } 2263 } 2264 2265 // Lower the camera in Mario mode 2266 if (sSelectionFlags & CAM_MODE_MARIO_ACTIVE) { 2267 marioFloorHeight -= 35.f; 2268 camFloorHeight -= 35.f; 2269 c->focus[1] -= 25.f; 2270 } 2271 2272 // If there's water below the camera, decide whether to keep the camera above the water surface 2273 waterHeight = find_water_level(cPos[0], cPos[2]); 2274 if (waterHeight != FLOOR_LOWER_LIMIT) { 2275 waterHeight += 125.f; 2276 distFromWater = waterHeight - marioFloorHeight; 2277 if (!(gCameraMovementFlags & CAM_MOVE_METAL_BELOW_WATER)) { 2278 if (distFromWater > 800.f && (sMarioCamState->action & ACT_FLAG_METAL_WATER)) { 2279 gCameraMovementFlags |= CAM_MOVE_METAL_BELOW_WATER; 2280 } 2281 } else { 2282 if (distFromWater < 400.f || !(sMarioCamState->action & ACT_FLAG_METAL_WATER)) { 2283 gCameraMovementFlags &= ~CAM_MOVE_METAL_BELOW_WATER; 2284 } 2285 } 2286 // If not wearing the metal cap, always stay above 2287 if (!(gCameraMovementFlags & CAM_MOVE_METAL_BELOW_WATER) && camFloorHeight < waterHeight) { 2288 camFloorHeight = waterHeight; 2289 } 2290 } else { 2291 gCameraMovementFlags &= ~CAM_MOVE_METAL_BELOW_WATER; 2292 } 2293 2294 cPos[1] = camFloorHeight; 2295 vec3f_copy(tempPos, cPos); 2296 tempPos[1] -= 125.f; 2297 if (marioFloor != NULL && camFloorHeight <= marioFloorHeight) { 2298 avoidStatus = is_range_behind_surface(c->focus, tempPos, marioFloor, 0, -1); 2299 if (avoidStatus != 1 && ceilHeight > marioFloorHeight) { 2300 camFloorHeight = marioFloorHeight; 2301 } 2302 } 2303 2304 posHeight = 0.f; 2305 if (c->mode == CAMERA_MODE_FREE_ROAM) { 2306 if (gCameraMovementFlags & CAM_MOVE_ZOOMED_OUT) { 2307 posHeight = 375.f; 2308 if (gCurrLevelArea == AREA_SSL_PYRAMID) { 2309 posHeight /= 2; 2310 } 2311 } else { 2312 posHeight = 100.f; 2313 } 2314 } 2315 if ((gCameraMovementFlags & CAM_MOVE_ZOOMED_OUT) && (sSelectionFlags & CAM_MODE_MARIO_ACTIVE)) { 2316 posHeight = 610.f; 2317 if (gCurrLevelArea == AREA_SSL_PYRAMID || gCurrLevelNum == LEVEL_CASTLE) { 2318 posHeight /= 2; 2319 } 2320 } 2321 2322 // Make Lakitu fly above the gas 2323 gasHeight = find_poison_gas_level(cPos[0], cPos[2]); 2324 if (gasHeight != FLOOR_LOWER_LIMIT) { 2325 if ((gasHeight += 130.f) > c->pos[1]) { 2326 c->pos[1] = gasHeight; 2327 } 2328 } 2329 2330 if (sMarioCamState->action & ACT_FLAG_HANGING || sMarioCamState->action == ACT_RIDING_HOOT) { 2331 camFloorHeight = sMarioCamState->pos[1] + 400.f; 2332 if (c->mode == CAMERA_MODE_FREE_ROAM) { 2333 camFloorHeight -= 100.f; 2334 } 2335 ceilHeight = CELL_HEIGHT_LIMIT; 2336 vec3f_copy(c->focus, sMarioCamState->pos); 2337 } 2338 2339 if (sMarioCamState->action & ACT_FLAG_ON_POLE) { 2340 camFloorHeight = gMarioStates[0].usedObj->oPosY + 125.f; 2341 if (sMarioCamState->pos[1] - 100.f > camFloorHeight) { 2342 camFloorHeight = sMarioCamState->pos[1] - 100.f; 2343 } 2344 ceilHeight = CELL_HEIGHT_LIMIT; 2345 vec3f_copy(c->focus, sMarioCamState->pos); 2346 } 2347 if (camFloorHeight != FLOOR_LOWER_LIMIT) { 2348 camFloorHeight += posHeight; 2349 approach_camera_height(c, camFloorHeight, 20.f); 2350 } 2351 c->pos[0] = cPos[0]; 2352 c->pos[2] = cPos[2]; 2353 cPos[0] = gLakituState.goalPos[0]; 2354 cPos[1] = c->pos[1]; 2355 cPos[2] = gLakituState.goalPos[2]; 2356 vec3f_get_dist_and_angle(cPos, c->pos, &dist, &tempPitch, &tempYaw); 2357 // Prevent the camera from lagging behind too much 2358 if (dist > 50.f) { 2359 dist = 50.f; 2360 vec3f_set_dist_and_angle(cPos, c->pos, dist, tempPitch, tempYaw); 2361 } 2362 if (sMarioGeometry.currFloorType != SURFACE_DEATH_PLANE) { 2363 vec3f_get_dist_and_angle(c->focus, c->pos, &dist, &tempPitch, &tempYaw); 2364 if (dist > zoomDist) { 2365 dist = zoomDist; 2366 vec3f_set_dist_and_angle(c->focus, c->pos, dist, tempPitch, tempYaw); 2367 } 2368 } 2369 if (ceilHeight != CELL_HEIGHT_LIMIT) { 2370 if (c->pos[1] > (ceilHeight -= 150.f) 2371 && (avoidStatus = is_range_behind_surface(c->pos, sMarioCamState->pos, ceil, 0, -1)) == 1) { 2372 c->pos[1] = ceilHeight; 2373 } 2374 } 2375 if (gCurrLevelArea == AREA_WDW_TOWN) { 2376 yaw = clamp_positions_and_find_yaw(c->pos, c->focus, 2254.f, -3789.f, 3790.f, -2253.f); 2377 } 2378 return yaw; 2379 } 2380 2381 /** 2382 * The default camera mode 2383 * Used by close and free roam modes 2384 */ 2385 void mode_default_camera(struct Camera *c) { 2386 set_fov_function(CAM_FOV_DEFAULT); 2387 c->nextYaw = update_default_camera(c); 2388 pan_ahead_of_player(c); 2389 } 2390 2391 /** 2392 * The mode used by close and free roam 2393 */ 2394 void mode_lakitu_camera(struct Camera *c) { 2395 gCameraZoomDist = 800.f; 2396 mode_default_camera(c); 2397 } 2398 2399 /** 2400 * When no other mode is active and the current R button mode is Mario 2401 */ 2402 void mode_mario_camera(struct Camera *c) { 2403 gCameraZoomDist = 350.f; 2404 mode_default_camera(c); 2405 } 2406 2407 /** 2408 * Rotates the camera around the spiral staircase. 2409 */ 2410 s32 update_spiral_stairs_camera(struct Camera *c, Vec3f focus, Vec3f pos) { 2411 UNUSED s16 unused; 2412 /// The returned yaw 2413 s16 camYaw; 2414 // unused 2415 s16 focPitch; 2416 /// The focus (Mario)'s yaw around the stairs 2417 s16 focYaw; 2418 // unused 2419 s16 posPitch; 2420 /// The camera's yaw around the stairs 2421 s16 posYaw; 2422 UNUSED u8 filler[4]; 2423 Vec3f cPos; 2424 Vec3f checkPos; 2425 struct Surface *floor; 2426 // unused 2427 f32 dist; 2428 f32 focusHeight; 2429 f32 floorHeight; 2430 f32 focY; 2431 2432 handle_c_button_movement(c); 2433 // Set base pos to the center of the staircase 2434 vec3f_set(sFixedModeBasePosition, -1280.f, 614.f, 1740.f); 2435 2436 // Focus on Mario, and move the focus up the staircase with him 2437 calc_y_to_curr_floor(&focusHeight, 1.f, 200.f, &focusHeight, 0.9f, 200.f); 2438 focus[0] = sMarioCamState->pos[0]; 2439 focY = sMarioCamState->pos[1] + 125.f + focusHeight; 2440 focus[2] = sMarioCamState->pos[2]; 2441 2442 vec3f_copy(cPos, pos); 2443 vec3f_get_dist_and_angle(sFixedModeBasePosition, focus, &dist, &focPitch, &focYaw); 2444 vec3f_get_dist_and_angle(sFixedModeBasePosition, cPos, &dist, &posPitch, &posYaw); 2445 2446 sSpiralStairsYawOffset = posYaw - focYaw; 2447 // posYaw will change if Mario is more than 90 degrees around the stairs, relative to the camera 2448 if (sSpiralStairsYawOffset < DEGREES(-90)) { 2449 sSpiralStairsYawOffset = DEGREES(-90); 2450 } 2451 if (sSpiralStairsYawOffset > DEGREES(90)) { 2452 sSpiralStairsYawOffset = DEGREES(90); 2453 } 2454 focYaw += sSpiralStairsYawOffset; 2455 posYaw = focYaw; 2456 //! @bug unnecessary 2457 camera_approach_s16_symmetric_bool(&posYaw, focYaw, 0x1000); 2458 2459 vec3f_set_dist_and_angle(sFixedModeBasePosition, cPos, 300.f, 0, posYaw); 2460 2461 // Move the camera's y coord up/down the staircase 2462 checkPos[0] = focus[0] + (cPos[0] - focus[0]) * 0.7f; 2463 checkPos[1] = focus[1] + (cPos[1] - focus[1]) * 0.7f + 300.f; 2464 checkPos[2] = focus[2] + (cPos[2] - focus[2]) * 0.7f; 2465 floorHeight = find_floor(checkPos[0], checkPos[1] + 50.f, checkPos[2], &floor); 2466 2467 if (floorHeight != FLOOR_LOWER_LIMIT) { 2468 if (floorHeight < sMarioGeometry.currFloorHeight) { 2469 floorHeight = sMarioGeometry.currFloorHeight; 2470 } 2471 pos[1] = approach_f32(pos[1], (floorHeight += 125.f), 30.f, 30.f); 2472 } 2473 2474 camera_approach_f32_symmetric_bool(&focus[1], focY, 30.f); 2475 pos[0] = cPos[0]; 2476 pos[2] = cPos[2]; 2477 camYaw = calculate_yaw(focus, pos); 2478 2479 return camYaw; 2480 } 2481 2482 /** 2483 * The mode used in the spiral staircase in the castle 2484 */ 2485 void mode_spiral_stairs_camera(struct Camera *c) { 2486 c->nextYaw = update_spiral_stairs_camera(c, c->focus, c->pos); 2487 } 2488 2489 s32 update_slide_or_0f_camera(UNUSED struct Camera *c, Vec3f focus, Vec3f pos) { 2490 s16 yaw = sMarioCamState->faceAngle[1] + sModeOffsetYaw + DEGREES(180); 2491 2492 focus_on_mario(focus, pos, 125.f, 125.f, 800.f, 5461, yaw); 2493 return sMarioCamState->faceAngle[1]; 2494 } 2495 2496 static UNUSED void unused_mode_0f_camera(struct Camera *c) { 2497 if (gPlayer1Controller->buttonPressed & U_CBUTTONS) { 2498 gCameraMovementFlags |= CAM_MOVE_C_UP_MODE; 2499 } 2500 c->nextYaw = update_slide_camera(c); 2501 } 2502 2503 /** 2504 * Slide/hoot mode. 2505 * In this mode, the camera is always at the back of Mario, because Mario generally only moves forward. 2506 */ 2507 void mode_slide_camera(struct Camera *c) { 2508 if (sMarioGeometry.currFloorType == SURFACE_CLOSE_CAMERA || 2509 sMarioGeometry.currFloorType == SURFACE_NO_CAM_COL_SLIPPERY) { 2510 mode_lakitu_camera(c); 2511 } else { 2512 if (gPlayer1Controller->buttonPressed & U_CBUTTONS) { 2513 gCameraMovementFlags |= CAM_MOVE_C_UP_MODE; 2514 } 2515 c->nextYaw = update_slide_camera(c); 2516 } 2517 } 2518 2519 void store_lakitu_cam_info_for_c_up(struct Camera *c) { 2520 vec3f_copy(sCameraStoreCUp.pos, c->pos); 2521 vec3f_sub(sCameraStoreCUp.pos, sMarioCamState->pos); 2522 // Only store the y value, and as an offset from Mario, for some reason 2523 vec3f_set(sCameraStoreCUp.focus, 0.f, c->focus[1] - sMarioCamState->pos[1], 0.f); 2524 } 2525 2526 /** 2527 * Start C-Up mode. The actual mode change is handled in update_mario_inputs() in mario.c 2528 * 2529 * @see update_mario_inputs 2530 */ 2531 s32 set_mode_c_up(struct Camera *c) { 2532 if (!(gCameraMovementFlags & CAM_MOVE_C_UP_MODE)) { 2533 gCameraMovementFlags |= CAM_MOVE_C_UP_MODE; 2534 store_lakitu_cam_info_for_c_up(c); 2535 sCameraSoundFlags &= ~CAM_SOUND_C_UP_PLAYED; 2536 return 1; 2537 } 2538 return 0; 2539 } 2540 2541 /** 2542 * Zoom the camera out of C-Up mode, avoiding moving into a wall, if possible, by searching for an open 2543 * direction. 2544 */ 2545 s32 exit_c_up(struct Camera *c) { 2546 struct Surface *surface; 2547 Vec3f checkFoc; 2548 Vec3f curPos; 2549 // Variables for searching for an open direction 2550 s32 searching = 0; 2551 /// The current sector of the circle that we are checking 2552 s32 sector; 2553 f32 ceilHeight; 2554 f32 floorHeight; 2555 f32 curDist; 2556 f32 d; 2557 s16 curPitch; 2558 s16 curYaw; 2559 s16 checkYaw = 0; 2560 Vec3f storePos; // unused 2561 Vec3f storeFoc; // unused 2562 2563 if ((gCameraMovementFlags & CAM_MOVE_C_UP_MODE) && !(gCameraMovementFlags & CAM_MOVE_STARTED_EXITING_C_UP)) { 2564 // Copy the stored pos and focus. This is unused. 2565 vec3f_copy(storePos, sCameraStoreCUp.pos); 2566 vec3f_add(storePos, sMarioCamState->pos); 2567 vec3f_copy(storeFoc, sCameraStoreCUp.focus); 2568 vec3f_add(storeFoc, sMarioCamState->pos); 2569 2570 vec3f_copy(checkFoc, c->focus); 2571 checkFoc[0] = sMarioCamState->pos[0]; 2572 checkFoc[2] = sMarioCamState->pos[2]; 2573 vec3f_get_dist_and_angle(checkFoc, c->pos, &curDist, &curPitch, &curYaw); 2574 vec3f_copy(curPos, c->pos); 2575 curDist = 80.f; 2576 2577 // Search for an open direction to zoom out in, if the camera is changing to close, free roam, 2578 // or spiral-stairs mode 2579 if (sModeInfo.lastMode == CAMERA_MODE_SPIRAL_STAIRS || sModeInfo.lastMode == CAMERA_MODE_CLOSE 2580 || sModeInfo.lastMode == CAMERA_MODE_FREE_ROAM) { 2581 searching = 1; 2582 // Check the whole circle around Mario for an open direction to zoom out to 2583 for (sector = 0; sector < 16 && searching == 1; sector++) { 2584 vec3f_set_dist_and_angle(checkFoc, curPos, curDist, 0, curYaw + checkYaw); 2585 2586 // If there are no walls this way, 2587 if (f32_find_wall_collision(&curPos[0], &curPos[1], &curPos[2], 20.f, 50.f) == 0) { 2588 2589 // Start close to Mario, check for walls, floors, and ceilings all the way to the 2590 // zoomed out distance 2591 for (d = curDist; d < gCameraZoomDist; d += 20.f) { 2592 vec3f_set_dist_and_angle(checkFoc, curPos, d, 0, curYaw + checkYaw); 2593 2594 // Check if we're zooming out into a floor or ceiling 2595 ceilHeight = find_ceil(curPos[0], curPos[1] - 150.f, curPos[2], &surface) + -10.f; 2596 if (surface != NULL && ceilHeight < curPos[1]) { 2597 break; 2598 } 2599 floorHeight = find_floor(curPos[0], curPos[1] + 150.f, curPos[2], &surface) + 10.f; 2600 if (surface != NULL && floorHeight > curPos[1]) { 2601 break; 2602 } 2603 2604 // Stop checking this direction if there is a wall blocking the way 2605 if (f32_find_wall_collision(&curPos[0], &curPos[1], &curPos[2], 20.f, 50.f) == 1) { 2606 break; 2607 } 2608 } 2609 2610 // If there was no collision found all the way to the max distance, it's an opening 2611 if (d >= gCameraZoomDist) { 2612 searching = 0; 2613 } 2614 } 2615 2616 // Alternate left and right, checking each 1/16th (22.5 degrees) of the circle 2617 if (searching == 1) { 2618 checkYaw = -checkYaw; 2619 if (checkYaw < 0) { 2620 checkYaw -= 0x1000; 2621 } else { 2622 checkYaw += 0x1000; 2623 } 2624 } 2625 } 2626 2627 // Update the stored focus and pos to the direction found in the search 2628 if (searching == 0) { 2629 vec3f_set_dist_and_angle(checkFoc, sCameraStoreCUp.pos, gCameraZoomDist, 0, curYaw + checkYaw); 2630 vec3f_copy(sCameraStoreCUp.focus, checkFoc); 2631 vec3f_sub(sCameraStoreCUp.pos, sMarioCamState->pos); 2632 vec3f_sub(sCameraStoreCUp.focus, sMarioCamState->pos); 2633 } 2634 2635 gCameraMovementFlags |= CAM_MOVE_STARTED_EXITING_C_UP; 2636 transition_next_state(c, 15); 2637 } else { 2638 // Let the next camera mode handle it 2639 gCameraMovementFlags &= ~(CAM_MOVE_STARTED_EXITING_C_UP | CAM_MOVE_C_UP_MODE); 2640 vec3f_set_dist_and_angle(checkFoc, c->pos, curDist, curPitch, curYaw + checkYaw); 2641 } 2642 play_sound_cbutton_down(); 2643 } 2644 return 0; 2645 } 2646 2647 /** 2648 * The mode used when C-Up is pressed. 2649 */ 2650 s32 update_c_up(UNUSED struct Camera *c, Vec3f focus, Vec3f pos) { 2651 s16 pitch = sCUpCameraPitch; 2652 s16 yaw = sMarioCamState->faceAngle[1] + sModeOffsetYaw + DEGREES(180); 2653 2654 focus_on_mario(focus, pos, 125.f, 125.f, 250.f, pitch, yaw); 2655 return sMarioCamState->faceAngle[1]; 2656 } 2657 2658 /** 2659 * Make Mario's head move in C-Up mode. 2660 */ 2661 void move_mario_head_c_up(UNUSED struct Camera *c) { 2662 UNUSED s16 pitch = sCUpCameraPitch; 2663 UNUSED s16 yaw = sModeOffsetYaw; 2664 2665 sCUpCameraPitch += (s16)(gPlayer1Controller->stickY * 10.f); 2666 sModeOffsetYaw -= (s16)(gPlayer1Controller->stickX * 10.f); 2667 2668 // Bound looking up to nearly 80 degrees. 2669 if (sCUpCameraPitch > 0x38E3) { 2670 sCUpCameraPitch = 0x38E3; 2671 } 2672 // Bound looking down to -45 degrees 2673 if (sCUpCameraPitch < -0x2000) { 2674 sCUpCameraPitch = -0x2000; 2675 } 2676 2677 // Bound the camera yaw to +-120 degrees 2678 if (sModeOffsetYaw > 0x5555) { 2679 sModeOffsetYaw = 0x5555; 2680 } 2681 if (sModeOffsetYaw < -0x5555) { 2682 sModeOffsetYaw = -0x5555; 2683 } 2684 2685 // Give Mario's neck natural-looking constraints 2686 sMarioCamState->headRotation[0] = sCUpCameraPitch * 3 / 4; 2687 sMarioCamState->headRotation[1] = sModeOffsetYaw * 3 / 4; 2688 } 2689 2690 /** 2691 * Zooms the camera in for C-Up mode 2692 */ 2693 void move_into_c_up(struct Camera *c) { 2694 struct LinearTransitionPoint *start = &sModeInfo.transitionStart; 2695 struct LinearTransitionPoint *end = &sModeInfo.transitionEnd; 2696 2697 f32 dist = end->dist - start->dist; 2698 s16 pitch = end->pitch - start->pitch; 2699 s16 yaw = end->yaw - start->yaw; 2700 2701 // Linearly interpolate from start to end position's polar coordinates 2702 dist = start->dist + dist * sModeInfo.frame / sModeInfo.max; 2703 pitch = start->pitch + pitch * sModeInfo.frame / sModeInfo.max; 2704 yaw = start->yaw + yaw * sModeInfo.frame / sModeInfo.max; 2705 2706 // Linearly interpolate the focus from start to end 2707 c->focus[0] = start->focus[0] + (end->focus[0] - start->focus[0]) * sModeInfo.frame / sModeInfo.max; 2708 c->focus[1] = start->focus[1] + (end->focus[1] - start->focus[1]) * sModeInfo.frame / sModeInfo.max; 2709 c->focus[2] = start->focus[2] + (end->focus[2] - start->focus[2]) * sModeInfo.frame / sModeInfo.max; 2710 2711 vec3f_add(c->focus, sMarioCamState->pos); 2712 vec3f_set_dist_and_angle(c->focus, c->pos, dist, pitch, yaw); 2713 2714 sMarioCamState->headRotation[0] = 0; 2715 sMarioCamState->headRotation[1] = 0; 2716 2717 // Finished zooming in 2718 if (++sModeInfo.frame == sModeInfo.max) { 2719 gCameraMovementFlags &= ~CAM_MOVING_INTO_MODE; 2720 } 2721 } 2722 2723 /** 2724 * The main update function for C-Up mode 2725 */ 2726 s32 mode_c_up_camera(struct Camera *c) { 2727 UNUSED u8 filler[12]; 2728 2729 // Play a sound when entering C-Up mode 2730 if (!(sCameraSoundFlags & CAM_SOUND_C_UP_PLAYED)) { 2731 play_sound_cbutton_up(); 2732 sCameraSoundFlags |= CAM_SOUND_C_UP_PLAYED; 2733 } 2734 2735 // Zoom in first 2736 if (gCameraMovementFlags & CAM_MOVING_INTO_MODE) { 2737 gCameraMovementFlags |= CAM_MOVE_C_UP_MODE; 2738 move_into_c_up(c); 2739 return 1; 2740 } 2741 2742 if (!(gCameraMovementFlags & CAM_MOVE_STARTED_EXITING_C_UP)) { 2743 // Normal update 2744 move_mario_head_c_up(c); 2745 update_c_up(c, c->focus, c->pos); 2746 } else { 2747 // Exiting C-Up 2748 if (sStatusFlags & CAM_FLAG_TRANSITION_OUT_OF_C_UP) { 2749 // Retrieve the previous position and focus 2750 vec3f_copy(c->pos, sCameraStoreCUp.pos); 2751 vec3f_add(c->pos, sMarioCamState->pos); 2752 vec3f_copy(c->focus, sCameraStoreCUp.focus); 2753 vec3f_add(c->focus, sMarioCamState->pos); 2754 // Make Mario look forward 2755 camera_approach_s16_symmetric_bool(&sMarioCamState->headRotation[0], 0, 1024); 2756 camera_approach_s16_symmetric_bool(&sMarioCamState->headRotation[1], 0, 1024); 2757 } else { 2758 // Finished exiting C-Up 2759 gCameraMovementFlags &= ~(CAM_MOVE_STARTED_EXITING_C_UP | CAM_MOVE_C_UP_MODE); 2760 } 2761 } 2762 sPanDistance = 0.f; 2763 2764 // Exit C-Up mode 2765 if (gPlayer1Controller->buttonPressed & (A_BUTTON | B_BUTTON | D_CBUTTONS | L_CBUTTONS | R_CBUTTONS)) { 2766 exit_c_up(c); 2767 } 2768 return 0; 2769 } 2770 2771 /** 2772 * Used when Mario is in a cannon. 2773 */ 2774 s32 update_in_cannon(UNUSED struct Camera *c, Vec3f focus, Vec3f pos) { 2775 focus_on_mario(pos, focus, 125.f + sCannonYOffset, 125.f, 800.f, 2776 sMarioCamState->faceAngle[0], sMarioCamState->faceAngle[1]); 2777 return sMarioCamState->faceAngle[1]; 2778 } 2779 2780 /** 2781 * Updates the camera when Mario is in a cannon. 2782 * sCannonYOffset is used to make the camera rotate down when Mario has just entered the cannon 2783 */ 2784 void mode_cannon_camera(struct Camera *c) { 2785 UNUSED u8 filler[24]; 2786 2787 sLakituPitch = 0; 2788 gCameraMovementFlags &= ~CAM_MOVING_INTO_MODE; 2789 c->nextYaw = update_in_cannon(c, c->focus, c->pos); 2790 if (gPlayer1Controller->buttonPressed & A_BUTTON) { 2791 set_camera_mode(c, CAMERA_MODE_BEHIND_MARIO, 1); 2792 sPanDistance = 0.f; 2793 sCannonYOffset = 0.f; 2794 sStatusFlags &= ~CAM_FLAG_BLOCK_SMOOTH_MOVEMENT; 2795 } else { 2796 sCannonYOffset = approach_f32(sCannonYOffset, 0.f, 100.f, 100.f); 2797 } 2798 } 2799 2800 /** 2801 * Cause Lakitu to fly to the next Camera position and focus over a number of frames. 2802 * 2803 * At the end of each frame, Lakitu's position and focus ("state") are stored. 2804 * Calling this function makes next_lakitu_state() fly from the last frame's state to the 2805 * current frame's calculated state. 2806 * 2807 * @see next_lakitu_state() 2808 */ 2809 void transition_next_state(UNUSED struct Camera *c, s16 frames) { 2810 if (!(sStatusFlags & CAM_FLAG_FRAME_AFTER_CAM_INIT)) { 2811 sStatusFlags |= (CAM_FLAG_START_TRANSITION | CAM_FLAG_TRANSITION_OUT_OF_C_UP); 2812 sModeTransition.framesLeft = frames; 2813 } 2814 } 2815 2816 /** 2817 * Sets the camera mode to `newMode` and initializes sModeTransition with `numFrames` frames 2818 * 2819 * Used to change the camera mode to 'level-oriented' modes 2820 * namely: RADIAL/OUTWARD_RADIAL, 8_DIRECTIONS, FREE_ROAM, CLOSE, SPIRAL_STAIRS, and SLIDE_HOOT 2821 */ 2822 void transition_to_camera_mode(struct Camera *c, s16 newMode, s16 numFrames) { 2823 if (c->mode != newMode) { 2824 sModeInfo.newMode = (newMode != -1) ? newMode : sModeInfo.lastMode; 2825 sModeInfo.lastMode = c->mode; 2826 c->mode = sModeInfo.newMode; 2827 2828 // Clear movement flags that would affect the transition 2829 gCameraMovementFlags &= (u16)~(CAM_MOVE_RESTRICT | CAM_MOVE_ROTATE); 2830 if (!(sStatusFlags & CAM_FLAG_FRAME_AFTER_CAM_INIT)) { 2831 transition_next_state(c, numFrames); 2832 sCUpCameraPitch = 0; 2833 sModeOffsetYaw = 0; 2834 sLakituDist = 0; 2835 sLakituPitch = 0; 2836 sAreaYawChange = 0; 2837 sPanDistance = 0.f; 2838 sCannonYOffset = 0.f; 2839 } 2840 } 2841 } 2842 2843 /** 2844 * Used to change the camera mode between its default/previous and certain Mario-oriented modes, 2845 * namely: C_UP, WATER_SURFACE, CLOSE, and BEHIND_MARIO 2846 * 2847 * Stores the current pos and focus in sModeInfo->transitionStart, and 2848 * stores the next pos and focus into sModeInfo->transitionEnd. These two fields are used in 2849 * move_into_c_up(). 2850 * 2851 * @param mode the mode to change to, or -1 to switch to the previous mode 2852 * @param frames number of frames the transition should last, only used when entering C_UP 2853 */ 2854 void set_camera_mode(struct Camera *c, s16 mode, s16 frames) { 2855 struct LinearTransitionPoint *start = &sModeInfo.transitionStart; 2856 struct LinearTransitionPoint *end = &sModeInfo.transitionEnd; 2857 2858 if (mode == CAMERA_MODE_WATER_SURFACE && gCurrLevelArea == AREA_TTM_OUTSIDE) { 2859 } else { 2860 // Clear movement flags that would affect the transition 2861 gCameraMovementFlags &= (u16)~(CAM_MOVE_RESTRICT | CAM_MOVE_ROTATE); 2862 gCameraMovementFlags |= CAM_MOVING_INTO_MODE; 2863 if (mode == CAMERA_MODE_NONE) { 2864 mode = CAMERA_MODE_CLOSE; 2865 } 2866 sCUpCameraPitch = 0; 2867 sModeOffsetYaw = 0; 2868 sLakituDist = 0; 2869 sLakituPitch = 0; 2870 sAreaYawChange = 0; 2871 2872 sModeInfo.newMode = (mode != -1) ? mode : sModeInfo.lastMode; 2873 sModeInfo.lastMode = c->mode; 2874 sModeInfo.max = frames; 2875 sModeInfo.frame = 1; 2876 2877 c->mode = sModeInfo.newMode; 2878 gLakituState.mode = c->mode; 2879 2880 vec3f_copy(end->focus, c->focus); 2881 vec3f_sub(end->focus, sMarioCamState->pos); 2882 2883 vec3f_copy(end->pos, c->pos); 2884 vec3f_sub(end->pos, sMarioCamState->pos); 2885 2886 sAreaYaw = sModeTransitions[sModeInfo.newMode](c, end->focus, end->pos); 2887 2888 // End was updated by sModeTransitions 2889 vec3f_sub(end->focus, sMarioCamState->pos); 2890 vec3f_sub(end->pos, sMarioCamState->pos); 2891 2892 vec3f_copy(start->focus, gLakituState.curFocus); 2893 vec3f_sub(start->focus, sMarioCamState->pos); 2894 2895 vec3f_copy(start->pos, gLakituState.curPos); 2896 vec3f_sub(start->pos, sMarioCamState->pos); 2897 2898 vec3f_get_dist_and_angle(start->focus, start->pos, &start->dist, &start->pitch, &start->yaw); 2899 vec3f_get_dist_and_angle(end->focus, end->pos, &end->dist, &end->pitch, &end->yaw); 2900 } 2901 } 2902 2903 /** 2904 * Updates Lakitu's position/focus and applies camera shakes. 2905 */ 2906 void update_lakitu(struct Camera *c) { 2907 struct Surface *floor = NULL; 2908 Vec3f newPos; 2909 Vec3f newFoc; 2910 UNUSED u8 filler1[12]; 2911 f32 distToFloor; 2912 s16 newYaw; 2913 UNUSED u8 filler2[8]; 2914 2915 if (gCameraMovementFlags & CAM_MOVE_PAUSE_SCREEN) { 2916 } else { 2917 if (c->cutscene) { 2918 } 2919 if (TRUE) { 2920 newYaw = next_lakitu_state(newPos, newFoc, c->pos, c->focus, sOldPosition, sOldFocus, 2921 c->nextYaw); 2922 set_or_approach_s16_symmetric(&c->yaw, newYaw, sYawSpeed); 2923 sStatusFlags &= ~CAM_FLAG_UNUSED_CUTSCENE_ACTIVE; 2924 } else { 2925 //! dead code, moved to next_lakitu_state() 2926 vec3f_copy(newPos, c->pos); 2927 vec3f_copy(newFoc, c->focus); 2928 } 2929 2930 // Update old state 2931 vec3f_copy(sOldPosition, newPos); 2932 vec3f_copy(sOldFocus, newFoc); 2933 2934 gLakituState.yaw = c->yaw; 2935 gLakituState.nextYaw = c->nextYaw; 2936 vec3f_copy(gLakituState.goalPos, c->pos); 2937 vec3f_copy(gLakituState.goalFocus, c->focus); 2938 2939 // Simulate Lakitu flying to the new position and turning towards the new focus 2940 set_or_approach_vec3f_asymptotic(gLakituState.curPos, newPos, 2941 gLakituState.posHSpeed, gLakituState.posVSpeed, 2942 gLakituState.posHSpeed); 2943 set_or_approach_vec3f_asymptotic(gLakituState.curFocus, newFoc, 2944 gLakituState.focHSpeed, gLakituState.focVSpeed, 2945 gLakituState.focHSpeed); 2946 // Adjust Lakitu's speed back to normal 2947 set_or_approach_f32_asymptotic(&gLakituState.focHSpeed, 0.8f, 0.05f); 2948 set_or_approach_f32_asymptotic(&gLakituState.focVSpeed, 0.3f, 0.05f); 2949 set_or_approach_f32_asymptotic(&gLakituState.posHSpeed, 0.3f, 0.05f); 2950 set_or_approach_f32_asymptotic(&gLakituState.posVSpeed, 0.3f, 0.05f); 2951 2952 // Turn on smooth movement when it hasn't been blocked for 2 frames 2953 if (sStatusFlags & CAM_FLAG_BLOCK_SMOOTH_MOVEMENT) { 2954 sStatusFlags &= ~CAM_FLAG_BLOCK_SMOOTH_MOVEMENT; 2955 } else { 2956 sStatusFlags |= CAM_FLAG_SMOOTH_MOVEMENT; 2957 } 2958 2959 vec3f_copy(gLakituState.pos, gLakituState.curPos); 2960 vec3f_copy(gLakituState.focus, gLakituState.curFocus); 2961 2962 if (c->cutscene) { 2963 vec3f_add(gLakituState.focus, sPlayer2FocusOffset); 2964 vec3f_set(sPlayer2FocusOffset, 0, 0, 0); 2965 } 2966 2967 vec3f_get_dist_and_angle(gLakituState.pos, gLakituState.focus, &gLakituState.focusDistance, 2968 &gLakituState.oldPitch, &gLakituState.oldYaw); 2969 2970 gLakituState.roll = 0; 2971 2972 // Apply camera shakes 2973 shake_camera_pitch(gLakituState.pos, gLakituState.focus); 2974 shake_camera_yaw(gLakituState.pos, gLakituState.focus); 2975 shake_camera_roll(&gLakituState.roll); 2976 shake_camera_handheld(gLakituState.pos, gLakituState.focus); 2977 2978 if (sMarioCamState->action == ACT_DIVE && gLakituState.lastFrameAction != ACT_DIVE) { 2979 set_camera_shake_from_hit(SHAKE_HIT_FROM_BELOW); 2980 } 2981 2982 gLakituState.roll += sHandheldShakeRoll; 2983 gLakituState.roll += gLakituState.keyDanceRoll; 2984 2985 if (c->mode != CAMERA_MODE_C_UP && c->cutscene == 0) { 2986 gCheckingSurfaceCollisionsForCamera = TRUE; 2987 distToFloor = find_floor(gLakituState.pos[0], 2988 gLakituState.pos[1] + 20.0f, 2989 gLakituState.pos[2], &floor); 2990 if (distToFloor != FLOOR_LOWER_LIMIT) { 2991 if (gLakituState.pos[1] < (distToFloor += 100.0f)) { 2992 gLakituState.pos[1] = distToFloor; 2993 } else { 2994 gCheckingSurfaceCollisionsForCamera = FALSE; 2995 } 2996 } 2997 } 2998 2999 vec3f_copy(sModeTransition.marioPos, sMarioCamState->pos); 3000 } 3001 clamp_pitch(gLakituState.pos, gLakituState.focus, 0x3E00, -0x3E00); 3002 gLakituState.mode = c->mode; 3003 gLakituState.defMode = c->defMode; 3004 } 3005 3006 3007 /** 3008 * The main camera update function. 3009 * Gets controller input, checks for cutscenes, handles mode changes, and moves the camera 3010 */ 3011 void update_camera(struct Camera *c) { 3012 UNUSED u8 filler[24]; 3013 3014 gCamera = c; 3015 update_camera_hud_status(c); 3016 if (c->cutscene == 0) { 3017 // Only process R_TRIG if 'fixed' is not selected in the menu 3018 if (cam_select_alt_mode(0) == CAM_SELECTION_MARIO) { 3019 if (gPlayer1Controller->buttonPressed & R_TRIG) { 3020 if (set_cam_angle(0) == CAM_ANGLE_LAKITU) { 3021 set_cam_angle(CAM_ANGLE_MARIO); 3022 } else { 3023 set_cam_angle(CAM_ANGLE_LAKITU); 3024 } 3025 } 3026 } 3027 play_sound_if_cam_switched_to_lakitu_or_mario(); 3028 } 3029 3030 // Initialize the camera 3031 sStatusFlags &= ~CAM_FLAG_FRAME_AFTER_CAM_INIT; 3032 if (gCameraMovementFlags & CAM_MOVE_INIT_CAMERA) { 3033 init_camera(c); 3034 gCameraMovementFlags &= ~CAM_MOVE_INIT_CAMERA; 3035 sStatusFlags |= CAM_FLAG_FRAME_AFTER_CAM_INIT; 3036 } 3037 3038 // Store previous geometry information 3039 sMarioGeometry.prevFloorHeight = sMarioGeometry.currFloorHeight; 3040 sMarioGeometry.prevCeilHeight = sMarioGeometry.currCeilHeight; 3041 sMarioGeometry.prevFloor = sMarioGeometry.currFloor; 3042 sMarioGeometry.prevCeil = sMarioGeometry.currCeil; 3043 sMarioGeometry.prevFloorType = sMarioGeometry.currFloorType; 3044 sMarioGeometry.prevCeilType = sMarioGeometry.currCeilType; 3045 3046 find_mario_floor_and_ceil(&sMarioGeometry); 3047 gCheckingSurfaceCollisionsForCamera = TRUE; 3048 vec3f_copy(c->pos, gLakituState.goalPos); 3049 vec3f_copy(c->focus, gLakituState.goalFocus); 3050 3051 c->yaw = gLakituState.yaw; 3052 c->nextYaw = gLakituState.nextYaw; 3053 c->mode = gLakituState.mode; 3054 c->defMode = gLakituState.defMode; 3055 3056 camera_course_processing(c); 3057 stub_camera_3(c); 3058 sCButtonsPressed = find_c_buttons_pressed(sCButtonsPressed, gPlayer1Controller->buttonPressed, 3059 gPlayer1Controller->buttonDown); 3060 3061 if (c->cutscene != 0) { 3062 sYawSpeed = 0; 3063 play_cutscene(c); 3064 sFramesSinceCutsceneEnded = 0; 3065 } else { 3066 // Clear the recent cutscene after 8 frames 3067 if (gRecentCutscene != 0 && sFramesSinceCutsceneEnded < 8) { 3068 sFramesSinceCutsceneEnded++; 3069 if (sFramesSinceCutsceneEnded >= 8) { 3070 gRecentCutscene = 0; 3071 sFramesSinceCutsceneEnded = 0; 3072 } 3073 } 3074 } 3075 // If not in a cutscene, do mode processing 3076 if (c->cutscene == 0) { 3077 sYawSpeed = 0x400; 3078 3079 if (sSelectionFlags & CAM_MODE_MARIO_ACTIVE) { 3080 switch (c->mode) { 3081 case CAMERA_MODE_BEHIND_MARIO: 3082 mode_behind_mario_camera(c); 3083 break; 3084 3085 case CAMERA_MODE_C_UP: 3086 mode_c_up_camera(c); 3087 break; 3088 3089 case CAMERA_MODE_WATER_SURFACE: 3090 mode_water_surface_camera(c); 3091 break; 3092 3093 case CAMERA_MODE_INSIDE_CANNON: 3094 mode_cannon_camera(c); 3095 break; 3096 3097 default: 3098 mode_mario_camera(c); 3099 } 3100 } else { 3101 switch (c->mode) { 3102 case CAMERA_MODE_BEHIND_MARIO: 3103 mode_behind_mario_camera(c); 3104 break; 3105 3106 case CAMERA_MODE_C_UP: 3107 mode_c_up_camera(c); 3108 break; 3109 3110 case CAMERA_MODE_WATER_SURFACE: 3111 mode_water_surface_camera(c); 3112 break; 3113 3114 case CAMERA_MODE_INSIDE_CANNON: 3115 mode_cannon_camera(c); 3116 break; 3117 3118 case CAMERA_MODE_8_DIRECTIONS: 3119 mode_8_directions_camera(c); 3120 break; 3121 3122 case CAMERA_MODE_RADIAL: 3123 mode_radial_camera(c); 3124 break; 3125 3126 case CAMERA_MODE_OUTWARD_RADIAL: 3127 mode_outward_radial_camera(c); 3128 break; 3129 3130 case CAMERA_MODE_CLOSE: 3131 mode_lakitu_camera(c); 3132 break; 3133 3134 case CAMERA_MODE_FREE_ROAM: 3135 mode_lakitu_camera(c); 3136 break; 3137 case CAMERA_MODE_BOSS_FIGHT: 3138 mode_boss_fight_camera(c); 3139 break; 3140 3141 case CAMERA_MODE_PARALLEL_TRACKING: 3142 mode_parallel_tracking_camera(c); 3143 break; 3144 3145 case CAMERA_MODE_SLIDE_HOOT: 3146 mode_slide_camera(c); 3147 break; 3148 3149 case CAMERA_MODE_FIXED: 3150 mode_fixed_camera(c); 3151 break; 3152 3153 case CAMERA_MODE_SPIRAL_STAIRS: 3154 mode_spiral_stairs_camera(c); 3155 break; 3156 } 3157 } 3158 } 3159 // Start any Mario-related cutscenes 3160 start_cutscene(c, get_cutscene_from_mario_status(c)); 3161 stub_camera_2(c); 3162 gCheckingSurfaceCollisionsForCamera = FALSE; 3163 if (gCurrLevelNum != LEVEL_CASTLE) { 3164 // If fixed camera is selected as the alternate mode, then fix the camera as long as the right 3165 // trigger is held 3166 if ((c->cutscene == 0 && 3167 (gPlayer1Controller->buttonDown & R_TRIG) && cam_select_alt_mode(0) == CAM_SELECTION_FIXED) 3168 || (gCameraMovementFlags & CAM_MOVE_FIX_IN_PLACE) 3169 || (sMarioCamState->action) == ACT_GETTING_BLOWN) { 3170 3171 // If this is the first frame that R_TRIG is held, play the "click" sound 3172 if (c->cutscene == 0 && (gPlayer1Controller->buttonPressed & R_TRIG) 3173 && cam_select_alt_mode(0) == CAM_SELECTION_FIXED) { 3174 sCameraSoundFlags |= CAM_SOUND_FIXED_ACTIVE; 3175 play_sound_rbutton_changed(); 3176 } 3177 3178 // Fixed mode only prevents Lakitu from moving. The camera pos still updates, so 3179 // Lakitu will fly to his next position as normal whenever R_TRIG is released. 3180 gLakituState.posHSpeed = 0.f; 3181 gLakituState.posVSpeed = 0.f; 3182 3183 c->nextYaw = calculate_yaw(gLakituState.focus, gLakituState.pos); 3184 c->yaw = c->nextYaw; 3185 gCameraMovementFlags &= ~CAM_MOVE_FIX_IN_PLACE; 3186 } else { 3187 // Play the "click" sound when fixed mode is released 3188 if (sCameraSoundFlags & CAM_SOUND_FIXED_ACTIVE) { 3189 play_sound_rbutton_changed(); 3190 sCameraSoundFlags &= ~CAM_SOUND_FIXED_ACTIVE; 3191 } 3192 } 3193 } else { 3194 if ((gPlayer1Controller->buttonPressed & R_TRIG) && cam_select_alt_mode(0) == CAM_SELECTION_FIXED) { 3195 play_sound_button_change_blocked(); 3196 } 3197 } 3198 3199 update_lakitu(c); 3200 3201 gLakituState.lastFrameAction = sMarioCamState->action; 3202 } 3203 3204 /** 3205 * Reset all the camera variables to their arcane defaults 3206 */ 3207 void reset_camera(struct Camera *c) { 3208 UNUSED s32 unused = 0; 3209 UNUSED u8 filler[16]; 3210 UNUSED struct LinearTransitionPoint *start = &sModeInfo.transitionStart; 3211 UNUSED struct LinearTransitionPoint *end = &sModeInfo.transitionEnd; 3212 3213 gCamera = c; 3214 gCameraMovementFlags = 0; 3215 s2ndRotateFlags = 0; 3216 sStatusFlags = 0; 3217 gCutsceneTimer = 0; 3218 sCutsceneShot = 0; 3219 gCutsceneObjSpawn = 0; 3220 gObjCutsceneDone = FALSE; 3221 gCutsceneFocus = NULL; 3222 unused8032CFC8 = 0; 3223 unused8032CFCC = 0; 3224 gSecondCameraFocus = NULL; 3225 sCButtonsPressed = 0; 3226 vec3f_copy(sModeTransition.marioPos, sMarioCamState->pos); 3227 sModeTransition.framesLeft = 0; 3228 unused8032CFCC = -1; 3229 unused8032CFC8 = -1; 3230 gCameraMovementFlags = 0; 3231 gCameraMovementFlags |= CAM_MOVE_INIT_CAMERA; 3232 unused8033B316 = 0; 3233 sStatusFlags = 0; 3234 unused8033B31A = 0; 3235 sCameraSoundFlags = 0; 3236 sCUpCameraPitch = 0; 3237 sModeOffsetYaw = 0; 3238 sSpiralStairsYawOffset = 0; 3239 sLakituDist = 0; 3240 sLakituPitch = 0; 3241 sAreaYaw = 0; 3242 sAreaYawChange = 0.f; 3243 sPanDistance = 0.f; 3244 sCannonYOffset = 0.f; 3245 sZoomAmount = 0.f; 3246 sZeroZoomDist = 0.f; 3247 sBehindMarioSoundTimer = 0; 3248 sCSideButtonYaw = 0; 3249 s8DirModeBaseYaw = 0; 3250 s8DirModeYawOffset = 0; 3251 c->doorStatus = DOOR_DEFAULT; 3252 sMarioCamState->headRotation[0] = 0; 3253 sMarioCamState->headRotation[1] = 0; 3254 sLuigiCamState->headRotation[0] = 0; 3255 sLuigiCamState->headRotation[1] = 0; 3256 sMarioCamState->cameraEvent = 0; 3257 sMarioCamState->usedObj = NULL; 3258 gLakituState.shakeMagnitude[0] = 0; 3259 gLakituState.shakeMagnitude[1] = 0; 3260 gLakituState.shakeMagnitude[2] = 0; 3261 gLakituState.unusedVec2[0] = 0; 3262 gLakituState.unusedVec2[1] = 0; 3263 gLakituState.unusedVec2[2] = 0; 3264 gLakituState.unusedVec1[0] = 0.f; 3265 gLakituState.unusedVec1[1] = 0.f; 3266 gLakituState.unusedVec1[2] = 0.f; 3267 gLakituState.lastFrameAction = 0; 3268 set_fov_function(CAM_FOV_DEFAULT); 3269 sFOVState.fov = 45.f; 3270 sFOVState.fovOffset = 0.f; 3271 sFOVState.unusedIsSleeping = 0; 3272 sFOVState.shakeAmplitude = 0.f; 3273 sFOVState.shakePhase = 0; 3274 sObjectCutscene = 0; 3275 gRecentCutscene = 0; 3276 unused8033B30C = 0; 3277 unused8033B310 = 0; 3278 } 3279 3280 void init_camera(struct Camera *c) { 3281 struct Surface *floor = 0; 3282 Vec3f marioOffset; 3283 s32 i; 3284 3285 sCreditsPlayer2Pitch = 0; 3286 sCreditsPlayer2Yaw = 0; 3287 gPrevLevel = gCurrLevelArea / 16; 3288 gCurrLevelArea = gCurrLevelNum * 16 + gCurrentArea->index; 3289 sSelectionFlags &= CAM_MODE_MARIO_SELECTED; 3290 sFramesPaused = 0; 3291 gLakituState.mode = c->mode; 3292 gLakituState.defMode = c->defMode; 3293 gLakituState.posHSpeed = 0.3f; 3294 gLakituState.posVSpeed = 0.3f; 3295 gLakituState.focHSpeed = 0.8f; 3296 gLakituState.focHSpeed = 0.3f; // @bug set focHSpeed back-to-back 3297 gLakituState.roll = 0; 3298 gLakituState.keyDanceRoll = 0; 3299 gLakituState.unused = 0; 3300 sStatusFlags &= ~CAM_FLAG_SMOOTH_MOVEMENT; 3301 vec3f_set(sCastleEntranceOffset, 0.f, 0.f, 0.f); 3302 vec3f_set(sPlayer2FocusOffset, 0.f, 0.f, 0.f); 3303 find_mario_floor_and_ceil(&sMarioGeometry); 3304 sMarioGeometry.prevFloorHeight = sMarioGeometry.currFloorHeight; 3305 sMarioGeometry.prevCeilHeight = sMarioGeometry.currCeilHeight; 3306 sMarioGeometry.prevFloor = sMarioGeometry.currFloor; 3307 sMarioGeometry.prevCeil = sMarioGeometry.currCeil; 3308 sMarioGeometry.prevFloorType = sMarioGeometry.currFloorType; 3309 sMarioGeometry.prevCeilType = sMarioGeometry.currCeilType; 3310 for (i = 0; i < 32; i++) { 3311 sCurCreditsSplinePos[i].index = -1; 3312 sCurCreditsSplineFocus[i].index = -1; 3313 } 3314 sCutsceneSplineSegment = 0; 3315 sCutsceneSplineSegmentProgress = 0.f; 3316 unused8033B6E8 = 0; 3317 sHandheldShakeInc = 0.f; 3318 sHandheldShakeTimer = 0.f; 3319 sHandheldShakeMag = 0; 3320 for (i = 0; i < 4; i++) { 3321 sHandheldShakeSpline[i].index = -1; 3322 } 3323 sHandheldShakePitch = 0; 3324 sHandheldShakeYaw = 0; 3325 sHandheldShakeRoll = 0; 3326 c->cutscene = 0; 3327 marioOffset[0] = 0.f; 3328 marioOffset[1] = 125.f; 3329 marioOffset[2] = 400.f; 3330 3331 // Set the camera's starting position or start a cutscene for certain levels 3332 switch (gCurrLevelNum) { 3333 // Calls the initial cutscene when you enter Bowser battle levels 3334 // Note: This replaced an "old" way to call these cutscenes using 3335 // a camEvent value: CAM_EVENT_BOWSER_INIT 3336 case LEVEL_BOWSER_1: 3337 #ifndef VERSION_JP 3338 // Since Bowser 1 has a demo entry, check for it 3339 // If it is, then set CamAct to the end to directly activate Bowser 3340 // If it isn't, then start cutscene 3341 if (gCurrDemoInput == NULL) { 3342 start_cutscene(c, CUTSCENE_ENTER_BOWSER_ARENA); 3343 } else if (gSecondCameraFocus != NULL) { 3344 gSecondCameraFocus->oBowserCamAct = BOWSER_CAM_ACT_END; 3345 } 3346 #else 3347 start_cutscene(c, CUTSCENE_ENTER_BOWSER_ARENA); 3348 #endif 3349 break; 3350 case LEVEL_BOWSER_2: 3351 start_cutscene(c, CUTSCENE_ENTER_BOWSER_ARENA); 3352 break; 3353 case LEVEL_BOWSER_3: 3354 start_cutscene(c, CUTSCENE_ENTER_BOWSER_ARENA); 3355 break; 3356 3357 //! Hardcoded position checks determine which cutscene to play when Mario enters castle grounds. 3358 case LEVEL_CASTLE_GROUNDS: 3359 if (is_within_100_units_of_mario(-1328.f, 260.f, 4664.f) != 1) { 3360 marioOffset[0] = -400.f; 3361 marioOffset[2] = -800.f; 3362 } 3363 if (is_within_100_units_of_mario(-6901.f, 2376.f, -6509.f) == 1) { 3364 start_cutscene(c, CUTSCENE_EXIT_WATERFALL); 3365 } 3366 if (is_within_100_units_of_mario(5408.f, 4500.f, 3637.f) == 1) { 3367 start_cutscene(c, CUTSCENE_EXIT_FALL_WMOTR); 3368 } 3369 gLakituState.mode = CAMERA_MODE_FREE_ROAM; 3370 break; 3371 case LEVEL_SA: 3372 marioOffset[2] = 200.f; 3373 break; 3374 case LEVEL_CASTLE_COURTYARD: 3375 marioOffset[2] = -300.f; 3376 break; 3377 case LEVEL_LLL: 3378 gCameraMovementFlags |= CAM_MOVE_ZOOMED_OUT; 3379 break; 3380 case LEVEL_CASTLE: 3381 marioOffset[2] = 150.f; 3382 break; 3383 case LEVEL_RR: 3384 vec3f_set(sFixedModeBasePosition, -2985.f, 478.f, -5568.f); 3385 break; 3386 } 3387 if (c->mode == CAMERA_MODE_8_DIRECTIONS) { 3388 gCameraMovementFlags |= CAM_MOVE_ZOOMED_OUT; 3389 } 3390 switch (gCurrLevelArea) { 3391 case AREA_SSL_EYEROK: 3392 vec3f_set(marioOffset, 0.f, 500.f, -100.f); 3393 break; 3394 case AREA_CCM_SLIDE: 3395 marioOffset[2] = -300.f; 3396 break; 3397 case AREA_THI_WIGGLER: 3398 marioOffset[2] = -300.f; 3399 break; 3400 case AREA_SL_IGLOO: 3401 marioOffset[2] = -300.f; 3402 break; 3403 case AREA_SL_OUTSIDE: 3404 if (is_within_100_units_of_mario(257.f, 2150.f, 1399.f) == 1) { 3405 marioOffset[2] = -300.f; 3406 } 3407 break; 3408 case AREA_CCM_OUTSIDE: 3409 gCameraMovementFlags |= CAM_MOVE_ZOOMED_OUT; 3410 break; 3411 case AREA_TTM_OUTSIDE: 3412 gLakituState.mode = CAMERA_MODE_RADIAL; 3413 break; 3414 } 3415 3416 // Set the camera pos to marioOffset (relative to Mario), added to Mario's position 3417 offset_rotated(c->pos, sMarioCamState->pos, marioOffset, sMarioCamState->faceAngle); 3418 if (c->mode != CAMERA_MODE_BEHIND_MARIO) { 3419 c->pos[1] = find_floor(sMarioCamState->pos[0], sMarioCamState->pos[1] + 100.f, 3420 sMarioCamState->pos[2], &floor) + 125.f; 3421 } 3422 vec3f_copy(c->focus, sMarioCamState->pos); 3423 vec3f_copy(gLakituState.curPos, c->pos); 3424 vec3f_copy(gLakituState.curFocus, c->focus); 3425 vec3f_copy(gLakituState.goalPos, c->pos); 3426 vec3f_copy(gLakituState.goalFocus, c->focus); 3427 vec3f_copy(gLakituState.pos, c->pos); 3428 vec3f_copy(gLakituState.focus, c->focus); 3429 if (c->mode == CAMERA_MODE_FIXED) { 3430 set_fixed_cam_axis_sa_lobby(c->mode); 3431 } 3432 store_lakitu_cam_info_for_c_up(c); 3433 gLakituState.yaw = calculate_yaw(c->focus, c->pos); 3434 gLakituState.nextYaw = gLakituState.yaw; 3435 c->yaw = gLakituState.yaw; 3436 c->nextYaw = gLakituState.yaw; 3437 } 3438 3439 /** 3440 * Zooms out the camera if paused and the level is 'outside', as determined by sZoomOutAreaMasks. 3441 * 3442 * Because gCurrLevelArea is assigned gCurrLevelNum * 16 + gCurrentArea->index, 3443 * dividing by 32 maps 2 levels to one index. 3444 * 3445 * areaBit definition: 3446 * (gCurrLevelArea & 0x10) / 4): 3447 * This adds 4 to the shift if the level is an odd multiple of 16 3448 * 3449 * ((gCurrLevelArea & 0xF) - 1) & 3): 3450 * This isolates the lower 16 'area' bits, subtracts 1 because areas are 1-indexed, and effectively 3451 * modulo-4's the result, because each 8-bit mask only has 4 area bits for each level 3452 */ 3453 void zoom_out_if_paused_and_outside(struct GraphNodeCamera *camera) { 3454 UNUSED u8 filler1[8]; 3455 UNUSED f32 dist; 3456 UNUSED s16 pitch; 3457 s16 yaw; 3458 UNUSED u8 filler2[4]; 3459 s32 areaMaskIndex = gCurrLevelArea / 32; 3460 s32 areaBit = 1 << (((gCurrLevelArea & 0x10) / 4) + (((gCurrLevelArea & 0xF) - 1) & 3)); 3461 3462 if (areaMaskIndex >= LEVEL_MAX / 2) { 3463 areaMaskIndex = 0; 3464 areaBit = 0; 3465 } 3466 if (gCameraMovementFlags & CAM_MOVE_PAUSE_SCREEN) { 3467 if (sFramesPaused >= 2) { 3468 if (sZoomOutAreaMasks[areaMaskIndex] & areaBit) { 3469 3470 camera->focus[0] = gCamera->areaCenX; 3471 camera->focus[1] = (sMarioCamState->pos[1] + gCamera->areaCenY) / 2; 3472 camera->focus[2] = gCamera->areaCenZ; 3473 vec3f_get_dist_and_angle(camera->focus, sMarioCamState->pos, &dist, &pitch, &yaw); 3474 vec3f_set_dist_and_angle(sMarioCamState->pos, camera->pos, 6000.f, 0x1000, yaw); 3475 if (gCurrLevelNum != LEVEL_THI) { 3476 find_in_bounds_yaw_wdw_bob_thi(camera->pos, camera->focus, 0); 3477 } 3478 } 3479 } else { 3480 sFramesPaused++; 3481 } 3482 } else { 3483 sFramesPaused = 0; 3484 } 3485 } 3486 3487 void select_mario_cam_mode(void) { 3488 sSelectionFlags = CAM_MODE_MARIO_SELECTED; 3489 } 3490 3491 /** 3492 * Allocate the GraphNodeCamera's config.camera, and copy `c`'s focus to the Camera's area center point. 3493 */ 3494 void create_camera(struct GraphNodeCamera *gc, struct AllocOnlyPool *pool) { 3495 s16 mode = gc->config.mode; 3496 struct Camera *c = alloc_only_pool_alloc(pool, sizeof(struct Camera)); 3497 3498 gc->config.camera = c; 3499 c->mode = mode; 3500 c->defMode = mode; 3501 c->cutscene = 0; 3502 c->doorStatus = DOOR_DEFAULT; 3503 c->areaCenX = gc->focus[0]; 3504 c->areaCenY = gc->focus[1]; 3505 c->areaCenZ = gc->focus[2]; 3506 c->yaw = 0; 3507 vec3f_copy(c->pos, gc->pos); 3508 vec3f_copy(c->focus, gc->focus); 3509 } 3510 3511 /** 3512 * Copy Lakitu's pos and foc into `gc` 3513 */ 3514 void update_graph_node_camera(struct GraphNodeCamera *gc) { 3515 UNUSED u8 filler[8]; 3516 UNUSED struct Camera *c = gc->config.camera; 3517 3518 gc->rollScreen = gLakituState.roll; 3519 vec3f_copy(gc->pos, gLakituState.pos); 3520 vec3f_copy(gc->focus, gLakituState.focus); 3521 zoom_out_if_paused_and_outside(gc); 3522 } 3523 3524 Gfx *geo_camera_main(s32 callContext, struct GraphNode *g, void *context) { 3525 struct GraphNodeCamera *gc = (struct GraphNodeCamera *) g; 3526 UNUSED Mat4 *unusedMat = context; 3527 3528 switch (callContext) { 3529 case GEO_CONTEXT_CREATE: 3530 create_camera(gc, context); 3531 break; 3532 case GEO_CONTEXT_RENDER: 3533 update_graph_node_camera(gc); 3534 break; 3535 } 3536 return NULL; 3537 } 3538 3539 void stub_camera_2(UNUSED struct Camera *c) { 3540 } 3541 3542 void stub_camera_3(UNUSED struct Camera *c) { 3543 } 3544 3545 void vec3f_sub(Vec3f dst, Vec3f src) { 3546 dst[0] -= src[0]; 3547 dst[1] -= src[1]; 3548 dst[2] -= src[2]; 3549 } 3550 3551 void object_pos_to_vec3f(Vec3f dst, struct Object *o) { 3552 dst[0] = o->oPosX; 3553 dst[1] = o->oPosY; 3554 dst[2] = o->oPosZ; 3555 } 3556 3557 void vec3f_to_object_pos(struct Object *o, Vec3f src) { 3558 o->oPosX = src[0]; 3559 o->oPosY = src[1]; 3560 o->oPosZ = src[2]; 3561 } 3562 3563 void unused_object_angle_to_vec3s(Vec3s dst, struct Object *o) { 3564 dst[0] = o->oMoveAnglePitch; 3565 dst[1] = o->oMoveAngleYaw; 3566 dst[2] = o->oMoveAngleRoll; 3567 } 3568 3569 /** 3570 * Produces values using a cubic b-spline curve. Basically Q is the used output, 3571 * u is a value between 0 and 1 that represents the position along the spline, 3572 * and a0-a3 are parameters that define the spline. 3573 * 3574 * The spline is described at http://www2.cs.uregina.ca/~anima/UniformBSpline.htm 3575 */ 3576 void evaluate_cubic_spline(f32 u, Vec3f Q, Vec3f a0, Vec3f a1, Vec3f a2, Vec3f a3) { 3577 f32 B[4]; 3578 f32 x; 3579 f32 y; 3580 f32 z; 3581 UNUSED u8 filler[16]; 3582 3583 if (u > 1.f) { 3584 u = 1.f; 3585 } 3586 3587 B[0] = (1.f - u) * (1.f - u) * (1.f - u) / 6.f; 3588 B[1] = u * u * u / 2.f - u * u + 0.6666667f; 3589 B[2] = -u * u * u / 2.f + u * u / 2.f + u / 2.f + 0.16666667f; 3590 B[3] = u * u * u / 6.f; 3591 3592 Q[0] = B[0] * a0[0] + B[1] * a1[0] + B[2] * a2[0] + B[3] * a3[0]; 3593 Q[1] = B[0] * a0[1] + B[1] * a1[1] + B[2] * a2[1] + B[3] * a3[1]; 3594 Q[2] = B[0] * a0[2] + B[1] * a1[2] + B[2] * a2[2] + B[3] * a3[2]; 3595 3596 // Unused code 3597 B[0] = -0.5f * u * u + u - 0.33333333f; 3598 B[1] = 1.5f * u * u - 2.f * u - 0.5f; 3599 B[2] = -1.5f * u * u + u + 1.f; 3600 B[3] = 0.5f * u * u - 0.16666667f; 3601 3602 x = B[0] * a0[0] + B[1] * a1[0] + B[2] * a2[0] + B[3] * a3[0]; 3603 y = B[0] * a0[1] + B[1] * a1[1] + B[2] * a2[1] + B[3] * a3[1]; 3604 z = B[0] * a0[2] + B[1] * a1[2] + B[2] * a2[2] + B[3] * a3[2]; 3605 3606 unusedSplinePitch = atan2s(sqrtf(x * x + z * z), y); 3607 unusedSplineYaw = atan2s(z, x); 3608 } 3609 3610 /** 3611 * Computes the point that is `progress` percent of the way through segment `splineSegment` of `spline`, 3612 * and stores the result in `p`. `progress` and `splineSegment` are updated if `progress` becomes >= 1.0. 3613 * 3614 * When neither of the next two points' speeds == 0, the number of frames is between 1 and 255. Otherwise 3615 * it's infinite. 3616 * 3617 * To calculate the number of frames it will take to progress through a spline segment: 3618 * If the next two speeds are the same and nonzero, it's 1.0 / firstSpeed. 3619 * 3620 * s1 and s2 are short hand for first/secondSpeed. The progress at any frame n is defined by a recurrency relation: 3621 * p(n+1) = (s2 - s1 + 1) * p(n) + s1 3622 * Which can be written as 3623 * p(n) = (s2 * ((s2 - s1 + 1)^(n) - 1)) / (s2 - s1) 3624 * 3625 * Solving for the number of frames: 3626 * n = log(((s2 - s1) / s1) + 1) / log(s2 - s1 + 1) 3627 * 3628 * @return 1 if the point has reached the end of the spline, when `progress` reaches 1.0 or greater, and 3629 * the 4th CutsceneSplinePoint in the current segment away from spline[splineSegment] has an index of -1. 3630 */ 3631 s32 move_point_along_spline(Vec3f p, struct CutsceneSplinePoint spline[], s16 *splineSegment, f32 *progress) { 3632 s32 finished = 0; 3633 Vec3f controlPoints[4]; 3634 s32 i = 0; 3635 f32 u = *progress; 3636 f32 progressChange; 3637 f32 firstSpeed = 0; 3638 f32 secondSpeed = 0; 3639 s32 segment = *splineSegment; 3640 3641 if (*splineSegment < 0) { 3642 segment = 0; 3643 u = 0; 3644 } 3645 if (spline[segment].index == -1 || spline[segment + 1].index == -1 || spline[segment + 2].index == -1) { 3646 return 1; 3647 } 3648 3649 for (i = 0; i < 4; i++) { 3650 controlPoints[i][0] = spline[segment + i].point[0]; 3651 controlPoints[i][1] = spline[segment + i].point[1]; 3652 controlPoints[i][2] = spline[segment + i].point[2]; 3653 } 3654 evaluate_cubic_spline(u, p, controlPoints[0], controlPoints[1], controlPoints[2], controlPoints[3]); 3655 3656 if (spline[*splineSegment + 1].speed != 0) { 3657 firstSpeed = 1.0f / spline[*splineSegment + 1].speed; 3658 } 3659 if (spline[*splineSegment + 2].speed != 0) { 3660 secondSpeed = 1.0f / spline[*splineSegment + 2].speed; 3661 } 3662 progressChange = (secondSpeed - firstSpeed) * *progress + firstSpeed; 3663 3664 #ifdef VERSION_EU 3665 if (gCamera->cutscene == CUTSCENE_INTRO_PEACH) { 3666 progressChange += progressChange * 0.19f; 3667 } 3668 if (gCamera->cutscene == CUTSCENE_CREDITS) { 3669 progressChange += progressChange * 0.15f; 3670 } 3671 if (gCamera->cutscene == CUTSCENE_ENDING) { 3672 progressChange += progressChange * 0.1f; 3673 } 3674 #endif 3675 3676 if (1 <= (*progress += progressChange)) { 3677 (*splineSegment)++; 3678 if (spline[*splineSegment + 3].index == -1) { 3679 *splineSegment = 0; 3680 finished = 1; 3681 } 3682 (*progress)--; 3683 } 3684 return finished; 3685 } 3686 3687 /** 3688 * If `selection` is 0, just get the current selection 3689 * If `selection` is 1, select 'Mario' as the alt mode. 3690 * If `selection` is 2, select 'fixed' as the alt mode. 3691 * 3692 * @return the current selection 3693 */ 3694 s32 cam_select_alt_mode(s32 selection) { 3695 s32 mode = CAM_SELECTION_FIXED; 3696 3697 if (selection == CAM_SELECTION_MARIO) { 3698 if (!(sSelectionFlags & CAM_MODE_MARIO_SELECTED)) { 3699 sSelectionFlags |= CAM_MODE_MARIO_SELECTED; 3700 } 3701 sCameraSoundFlags |= CAM_SOUND_UNUSED_SELECT_MARIO; 3702 } 3703 3704 // The alternate mode is up-close, but the player just selected fixed in the pause menu 3705 if (selection == CAM_SELECTION_FIXED && (sSelectionFlags & CAM_MODE_MARIO_SELECTED)) { 3706 // So change to normal mode in case the user paused in up-close mode 3707 set_cam_angle(CAM_ANGLE_LAKITU); 3708 sSelectionFlags &= ~CAM_MODE_MARIO_SELECTED; 3709 sCameraSoundFlags |= CAM_SOUND_UNUSED_SELECT_FIXED; 3710 } 3711 3712 if (sSelectionFlags & CAM_MODE_MARIO_SELECTED) { 3713 mode = CAM_SELECTION_MARIO; 3714 } 3715 return mode; 3716 } 3717 3718 /** 3719 * Sets the camera angle to either Lakitu or Mario mode. Returns the current mode. 3720 * 3721 * If `mode` is 0, just returns the current mode. 3722 * If `mode` is 1, start Mario mode 3723 * If `mode` is 2, start Lakitu mode 3724 */ 3725 s32 set_cam_angle(s32 mode) { 3726 s32 curMode = CAM_ANGLE_LAKITU; 3727 3728 // Switch to Mario mode 3729 if (mode == CAM_ANGLE_MARIO && !(sSelectionFlags & CAM_MODE_MARIO_ACTIVE)) { 3730 sSelectionFlags |= CAM_MODE_MARIO_ACTIVE; 3731 if (gCameraMovementFlags & CAM_MOVE_ZOOMED_OUT) { 3732 sSelectionFlags |= CAM_MODE_LAKITU_WAS_ZOOMED_OUT; 3733 gCameraMovementFlags &= ~CAM_MOVE_ZOOMED_OUT; 3734 } 3735 sCameraSoundFlags |= CAM_SOUND_MARIO_ACTIVE; 3736 } 3737 3738 // Switch back to normal mode 3739 if (mode == CAM_ANGLE_LAKITU && (sSelectionFlags & CAM_MODE_MARIO_ACTIVE)) { 3740 sSelectionFlags &= ~CAM_MODE_MARIO_ACTIVE; 3741 if (sSelectionFlags & CAM_MODE_LAKITU_WAS_ZOOMED_OUT) { 3742 sSelectionFlags &= ~CAM_MODE_LAKITU_WAS_ZOOMED_OUT; 3743 gCameraMovementFlags |= CAM_MOVE_ZOOMED_OUT; 3744 } else { 3745 gCameraMovementFlags &= ~CAM_MOVE_ZOOMED_OUT; 3746 } 3747 sCameraSoundFlags |= CAM_SOUND_NORMAL_ACTIVE; 3748 } 3749 if (sSelectionFlags & CAM_MODE_MARIO_ACTIVE) { 3750 curMode = CAM_ANGLE_MARIO; 3751 } 3752 return curMode; 3753 } 3754 3755 /** 3756 * Enables the handheld shake effect for this frame. 3757 * 3758 * @see shake_camera_handheld() 3759 */ 3760 void set_handheld_shake(u8 mode) { 3761 switch (mode) { 3762 // They're not in numerical order because that would be too simple... 3763 case HAND_CAM_SHAKE_CUTSCENE: // Lowest increment 3764 sHandheldShakeMag = 0x600; 3765 sHandheldShakeInc = 0.04f; 3766 break; 3767 case HAND_CAM_SHAKE_LOW: // Lowest magnitude 3768 sHandheldShakeMag = 0x300; 3769 sHandheldShakeInc = 0.06f; 3770 break; 3771 case HAND_CAM_SHAKE_HIGH: // Highest mag and inc 3772 sHandheldShakeMag = 0x1000; 3773 sHandheldShakeInc = 0.1f; 3774 break; 3775 case HAND_CAM_SHAKE_UNUSED: // Never used 3776 sHandheldShakeMag = 0x600; 3777 sHandheldShakeInc = 0.07f; 3778 break; 3779 case HAND_CAM_SHAKE_HANG_OWL: // exactly the same as UNUSED... 3780 sHandheldShakeMag = 0x600; 3781 sHandheldShakeInc = 0.07f; 3782 break; 3783 case HAND_CAM_SHAKE_STAR_DANCE: // Slightly steadier than HANG_OWL and UNUSED 3784 sHandheldShakeMag = 0x400; 3785 sHandheldShakeInc = 0.07f; 3786 break; 3787 default: 3788 sHandheldShakeMag = 0x0; 3789 sHandheldShakeInc = 0.f; 3790 } 3791 } 3792 3793 /** 3794 * When sHandheldShakeMag is nonzero, this function adds small random offsets to `focus` every time 3795 * sHandheldShakeTimer increases above 1.0, simulating the camera shake caused by unsteady hands. 3796 * 3797 * This function must be called every frame in order to actually apply the effect, since the effect's 3798 * mag and inc are set to 0 every frame at the end of this function. 3799 */ 3800 void shake_camera_handheld(Vec3f pos, Vec3f focus) { 3801 s32 i; 3802 Vec3f shakeOffset; 3803 Vec3f shakeSpline[4]; 3804 f32 dist; 3805 s16 pitch; 3806 s16 yaw; 3807 UNUSED u8 filler[8]; 3808 3809 if (sHandheldShakeMag == 0) { 3810 vec3f_set(shakeOffset, 0.f, 0.f, 0.f); 3811 } else { 3812 for (i = 0; i < 4; i++) { 3813 shakeSpline[i][0] = sHandheldShakeSpline[i].point[0]; 3814 shakeSpline[i][1] = sHandheldShakeSpline[i].point[1]; 3815 shakeSpline[i][2] = sHandheldShakeSpline[i].point[2]; 3816 } 3817 evaluate_cubic_spline(sHandheldShakeTimer, shakeOffset, shakeSpline[0], 3818 shakeSpline[1], shakeSpline[2], shakeSpline[3]); 3819 if (1.f <= (sHandheldShakeTimer += sHandheldShakeInc)) { 3820 // The first 3 control points are always (0,0,0), so the random spline is always just a 3821 // straight line 3822 for (i = 0; i < 3; i++) { 3823 vec3s_copy(sHandheldShakeSpline[i].point, sHandheldShakeSpline[i + 1].point); 3824 } 3825 random_vec3s(sHandheldShakeSpline[3].point, sHandheldShakeMag, sHandheldShakeMag, sHandheldShakeMag / 2); 3826 sHandheldShakeTimer -= 1.f; 3827 3828 // Code dead, this is set to be 0 before it is used. 3829 sHandheldShakeInc = random_float() * 0.5f; 3830 if (sHandheldShakeInc < 0.02f) { 3831 sHandheldShakeInc = 0.02f; 3832 } 3833 } 3834 } 3835 3836 approach_s16_asymptotic_bool(&sHandheldShakePitch, shakeOffset[0], 0x08); 3837 approach_s16_asymptotic_bool(&sHandheldShakeYaw, shakeOffset[1], 0x08); 3838 approach_s16_asymptotic_bool(&sHandheldShakeRoll, shakeOffset[2], 0x08); 3839 3840 if (sHandheldShakePitch | sHandheldShakeYaw) { 3841 vec3f_get_dist_and_angle(pos, focus, &dist, &pitch, &yaw); 3842 pitch += sHandheldShakePitch; 3843 yaw += sHandheldShakeYaw; 3844 vec3f_set_dist_and_angle(pos, focus, dist, pitch, yaw); 3845 } 3846 3847 // Unless called every frame, the effect will stop after the first time. 3848 sHandheldShakeMag = 0; 3849 sHandheldShakeInc = 0.f; 3850 } 3851 3852 /** 3853 * Updates C Button input state and stores it in `currentState` 3854 */ 3855 s32 find_c_buttons_pressed(u16 currentState, u16 buttonsPressed, u16 buttonsDown) { 3856 buttonsPressed &= CBUTTON_MASK; 3857 buttonsDown &= CBUTTON_MASK; 3858 3859 if (buttonsPressed & L_CBUTTONS) { 3860 currentState |= L_CBUTTONS; 3861 currentState &= ~R_CBUTTONS; 3862 } 3863 if (!(buttonsDown & L_CBUTTONS)) { 3864 currentState &= ~L_CBUTTONS; 3865 } 3866 3867 if (buttonsPressed & R_CBUTTONS) { 3868 currentState |= R_CBUTTONS; 3869 currentState &= ~L_CBUTTONS; 3870 } 3871 if (!(buttonsDown & R_CBUTTONS)) { 3872 currentState &= ~R_CBUTTONS; 3873 } 3874 3875 if (buttonsPressed & U_CBUTTONS) { 3876 currentState |= U_CBUTTONS; 3877 currentState &= ~D_CBUTTONS; 3878 } 3879 if (!(buttonsDown & U_CBUTTONS)) { 3880 currentState &= ~U_CBUTTONS; 3881 } 3882 3883 if (buttonsPressed & D_CBUTTONS) { 3884 currentState |= D_CBUTTONS; 3885 currentState &= ~U_CBUTTONS; 3886 } 3887 if (!(buttonsDown & D_CBUTTONS)) { 3888 currentState &= ~D_CBUTTONS; 3889 } 3890 3891 return currentState; 3892 } 3893 3894 /** 3895 * Determine which icon to show on the HUD 3896 */ 3897 s32 update_camera_hud_status(struct Camera *c) { 3898 s16 status = CAM_STATUS_NONE; 3899 3900 if (c->cutscene != 0 3901 || ((gPlayer1Controller->buttonDown & R_TRIG) && cam_select_alt_mode(0) == CAM_SELECTION_FIXED)) { 3902 status |= CAM_STATUS_FIXED; 3903 } else if (set_cam_angle(0) == CAM_ANGLE_MARIO) { 3904 status |= CAM_STATUS_MARIO; 3905 } else { 3906 status |= CAM_STATUS_LAKITU; 3907 } 3908 if (gCameraMovementFlags & CAM_MOVE_ZOOMED_OUT) { 3909 status |= CAM_STATUS_C_DOWN; 3910 } 3911 if (gCameraMovementFlags & CAM_MOVE_C_UP_MODE) { 3912 status |= CAM_STATUS_C_UP; 3913 } 3914 set_hud_camera_status(status); 3915 return status; 3916 } 3917 3918 /** 3919 * Check `pos` for collisions within `radius`, and update `pos` 3920 * 3921 * @return the number of collisions found 3922 */ 3923 s32 collide_with_walls(Vec3f pos, f32 offsetY, f32 radius) { 3924 struct WallCollisionData collisionData; 3925 struct Surface *wall = NULL; 3926 f32 normX; 3927 f32 normY; 3928 f32 normZ; 3929 f32 originOffset; 3930 f32 offset; 3931 f32 offsetAbsolute; 3932 Vec3f newPos[4]; 3933 s32 i; 3934 s32 numCollisions = 0; 3935 3936 collisionData.x = pos[0]; 3937 collisionData.y = pos[1]; 3938 collisionData.z = pos[2]; 3939 collisionData.radius = radius; 3940 collisionData.offsetY = offsetY; 3941 numCollisions = find_wall_collisions(&collisionData); 3942 if (numCollisions != 0) { 3943 for (i = 0; i < collisionData.numWalls; i++) { 3944 wall = collisionData.walls[collisionData.numWalls - 1]; 3945 vec3f_copy(newPos[i], pos); 3946 normX = wall->normal.x; 3947 normY = wall->normal.y; 3948 normZ = wall->normal.z; 3949 originOffset = wall->originOffset; 3950 offset = normX * newPos[i][0] + normY * newPos[i][1] + normZ * newPos[i][2] + originOffset; 3951 offsetAbsolute = ABS2(offset); 3952 if (offsetAbsolute < radius) { 3953 newPos[i][0] += normX * (radius - offset); 3954 newPos[i][2] += normZ * (radius - offset); 3955 vec3f_copy(pos, newPos[i]); 3956 } 3957 } 3958 } 3959 return numCollisions; 3960 } 3961 3962 /** 3963 * Compare a vector to a position, return TRUE if they match. 3964 */ 3965 s32 vec3f_compare(Vec3f pos, f32 posX, f32 posY, f32 posZ) { 3966 s32 equal = FALSE; 3967 3968 if (pos[0] == posX && pos[1] == posY && pos[2] == posZ) { 3969 equal = TRUE; 3970 } 3971 return equal; 3972 } 3973 3974 s32 clamp_pitch(Vec3f from, Vec3f to, s16 maxPitch, s16 minPitch) { 3975 s32 outOfRange = 0; 3976 s16 pitch; 3977 s16 yaw; 3978 f32 dist; 3979 3980 vec3f_get_dist_and_angle(from, to, &dist, &pitch, &yaw); 3981 if (pitch > maxPitch) { 3982 pitch = maxPitch; 3983 outOfRange++; 3984 } 3985 if (pitch < minPitch) { 3986 pitch = minPitch; 3987 outOfRange++; 3988 } 3989 vec3f_set_dist_and_angle(from, to, dist, pitch, yaw); 3990 return outOfRange; 3991 } 3992 3993 s32 is_within_100_units_of_mario(f32 posX, f32 posY, f32 posZ) { 3994 s32 isCloseToMario = 0; 3995 Vec3f pos; 3996 3997 vec3f_set(pos, posX, posY, posZ); 3998 if (calc_abs_dist(sMarioCamState->pos, pos) < 100.f) { 3999 isCloseToMario = 1; 4000 } 4001 return isCloseToMario; 4002 } 4003 4004 s32 set_or_approach_f32_asymptotic(f32 *dst, f32 goal, f32 scale) { 4005 if (sStatusFlags & CAM_FLAG_SMOOTH_MOVEMENT) { 4006 approach_f32_asymptotic_bool(dst, goal, scale); 4007 } else { 4008 *dst = goal; 4009 } 4010 if (*dst == goal) { 4011 return FALSE; 4012 } else { 4013 return TRUE; 4014 } 4015 } 4016 4017 /** 4018 * Approaches an f32 value by taking the difference between the target and current value 4019 * and adding a fraction of that to the current value. 4020 * Edits the current value directly, returns TRUE if the target has been reached, FALSE otherwise. 4021 */ 4022 s32 approach_f32_asymptotic_bool(f32 *current, f32 target, f32 multiplier) { 4023 if (multiplier > 1.f) { 4024 multiplier = 1.f; 4025 } 4026 *current = *current + (target - *current) * multiplier; 4027 if (*current == target) { 4028 return FALSE; 4029 } else { 4030 return TRUE; 4031 } 4032 } 4033 4034 /** 4035 * Nearly the same as the above function, returns new value instead. 4036 */ 4037 f32 approach_f32_asymptotic(f32 current, f32 target, f32 multiplier) { 4038 current = current + (target - current) * multiplier; 4039 return current; 4040 } 4041 4042 /** 4043 * Approaches an s16 value in the same fashion as approach_f32_asymptotic_bool, returns TRUE if target 4044 * is reached. Note: Since this function takes integers as parameters, the last argument is the 4045 * reciprocal of what it would be in the previous two functions. 4046 */ 4047 s32 approach_s16_asymptotic_bool(s16 *current, s16 target, s16 divisor) { 4048 s16 temp = *current; 4049 4050 if (divisor == 0) { 4051 *current = target; 4052 } else { 4053 temp -= target; 4054 temp -= temp / divisor; 4055 temp += target; 4056 *current = temp; 4057 } 4058 if (*current == target) { 4059 return FALSE; 4060 } else { 4061 return TRUE; 4062 } 4063 } 4064 4065 /** 4066 * Approaches an s16 value in the same fashion as approach_f32_asymptotic, returns the new value. 4067 * Note: last parameter is the reciprocal of what it would be in the f32 functions 4068 */ 4069 s32 approach_s16_asymptotic(s16 current, s16 target, s16 divisor) { 4070 s16 temp = current; 4071 4072 if (divisor == 0) { 4073 current = target; 4074 } else { 4075 temp -= target; 4076 temp -= temp / divisor; 4077 temp += target; 4078 current = temp; 4079 } 4080 return current; 4081 } 4082 4083 /** 4084 * Applies the approach_f32_asymptotic_bool function to each of the X, Y, & Z components of the given 4085 * vector. 4086 */ 4087 void approach_vec3f_asymptotic(Vec3f current, Vec3f target, f32 xMul, f32 yMul, f32 zMul) { 4088 approach_f32_asymptotic_bool(¤t[0], target[0], xMul); 4089 approach_f32_asymptotic_bool(¤t[1], target[1], yMul); 4090 approach_f32_asymptotic_bool(¤t[2], target[2], zMul); 4091 } 4092 4093 /** 4094 * Applies the set_or_approach_f32_asymptotic_bool function to each of the X, Y, & Z components of the 4095 * given vector. 4096 */ 4097 void set_or_approach_vec3f_asymptotic(Vec3f dst, Vec3f goal, f32 xMul, f32 yMul, f32 zMul) { 4098 set_or_approach_f32_asymptotic(&dst[0], goal[0], xMul); 4099 set_or_approach_f32_asymptotic(&dst[1], goal[1], yMul); 4100 set_or_approach_f32_asymptotic(&dst[2], goal[2], zMul); 4101 } 4102 4103 /** 4104 * Applies the approach_s32_asymptotic function to each of the X, Y, & Z components of the given 4105 * vector. 4106 */ 4107 void approach_vec3s_asymptotic(Vec3s current, Vec3s target, s16 xMul, s16 yMul, s16 zMul) { 4108 approach_s16_asymptotic_bool(¤t[0], target[0], xMul); 4109 approach_s16_asymptotic_bool(¤t[1], target[1], yMul); 4110 approach_s16_asymptotic_bool(¤t[2], target[2], zMul); 4111 } 4112 4113 s32 camera_approach_s16_symmetric_bool(s16 *current, s16 target, s16 increment) { 4114 s16 dist = target - *current; 4115 4116 if (increment < 0) { 4117 increment = -1 * increment; 4118 } 4119 if (dist > 0) { 4120 dist -= increment; 4121 if (dist >= 0) { 4122 *current = target - dist; 4123 } else { 4124 *current = target; 4125 } 4126 } else { 4127 dist += increment; 4128 if (dist <= 0) { 4129 *current = target - dist; 4130 } else { 4131 *current = target; 4132 } 4133 } 4134 if (*current == target) { 4135 return FALSE; 4136 } else { 4137 return TRUE; 4138 } 4139 } 4140 4141 s32 camera_approach_s16_symmetric(s16 current, s16 target, s16 increment) { 4142 s16 dist = target - current; 4143 4144 if (increment < 0) { 4145 increment = -1 * increment; 4146 } 4147 if (dist > 0) { 4148 dist -= increment; 4149 if (dist >= 0) { 4150 current = target - dist; 4151 } else { 4152 current = target; 4153 } 4154 } else { 4155 dist += increment; 4156 if (dist <= 0) { 4157 current = target - dist; 4158 } else { 4159 current = target; 4160 } 4161 } 4162 return current; 4163 } 4164 4165 s32 set_or_approach_s16_symmetric(s16 *current, s16 target, s16 increment) { 4166 if (sStatusFlags & CAM_FLAG_SMOOTH_MOVEMENT) { 4167 camera_approach_s16_symmetric_bool(current, target, increment); 4168 } else { 4169 *current = target; 4170 } 4171 if (*current == target) { 4172 return FALSE; 4173 } else { 4174 return TRUE; 4175 } 4176 } 4177 4178 /** 4179 * Approaches a value by a given increment, returns FALSE if the target is reached. 4180 * Appears to be a strange way of implementing approach_f32_symmetric from object_helpers.c. 4181 * It could possibly be an older version of the function 4182 */ 4183 s32 camera_approach_f32_symmetric_bool(f32 *current, f32 target, f32 increment) { 4184 f32 dist = target - *current; 4185 4186 if (increment < 0) { 4187 increment = -1 * increment; 4188 } 4189 if (dist > 0) { 4190 dist -= increment; 4191 if (dist > 0) { 4192 *current = target - dist; 4193 } else { 4194 *current = target; 4195 } 4196 } else { 4197 dist += increment; 4198 if (dist < 0) { 4199 *current = target - dist; 4200 } else { 4201 *current = target; 4202 } 4203 } 4204 if (*current == target) { 4205 return FALSE; 4206 } else { 4207 return TRUE; 4208 } 4209 } 4210 4211 /** 4212 * Nearly the same as the above function, this one returns the new value in place of a bool. 4213 */ 4214 f32 camera_approach_f32_symmetric(f32 current, f32 target, f32 increment) { 4215 f32 dist = target - current; 4216 4217 if (increment < 0) { 4218 increment = -1 * increment; 4219 } 4220 if (dist > 0) { 4221 dist -= increment; 4222 if (dist > 0) { 4223 current = target - dist; 4224 } else { 4225 current = target; 4226 } 4227 } else { 4228 dist += increment; 4229 if (dist < 0) { 4230 current = target - dist; 4231 } else { 4232 current = target; 4233 } 4234 } 4235 return current; 4236 } 4237 4238 /** 4239 * Generate a vector with all three values about zero. The 4240 * three ranges determine how wide the range about zero. 4241 */ 4242 void random_vec3s(Vec3s dst, s16 xRange, s16 yRange, s16 zRange) { 4243 f32 randomFloat; 4244 UNUSED u8 filler[4]; 4245 f32 tempXRange; 4246 f32 tempYRange; 4247 f32 tempZRange; 4248 4249 randomFloat = random_float(); 4250 tempXRange = xRange; 4251 dst[0] = randomFloat * tempXRange - tempXRange / 2; 4252 4253 randomFloat = random_float(); 4254 tempYRange = yRange; 4255 dst[1] = randomFloat * tempYRange - tempYRange / 2; 4256 4257 randomFloat = random_float(); 4258 tempZRange = zRange; 4259 dst[2] = randomFloat * tempZRange - tempZRange / 2; 4260 } 4261 4262 /** 4263 * Decrease value by multiplying it by the distance from (`posX`, `posY`, `posZ`) to 4264 * the camera divided by `maxDist` 4265 * 4266 * @return the reduced value 4267 */ 4268 s16 reduce_by_dist_from_camera(s16 value, f32 maxDist, f32 posX, f32 posY, f32 posZ) { 4269 Vec3f pos; 4270 f32 dist; 4271 s16 pitch; 4272 s16 yaw; 4273 s16 goalPitch; 4274 s16 goalYaw; 4275 s16 result = 0; 4276 // Direction from pos to (Lakitu's) goalPos 4277 f32 goalDX = gLakituState.goalPos[0] - posX; 4278 f32 goalDY = gLakituState.goalPos[1] - posY; 4279 f32 goalDZ = gLakituState.goalPos[2] - posZ; 4280 4281 dist = sqrtf(goalDX * goalDX + goalDY * goalDY + goalDZ * goalDZ); 4282 if (maxDist > dist) { 4283 pos[0] = posX; 4284 pos[1] = posY; 4285 pos[2] = posZ; 4286 vec3f_get_dist_and_angle(gLakituState.goalPos, pos, &dist, &pitch, &yaw); 4287 if (dist < maxDist) { 4288 calculate_angles(gLakituState.goalPos, gLakituState.goalFocus, &goalPitch, &goalYaw); 4289 //! Must be same line to match on -O2 4290 pitch -= goalPitch; yaw -= goalYaw; 4291 dist -= 2000.f; 4292 if (dist < 0.f) { 4293 dist = 0.f; 4294 } 4295 maxDist -= 2000.f; 4296 if (maxDist < 2000.f) { 4297 maxDist = 2000.f; 4298 } 4299 result = value * (1.f - dist / maxDist); 4300 if (pitch < -0x1800 || pitch > 0x400 || 4301 yaw < -0x1800 || yaw > 0x1800) { 4302 result /= 2; 4303 } 4304 } 4305 } 4306 return result; 4307 } 4308 4309 s32 clamp_positions_and_find_yaw(Vec3f pos, Vec3f origin, f32 xMax, f32 xMin, f32 zMax, f32 zMin) { 4310 s16 yaw = gCamera->nextYaw; 4311 4312 if (pos[0] >= xMax) { 4313 pos[0] = xMax; 4314 } 4315 if (pos[0] <= xMin) { 4316 pos[0] = xMin; 4317 } 4318 if (pos[2] >= zMax) { 4319 pos[2] = zMax; 4320 } 4321 if (pos[2] <= zMin) { 4322 pos[2] = zMin; 4323 } 4324 yaw = calculate_yaw(origin, pos); 4325 return yaw; 4326 } 4327 4328 /** 4329 * The yaw passed here is the yaw of the direction FROM Mario TO Lakitu. 4330 * 4331 * wallYaw always has 90 degrees added to it before this is called -- it's parallel to the wall. 4332 * 4333 * @return the new yaw from Mario to rotate towards. 4334 * 4335 * @warning this is jank. It actually returns the yaw that will rotate further INTO the wall. So, the 4336 * developers just add 180 degrees to the result. 4337 */ 4338 s32 calc_avoid_yaw(s16 yawFromMario, s16 wallYaw) { 4339 s16 yawDiff; 4340 UNUSED u8 filler[34]; // Debug print buffer? ;) 4341 UNUSED s32 unused1 = 0; 4342 UNUSED s32 unused2 = 0; 4343 4344 yawDiff = wallYaw - yawFromMario + DEGREES(90); 4345 4346 if (yawDiff < 0) { 4347 // Deflect to the right 4348 yawFromMario = wallYaw; 4349 } else { 4350 // Note: this favors the left side if the wall is exactly perpendicular to the camera. 4351 // Deflect to the left 4352 yawFromMario = wallYaw + DEGREES(180); 4353 } 4354 return yawFromMario; 4355 } 4356 4357 /** 4358 * Checks if `surf` is within the rect prism defined by xMax, yMax, and zMax 4359 * 4360 * @param surf surface to check 4361 * @param xMax absolute-value max size in x, set to -1 to ignore 4362 * @param yMax absolute-value max size in y, set to -1 to ignore 4363 * @param zMax absolute-value max size in z, set to -1 to ignore 4364 */ 4365 s32 is_surf_within_bounding_box(struct Surface *surf, f32 xMax, f32 yMax, f32 zMax) { 4366 // Surface vertex coordinates 4367 Vec3s sx; 4368 Vec3s sy; 4369 Vec3s sz; 4370 // Max delta between x, y, and z 4371 s16 dxMax = 0; 4372 s16 dyMax = 0; 4373 s16 dzMax = 0; 4374 // Current deltas between x, y, and z 4375 f32 dx; 4376 f32 dy; 4377 f32 dz; 4378 UNUSED u8 filler[4]; 4379 s32 i; 4380 s32 j; 4381 // result 4382 s32 smaller = FALSE; 4383 4384 sx[0] = surf->vertex1[0]; 4385 sx[1] = surf->vertex2[0]; 4386 sx[2] = surf->vertex3[0]; 4387 sy[0] = surf->vertex1[1]; 4388 sy[1] = surf->vertex2[1]; 4389 sy[2] = surf->vertex3[1]; 4390 sz[0] = surf->vertex1[2]; 4391 sz[1] = surf->vertex2[2]; 4392 sz[2] = surf->vertex3[2]; 4393 4394 for (i = 0; i < 3; i++) { 4395 j = i + 1; 4396 if (j >= 3) { 4397 j = 0; 4398 } 4399 dx = ABS(sx[i] - sx[j]); 4400 if (dx > dxMax) { 4401 dxMax = dx; 4402 } 4403 dy = ABS(sy[i] - sy[j]); 4404 if (dy > dyMax) { 4405 dyMax = dy; 4406 } 4407 dz = ABS(sz[i] - sz[j]); 4408 if (dz > dzMax) { 4409 dzMax = dz; 4410 } 4411 } 4412 if (yMax != -1.f) { 4413 if (dyMax < yMax) { 4414 smaller = TRUE; 4415 } 4416 } 4417 if (xMax != -1.f && zMax != -1.f) { 4418 if (dxMax < xMax && dzMax < zMax) { 4419 smaller = TRUE; 4420 } 4421 } 4422 return smaller; 4423 } 4424 4425 /** 4426 * Checks if `pos` is behind the surface, using the dot product. 4427 * 4428 * Because the function only uses `surf`s first vertex, some surfaces can shadow others. 4429 */ 4430 s32 is_behind_surface(Vec3f pos, struct Surface *surf) { 4431 s32 behindSurface = 0; 4432 // Surface normal 4433 f32 normX = (surf->vertex2[1] - surf->vertex1[1]) * (surf->vertex3[2] - surf->vertex2[2]) - 4434 (surf->vertex3[1] - surf->vertex2[1]) * (surf->vertex2[2] - surf->vertex1[2]); 4435 f32 normY = (surf->vertex2[2] - surf->vertex1[2]) * (surf->vertex3[0] - surf->vertex2[0]) - 4436 (surf->vertex3[2] - surf->vertex2[2]) * (surf->vertex2[0] - surf->vertex1[0]); 4437 f32 normZ = (surf->vertex2[0] - surf->vertex1[0]) * (surf->vertex3[1] - surf->vertex2[1]) - 4438 (surf->vertex3[0] - surf->vertex2[0]) * (surf->vertex2[1] - surf->vertex1[1]); 4439 f32 dirX = surf->vertex1[0] - pos[0]; 4440 f32 dirY = surf->vertex1[1] - pos[1]; 4441 f32 dirZ = surf->vertex1[2] - pos[2]; 4442 4443 if (dirX * normX + dirY * normY + dirZ * normZ < 0) { 4444 behindSurface = 1; 4445 } 4446 return behindSurface; 4447 } 4448 4449 /** 4450 * Checks if the whole circular sector is behind the surface. 4451 */ 4452 s32 is_range_behind_surface(Vec3f from, Vec3f to, struct Surface *surf, s16 range, s16 surfType) { 4453 s32 behindSurface = TRUE; 4454 s32 leftBehind = 0; 4455 s32 rightBehind = 0; 4456 UNUSED u8 filler[20]; 4457 f32 checkDist; 4458 s16 checkPitch; 4459 s16 checkYaw; 4460 Vec3f checkPos; 4461 4462 if (surf != NULL) { 4463 if (surfType == -1 || surf->type != surfType) { 4464 if (range == 0) { 4465 behindSurface = is_behind_surface(to, surf); 4466 } else { 4467 vec3f_get_dist_and_angle(from, to, &checkDist, &checkPitch, &checkYaw); 4468 vec3f_set_dist_and_angle(from, checkPos, checkDist, checkPitch, checkYaw + range); 4469 leftBehind = is_behind_surface(checkPos, surf); 4470 vec3f_set_dist_and_angle(from, checkPos, checkDist, checkPitch, checkYaw - range); 4471 rightBehind = is_behind_surface(checkPos, surf); 4472 behindSurface = leftBehind * rightBehind; 4473 } 4474 } 4475 } 4476 return behindSurface; 4477 } 4478 4479 s32 is_mario_behind_surface(UNUSED struct Camera *c, struct Surface *surf) { 4480 s32 behindSurface = is_behind_surface(sMarioCamState->pos, surf); 4481 4482 return behindSurface; 4483 } 4484 4485 /** 4486 * Calculates the distance between two points and sets a vector to a point 4487 * scaled along a line between them. Typically, somewhere in the middle. 4488 */ 4489 void scale_along_line(Vec3f dst, Vec3f from, Vec3f to, f32 scale) { 4490 Vec3f tempVec; 4491 4492 tempVec[0] = (to[0] - from[0]) * scale + from[0]; 4493 tempVec[1] = (to[1] - from[1]) * scale + from[1]; 4494 tempVec[2] = (to[2] - from[2]) * scale + from[2]; 4495 vec3f_copy(dst, tempVec); 4496 } 4497 /** 4498 * Effectively created a rectangular prism defined by a vector starting at the center 4499 * and extending to the corners. If the position is in this box, the function returns true. 4500 */ 4501 s32 is_pos_in_bounds(Vec3f pos, Vec3f center, Vec3f bounds, s16 boundsYaw) { 4502 s32 inBound = FALSE; 4503 Vec3f rel; 4504 4505 rel[0] = center[0] - pos[0]; 4506 rel[1] = center[1] - pos[1]; 4507 rel[2] = center[2] - pos[2]; 4508 4509 rotate_in_xz(rel, rel, boundsYaw); 4510 4511 if (-bounds[0] < rel[0] && rel[0] < bounds[0] && 4512 -bounds[1] < rel[1] && rel[1] < bounds[1] && 4513 -bounds[2] < rel[2] && rel[2] < bounds[2]) { 4514 inBound = TRUE; 4515 } 4516 return inBound; 4517 } 4518 4519 s16 calculate_pitch(Vec3f from, Vec3f to) { 4520 f32 dx = to[0] - from[0]; 4521 f32 dy = to[1] - from[1]; 4522 f32 dz = to[2] - from[2]; 4523 s16 pitch = atan2s(sqrtf(dx * dx + dz * dz), dy); 4524 4525 return pitch; 4526 } 4527 4528 s16 calculate_yaw(Vec3f from, Vec3f to) { 4529 f32 dx = to[0] - from[0]; 4530 UNUSED f32 dy = to[1] - from[1]; 4531 f32 dz = to[2] - from[2]; 4532 s16 yaw = atan2s(dz, dx); 4533 4534 return yaw; 4535 } 4536 4537 /** 4538 * Calculates the pitch and yaw between two vectors. 4539 */ 4540 void calculate_angles(Vec3f from, Vec3f to, s16 *pitch, s16 *yaw) { 4541 f32 dx = to[0] - from[0]; 4542 f32 dy = to[1] - from[1]; 4543 f32 dz = to[2] - from[2]; 4544 4545 *pitch = atan2s(sqrtf(dx * dx + dz * dz), dy); 4546 *yaw = atan2s(dz, dx); 4547 } 4548 4549 /** 4550 * Finds the distance between two vectors. 4551 */ 4552 f32 calc_abs_dist(Vec3f a, Vec3f b) { 4553 f32 distX = b[0] - a[0]; 4554 f32 distY = b[1] - a[1]; 4555 f32 distZ = b[2] - a[2]; 4556 f32 distAbs = sqrtf(distX * distX + distY * distY + distZ * distZ); 4557 4558 return distAbs; 4559 } 4560 4561 /** 4562 * Finds the horizontal distance between two vectors. 4563 */ 4564 f32 calc_hor_dist(Vec3f a, Vec3f b) { 4565 f32 distX = b[0] - a[0]; 4566 f32 distZ = b[2] - a[2]; 4567 f32 distHor = sqrtf(distX * distX + distZ * distZ); 4568 4569 return distHor; 4570 } 4571 4572 /** 4573 * Rotates a vector in the horizontal plane and copies it to a new vector. 4574 */ 4575 void rotate_in_xz(Vec3f dst, Vec3f src, s16 yaw) { 4576 Vec3f tempVec; 4577 4578 vec3f_copy(tempVec, src); 4579 dst[0] = tempVec[2] * sins(yaw) + tempVec[0] * coss(yaw); 4580 dst[1] = tempVec[1]; 4581 dst[2] = tempVec[2] * coss(yaw) - tempVec[0] * sins(yaw); 4582 } 4583 4584 /** 4585 * Rotates a vector in the YZ plane and copies it to a new vector. 4586 * 4587 * Note: This function also flips the Z axis, so +Z moves forward, not backward like it would in world 4588 * space. If possible, use vec3f_set_dist_and_angle() 4589 */ 4590 void rotate_in_yz(Vec3f dst, Vec3f src, s16 pitch) { 4591 Vec3f tempVec; 4592 4593 vec3f_copy(tempVec, src); 4594 dst[2] = -(tempVec[2] * coss(pitch) - tempVec[1] * sins(pitch)); 4595 dst[1] = tempVec[2] * sins(pitch) + tempVec[1] * coss(pitch); 4596 dst[0] = tempVec[0]; 4597 } 4598 4599 /** 4600 * Start shaking the camera's pitch (up and down) 4601 */ 4602 void set_camera_pitch_shake(s16 mag, s16 decay, s16 inc) { 4603 if (gLakituState.shakeMagnitude[0] < mag) { 4604 gLakituState.shakeMagnitude[0] = mag; 4605 gLakituState.shakePitchDecay = decay; 4606 gLakituState.shakePitchVel = inc; 4607 } 4608 } 4609 4610 /** 4611 * Start shaking the camera's yaw (side to side) 4612 */ 4613 void set_camera_yaw_shake(s16 mag, s16 decay, s16 inc) { 4614 if (ABS(mag) > ABS(gLakituState.shakeMagnitude[1])) { 4615 gLakituState.shakeMagnitude[1] = mag; 4616 gLakituState.shakeYawDecay = decay; 4617 gLakituState.shakeYawVel = inc; 4618 } 4619 } 4620 4621 /** 4622 * Start shaking the camera's roll (rotate screen clockwise and counterclockwise) 4623 */ 4624 void set_camera_roll_shake(s16 mag, s16 decay, s16 inc) { 4625 if (gLakituState.shakeMagnitude[2] < mag) { 4626 gLakituState.shakeMagnitude[2] = mag; 4627 gLakituState.shakeRollDecay = decay; 4628 gLakituState.shakeRollVel = inc; 4629 } 4630 } 4631 4632 /** 4633 * Start shaking the camera's pitch, but reduce `mag` by it's distance from the camera 4634 */ 4635 void set_pitch_shake_from_point(s16 mag, s16 decay, s16 inc, f32 maxDist, f32 posX, f32 posY, f32 posZ) { 4636 Vec3f pos; 4637 f32 dist; 4638 s16 dummyPitch; 4639 s16 dummyYaw; 4640 4641 pos[0] = posX; 4642 pos[1] = posY; 4643 pos[2] = posZ; 4644 vec3f_get_dist_and_angle(gLakituState.goalPos, pos, &dist, &dummyPitch, &dummyYaw); 4645 mag = reduce_by_dist_from_camera(mag, maxDist, posX, posY, posZ); 4646 if (mag != 0) { 4647 set_camera_pitch_shake(mag, decay, inc); 4648 } 4649 } 4650 4651 /** 4652 * Start shaking the camera's yaw, but reduce `mag` by it's distance from the camera 4653 */ 4654 void set_yaw_shake_from_point(s16 mag, s16 decay, s16 inc, f32 maxDist, f32 posX, f32 posY, f32 posZ) { 4655 Vec3f pos; 4656 f32 dist; 4657 s16 dummyPitch; 4658 s16 dummyYaw; 4659 4660 pos[0] = posX; 4661 pos[1] = posY; 4662 pos[2] = posZ; 4663 vec3f_get_dist_and_angle(gLakituState.goalPos, pos, &dist, &dummyPitch, &dummyYaw); 4664 mag = reduce_by_dist_from_camera(mag, maxDist, posX, posY, posZ); 4665 if (mag != 0) { 4666 set_camera_yaw_shake(mag, decay, inc); 4667 } 4668 } 4669 4670 /** 4671 * Update the shake offset by `increment` 4672 */ 4673 void increment_shake_offset(s16 *offset, s16 increment) { 4674 if (increment == -0x8000) { 4675 *offset = (*offset & 0x8000) + 0xC000; 4676 } else { 4677 *offset += increment; 4678 } 4679 } 4680 4681 /** 4682 * Apply a vertical shake to the camera by adjusting its pitch 4683 */ 4684 void shake_camera_pitch(Vec3f pos, Vec3f focus) { 4685 f32 dist; 4686 s16 pitch; 4687 s16 yaw; 4688 4689 if (gLakituState.shakeMagnitude[0] | gLakituState.shakeMagnitude[1]) { 4690 vec3f_get_dist_and_angle(pos, focus, &dist, &pitch, &yaw); 4691 pitch += gLakituState.shakeMagnitude[0] * sins(gLakituState.shakePitchPhase); 4692 vec3f_set_dist_and_angle(pos, focus, dist, pitch, yaw); 4693 increment_shake_offset(&gLakituState.shakePitchPhase, gLakituState.shakePitchVel); 4694 if (camera_approach_s16_symmetric_bool(&gLakituState.shakeMagnitude[0], 0, 4695 gLakituState.shakePitchDecay) == 0) { 4696 gLakituState.shakePitchPhase = 0; 4697 } 4698 } 4699 } 4700 4701 /** 4702 * Apply a horizontal shake to the camera by adjusting its yaw 4703 */ 4704 void shake_camera_yaw(Vec3f pos, Vec3f focus) { 4705 f32 dist; 4706 s16 pitch; 4707 s16 yaw; 4708 4709 if (gLakituState.shakeMagnitude[1] != 0) { 4710 vec3f_get_dist_and_angle(pos, focus, &dist, &pitch, &yaw); 4711 yaw += gLakituState.shakeMagnitude[1] * sins(gLakituState.shakeYawPhase); 4712 vec3f_set_dist_and_angle(pos, focus, dist, pitch, yaw); 4713 increment_shake_offset(&gLakituState.shakeYawPhase, gLakituState.shakeYawVel); 4714 if (camera_approach_s16_symmetric_bool(&gLakituState.shakeMagnitude[1], 0, 4715 gLakituState.shakeYawDecay) == 0) { 4716 gLakituState.shakeYawPhase = 0; 4717 } 4718 } 4719 } 4720 4721 /** 4722 * Apply a rotational shake to the camera by adjusting its roll 4723 */ 4724 void shake_camera_roll(s16 *roll) { 4725 UNUSED u8 filler[8]; 4726 4727 if (gLakituState.shakeMagnitude[2] != 0) { 4728 increment_shake_offset(&gLakituState.shakeRollPhase, gLakituState.shakeRollVel); 4729 *roll += gLakituState.shakeMagnitude[2] * sins(gLakituState.shakeRollPhase); 4730 if (camera_approach_s16_symmetric_bool(&gLakituState.shakeMagnitude[2], 0, 4731 gLakituState.shakeRollDecay) == 0) { 4732 gLakituState.shakeRollPhase = 0; 4733 } 4734 } 4735 } 4736 4737 /** 4738 * Add an offset to the camera's yaw, used in levels that are inside a rectangular building, like the 4739 * pyramid or TTC. 4740 */ 4741 s32 offset_yaw_outward_radial(struct Camera *c, s16 areaYaw) { 4742 s16 yawGoal = DEGREES(60); 4743 s16 yaw = sModeOffsetYaw; 4744 f32 distFromAreaCenter; 4745 Vec3f areaCenter; 4746 s16 dYaw; 4747 switch (gCurrLevelArea) { 4748 case AREA_TTC: 4749 areaCenter[0] = c->areaCenX; 4750 areaCenter[1] = sMarioCamState->pos[1]; 4751 areaCenter[2] = c->areaCenZ; 4752 distFromAreaCenter = calc_abs_dist(areaCenter, sMarioCamState->pos); 4753 if (800.f > distFromAreaCenter) { 4754 yawGoal = 0x3800; 4755 } 4756 break; 4757 case AREA_SSL_PYRAMID: 4758 // This mask splits the 360 degrees of yaw into 4 corners. It adds 45 degrees so that the yaw 4759 // offset at the corner will be 0, but the yaw offset near the center will face more towards 4760 // the direction Mario is running in. 4761 yawGoal = (areaYaw & 0xC000) - areaYaw + DEGREES(45); 4762 if (yawGoal < 0) { 4763 yawGoal = -yawGoal; 4764 } 4765 yawGoal = yawGoal / 32 * 48; 4766 break; 4767 case AREA_LLL_OUTSIDE: 4768 yawGoal = 0; 4769 break; 4770 } 4771 dYaw = gMarioStates[0].forwardVel / 32.f * 128.f; 4772 4773 if (sAreaYawChange < 0) { 4774 camera_approach_s16_symmetric_bool(&yaw, -yawGoal, dYaw); 4775 } 4776 if (sAreaYawChange > 0) { 4777 camera_approach_s16_symmetric_bool(&yaw, yawGoal, dYaw); 4778 } 4779 // When the final yaw is out of [-60,60] degrees, approach yawGoal faster than dYaw will ever be, 4780 // making the camera lock in one direction until yawGoal drops below 60 (or Mario presses a C button) 4781 if (yaw < -DEGREES(60)) { 4782 //! Maybe they meant to reverse yawGoal's sign? 4783 camera_approach_s16_symmetric_bool(&yaw, -yawGoal, 0x200); 4784 } 4785 if (yaw > DEGREES(60)) { 4786 //! Maybe they meant to reverse yawGoal's sign? 4787 camera_approach_s16_symmetric_bool(&yaw, yawGoal, 0x200); 4788 } 4789 return yaw; 4790 } 4791 4792 /** 4793 * Plays the background music that starts while peach reads the intro message. 4794 */ 4795 void cutscene_intro_peach_play_message_music(void) { 4796 play_music(SEQ_PLAYER_LEVEL, SEQUENCE_ARGS(4, SEQ_EVENT_PEACH_MESSAGE), 0); 4797 } 4798 4799 /** 4800 * Plays the music that starts after peach fades and Lakitu appears. 4801 */ 4802 void cutscene_intro_peach_play_lakitu_flying_music(void) { 4803 play_music(SEQ_PLAYER_LEVEL, SEQUENCE_ARGS(15, SEQ_EVENT_CUTSCENE_INTRO), 0); 4804 } 4805 4806 void play_camera_buzz_if_cdown(void) { 4807 if (gPlayer1Controller->buttonPressed & D_CBUTTONS) { 4808 play_sound_button_change_blocked(); 4809 } 4810 } 4811 4812 void play_camera_buzz_if_cbutton(void) { 4813 if (gPlayer1Controller->buttonPressed & CBUTTON_MASK) { 4814 play_sound_button_change_blocked(); 4815 } 4816 } 4817 4818 void play_camera_buzz_if_c_sideways(void) { 4819 if ((gPlayer1Controller->buttonPressed & L_CBUTTONS) 4820 || (gPlayer1Controller->buttonPressed & R_CBUTTONS)) { 4821 play_sound_button_change_blocked(); 4822 } 4823 } 4824 4825 void play_sound_cbutton_up(void) { 4826 play_sound(SOUND_MENU_CAMERA_ZOOM_IN, gGlobalSoundSource); 4827 } 4828 4829 void play_sound_cbutton_down(void) { 4830 play_sound(SOUND_MENU_CAMERA_ZOOM_OUT, gGlobalSoundSource); 4831 } 4832 4833 void play_sound_cbutton_side(void) { 4834 play_sound(SOUND_MENU_CAMERA_TURN, gGlobalSoundSource); 4835 } 4836 4837 void play_sound_button_change_blocked(void) { 4838 play_sound(SOUND_MENU_CAMERA_BUZZ, gGlobalSoundSource); 4839 } 4840 4841 void play_sound_rbutton_changed(void) { 4842 play_sound(SOUND_MENU_CLICK_CHANGE_VIEW, gGlobalSoundSource); 4843 } 4844 4845 void play_sound_if_cam_switched_to_lakitu_or_mario(void) { 4846 if (sCameraSoundFlags & CAM_SOUND_MARIO_ACTIVE) { 4847 play_sound_rbutton_changed(); 4848 } 4849 if (sCameraSoundFlags & CAM_SOUND_NORMAL_ACTIVE) { 4850 play_sound_rbutton_changed(); 4851 } 4852 sCameraSoundFlags &= ~(CAM_SOUND_MARIO_ACTIVE | CAM_SOUND_NORMAL_ACTIVE); 4853 } 4854 4855 /** 4856 * Handles input for radial, outwards radial, parallel tracking, and 8 direction mode. 4857 */ 4858 s32 radial_camera_input(struct Camera *c, UNUSED f32 unused) { 4859 s16 dummy; 4860 #ifdef AVOID_UB 4861 dummy = 0; 4862 #endif 4863 4864 if ((gCameraMovementFlags & CAM_MOVE_ENTERED_ROTATE_SURFACE) || !(gCameraMovementFlags & CAM_MOVE_ROTATE)) { 4865 4866 // If C-L or C-R are pressed, the camera is rotating 4867 if (gPlayer1Controller->buttonPressed & (L_CBUTTONS | R_CBUTTONS)) { 4868 gCameraMovementFlags &= ~CAM_MOVE_ENTERED_ROTATE_SURFACE; 4869 // @bug this does not clear the rotation flags set by the surface. It's possible to set 4870 // both ROTATE_LEFT and ROTATE_RIGHT, locking the camera. 4871 // Ex: If a surface set CAM_MOVE_ROTATE_RIGHT and the user presses C-R, it locks the 4872 // camera until a different mode is activated 4873 } 4874 4875 // Rotate Right and left 4876 if (gPlayer1Controller->buttonPressed & R_CBUTTONS) { 4877 if (sModeOffsetYaw > -0x800) { 4878 // The camera is now rotating right 4879 if (!(gCameraMovementFlags & CAM_MOVE_ROTATE_RIGHT)) { 4880 gCameraMovementFlags |= CAM_MOVE_ROTATE_RIGHT; 4881 } 4882 4883 if (c->mode == CAMERA_MODE_RADIAL) { 4884 // if > ~48 degrees, we're rotating for the second time. 4885 if (sModeOffsetYaw > 0x22AA) { 4886 s2ndRotateFlags |= CAM_MOVE_ROTATE_RIGHT; 4887 } 4888 4889 if (sModeOffsetYaw == DEGREES(105)) { 4890 play_sound_button_change_blocked(); 4891 } else { 4892 play_sound_cbutton_side(); 4893 } 4894 } else { 4895 if (sModeOffsetYaw == DEGREES(60)) { 4896 play_sound_button_change_blocked(); 4897 } else { 4898 play_sound_cbutton_side(); 4899 } 4900 } 4901 } else { 4902 gCameraMovementFlags |= CAM_MOVE_RETURN_TO_MIDDLE; 4903 play_sound_cbutton_up(); 4904 } 4905 } 4906 if (gPlayer1Controller->buttonPressed & L_CBUTTONS) { 4907 if (sModeOffsetYaw < 0x800) { 4908 if (!(gCameraMovementFlags & CAM_MOVE_ROTATE_LEFT)) { 4909 gCameraMovementFlags |= CAM_MOVE_ROTATE_LEFT; 4910 } 4911 4912 if (c->mode == CAMERA_MODE_RADIAL) { 4913 // if < ~48 degrees, we're rotating for the second time. 4914 if (sModeOffsetYaw < -0x22AA) { 4915 s2ndRotateFlags |= CAM_MOVE_ROTATE_LEFT; 4916 } 4917 4918 if (sModeOffsetYaw == DEGREES(-105)) { 4919 play_sound_button_change_blocked(); 4920 } else { 4921 play_sound_cbutton_side(); 4922 } 4923 } else { 4924 if (sModeOffsetYaw == DEGREES(-60)) { 4925 play_sound_button_change_blocked(); 4926 } else { 4927 play_sound_cbutton_side(); 4928 } 4929 } 4930 } else { 4931 gCameraMovementFlags |= CAM_MOVE_RETURN_TO_MIDDLE; 4932 play_sound_cbutton_up(); 4933 } 4934 } 4935 } 4936 4937 // Zoom in / enter C-Up 4938 if (gPlayer1Controller->buttonPressed & U_CBUTTONS) { 4939 if (gCameraMovementFlags & CAM_MOVE_ZOOMED_OUT) { 4940 gCameraMovementFlags &= ~CAM_MOVE_ZOOMED_OUT; 4941 play_sound_cbutton_up(); 4942 } else { 4943 set_mode_c_up(c); 4944 } 4945 } 4946 4947 // Zoom out 4948 if (gPlayer1Controller->buttonPressed & D_CBUTTONS) { 4949 if (gCameraMovementFlags & CAM_MOVE_ZOOMED_OUT) { 4950 gCameraMovementFlags |= CAM_MOVE_ALREADY_ZOOMED_OUT; 4951 #ifndef VERSION_JP 4952 play_camera_buzz_if_cdown(); 4953 #endif 4954 } else { 4955 gCameraMovementFlags |= CAM_MOVE_ZOOMED_OUT; 4956 play_sound_cbutton_down(); 4957 } 4958 } 4959 4960 //! returning uninitialized variable 4961 return dummy; 4962 } 4963 4964 /** 4965 * Starts a cutscene dialog. Only has an effect when `trigger` is 1 4966 */ 4967 s32 trigger_cutscene_dialog(s32 trigger) { 4968 s32 result = 0; 4969 UNUSED struct Camera *c = gCamera; 4970 4971 if (trigger == 1) { 4972 start_object_cutscene_without_focus(CUTSCENE_READ_MESSAGE); 4973 } 4974 if (trigger == 2) { 4975 } 4976 return result; 4977 } 4978 4979 /** 4980 * Updates the camera based on which C buttons are pressed this frame 4981 */ 4982 void handle_c_button_movement(struct Camera *c) { 4983 s16 cSideYaw; 4984 4985 // Zoom in 4986 if (gPlayer1Controller->buttonPressed & U_CBUTTONS) { 4987 if (c->mode != CAMERA_MODE_FIXED && (gCameraMovementFlags & CAM_MOVE_ZOOMED_OUT)) { 4988 gCameraMovementFlags &= ~CAM_MOVE_ZOOMED_OUT; 4989 play_sound_cbutton_up(); 4990 } else { 4991 set_mode_c_up(c); 4992 if (sZeroZoomDist > gCameraZoomDist) { 4993 sZoomAmount = -gCameraZoomDist; 4994 } else { 4995 sZoomAmount = gCameraZoomDist; 4996 } 4997 } 4998 } 4999 if (c->mode != CAMERA_MODE_FIXED) { 5000 // Zoom out 5001 if (gPlayer1Controller->buttonPressed & D_CBUTTONS) { 5002 if (gCameraMovementFlags & CAM_MOVE_ZOOMED_OUT) { 5003 gCameraMovementFlags |= CAM_MOVE_ALREADY_ZOOMED_OUT; 5004 sZoomAmount = gCameraZoomDist + 400.f; 5005 #ifndef VERSION_JP 5006 play_camera_buzz_if_cdown(); 5007 #endif 5008 } else { 5009 gCameraMovementFlags |= CAM_MOVE_ZOOMED_OUT; 5010 sZoomAmount = gCameraZoomDist + 400.f; 5011 play_sound_cbutton_down(); 5012 } 5013 } 5014 5015 // Rotate left or right 5016 cSideYaw = 0x1000; 5017 if (gPlayer1Controller->buttonPressed & R_CBUTTONS) { 5018 if (gCameraMovementFlags & CAM_MOVE_ROTATE_LEFT) { 5019 gCameraMovementFlags &= ~CAM_MOVE_ROTATE_LEFT; 5020 } else { 5021 gCameraMovementFlags |= CAM_MOVE_ROTATE_RIGHT; 5022 if (sCSideButtonYaw == 0) { 5023 play_sound_cbutton_side(); 5024 } 5025 sCSideButtonYaw = -cSideYaw; 5026 } 5027 } 5028 if (gPlayer1Controller->buttonPressed & L_CBUTTONS) { 5029 if (gCameraMovementFlags & CAM_MOVE_ROTATE_RIGHT) { 5030 gCameraMovementFlags &= ~CAM_MOVE_ROTATE_RIGHT; 5031 } else { 5032 gCameraMovementFlags |= CAM_MOVE_ROTATE_LEFT; 5033 if (sCSideButtonYaw == 0) { 5034 play_sound_cbutton_side(); 5035 } 5036 sCSideButtonYaw = cSideYaw; 5037 } 5038 } 5039 } 5040 } 5041 5042 /** 5043 * Zero the 10 cvars. 5044 */ 5045 void clear_cutscene_vars(UNUSED struct Camera *c) { 5046 s32 i; 5047 5048 for (i = 0; i < 10; i++) { 5049 sCutsceneVars[i].unused1 = 0; 5050 vec3f_set(sCutsceneVars[i].point, 0.f, 0.f, 0.f); 5051 vec3f_set(sCutsceneVars[i].unusedPoint, 0.f, 0.f, 0.f); 5052 vec3s_set(sCutsceneVars[i].angle, 0, 0, 0); 5053 sCutsceneVars[i].unused2 = 0; 5054 } 5055 } 5056 5057 /** 5058 * Start the cutscene, `cutscene`, if it is not already playing. 5059 */ 5060 void start_cutscene(struct Camera *c, u8 cutscene) { 5061 if (c->cutscene != cutscene) { 5062 c->cutscene = cutscene; 5063 clear_cutscene_vars(c); 5064 } 5065 } 5066 5067 /** 5068 * Look up the victory dance cutscene in sDanceCutsceneTable 5069 * 5070 * First the index entry is determined based on the course and the star that was just picked up 5071 * Like the entries in sZoomOutAreaMasks, each entry represents two stars 5072 * The current courses's 4 bits of the index entry are used as the actual index into sDanceCutsceneTable 5073 * 5074 * @return the victory cutscene to use 5075 */ 5076 s32 determine_dance_cutscene(UNUSED struct Camera *c) { 5077 u8 cutscene = 0; 5078 u8 cutsceneIndex = 0; 5079 u8 starIndex = (gLastCompletedStarNum - 1) / 2; 5080 u8 courseNum = gCurrCourseNum; 5081 5082 if (starIndex > 3) { 5083 starIndex = 0; 5084 } 5085 if (courseNum > COURSE_MAX) { 5086 courseNum = COURSE_NONE; 5087 } 5088 cutsceneIndex = sDanceCutsceneIndexTable[courseNum][starIndex]; 5089 5090 if (gLastCompletedStarNum & 1) { 5091 // Odd stars take the lower four bytes 5092 cutsceneIndex &= 0xF; 5093 } else { 5094 // Even stars use the upper four bytes 5095 cutsceneIndex = cutsceneIndex >> 4; 5096 } 5097 cutscene = sDanceCutsceneTable[cutsceneIndex]; 5098 return cutscene; 5099 } 5100 5101 /** 5102 * @return `pullResult` or `pushResult` depending on Mario's door action 5103 */ 5104 u8 open_door_cutscene(u8 pullResult, u8 pushResult) { 5105 s16 result; 5106 5107 if (sMarioCamState->action == ACT_PULLING_DOOR) { 5108 result = pullResult; 5109 } 5110 if (sMarioCamState->action == ACT_PUSHING_DOOR) { 5111 result = pushResult; 5112 } 5113 return result; 5114 } 5115 5116 /** 5117 * If no cutscenes are playing, determines if a cutscene should play based on Mario's action and 5118 * cameraEvent 5119 * 5120 * @return the cutscene that should start, 0 if none 5121 */ 5122 u8 get_cutscene_from_mario_status(struct Camera *c) { 5123 UNUSED u8 filler1[4]; 5124 u8 cutscene = c->cutscene; 5125 UNUSED u8 filler2[12]; 5126 5127 if (cutscene == 0) { 5128 // A cutscene started by an object, if any, will start if nothing else happened 5129 cutscene = sObjectCutscene; 5130 sObjectCutscene = 0; 5131 if (sMarioCamState->cameraEvent == CAM_EVENT_DOOR) { 5132 switch (gCurrLevelArea) { 5133 case AREA_CASTLE_LOBBY: 5134 //! doorStatus is never DOOR_ENTER_LOBBY when cameraEvent == 6, because 5135 //! doorStatus is only used for the star door in the lobby, which uses 5136 //! ACT_ENTERING_STAR_DOOR 5137 if (c->mode == CAMERA_MODE_SPIRAL_STAIRS || c->mode == CAMERA_MODE_CLOSE 5138 || c->doorStatus == DOOR_ENTER_LOBBY) { 5139 cutscene = open_door_cutscene(CUTSCENE_DOOR_PULL_MODE, CUTSCENE_DOOR_PUSH_MODE); 5140 } else { 5141 cutscene = open_door_cutscene(CUTSCENE_DOOR_PULL, CUTSCENE_DOOR_PUSH); 5142 } 5143 break; 5144 case AREA_BBH: 5145 //! Castle Lobby uses 0 to mean 'no special modes', but BBH uses 1... 5146 if (c->doorStatus == DOOR_LEAVING_SPECIAL) { 5147 cutscene = open_door_cutscene(CUTSCENE_DOOR_PULL, CUTSCENE_DOOR_PUSH); 5148 } else { 5149 cutscene = open_door_cutscene(CUTSCENE_DOOR_PULL_MODE, CUTSCENE_DOOR_PUSH_MODE); 5150 } 5151 break; 5152 default: 5153 cutscene = open_door_cutscene(CUTSCENE_DOOR_PULL, CUTSCENE_DOOR_PUSH); 5154 break; 5155 } 5156 } 5157 if (sMarioCamState->cameraEvent == CAM_EVENT_DOOR_WARP) { 5158 cutscene = CUTSCENE_DOOR_WARP; 5159 } 5160 if (sMarioCamState->cameraEvent == CAM_EVENT_CANNON) { 5161 cutscene = CUTSCENE_ENTER_CANNON; 5162 } 5163 if (SURFACE_IS_PAINTING_WARP(sMarioGeometry.currFloorType)) { 5164 cutscene = CUTSCENE_ENTER_PAINTING; 5165 } 5166 switch (sMarioCamState->action) { 5167 case ACT_DEATH_EXIT: 5168 cutscene = CUTSCENE_DEATH_EXIT; 5169 break; 5170 case ACT_EXIT_AIRBORNE: 5171 cutscene = CUTSCENE_EXIT_PAINTING_SUCC; 5172 break; 5173 case ACT_SPECIAL_EXIT_AIRBORNE: 5174 if (gPrevLevel == LEVEL_BOWSER_1 || gPrevLevel == LEVEL_BOWSER_2 5175 || gPrevLevel == LEVEL_BOWSER_3) { 5176 cutscene = CUTSCENE_EXIT_BOWSER_SUCC; 5177 } else { 5178 cutscene = CUTSCENE_EXIT_SPECIAL_SUCC; 5179 } 5180 break; 5181 case ACT_SPECIAL_DEATH_EXIT: 5182 if (gPrevLevel == LEVEL_BOWSER_1 || gPrevLevel == LEVEL_BOWSER_2 5183 || gPrevLevel == LEVEL_BOWSER_3) { 5184 cutscene = CUTSCENE_EXIT_BOWSER_DEATH; 5185 } else { 5186 cutscene = CUTSCENE_NONPAINTING_DEATH; 5187 } 5188 break; 5189 case ACT_ENTERING_STAR_DOOR: 5190 if (c->doorStatus == DOOR_DEFAULT) { 5191 cutscene = CUTSCENE_SLIDING_DOORS_OPEN; 5192 } else { 5193 cutscene = CUTSCENE_DOOR_PULL_MODE; 5194 } 5195 break; 5196 case ACT_UNLOCKING_KEY_DOOR: 5197 cutscene = CUTSCENE_UNLOCK_KEY_DOOR; 5198 break; 5199 case ACT_WATER_DEATH: 5200 cutscene = CUTSCENE_WATER_DEATH; 5201 break; 5202 case ACT_DEATH_ON_BACK: 5203 cutscene = CUTSCENE_DEATH_ON_BACK; 5204 break; 5205 case ACT_DEATH_ON_STOMACH: 5206 cutscene = CUTSCENE_DEATH_ON_STOMACH; 5207 break; 5208 case ACT_STANDING_DEATH: 5209 cutscene = CUTSCENE_STANDING_DEATH; 5210 break; 5211 case ACT_SUFFOCATION: 5212 cutscene = CUTSCENE_SUFFOCATION_DEATH; 5213 break; 5214 case ACT_QUICKSAND_DEATH: 5215 cutscene = CUTSCENE_QUICKSAND_DEATH; 5216 break; 5217 case ACT_ELECTROCUTION: 5218 cutscene = CUTSCENE_STANDING_DEATH; 5219 break; 5220 case ACT_STAR_DANCE_EXIT: 5221 cutscene = determine_dance_cutscene(c); 5222 break; 5223 case ACT_STAR_DANCE_WATER: 5224 cutscene = determine_dance_cutscene(c); 5225 break; 5226 case ACT_STAR_DANCE_NO_EXIT: 5227 cutscene = CUTSCENE_DANCE_DEFAULT; 5228 break; 5229 } 5230 switch (sMarioCamState->cameraEvent) { 5231 case CAM_EVENT_START_INTRO: 5232 cutscene = CUTSCENE_INTRO_PEACH; 5233 break; 5234 case CAM_EVENT_START_GRAND_STAR: 5235 cutscene = CUTSCENE_GRAND_STAR; 5236 break; 5237 case CAM_EVENT_START_ENDING: 5238 cutscene = CUTSCENE_ENDING; 5239 break; 5240 case CAM_EVENT_START_END_WAVING: 5241 cutscene = CUTSCENE_END_WAVING; 5242 break; 5243 case CAM_EVENT_START_CREDITS: 5244 cutscene = CUTSCENE_CREDITS; 5245 break; 5246 } 5247 } 5248 //! doorStatus is reset every frame. CameraTriggers need to constantly set doorStatus 5249 c->doorStatus = DOOR_DEFAULT; 5250 5251 return cutscene; 5252 } 5253 5254 /** 5255 * Moves the camera when Mario has triggered a warp 5256 */ 5257 void warp_camera(f32 displacementX, f32 displacementY, f32 displacementZ) { 5258 Vec3f displacement; 5259 struct MarioState *marioStates = &gMarioStates[0]; 5260 struct LinearTransitionPoint *start = &sModeInfo.transitionStart; 5261 struct LinearTransitionPoint *end = &sModeInfo.transitionEnd; 5262 5263 gCurrLevelArea = gCurrLevelNum * 16 + gCurrentArea->index; 5264 displacement[0] = displacementX; 5265 displacement[1] = displacementY; 5266 displacement[2] = displacementZ; 5267 vec3f_add(gLakituState.curPos, displacement); 5268 vec3f_add(gLakituState.curFocus, displacement); 5269 vec3f_add(gLakituState.goalPos, displacement); 5270 vec3f_add(gLakituState.goalFocus, displacement); 5271 marioStates->waterLevel += displacementY; 5272 5273 vec3f_add(start->focus, displacement); 5274 vec3f_add(start->pos, displacement); 5275 vec3f_add(end->focus, displacement); 5276 vec3f_add(end->pos, displacement); 5277 } 5278 5279 /** 5280 * Make the camera's y coordinate approach `goal`, 5281 * unless smooth movement is off, in which case the y coordinate is simply set to `goal` 5282 */ 5283 void approach_camera_height(struct Camera *c, f32 goal, f32 inc) { 5284 if (sStatusFlags & CAM_FLAG_SMOOTH_MOVEMENT) { 5285 if (c->pos[1] < goal) { 5286 if ((c->pos[1] += inc) > goal) { 5287 c->pos[1] = goal; 5288 } 5289 } else { 5290 if ((c->pos[1] -= inc) < goal) { 5291 c->pos[1] = goal; 5292 } 5293 } 5294 } else { 5295 c->pos[1] = goal; 5296 } 5297 } 5298 5299 void stub_camera_4(UNUSED s32 a, UNUSED s32 b, UNUSED s32 c, UNUSED s32 d) { 5300 } 5301 5302 /** 5303 * Set the camera's focus to Mario's position, and add several relative offsets. 5304 * 5305 * @param leftRight offset to Mario's left/right, relative to his faceAngle 5306 * @param yOff y offset 5307 * @param forwBack offset to Mario's front/back, relative to his faceAngle 5308 * @param yawOff offset to Mario's faceAngle, changes the direction of `leftRight` and `forwBack` 5309 */ 5310 void set_focus_rel_mario(struct Camera *c, f32 leftRight, f32 yOff, f32 forwBack, s16 yawOff) { 5311 s16 yaw; 5312 UNUSED u16 unused; 5313 f32 focFloorYOff; 5314 5315 calc_y_to_curr_floor(&focFloorYOff, 1.f, 200.f, &focFloorYOff, 0.9f, 200.f); 5316 yaw = sMarioCamState->faceAngle[1] + yawOff; 5317 c->focus[2] = sMarioCamState->pos[2] + forwBack * coss(yaw) - leftRight * sins(yaw); 5318 c->focus[0] = sMarioCamState->pos[0] + forwBack * sins(yaw) + leftRight * coss(yaw); 5319 c->focus[1] = sMarioCamState->pos[1] + yOff + focFloorYOff; 5320 } 5321 5322 /** 5323 * Set the camera's position to Mario's position, and add several relative offsets. Unused. 5324 * 5325 * @param leftRight offset to Mario's left/right, relative to his faceAngle 5326 * @param yOff y offset 5327 * @param forwBack offset to Mario's front/back, relative to his faceAngle 5328 * @param yawOff offset to Mario's faceAngle, changes the direction of `leftRight` and `forwBack` 5329 */ 5330 UNUSED static void unused_set_pos_rel_mario(struct Camera *c, f32 leftRight, f32 yOff, f32 forwBack, s16 yawOff) { 5331 u16 yaw = sMarioCamState->faceAngle[1] + yawOff; 5332 5333 c->pos[0] = sMarioCamState->pos[0] + forwBack * sins(yaw) + leftRight * coss(yaw); 5334 c->pos[1] = sMarioCamState->pos[1] + yOff; 5335 c->pos[2] = sMarioCamState->pos[2] + forwBack * coss(yaw) - leftRight * sins(yaw); 5336 } 5337 5338 /** 5339 * Rotates the offset `to` according to the pitch and yaw values in `rotation`. 5340 * Adds `from` to the rotated offset, and stores the result in `dst`. 5341 * 5342 * @warning Flips the Z axis, so that relative to `rotation`, -Z moves forwards and +Z moves backwards. 5343 */ 5344 void offset_rotated(Vec3f dst, Vec3f from, Vec3f to, Vec3s rotation) { 5345 Vec3f unusedCopy; 5346 Vec3f pitchRotated; 5347 5348 vec3f_copy(unusedCopy, from); 5349 5350 // First rotate the direction by rotation's pitch 5351 //! The Z axis is flipped here. 5352 pitchRotated[2] = -(to[2] * coss(rotation[0]) - to[1] * sins(rotation[0])); 5353 pitchRotated[1] = to[2] * sins(rotation[0]) + to[1] * coss(rotation[0]); 5354 pitchRotated[0] = to[0]; 5355 5356 // Rotate again by rotation's yaw 5357 dst[0] = from[0] + pitchRotated[2] * sins(rotation[1]) + pitchRotated[0] * coss(rotation[1]); 5358 dst[1] = from[1] + pitchRotated[1]; 5359 dst[2] = from[2] + pitchRotated[2] * coss(rotation[1]) - pitchRotated[0] * sins(rotation[1]); 5360 } 5361 5362 /** 5363 * Rotates the offset defined by (`xTo`, `yTo`, `zTo`) according to the pitch and yaw values in `rotation`. 5364 * Adds `from` to the rotated offset, and stores the result in `dst`. 5365 * 5366 * @warning Flips the Z axis, so that relative to `rotation`, -Z moves forwards and +Z moves backwards. 5367 */ 5368 void offset_rotated_coords(Vec3f dst, Vec3f from, Vec3s rotation, f32 xTo, f32 yTo, f32 zTo) { 5369 Vec3f to; 5370 5371 vec3f_set(to, xTo, yTo, zTo); 5372 offset_rotated(dst, from, to, rotation); 5373 } 5374 5375 void determine_pushing_or_pulling_door(s16 *rotation) { 5376 if (sMarioCamState->action == ACT_PULLING_DOOR) { 5377 *rotation = 0; 5378 } else { 5379 *rotation = DEGREES(-180); 5380 } 5381 } 5382 5383 /** 5384 * Calculate Lakitu's next position and focus, according to gCamera's state, 5385 * and store them in `newPos` and `newFoc`. 5386 * 5387 * @param newPos where Lakitu should fly towards this frame 5388 * @param newFoc where Lakitu should look towards this frame 5389 * 5390 * @param curPos gCamera's pos this frame 5391 * @param curFoc gCamera's foc this frame 5392 * 5393 * @param oldPos gCamera's pos last frame 5394 * @param oldFoc gCamera's foc last frame 5395 * 5396 * @return Lakitu's next yaw, which is the same as the yaw passed in if no transition happened 5397 */ 5398 s16 next_lakitu_state(Vec3f newPos, Vec3f newFoc, Vec3f curPos, Vec3f curFoc, 5399 Vec3f oldPos, Vec3f oldFoc, s16 yaw) { 5400 s16 yawVelocity; 5401 s16 pitchVelocity; 5402 f32 distVelocity; 5403 f32 goalDist; 5404 UNUSED u8 filler1[4]; 5405 s16 goalPitch; 5406 s16 goalYaw; 5407 UNUSED u8 filler2[4]; 5408 f32 distTimer = sModeTransition.framesLeft; 5409 s16 angleTimer = sModeTransition.framesLeft; 5410 UNUSED s16 inTransition = FALSE; 5411 Vec3f nextPos; 5412 Vec3f nextFoc; 5413 Vec3f startPos; 5414 Vec3f startFoc; 5415 s32 i; 5416 f32 floorHeight; 5417 struct Surface *floor; 5418 5419 // If not transitioning, just use gCamera's current pos and foc 5420 vec3f_copy(newPos, curPos); 5421 vec3f_copy(newFoc, curFoc); 5422 5423 if (sStatusFlags & CAM_FLAG_START_TRANSITION) { 5424 for (i = 0; i < 3; i++) { 5425 // Add Mario's displacement from this frame to the last frame's pos and focus 5426 // Makes the transition start from where the camera would have moved 5427 startPos[i] = oldPos[i] + sMarioCamState->pos[i] - sModeTransition.marioPos[i]; 5428 startFoc[i] = oldFoc[i] + sMarioCamState->pos[i] - sModeTransition.marioPos[i]; 5429 } 5430 5431 5432 vec3f_get_dist_and_angle(curFoc, startFoc, &sModeTransition.focDist, &sModeTransition.focPitch, 5433 &sModeTransition.focYaw); 5434 vec3f_get_dist_and_angle(curFoc, startPos, &sModeTransition.posDist, &sModeTransition.posPitch, 5435 &sModeTransition.posYaw); 5436 sStatusFlags &= ~CAM_FLAG_START_TRANSITION; 5437 } 5438 5439 // Transition from the last mode to the current one 5440 if (sModeTransition.framesLeft > 0) { 5441 inTransition = TRUE; 5442 5443 vec3f_get_dist_and_angle(curFoc, curPos, &goalDist, &goalPitch, &goalYaw); 5444 distVelocity = ABS(goalDist - sModeTransition.posDist) / distTimer; 5445 pitchVelocity = ABS(goalPitch - sModeTransition.posPitch) / angleTimer; 5446 yawVelocity = ABS(goalYaw - sModeTransition.posYaw) / angleTimer; 5447 5448 camera_approach_f32_symmetric_bool(&sModeTransition.posDist, goalDist, distVelocity); 5449 camera_approach_s16_symmetric_bool(&sModeTransition.posYaw, goalYaw, yawVelocity); 5450 camera_approach_s16_symmetric_bool(&sModeTransition.posPitch, goalPitch, pitchVelocity); 5451 vec3f_set_dist_and_angle(curFoc, nextPos, sModeTransition.posDist, sModeTransition.posPitch, 5452 sModeTransition.posYaw); 5453 5454 vec3f_get_dist_and_angle(curPos, curFoc, &goalDist, &goalPitch, &goalYaw); 5455 pitchVelocity = sModeTransition.focPitch / (s16) sModeTransition.framesLeft; 5456 yawVelocity = sModeTransition.focYaw / (s16) sModeTransition.framesLeft; 5457 distVelocity = sModeTransition.focDist / sModeTransition.framesLeft; 5458 5459 camera_approach_s16_symmetric_bool(&sModeTransition.focPitch, goalPitch, pitchVelocity); 5460 camera_approach_s16_symmetric_bool(&sModeTransition.focYaw, goalYaw, yawVelocity); 5461 camera_approach_f32_symmetric_bool(&sModeTransition.focDist, 0, distVelocity); 5462 vec3f_set_dist_and_angle(curFoc, nextFoc, sModeTransition.focDist, sModeTransition.focPitch, 5463 sModeTransition.focYaw); 5464 5465 vec3f_copy(newFoc, nextFoc); 5466 vec3f_copy(newPos, nextPos); 5467 5468 if (gCamera->cutscene != 0 || !(gCameraMovementFlags & CAM_MOVE_C_UP_MODE)) { 5469 floorHeight = find_floor(newPos[0], newPos[1], newPos[2], &floor); 5470 if (floorHeight != FLOOR_LOWER_LIMIT) { 5471 if ((floorHeight += 125.f) > newPos[1]) { 5472 newPos[1] = floorHeight; 5473 } 5474 } 5475 f32_find_wall_collision(&newPos[0], &newPos[1], &newPos[2], 0.f, 100.f); 5476 } 5477 sModeTransition.framesLeft--; 5478 yaw = calculate_yaw(newFoc, newPos); 5479 } else { 5480 sModeTransition.posDist = 0.f; 5481 sModeTransition.posPitch = 0; 5482 sModeTransition.posYaw = 0; 5483 sStatusFlags &= ~CAM_FLAG_TRANSITION_OUT_OF_C_UP; 5484 } 5485 vec3f_copy(sModeTransition.marioPos, sMarioCamState->pos); 5486 return yaw; 5487 } 5488 5489 static UNUSED void stop_transitional_movement(void) { 5490 sStatusFlags &= ~(CAM_FLAG_START_TRANSITION | CAM_FLAG_TRANSITION_OUT_OF_C_UP); 5491 sModeTransition.framesLeft = 0; 5492 } 5493 5494 /** 5495 * Start fixed camera mode, setting the base position to (`x`, `y`, `z`) 5496 * 5497 * @return TRUE if the base pos was updated 5498 */ 5499 s32 set_camera_mode_fixed(struct Camera *c, s16 x, s16 y, s16 z) { 5500 s32 basePosSet = FALSE; 5501 f32 posX = x; 5502 f32 posY = y; 5503 f32 posZ = z; 5504 5505 if (sFixedModeBasePosition[0] != posX || sFixedModeBasePosition[1] != posY 5506 || sFixedModeBasePosition[2] != posZ) { 5507 basePosSet = TRUE; 5508 sStatusFlags &= ~CAM_FLAG_SMOOTH_MOVEMENT; 5509 } 5510 vec3f_set(sFixedModeBasePosition, posX, posY, posZ); 5511 if (c->mode != CAMERA_MODE_FIXED) { 5512 sStatusFlags &= ~CAM_FLAG_SMOOTH_MOVEMENT; 5513 c->mode = CAMERA_MODE_FIXED; 5514 vec3f_set(c->pos, sFixedModeBasePosition[0], sMarioCamState->pos[1], 5515 sFixedModeBasePosition[2]); 5516 } 5517 return basePosSet; 5518 } 5519 5520 void set_camera_mode_8_directions(struct Camera *c) { 5521 if (c->mode != CAMERA_MODE_8_DIRECTIONS) { 5522 c->mode = CAMERA_MODE_8_DIRECTIONS; 5523 sStatusFlags &= ~CAM_FLAG_SMOOTH_MOVEMENT; 5524 s8DirModeBaseYaw = 0; 5525 s8DirModeYawOffset = 0; 5526 } 5527 } 5528 5529 /** 5530 * If the camera mode is not already the boss fight camera (camera with two foci) 5531 * set it to be so. 5532 */ 5533 void set_camera_mode_boss_fight(struct Camera *c) { 5534 if (c->mode != CAMERA_MODE_BOSS_FIGHT) { 5535 transition_to_camera_mode(c, CAMERA_MODE_BOSS_FIGHT, 15); 5536 sModeOffsetYaw = c->nextYaw - DEGREES(45); 5537 } 5538 } 5539 5540 void set_camera_mode_close_cam(u8 *mode) { 5541 if (*mode != CAMERA_MODE_CLOSE) { 5542 sStatusFlags &= ~CAM_FLAG_SMOOTH_MOVEMENT; 5543 *mode = CAMERA_MODE_CLOSE; 5544 } 5545 } 5546 5547 /** 5548 * Change to radial mode. 5549 * If the difference in yaw between pos -> Mario and pos > focus is < 90 degrees, transition. 5550 * Otherwise jump to radial mode. 5551 */ 5552 void set_camera_mode_radial(struct Camera *c, s16 transitionTime) { 5553 Vec3f focus; 5554 s16 yaw; 5555 5556 focus[0] = c->areaCenX; 5557 focus[1] = sMarioCamState->pos[1]; 5558 focus[2] = c->areaCenZ; 5559 if (c->mode != CAMERA_MODE_RADIAL) { 5560 yaw = calculate_yaw(focus, sMarioCamState->pos) - calculate_yaw(c->focus, c->pos) + DEGREES(90); 5561 if (yaw > 0) { 5562 transition_to_camera_mode(c, CAMERA_MODE_RADIAL, transitionTime); 5563 } else { 5564 c->mode = CAMERA_MODE_RADIAL; 5565 sStatusFlags &= ~CAM_FLAG_SMOOTH_MOVEMENT; 5566 } 5567 sModeOffsetYaw = 0; 5568 } 5569 } 5570 5571 /** 5572 * Start parallel tracking mode using the path `path` 5573 */ 5574 void parallel_tracking_init(struct Camera *c, struct ParallelTrackingPoint *path) { 5575 if (c->mode != CAMERA_MODE_PARALLEL_TRACKING) { 5576 sParTrackPath = path; 5577 sParTrackIndex = 0; 5578 sParTrackTransOff.pos[0] = 0.f; 5579 sParTrackTransOff.pos[1] = 0.f; 5580 sParTrackTransOff.pos[2] = 0.f; 5581 // Place the camera in the middle of the path 5582 c->pos[0] = (sParTrackPath[0].pos[0] + sParTrackPath[1].pos[0]) / 2; 5583 c->pos[1] = (sParTrackPath[0].pos[1] + sParTrackPath[1].pos[1]) / 2; 5584 c->pos[2] = (sParTrackPath[0].pos[2] + sParTrackPath[1].pos[2]) / 2; 5585 sStatusFlags &= ~CAM_FLAG_SMOOTH_MOVEMENT; 5586 c->mode = CAMERA_MODE_PARALLEL_TRACKING; 5587 } 5588 } 5589 5590 /** 5591 * Set the fixed camera base pos depending on the current level area 5592 */ 5593 void set_fixed_cam_axis_sa_lobby(UNUSED s16 preset) { 5594 switch (gCurrLevelArea) { 5595 case AREA_SA: 5596 vec3f_set(sFixedModeBasePosition, 646.f, 143.f, -1513.f); 5597 break; 5598 5599 case AREA_CASTLE_LOBBY: 5600 vec3f_set(sFixedModeBasePosition, -577.f, 143.f, 1443.f); 5601 break; 5602 } 5603 } 5604 5605 /** 5606 * Block area-specific CameraTrigger and special surface modes. 5607 * Generally, block area mode changes if: 5608 * Mario is wearing the metal cap, or at the water's surface, or the camera is in Mario mode 5609 * 5610 * However, if the level is WDW, DDD, or CotMC (levels that have metal cap and water): 5611 * Only block area mode changes if Mario is in a cannon, 5612 * or if the camera is in Mario mode and Mario is not swimming or in water with the metal cap 5613 */ 5614 void check_blocking_area_processing(const u8 *mode) { 5615 if (sMarioCamState->action & ACT_FLAG_METAL_WATER || 5616 *mode == CAMERA_MODE_BEHIND_MARIO || *mode == CAMERA_MODE_WATER_SURFACE) { 5617 sStatusFlags |= CAM_FLAG_BLOCK_AREA_PROCESSING; 5618 } 5619 5620 if (gCurrLevelNum == LEVEL_DDD || gCurrLevelNum == LEVEL_WDW || gCurrLevelNum == LEVEL_COTMC) { 5621 sStatusFlags &= ~CAM_FLAG_BLOCK_AREA_PROCESSING; 5622 } 5623 5624 if ((*mode == CAMERA_MODE_BEHIND_MARIO && 5625 !(sMarioCamState->action & (ACT_FLAG_SWIMMING | ACT_FLAG_METAL_WATER))) || 5626 *mode == CAMERA_MODE_INSIDE_CANNON) { 5627 sStatusFlags |= CAM_FLAG_BLOCK_AREA_PROCESSING; 5628 } 5629 } 5630 5631 BAD_RETURN(s32) cam_rr_exit_building_side(struct Camera *c) { 5632 set_camera_mode_8_directions(c); 5633 s8DirModeBaseYaw = DEGREES(90); 5634 } 5635 5636 BAD_RETURN(s32) cam_rr_exit_building_top(struct Camera *c) { 5637 set_camera_mode_8_directions(c); 5638 if (c->pos[1] < 6343.f) { 5639 c->pos[1] = 7543.f; 5640 gLakituState.goalPos[1] = c->pos[1]; 5641 gLakituState.curPos[1] = c->pos[1]; 5642 sStatusFlags &= ~CAM_FLAG_SMOOTH_MOVEMENT; 5643 } 5644 } 5645 5646 BAD_RETURN(s32) cam_rr_enter_building_window(struct Camera *c) { 5647 if (c->mode != CAMERA_MODE_FIXED) { 5648 set_camera_mode_fixed(c, -2974, 478, -3975); 5649 } 5650 } 5651 5652 BAD_RETURN(s32) cam_rr_enter_building(struct Camera *c) { 5653 if (c->mode != CAMERA_MODE_FIXED) { 5654 set_camera_mode_fixed(c, -2953, 798, -3943); 5655 } 5656 // Prevent the camera from being above the roof 5657 if (c->pos[1] > 6043.f) { 5658 c->pos[1] = 6043.f; 5659 } 5660 } 5661 5662 BAD_RETURN(s32) cam_rr_enter_building_side(struct Camera *c) { 5663 if (c->mode != CAMERA_MODE_FIXED) { 5664 sStatusFlags &= ~CAM_FLAG_SMOOTH_MOVEMENT; 5665 c->mode = CAMERA_MODE_FIXED; 5666 } 5667 } 5668 5669 /** 5670 * Fix the camera in place as Mario gets exits out the MC cave into the waterfall. 5671 */ 5672 BAD_RETURN(s32) cam_cotmc_exit_waterfall(UNUSED struct Camera *c) { 5673 gCameraMovementFlags |= CAM_MOVE_FIX_IN_PLACE; 5674 } 5675 5676 /** 5677 * Sets 8 directional mode and blocks the next trigger from processing. 5678 * Activated when Mario is walking in front of the snowman's head. 5679 */ 5680 BAD_RETURN(s32) cam_sl_snowman_head_8dir(struct Camera *c) { 5681 sStatusFlags |= CAM_FLAG_BLOCK_AREA_PROCESSING; 5682 transition_to_camera_mode(c, CAMERA_MODE_8_DIRECTIONS, 60); 5683 s8DirModeBaseYaw = 0x1D27; 5684 } 5685 5686 /** 5687 * Sets free roam mode in SL, called by a trigger that covers a large area and surrounds the 8 direction 5688 * trigger. 5689 */ 5690 BAD_RETURN(s32) cam_sl_free_roam(struct Camera *c) { 5691 transition_to_camera_mode(c, CAMERA_MODE_FREE_ROAM, 60); 5692 } 5693 5694 /** 5695 * Warps the camera underneath the floor, used in HMC to move under the elevator platforms 5696 */ 5697 void move_camera_through_floor_while_descending(struct Camera *c, f32 height) { 5698 UNUSED u8 filler[4]; 5699 5700 if ((sMarioGeometry.currFloorHeight < height - 100.f) 5701 && (sMarioGeometry.prevFloorHeight > sMarioGeometry.currFloorHeight)) { 5702 c->pos[1] = height - 400.f; 5703 gLakituState.curPos[1] = height - 400.f; 5704 gLakituState.goalPos[1] = height - 400.f; 5705 } 5706 } 5707 5708 BAD_RETURN(s32) cam_hmc_enter_maze(struct Camera *c) { 5709 s16 pitch, yaw; 5710 f32 dist; 5711 5712 if (c->pos[1] > -102.f) { 5713 vec3f_get_dist_and_angle(c->focus, gLakituState.goalPos, &dist, &pitch, &yaw); 5714 vec3f_set_dist_and_angle(c->focus, gLakituState.goalPos, 300.f, pitch, yaw); 5715 gLakituState.goalPos[1] = -800.f; 5716 #ifndef VERSION_JP 5717 c->pos[1] = gLakituState.goalPos[1]; 5718 gLakituState.curPos[1] = gLakituState.goalPos[1]; 5719 #endif 5720 sStatusFlags &= ~CAM_FLAG_SMOOTH_MOVEMENT; 5721 } 5722 } 5723 5724 BAD_RETURN(s32) cam_hmc_elevator_black_hole(struct Camera *c) { 5725 move_camera_through_floor_while_descending(c, 1536.f); 5726 } 5727 5728 BAD_RETURN(s32) cam_hmc_elevator_maze_emergency_exit(struct Camera *c) { 5729 move_camera_through_floor_while_descending(c, 2355.f); 5730 } 5731 5732 BAD_RETURN(s32) cam_hmc_elevator_lake(struct Camera *c) { 5733 move_camera_through_floor_while_descending(c, 1843.f); 5734 } 5735 5736 BAD_RETURN(s32) cam_hmc_elevator_maze(struct Camera *c) { 5737 move_camera_through_floor_while_descending(c, 1843.f); 5738 } 5739 5740 /** 5741 * Starts the "Enter Pyramid Top" cutscene. 5742 */ 5743 BAD_RETURN(s32) cam_ssl_enter_pyramid_top(UNUSED struct Camera *c) { 5744 start_object_cutscene_without_focus(CUTSCENE_ENTER_PYRAMID_TOP); 5745 } 5746 5747 /** 5748 * Change to close mode in the center of the pyramid. Outside this trigger, the default mode is outwards 5749 * radial. 5750 */ 5751 BAD_RETURN(s32) cam_ssl_pyramid_center(struct Camera *c) { 5752 sStatusFlags |= CAM_FLAG_BLOCK_AREA_PROCESSING; 5753 transition_to_camera_mode(c, CAMERA_MODE_CLOSE, 90); 5754 } 5755 5756 /** 5757 * Changes the mode back to outward radial in the boss room inside the pyramid. 5758 */ 5759 BAD_RETURN(s32) cam_ssl_boss_room(struct Camera *c) { 5760 sStatusFlags |= CAM_FLAG_BLOCK_AREA_PROCESSING; 5761 transition_to_camera_mode(c, CAMERA_MODE_OUTWARD_RADIAL, 90); 5762 } 5763 5764 /** 5765 * Moves the camera to through the tunnel by forcing sModeOffsetYaw 5766 */ 5767 BAD_RETURN(s32) cam_thi_move_cam_through_tunnel(UNUSED struct Camera *c) { 5768 if (sModeOffsetYaw < DEGREES(60)) { 5769 sModeOffsetYaw = DEGREES(60); 5770 } 5771 } 5772 5773 /** 5774 * Aligns the camera to look through the tunnel 5775 */ 5776 BAD_RETURN(s32) cam_thi_look_through_tunnel(UNUSED struct Camera *c) { 5777 // ~82.5 degrees 5778 if (sModeOffsetYaw > 0x3AAA) { 5779 sModeOffsetYaw = 0x3AAA; 5780 } 5781 } 5782 5783 /** 5784 * Unused. Changes the camera to radial mode when Mario is on the tower. 5785 * 5786 * @see sCamBOB for bounds. 5787 */ 5788 BAD_RETURN(s32) cam_bob_tower(struct Camera *c) { 5789 sStatusFlags |= CAM_FLAG_BLOCK_AREA_PROCESSING; 5790 transition_to_camera_mode(c, CAMERA_MODE_RADIAL, 90); 5791 } 5792 5793 /** 5794 * Unused. Changes the camera to free roam mode when Mario is not climbing the tower. 5795 * 5796 * This is the only CameraTrigger event that uses the area == -1 feature: 5797 * If this was used, it would be called by default in BoB. 5798 * 5799 * @see sCamBOB 5800 */ 5801 BAD_RETURN(s32) cam_bob_default_free_roam(struct Camera *c) { 5802 transition_to_camera_mode(c, CAMERA_MODE_FREE_ROAM, 90); 5803 } 5804 5805 /** 5806 * Starts the pool entrance cutscene if Mario is not exiting the pool. 5807 * Used in both the castle and HMC. 5808 */ 5809 BAD_RETURN(s32) cam_castle_hmc_start_pool_cutscene(struct Camera *c) { 5810 if ((sMarioCamState->action != ACT_SPECIAL_DEATH_EXIT) 5811 && (sMarioCamState->action != ACT_SPECIAL_EXIT_AIRBORNE)) { 5812 start_cutscene(c, CUTSCENE_ENTER_POOL); 5813 } 5814 } 5815 5816 /** 5817 * Sets the fixed mode pos offset so that the camera faces the doorway when Mario is near the entrance 5818 * to the castle lobby 5819 */ 5820 BAD_RETURN(s32) cam_castle_lobby_entrance(UNUSED struct Camera *c) { 5821 vec3f_set(sCastleEntranceOffset, -813.f - sFixedModeBasePosition[0], 5822 378.f - sFixedModeBasePosition[1], 1103.f - sFixedModeBasePosition[2]); 5823 } 5824 5825 /** 5826 * Make the camera look up the stairs from the 2nd to 3rd floor of the castle 5827 */ 5828 BAD_RETURN(s32) cam_castle_look_upstairs(struct Camera *c) { 5829 struct Surface *floor; 5830 f32 floorHeight = find_floor(c->pos[0], c->pos[1], c->pos[2], &floor); 5831 5832 // If Mario is on the first few steps, fix the camera pos, making it look up 5833 if ((sMarioGeometry.currFloorHeight > 1229.f) && (floorHeight < 1229.f) 5834 && (sCSideButtonYaw == 0)) { 5835 vec3f_set(c->pos, -227.f, 1425.f, 1533.f); 5836 } 5837 } 5838 5839 /** 5840 * Make the camera look down the stairs towards the basement star door 5841 */ 5842 BAD_RETURN(s32) cam_castle_basement_look_downstairs(struct Camera *c) { 5843 struct Surface *floor; 5844 f32 floorHeight = find_floor(c->pos[0], c->pos[1], c->pos[2], &floor); 5845 5846 // Fix the camera pos, making it look downwards. Only active on the top few steps 5847 if ((floorHeight > -110.f) && (sCSideButtonYaw == 0)) { 5848 vec3f_set(c->pos, -980.f, 249.f, -1398.f); 5849 } 5850 } 5851 5852 /** 5853 * Enter the fixed-mode castle lobby. A trigger for this is placed in every entrance so that the camera 5854 * changes to fixed mode. 5855 */ 5856 BAD_RETURN(s32) cam_castle_enter_lobby(struct Camera *c) { 5857 if (c->mode != CAMERA_MODE_FIXED) { 5858 sStatusFlags &= ~CAM_FLAG_SMOOTH_MOVEMENT; 5859 set_fixed_cam_axis_sa_lobby(c->mode); 5860 c->mode = CAMERA_MODE_FIXED; 5861 } 5862 } 5863 5864 /** 5865 * Starts spiral stairs mode. 5866 */ 5867 BAD_RETURN(s32) cam_castle_enter_spiral_stairs(struct Camera *c) { 5868 transition_to_camera_mode(c, CAMERA_MODE_SPIRAL_STAIRS, 20); 5869 } 5870 5871 /** 5872 * unused, starts close mode if the camera is in spiral stairs mode. 5873 * This was replaced with cam_castle_close_mode 5874 */ 5875 static UNUSED BAD_RETURN(s32) cam_castle_leave_spiral_stairs(struct Camera *c) { 5876 if (c->mode == CAMERA_MODE_SPIRAL_STAIRS) { 5877 transition_to_camera_mode(c, CAMERA_MODE_CLOSE, 30); 5878 } else { 5879 set_camera_mode_close_cam(&c->mode); 5880 } 5881 } 5882 5883 /** 5884 * The default mode when outside of the lobby and spiral staircase. A trigger for this is placed at 5885 * every door leaving the lobby and spiral staircase. 5886 */ 5887 BAD_RETURN(s32) cam_castle_close_mode(struct Camera *c) { 5888 set_camera_mode_close_cam(&c->mode); 5889 } 5890 5891 /** 5892 * Functions the same as cam_castle_close_mode, but sets doorStatus so that the camera will enter 5893 * fixed-mode when Mario leaves the room. 5894 */ 5895 BAD_RETURN(s32) cam_castle_leave_lobby_sliding_door(struct Camera *c) { 5896 cam_castle_close_mode(c); 5897 c->doorStatus = DOOR_ENTER_LOBBY; 5898 } 5899 5900 /** 5901 * Just calls cam_castle_enter_lobby 5902 */ 5903 BAD_RETURN(s32) cam_castle_enter_lobby_sliding_door(struct Camera *c) { 5904 cam_castle_enter_lobby(c); 5905 } 5906 5907 BAD_RETURN(s32) cam_bbh_room_6(struct Camera *c) { 5908 parallel_tracking_init(c, sBBHLibraryParTrackPath); 5909 } 5910 5911 BAD_RETURN(s32) cam_bbh_fall_off_roof(struct Camera *c) { 5912 set_camera_mode_close_cam(&c->mode); 5913 } 5914 5915 BAD_RETURN(s32) cam_bbh_fall_into_pool(struct Camera *c) { 5916 Vec3f dir; 5917 set_camera_mode_close_cam(&c->mode); 5918 vec3f_set(dir, 0.f, 0.f, 300.f); 5919 offset_rotated(gLakituState.goalPos, sMarioCamState->pos, dir, sMarioCamState->faceAngle); 5920 gLakituState.goalPos[1] = -2300.f; 5921 vec3f_copy(c->pos, gLakituState.goalPos); 5922 sStatusFlags &= ~CAM_FLAG_SMOOTH_MOVEMENT; 5923 } 5924 5925 BAD_RETURN(s32) cam_bbh_room_1(struct Camera *c) { 5926 set_camera_mode_fixed(c, 956, 440, 1994); 5927 } 5928 5929 BAD_RETURN(s32) cam_bbh_leave_front_door(struct Camera *c) { 5930 c->doorStatus = DOOR_LEAVING_SPECIAL; 5931 cam_bbh_room_1(c); 5932 } 5933 5934 BAD_RETURN(s32) cam_bbh_room_2_lower(struct Camera *c) { 5935 set_camera_mode_fixed(c, 2591, 400, 1284); 5936 } 5937 5938 BAD_RETURN(s32) cam_bbh_room_4(struct Camera *c) { 5939 set_camera_mode_fixed(c, 3529, 340, -1384); 5940 } 5941 5942 BAD_RETURN(s32) cam_bbh_room_8(struct Camera *c) { 5943 set_camera_mode_fixed(c, -500, 740, -1306); 5944 } 5945 5946 /** 5947 * In BBH's room 5's library (the first floor room with the vanish cap/boo painting) 5948 * set the camera mode to fixed and position to (-2172, 200, 675) 5949 */ 5950 BAD_RETURN(s32) cam_bbh_room_5_library(struct Camera *c) { 5951 set_camera_mode_fixed(c, -2172, 200, 675); 5952 } 5953 5954 /** 5955 * In BBH's room 5 (the first floor room with the vanish cap/boo painting) 5956 * set the camera mode to to the hidden room's position 5957 * if coming from the library. 5958 */ 5959 BAD_RETURN(s32) cam_bbh_room_5_library_to_hidden_transition(struct Camera *c) { 5960 if (set_camera_mode_fixed(c, -2172, 200, 675) == 1) { 5961 transition_next_state(c, 20); 5962 } 5963 } 5964 5965 BAD_RETURN(s32) cam_bbh_room_5_hidden_to_library_transition(struct Camera *c) { 5966 if (set_camera_mode_fixed(c, -1542, 320, -307) == 1) { 5967 transition_next_state(c, 20); 5968 } 5969 } 5970 5971 BAD_RETURN(s32) cam_bbh_room_5_hidden(struct Camera *c) { 5972 c->doorStatus = DOOR_LEAVING_SPECIAL; 5973 set_camera_mode_fixed(c, -1542, 320, -307); 5974 } 5975 5976 BAD_RETURN(s32) cam_bbh_room_3(struct Camera *c) { 5977 set_camera_mode_fixed(c, -1893, 320, 2327); 5978 } 5979 5980 BAD_RETURN(s32) cam_bbh_room_7_mr_i(struct Camera *c) { 5981 set_camera_mode_fixed(c, 1371, 360, -1302); 5982 } 5983 5984 BAD_RETURN(s32) cam_bbh_room_7_mr_i_to_coffins_transition(struct Camera *c) { 5985 if (set_camera_mode_fixed(c, 1371, 360, -1302) == 1) { 5986 transition_next_state(c, 20); 5987 } 5988 } 5989 5990 BAD_RETURN(s32) cam_bbh_room_7_coffins_to_mr_i_transition(struct Camera *c) { 5991 if (set_camera_mode_fixed(c, 2115, 260, -772) == 1) { 5992 transition_next_state(c, 20); 5993 } 5994 } 5995 5996 BAD_RETURN(s32) cam_bbh_elevator_room_lower(struct Camera *c) { 5997 c->doorStatus = DOOR_LEAVING_SPECIAL; 5998 set_camera_mode_close_cam(&c->mode); 5999 } 6000 6001 BAD_RETURN(s32) cam_bbh_room_0_back_entrance(struct Camera *c) { 6002 set_camera_mode_close_cam(&c->mode); 6003 } 6004 6005 BAD_RETURN(s32) cam_bbh_elevator(struct Camera *c) { 6006 if (c->mode == CAMERA_MODE_FIXED) { 6007 set_camera_mode_close_cam(&c->mode); 6008 c->pos[1] = -405.f; 6009 gLakituState.goalPos[1] = -405.f; 6010 } 6011 } 6012 6013 BAD_RETURN(s32) cam_bbh_room_12_upper(struct Camera *c) { 6014 c->doorStatus = DOOR_LEAVING_SPECIAL; 6015 set_camera_mode_fixed(c, -2932, 296, 4429); 6016 } 6017 6018 BAD_RETURN(s32) cam_bbh_enter_front_door(struct Camera *c) { 6019 set_camera_mode_close_cam(&c->mode); 6020 } 6021 6022 BAD_RETURN(s32) cam_bbh_room_2_library(struct Camera *c) { 6023 set_camera_mode_fixed(c, 3493, 440, 617); 6024 } 6025 6026 BAD_RETURN(s32) cam_bbh_room_2_library_to_trapdoor_transition(struct Camera *c) { 6027 if (set_camera_mode_fixed(c, 3493, 440, 617) == 1) { 6028 transition_next_state(c, 20); 6029 } 6030 } 6031 6032 BAD_RETURN(s32) cam_bbh_room_2_trapdoor(struct Camera *c) { 6033 set_camera_mode_fixed(c, 3502, 440, 1217); 6034 } 6035 6036 BAD_RETURN(s32) cam_bbh_room_2_trapdoor_transition(struct Camera *c) { 6037 if (set_camera_mode_fixed(c, 3502, 440, 1217) == 1) { 6038 transition_next_state(c, 20); 6039 } 6040 } 6041 6042 BAD_RETURN(s32) cam_bbh_room_9_attic(struct Camera *c) { 6043 set_camera_mode_fixed(c, -670, 460, 372); 6044 } 6045 6046 BAD_RETURN(s32) cam_bbh_room_9_attic_transition(struct Camera *c) { 6047 if (set_camera_mode_fixed(c, -670, 460, 372) == 1) { 6048 transition_next_state(c, 20); 6049 } 6050 } 6051 6052 BAD_RETURN(s32) cam_bbh_room_9_mr_i_transition(struct Camera *c) { 6053 if (set_camera_mode_fixed(c, 131, 380, -263) == 1) { 6054 transition_next_state(c, 20); 6055 } 6056 } 6057 6058 BAD_RETURN(s32) cam_bbh_room_13_balcony(struct Camera *c) { 6059 set_camera_mode_fixed(c, 210, 420, 3109); 6060 } 6061 6062 BAD_RETURN(s32) cam_bbh_room_0(struct Camera *c) { 6063 c->doorStatus = DOOR_LEAVING_SPECIAL; 6064 set_camera_mode_fixed(c, -204, 807, 204); 6065 } 6066 6067 BAD_RETURN(s32) cam_ccm_enter_slide_shortcut(UNUSED struct Camera *c) { 6068 sStatusFlags |= CAM_FLAG_CCM_SLIDE_SHORTCUT; 6069 } 6070 6071 BAD_RETURN(s32) cam_ccm_leave_slide_shortcut(UNUSED struct Camera *c) { 6072 sStatusFlags &= ~CAM_FLAG_CCM_SLIDE_SHORTCUT; 6073 } 6074 6075 /** 6076 * Apply any modes that are triggered by special floor surface types 6077 */ 6078 u32 surface_type_modes(struct Camera *c) { 6079 u32 modeChanged = 0; 6080 6081 switch (sMarioGeometry.currFloorType) { 6082 case SURFACE_CLOSE_CAMERA: 6083 transition_to_camera_mode(c, CAMERA_MODE_CLOSE, 90); 6084 modeChanged++; 6085 break; 6086 6087 case SURFACE_CAMERA_FREE_ROAM: 6088 transition_to_camera_mode(c, CAMERA_MODE_FREE_ROAM, 90); 6089 modeChanged++; 6090 break; 6091 6092 case SURFACE_NO_CAM_COL_SLIPPERY: 6093 transition_to_camera_mode(c, CAMERA_MODE_CLOSE, 90); 6094 modeChanged++; 6095 break; 6096 } 6097 return modeChanged; 6098 } 6099 6100 /** 6101 * Set the camera mode to `mode` if Mario is not standing on a special surface 6102 */ 6103 u32 set_mode_if_not_set_by_surface(struct Camera *c, u8 mode) { 6104 u32 modeChanged = 0; 6105 modeChanged = surface_type_modes(c); 6106 6107 if ((modeChanged == 0) && (mode != 0)) { 6108 transition_to_camera_mode(c, mode, 90); 6109 } 6110 6111 return modeChanged; 6112 } 6113 6114 /** 6115 * Used in THI, check if Mario is standing on any of the special surfaces in that area 6116 */ 6117 void surface_type_modes_thi(struct Camera *c) { 6118 switch (sMarioGeometry.currFloorType) { 6119 case SURFACE_CLOSE_CAMERA: 6120 if (c->mode != CAMERA_MODE_CLOSE) { 6121 transition_to_camera_mode(c, CAMERA_MODE_FREE_ROAM, 90); 6122 } 6123 break; 6124 6125 case SURFACE_CAMERA_FREE_ROAM: 6126 if (c->mode != CAMERA_MODE_CLOSE) { 6127 transition_to_camera_mode(c, CAMERA_MODE_FREE_ROAM, 90); 6128 } 6129 break; 6130 6131 case SURFACE_NO_CAM_COL_SLIPPERY: 6132 if (c->mode != CAMERA_MODE_CLOSE) { 6133 transition_to_camera_mode(c, CAMERA_MODE_FREE_ROAM, 90); 6134 } 6135 break; 6136 6137 case SURFACE_CAMERA_8_DIR: 6138 transition_to_camera_mode(c, CAMERA_MODE_8_DIRECTIONS, 90); 6139 break; 6140 6141 default: 6142 transition_to_camera_mode(c, CAMERA_MODE_RADIAL, 90); 6143 } 6144 } 6145 6146 /** 6147 * Terminates a list of CameraTriggers. 6148 */ 6149 #define NULL_TRIGGER \ 6150 { 0, NULL, 0, 0, 0, 0, 0, 0, 0 } 6151 6152 /** 6153 * The SL triggers operate camera behavior in front of the snowman who blows air. 6154 * The first sets a 8 direction mode, while the latter (which encompasses the former) 6155 * sets free roam mode. 6156 * 6157 * This behavior is exploitable, since the ranges assume that Mario must pass through the latter on 6158 * exit. Using hyperspeed, the earlier area can be directly exited from, keeping the changes it applies. 6159 */ 6160 struct CameraTrigger sCamSL[] = { 6161 { 1, cam_sl_snowman_head_8dir, 1119, 3584, 1125, 1177, 358, 358, -0x1D27 }, 6162 // This trigger surrounds the previous one 6163 { 1, cam_sl_free_roam, 1119, 3584, 1125, 4096, 4096, 4096, -0x1D27 }, 6164 NULL_TRIGGER 6165 }; 6166 6167 /** 6168 * The THI triggers are specifically for the tunnel near the start of the Huge Island. 6169 * The first helps the camera from getting stuck on the starting side, the latter aligns with the 6170 * tunnel. Both sides achieve their effect by editing the camera yaw. 6171 */ 6172 struct CameraTrigger sCamTHI[] = { 6173 { 1, cam_thi_move_cam_through_tunnel, -4609, -2969, 6448, 100, 300, 300, 0 }, 6174 { 1, cam_thi_look_through_tunnel, -4809, -2969, 6448, 100, 300, 300, 0 }, 6175 NULL_TRIGGER 6176 }; 6177 6178 /** 6179 * The HMC triggers are mostly for warping the camera below platforms, but the second trigger is used to 6180 * start the cutscene for entering the CotMC pool. 6181 */ 6182 struct CameraTrigger sCamHMC[] = { 6183 { 1, cam_hmc_enter_maze, 1996, 102, 0, 205, 100, 205, 0 }, 6184 { 1, cam_castle_hmc_start_pool_cutscene, 3350, -4689, 4800, 600, 50, 600, 0 }, 6185 { 1, cam_hmc_elevator_black_hole, -3278, 1236, 1379, 358, 200, 358, 0 }, 6186 { 1, cam_hmc_elevator_maze_emergency_exit, -2816, 2055, -2560, 358, 200, 358, 0 }, 6187 { 1, cam_hmc_elevator_lake, -3532, 1543, -7040, 358, 200, 358, 0 }, 6188 { 1, cam_hmc_elevator_maze, -972, 1543, -7347, 358, 200, 358, 0 }, 6189 NULL_TRIGGER 6190 }; 6191 6192 /** 6193 * The SSL triggers are for starting the enter pyramid top cutscene, 6194 * setting close mode in the middle of the pyramid, and setting the boss fight camera mode to outward 6195 * radial. 6196 */ 6197 struct CameraTrigger sCamSSL[] = { 6198 { 1, cam_ssl_enter_pyramid_top, -2048, 1080, -1024, 150, 150, 150, 0 }, 6199 { 2, cam_ssl_pyramid_center, 0, -104, -104, 1248, 1536, 2950, 0 }, 6200 { 2, cam_ssl_pyramid_center, 0, 2500, 256, 515, 5000, 515, 0 }, 6201 { 3, cam_ssl_boss_room, 0, -1534, -2040, 1000, 800, 1000, 0 }, 6202 NULL_TRIGGER 6203 }; 6204 6205 /** 6206 * The RR triggers are for changing between fixed and 8 direction mode when entering / leaving the building at 6207 * the end of the ride. 6208 */ 6209 struct CameraTrigger sCamRR[] = { 6210 { 1, cam_rr_exit_building_side, -4197, 3819, -3087, 1769, 1490, 342, 0 }, 6211 { 1, cam_rr_enter_building_side, -4197, 3819, -3771, 769, 490, 342, 0 }, 6212 { 1, cam_rr_enter_building_window, -5603, 4834, -5209, 300, 600, 591, 0 }, 6213 { 1, cam_rr_enter_building, -2609, 3730, -5463, 300, 650, 577, 0 }, 6214 { 1, cam_rr_exit_building_top, -4196, 7343, -5155, 4500, 1000, 4500, 0 }, 6215 { 1, cam_rr_enter_building, -4196, 6043, -5155, 500, 300, 500, 0 }, 6216 NULL_TRIGGER, 6217 }; 6218 6219 /** 6220 * These triggers are unused, but because the first trigger surrounds the BoB tower and activates radial 6221 * mode (which is called "tower mode" in the patent), it's speculated they belonged to BoB. 6222 * 6223 * This table contains the only instance of a CameraTrigger with an area set to -1, and it sets the mode 6224 * to free_roam when Mario is not walking up the tower. 6225 */ 6226 struct CameraTrigger sCamBOB[] = { 6227 { 1, cam_bob_tower, 2468, 2720, -4608, 3263, 1696, 3072, 0 }, 6228 { -1, cam_bob_default_free_roam, 0, 0, 0, 0, 0, 0, 0 }, 6229 NULL_TRIGGER 6230 }; 6231 6232 /** 6233 * The CotMC trigger is only used to prevent fix Lakitu in place when Mario exits through the waterfall. 6234 */ 6235 struct CameraTrigger sCamCotMC[] = { 6236 { 1, cam_cotmc_exit_waterfall, 0, 1500, 3500, 550, 10000, 1500, 0 }, 6237 NULL_TRIGGER 6238 }; 6239 6240 /** 6241 * The CCM triggers are used to set the flag that says when Mario is in the slide shortcut. 6242 */ 6243 struct CameraTrigger sCamCCM[] = { 6244 { 2, cam_ccm_enter_slide_shortcut, -4846, 2061, 27, 1229, 1342, 396, 0 }, 6245 { 2, cam_ccm_leave_slide_shortcut, -6412, -3917, -6246, 307, 185, 132, 0 }, 6246 NULL_TRIGGER 6247 }; 6248 6249 /** 6250 * The Castle triggers are used to set the camera to fixed mode when entering the lobby, and to set it 6251 * to close mode when leaving it. They also set the mode to spiral staircase. 6252 * 6253 * There are two triggers for looking up and down straight staircases when Mario is at the start, 6254 * and one trigger that starts the enter pool cutscene when Mario enters HMC. 6255 */ 6256 struct CameraTrigger sCamCastle[] = { 6257 { 1, cam_castle_close_mode, -1100, 657, -1346, 300, 150, 300, 0 }, 6258 { 1, cam_castle_enter_lobby, -1099, 657, -803, 300, 150, 300, 0 }, 6259 { 1, cam_castle_close_mode, -2304, -264, -4072, 140, 150, 140, 0 }, 6260 { 1, cam_castle_close_mode, -2304, 145, -1344, 140, 150, 140, 0 }, 6261 { 1, cam_castle_enter_lobby, -2304, 145, -802, 140, 150, 140, 0 }, 6262 //! Sets the camera mode when leaving secret aquarium 6263 { 1, cam_castle_close_mode, 2816, 1200, -256, 100, 100, 100, 0 }, 6264 { 1, cam_castle_close_mode, 256, -161, -4226, 140, 150, 140, 0 }, 6265 { 1, cam_castle_close_mode, 256, 145, -1344, 140, 150, 140, 0 }, 6266 { 1, cam_castle_enter_lobby, 256, 145, -802, 140, 150, 140, 0 }, 6267 { 1, cam_castle_close_mode, -1023, 44, -4870, 140, 150, 140, 0 }, 6268 { 1, cam_castle_close_mode, -459, 145, -1020, 140, 150, 140, 0x6000 }, 6269 { 1, cam_castle_enter_lobby, -85, 145, -627, 140, 150, 140, 0 }, 6270 { 1, cam_castle_close_mode, -1589, 145, -1020, 140, 150, 140, -0x6000 }, 6271 { 1, cam_castle_enter_lobby, -1963, 145, -627, 140, 150, 140, 0 }, 6272 { 1, cam_castle_leave_lobby_sliding_door, -2838, 657, -1659, 200, 150, 150, 0x2000 }, 6273 { 1, cam_castle_enter_lobby_sliding_door, -2319, 512, -1266, 300, 150, 300, 0x2000 }, 6274 { 1, cam_castle_close_mode, 844, 759, -1657, 40, 150, 40, -0x2000 }, 6275 { 1, cam_castle_enter_lobby, 442, 759, -1292, 140, 150, 140, -0x2000 }, 6276 { 2, cam_castle_enter_spiral_stairs, -1000, 657, 1740, 200, 300, 200, 0 }, 6277 { 2, cam_castle_enter_spiral_stairs, -996, 1348, 1814, 200, 300, 200, 0 }, 6278 { 2, cam_castle_close_mode, -946, 657, 2721, 50, 150, 50, 0 }, 6279 { 2, cam_castle_close_mode, -996, 1348, 907, 50, 150, 50, 0 }, 6280 { 2, cam_castle_close_mode, -997, 1348, 1450, 140, 150, 140, 0 }, 6281 { 1, cam_castle_close_mode, -4942, 452, -461, 140, 150, 140, 0x4000 }, 6282 { 1, cam_castle_close_mode, -3393, 350, -793, 140, 150, 140, 0x4000 }, 6283 { 1, cam_castle_enter_lobby, -2851, 350, -792, 140, 150, 140, 0x4000 }, 6284 { 1, cam_castle_enter_lobby, 803, 350, -228, 140, 150, 140, -0x4000 }, 6285 //! Duplicate camera trigger outside JRB door 6286 { 1, cam_castle_enter_lobby, 803, 350, -228, 140, 150, 140, -0x4000 }, 6287 { 1, cam_castle_close_mode, 1345, 350, -229, 140, 150, 140, 0x4000 }, 6288 { 1, cam_castle_close_mode, -946, -929, 622, 300, 150, 300, 0 }, 6289 { 2, cam_castle_look_upstairs, -205, 1456, 2508, 210, 928, 718, 0 }, 6290 { 1, cam_castle_basement_look_downstairs, -1027, -587, -718, 318, 486, 577, 0 }, 6291 { 1, cam_castle_lobby_entrance, -1023, 376, 1830, 300, 400, 300, 0 }, 6292 { 3, cam_castle_hmc_start_pool_cutscene, 2485, -1689, -2659, 600, 50, 600, 0 }, 6293 NULL_TRIGGER 6294 }; 6295 6296 /** 6297 * The BBH triggers are the most complex, they cause the camera to enter fixed mode for each room, 6298 * transition between rooms, and enter free roam when outside. 6299 * 6300 * The triggers are also responsible for warping the camera below platforms. 6301 */ 6302 struct CameraTrigger sCamBBH[] = { 6303 { 1, cam_bbh_enter_front_door, 742, 0, 2369, 200, 200, 200, 0 }, 6304 { 1, cam_bbh_leave_front_door, 741, 0, 1827, 200, 200, 200, 0 }, 6305 { 1, cam_bbh_room_1, 222, 0, 1458, 200, 200, 200, 0 }, 6306 { 1, cam_bbh_room_1, 222, 0, 639, 200, 200, 200, 0 }, 6307 { 1, cam_bbh_room_1, 435, 0, 222, 200, 200, 200, 0 }, 6308 { 1, cam_bbh_room_1, 1613, 0, 222, 200, 200, 200, 0 }, 6309 { 1, cam_bbh_room_1, 1827, 0, 1459, 200, 200, 200, 0 }, 6310 { 1, cam_bbh_room_1, -495, 819, 1407, 200, 200, 200, 0 }, 6311 { 1, cam_bbh_room_1, -495, 819, 640, 250, 200, 200, 0 }, 6312 { 1, cam_bbh_room_1, 179, 819, 222, 200, 200, 200, 0 }, 6313 { 1, cam_bbh_room_1, 1613, 819, 222, 200, 200, 200, 0 }, 6314 { 1, cam_bbh_room_1, 1827, 819, 486, 200, 200, 200, 0 }, 6315 { 1, cam_bbh_room_1, 1827, 819, 1818, 200, 200, 200, 0 }, 6316 { 1, cam_bbh_room_2_lower, 2369, 0, 1459, 200, 200, 200, 0 }, 6317 { 1, cam_bbh_room_2_lower, 3354, 0, 1347, 200, 200, 200, 0 }, 6318 { 1, cam_bbh_room_2_lower, 2867, 514, 1843, 512, 102, 409, 0 }, 6319 { 1, cam_bbh_room_4, 3354, 0, 804, 200, 200, 200, 0 }, 6320 { 1, cam_bbh_room_4, 1613, 0, -320, 200, 200, 200, 0 }, 6321 { 1, cam_bbh_room_8, 435, 0, -320, 200, 200, 200, 0 }, 6322 { 1, cam_bbh_room_5_library, -2021, 0, 803, 200, 200, 200, 0 }, 6323 { 1, cam_bbh_room_5_library, -320, 0, 640, 200, 200, 200, 0 }, 6324 { 1, cam_bbh_room_5_library_to_hidden_transition, -1536, 358, -254, 716, 363, 102, 0 }, 6325 { 1, cam_bbh_room_5_hidden_to_library_transition, -1536, 358, -459, 716, 363, 102, 0 }, 6326 { 1, cam_bbh_room_5_hidden, -1560, 0, -1314, 200, 200, 200, 0 }, 6327 { 1, cam_bbh_room_3, -320, 0, 1459, 200, 200, 200, 0 }, 6328 { 1, cam_bbh_room_3, -2021, 0, 1345, 200, 200, 200, 0 }, 6329 { 1, cam_bbh_room_2_library, 2369, 819, 486, 200, 200, 200, 0 }, 6330 { 1, cam_bbh_room_2_library, 2369, 1741, 486, 200, 200, 200, 0 }, 6331 { 1, cam_bbh_room_2_library_to_trapdoor_transition, 2867, 1228, 1174, 716, 414, 102, 0 }, 6332 { 1, cam_bbh_room_2_trapdoor_transition, 2867, 1228, 1378, 716, 414, 102, 0 }, 6333 { 1, cam_bbh_room_2_trapdoor, 2369, 819, 1818, 200, 200, 200, 0 }, 6334 { 1, cam_bbh_room_9_attic, 1829, 1741, 486, 200, 200, 200, 0 }, 6335 { 1, cam_bbh_room_9_attic, 741, 1741, 1587, 200, 200, 200, 0 }, 6336 { 1, cam_bbh_room_9_attic_transition, 102, 2048, -191, 100, 310, 307, 0 }, 6337 { 1, cam_bbh_room_9_mr_i_transition, 409, 2048, -191, 100, 310, 307, 0 }, 6338 { 1, cam_bbh_room_13_balcony, 742, 1922, 2164, 200, 200, 200, 0 }, 6339 { 1, cam_bbh_fall_off_roof, 587, 1322, 2677, 1000, 400, 600, 0 }, 6340 { 1, cam_bbh_room_3, -1037, 819, 1408, 200, 200, 200, 0 }, 6341 { 1, cam_bbh_room_3, -1970, 1024, 1345, 200, 200, 200, 0 }, 6342 { 1, cam_bbh_room_8, 179, 819, -320, 200, 200, 200, 0 }, 6343 { 1, cam_bbh_room_7_mr_i, 1613, 819, -320, 200, 200, 200, 0 }, 6344 { 1, cam_bbh_room_7_mr_i_to_coffins_transition, 2099, 1228, -819, 102, 414, 716, 0 }, 6345 { 1, cam_bbh_room_7_coffins_to_mr_i_transition, 2304, 1228, -819, 102, 414, 716, 0 }, 6346 { 1, cam_bbh_room_6, -1037, 819, 640, 200, 200, 200, 0 }, 6347 { 1, cam_bbh_room_6, -1970, 1024, 803, 200, 200, 200, 0 }, 6348 { 1, cam_bbh_room_1, 1827, 819, 1818, 200, 200, 200, 0 }, 6349 { 1, cam_bbh_fall_into_pool, 2355, -1112, -193, 1228, 500, 1343, 0 }, 6350 { 1, cam_bbh_fall_into_pool, 2355, -1727, 1410, 1228, 500, 705, 0 }, 6351 { 1, cam_bbh_elevator_room_lower, 0, -2457, 1827, 250, 200, 250, 0 }, 6352 { 1, cam_bbh_elevator_room_lower, 0, -2457, 2369, 250, 200, 250, 0 }, 6353 { 1, cam_bbh_elevator_room_lower, 0, -2457, 4929, 250, 200, 250, 0 }, 6354 { 1, cam_bbh_elevator_room_lower, 0, -2457, 4387, 250, 200, 250, 0 }, 6355 { 1, cam_bbh_room_0_back_entrance, 1887, -2457, 204, 250, 200, 250, 0 }, 6356 { 1, cam_bbh_room_0, 1272, -2457, 204, 250, 200, 250, 0 }, 6357 { 1, cam_bbh_room_0, -1681, -2457, 204, 250, 200, 250, 0 }, 6358 { 1, cam_bbh_room_0_back_entrance, -2296, -2457, 204, 250, 200, 250, 0 }, 6359 { 1, cam_bbh_elevator, -2939, -605, 5367, 800, 100, 800, 0 }, 6360 { 1, cam_bbh_room_12_upper, -2939, -205, 5367, 300, 100, 300, 0 }, 6361 { 1, cam_bbh_room_12_upper, -2332, -204, 4714, 250, 200, 250, 0x6000 }, 6362 { 1, cam_bbh_room_0_back_entrance, -1939, -204, 4340, 250, 200, 250, 0x6000 }, 6363 NULL_TRIGGER 6364 }; 6365 6366 #define _ NULL 6367 #define STUB_LEVEL(_0, _1, _2, _3, _4, _5, _6, _7, cameratable) cameratable, 6368 #define DEFINE_LEVEL(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, cameratable) cameratable, 6369 6370 /* 6371 * This table has an extra 2 levels after the last unknown_38 stub level. What I think 6372 * the programmer was thinking was that the table is null terminated and so used the 6373 * level count as a correspondence to the ID of the final level, but the enum represents 6374 * an ID *after* the last stub level, not before or during it. 6375 * 6376 * Each table is terminated with NULL_TRIGGER 6377 */ 6378 struct CameraTrigger *sCameraTriggers[LEVEL_COUNT + 1] = { 6379 NULL, 6380 #include "levels/level_defines.h" 6381 }; 6382 #undef _ 6383 #undef STUB_LEVEL 6384 #undef DEFINE_LEVEL 6385 6386 struct CutsceneSplinePoint sIntroStartToPipePosition[] = { 6387 { 0, 0, { 2122, 8762, 9114 } }, { 0, 0, { 2122, 8762, 9114 } }, { 1, 0, { 2122, 7916, 9114 } }, 6388 { 1, 0, { 2122, 7916, 9114 } }, { 2, 0, { 957, 5166, 8613 } }, { 3, 0, { 589, 4338, 7727 } }, 6389 { 4, 0, { 690, 3366, 6267 } }, { 5, 0, { -1600, 2151, 4955 } }, { 6, 0, { -1557, 232, 1283 } }, 6390 { 7, 0, { -6962, -295, 2729 } }, { 8, 0, { -6979, 131, 3246 } }, { 9, 0, { -6360, -283, 4044 } }, 6391 { 0, 0, { -5695, -334, 5264 } }, { 1, 0, { -5568, -319, 7933 } }, { 2, 0, { -3848, -200, 6278 } }, 6392 { 3, 0, { -965, -263, 6092 } }, { 4, 0, { 1607, 2465, 6329 } }, { 5, 0, { 2824, 180, 3548 } }, 6393 { 6, 0, { 1236, 136, 945 } }, { 0, 0, { 448, 136, 564 } }, { 0, 0, { 448, 136, 564 } }, 6394 { 0, 0, { 448, 136, 564 } }, { -1, 0, { 448, 136, 564 } } 6395 }; 6396 6397 struct CutsceneSplinePoint sIntroStartToPipeFocus[] = { 6398 { 0, 50, { 1753, 29800, 8999 } }, { 0, 50, { 1753, 29800, 8999 } }, 6399 { 1, 50, { 1753, 8580, 8999 } }, { 1, 100, { 1753, 8580, 8999 } }, 6400 { 2, 50, { 520, 5400, 8674 } }, { 3, 50, { 122, 4437, 7875 } }, 6401 { 4, 50, { 316, 3333, 6538 } }, { 5, 36, { -1526, 2189, 5448 } }, 6402 { 6, 50, { -1517, 452, 1731 } }, { 7, 50, { -6659, -181, 3109 } }, 6403 { 8, 17, { -6649, 183, 3618 } }, { 9, 20, { -6009, -214, 4395 } }, 6404 { 0, 50, { -5258, -175, 5449 } }, { 1, 36, { -5158, -266, 7651 } }, 6405 { 2, 26, { -3351, -192, 6222 } }, { 3, 25, { -483, -137, 6060 } }, 6406 { 4, 100, { 1833, 2211, 5962 } }, { 5, 26, { 3022, 207, 3090 } }, 6407 { 6, 20, { 1250, 197, 449 } }, { 7, 50, { 248, 191, 227 } }, 6408 { 7, 0, { 48, 191, 227 } }, { 7, 0, { 48, 191, 227 } }, 6409 { -1, 0, { 48, 191, 227 } } 6410 }; 6411 6412 /** 6413 * Describes the spline the camera follows, starting when the camera jumps to Lakitu and ending after 6414 * Mario jumps out of the pipe when the first dialog opens. This table specifically updates the 6415 * camera's position. 6416 */ 6417 struct CutsceneSplinePoint sIntroPipeToDialogPosition[] = { 6418 { 0, 0, { -785, 625, 4527 } }, { 1, 0, { -785, 625, 4527 } }, { 2, 0, { -1286, 644, 4376 } }, 6419 { 3, 0, { -1286, 623, 4387 } }, { 4, 0, { -1286, 388, 3963 } }, { 5, 0, { -1286, 358, 4093 } }, 6420 { 6, 0, { -1386, 354, 4159 } }, { 7, 0, { -1477, 306, 4223 } }, { 8, 0, { -1540, 299, 4378 } }, 6421 { 9, 0, { -1473, 316, 4574 } }, { 0, 0, { -1328, 485, 5017 } }, { 0, 0, { -1328, 485, 5017 } }, 6422 { 0, 0, { -1328, 485, 5017 } }, { -1, 0, { -1328, 485, 5017 } } 6423 }; 6424 6425 /** 6426 * Describes the spline that the camera's focus follows, during the same part of the intro as the above. 6427 */ 6428 #ifdef VERSION_EU 6429 struct CutsceneSplinePoint sIntroPipeToDialogFocus[] = { 6430 { 0, 25, { -1248, 450, 4596 } }, { 1, 71, { -1258, 485, 4606 } }, { 2, 71, { -1379, 344, 4769 } }, 6431 { 3, 22, { -1335, 366, 4815 } }, { 4, 23, { -1315, 370, 4450 } }, { 5, 40, { -1322, 333, 4591 } }, 6432 { 6, 25, { -1185, 329, 4616 } }, { 7, 21, { -1059, 380, 4487 } }, { 8, 14, { -1086, 421, 4206 } }, 6433 { 9, 21, { -1321, 346, 4098 } }, { 0, 0, { -1328, 385, 4354 } }, { 0, 0, { -1328, 385, 4354 } }, 6434 { 0, 0, { -1328, 385, 4354 } }, { -1, 0, { -1328, 385, 4354 } } 6435 }; 6436 #else 6437 struct CutsceneSplinePoint sIntroPipeToDialogFocus[] = { 6438 { 0, 20, { -1248, 450, 4596 } }, { 1, 59, { -1258, 485, 4606 } }, { 2, 59, { -1379, 344, 4769 } }, 6439 { 3, 20, { -1335, 366, 4815 } }, { 4, 23, { -1315, 370, 4450 } }, { 5, 40, { -1322, 333, 4591 } }, 6440 { 6, 25, { -1185, 329, 4616 } }, { 7, 21, { -1059, 380, 4487 } }, { 8, 14, { -1086, 421, 4206 } }, 6441 { 9, 21, { -1321, 346, 4098 } }, { 0, 0, { -1328, 385, 4354 } }, { 0, 0, { -1328, 385, 4354 } }, 6442 { 0, 0, { -1328, 385, 4354 } }, { -1, 0, { -1328, 385, 4354 } } 6443 }; 6444 #endif 6445 6446 struct CutsceneSplinePoint sEndingFlyToWindowPos[] = { 6447 { 0, 0, { -86, 876, 640 } }, { 1, 0, { -86, 876, 610 } }, { 2, 0, { -66, 945, 393 } }, 6448 { 3, 0, { -80, 976, 272 } }, { 4, 0, { -66, 1306, -36 } }, { 5, 0, { -70, 1869, -149 } }, 6449 { 6, 0, { -10, 2093, -146 } }, { 7, 0, { -10, 2530, -248 } }, { 8, 0, { -10, 2530, -263 } }, 6450 { 9, 0, { -10, 2530, -273 } } 6451 }; 6452 6453 struct CutsceneSplinePoint sEndingFlyToWindowFocus[] = { 6454 { 0, 50, { -33, 889, -7 } }, { 1, 35, { -33, 889, -7 } }, { 2, 31, { -17, 1070, -193 } }, 6455 { 3, 25, { -65, 1182, -272 } }, { 4, 20, { -64, 1559, -542 } }, { 5, 25, { -68, 2029, -677 } }, 6456 { 6, 25, { -9, 2204, -673 } }, { 7, 25, { -8, 2529, -772 } }, { 8, 0, { -8, 2529, -772 } }, 6457 { 9, 0, { -8, 2529, -772 } }, { -1, 0, { -8, 2529, -772 } } 6458 }; 6459 6460 struct CutsceneSplinePoint sEndingPeachDescentCamPos[] = { 6461 { 0, 50, { 1, 120, -1150 } }, { 1, 50, { 1, 120, -1150 } }, { 2, 40, { 118, 121, -1199 } }, 6462 { 3, 40, { 147, 74, -1306 } }, { 4, 40, { 162, 95, -1416 } }, { 5, 40, { 25, 111, -1555 } }, 6463 { 6, 40, { -188, 154, -1439 } }, { 7, 40, { -203, 181, -1242 } }, { 8, 40, { 7, 191, -1057 } }, 6464 { 9, 40, { 262, 273, -1326 } }, { 0, 40, { -4, 272, -1627 } }, { 1, 35, { -331, 206, -1287 } }, 6465 { 2, 30, { -65, 219, -877 } }, { 3, 25, { 6, 216, -569 } }, { 4, 25, { -8, 157, 40 } }, 6466 { 5, 25, { -4, 106, 200 } }, { 6, 25, { -6, 72, 574 } }, { 7, 0, { -6, 72, 574 } }, 6467 { 8, 0, { -6, 72, 574 } }, { -1, 0, { -6, 72, 574 } } 6468 }; 6469 6470 struct CutsceneSplinePoint sEndingMarioToPeachPos[] = { 6471 { 0, 0, { -130, 1111, -1815 } }, { 1, 0, { -131, 1052, -1820 } }, { 2, 0, { -271, 1008, -1651 } }, 6472 { 3, 0, { -439, 1043, -1398 } }, { 4, 0, { -433, 1040, -1120 } }, { 5, 0, { -417, 1040, -1076 } }, 6473 { 6, 0, { -417, 1040, -1076 } }, { 7, 0, { -417, 1040, -1076 } }, { -1, 0, { -417, 1040, -1076 } } 6474 }; 6475 6476 struct CutsceneSplinePoint sEndingMarioToPeachFocus[] = { 6477 { 0, 50, { -37, 1020, -1332 } }, { 1, 20, { -36, 1012, -1330 } }, { 2, 20, { -24, 1006, -1215 } }, 6478 { 3, 20, { 28, 1002, -1224 } }, { 4, 24, { 45, 1013, -1262 } }, { 5, 35, { 34, 1000, -1287 } }, 6479 { 6, 0, { 34, 1000, -1287 } }, { 7, 0, { 34, 1000, -1287 } }, { -1, 0, { 34, 1000, -1287 } } 6480 }; 6481 6482 struct CutsceneSplinePoint sEndingLookUpAtCastle[] = { 6483 { 0, 50, { 200, 1066, -1414 } }, { 0, 50, { 200, 1066, -1414 } }, { 0, 30, { 198, 1078, -1412 } }, 6484 { 0, 33, { 15, 1231, -1474 } }, { 0, 39, { -94, 1381, -1368 } }, { 0, 0, { -92, 1374, -1379 } }, 6485 { 0, 0, { -92, 1374, -1379 } }, { -1, 0, { -92, 1374, -1379 } } 6486 }; 6487 6488 struct CutsceneSplinePoint sEndingLookAtSkyFocus[] = { 6489 #ifdef VERSION_EU 6490 { 0, 50, { 484, 1368, -868 } }, { 0, 72, { 479, 1372, -872 } }, { 0, 50, { 351, 1817, -918 } }, 6491 #else 6492 { 0, 50, { 484, 1368, -888 } }, { 0, 72, { 479, 1372, -892 } }, { 0, 50, { 351, 1817, -918 } }, 6493 #endif 6494 { 0, 50, { 351, 1922, -598 } }, { 0, 0, { 636, 2027, -415 } }, { 0, 0, { 636, 2027, -415 } }, 6495 { -1, 0, { 636, 2027, -415 } } 6496 }; 6497 6498 /** 6499 * Activates any CameraTriggers that Mario is inside. 6500 * Then, applies area-specific processing to the camera, such as setting the default mode, or changing 6501 * the mode based on the terrain type Mario is standing on. 6502 * 6503 * @return the camera's mode after processing, although this is unused in the code 6504 */ 6505 s16 camera_course_processing(struct Camera *c) { 6506 s16 level = gCurrLevelNum; 6507 s16 mode; 6508 s8 area = gCurrentArea->index; 6509 // Bounds iterator 6510 u32 b; 6511 // Camera trigger's bounding box 6512 Vec3f center, bounds; 6513 u32 insideBounds = FALSE; 6514 UNUSED struct CameraTrigger unused; 6515 u8 oldMode = c->mode; 6516 6517 if (c->mode == CAMERA_MODE_C_UP) { 6518 c->mode = sModeInfo.lastMode; 6519 } 6520 check_blocking_area_processing(&c->mode); 6521 if (level > LEVEL_COUNT + 1) { 6522 level = LEVEL_COUNT + 1; 6523 } 6524 6525 if (sCameraTriggers[level] != NULL) { 6526 b = 0; 6527 6528 // Process positional triggers. 6529 // All triggered events are called, not just the first one. 6530 while (sCameraTriggers[level][b].event != NULL) { 6531 6532 // Check only the current area's triggers 6533 if (sCameraTriggers[level][b].area == area) { 6534 // Copy the bounding box into center and bounds 6535 vec3f_set(center, sCameraTriggers[level][b].centerX, 6536 sCameraTriggers[level][b].centerY, 6537 sCameraTriggers[level][b].centerZ); 6538 vec3f_set(bounds, sCameraTriggers[level][b].boundsX, 6539 sCameraTriggers[level][b].boundsY, 6540 sCameraTriggers[level][b].boundsZ); 6541 6542 // Check if Mario is inside the bounds 6543 if (is_pos_in_bounds(sMarioCamState->pos, center, bounds, 6544 sCameraTriggers[level][b].boundsYaw) == TRUE) { 6545 //! This should be checked before calling is_pos_in_bounds. (It doesn't belong 6546 //! outside the while loop because some events disable area processing) 6547 if (!(sStatusFlags & CAM_FLAG_BLOCK_AREA_PROCESSING)) { 6548 sCameraTriggers[level][b].event(c); 6549 insideBounds = TRUE; 6550 } 6551 } 6552 } 6553 6554 if ((sCameraTriggers[level])[b].area == -1) { 6555 // Default triggers are only active if Mario is not already inside another trigger 6556 if (!insideBounds) { 6557 if (!(sStatusFlags & CAM_FLAG_BLOCK_AREA_PROCESSING)) { 6558 sCameraTriggers[level][b].event(c); 6559 } 6560 } 6561 } 6562 6563 b++; 6564 } 6565 } 6566 6567 // Area-specific camera processing 6568 if (!(sStatusFlags & CAM_FLAG_BLOCK_AREA_PROCESSING)) { 6569 switch (gCurrLevelArea) { 6570 case AREA_WF: 6571 if (sMarioCamState->action == ACT_RIDING_HOOT) { 6572 transition_to_camera_mode(c, CAMERA_MODE_SLIDE_HOOT, 60); 6573 } else { 6574 switch (sMarioGeometry.currFloorType) { 6575 case SURFACE_CAMERA_8_DIR: 6576 transition_to_camera_mode(c, CAMERA_MODE_8_DIRECTIONS, 90); 6577 s8DirModeBaseYaw = DEGREES(90); 6578 break; 6579 6580 case SURFACE_BOSS_FIGHT_CAMERA: 6581 if (gCurrActNum == 1) { 6582 set_camera_mode_boss_fight(c); 6583 } else { 6584 set_camera_mode_radial(c, 60); 6585 } 6586 break; 6587 default: 6588 set_camera_mode_radial(c, 60); 6589 } 6590 } 6591 break; 6592 6593 case AREA_BBH: 6594 // if camera is fixed at bbh_room_13_balcony_camera (but as floats) 6595 if (vec3f_compare(sFixedModeBasePosition, 210.f, 420.f, 3109.f) == TRUE) { 6596 if (sMarioCamState->pos[1] < 1800.f) { 6597 transition_to_camera_mode(c, CAMERA_MODE_CLOSE, 30); 6598 } 6599 } 6600 break; 6601 6602 case AREA_SSL_PYRAMID: 6603 set_mode_if_not_set_by_surface(c, CAMERA_MODE_OUTWARD_RADIAL); 6604 break; 6605 6606 case AREA_SSL_OUTSIDE: 6607 set_mode_if_not_set_by_surface(c, CAMERA_MODE_RADIAL); 6608 break; 6609 6610 case AREA_THI_HUGE: 6611 break; 6612 6613 case AREA_THI_TINY: 6614 surface_type_modes_thi(c); 6615 break; 6616 6617 case AREA_TTC: 6618 set_mode_if_not_set_by_surface(c, CAMERA_MODE_OUTWARD_RADIAL); 6619 break; 6620 6621 case AREA_BOB: 6622 if (set_mode_if_not_set_by_surface(c, CAMERA_MODE_NONE) == 0) { 6623 if (sMarioGeometry.currFloorType == SURFACE_BOSS_FIGHT_CAMERA) { 6624 set_camera_mode_boss_fight(c); 6625 } else { 6626 if (c->mode == CAMERA_MODE_CLOSE) { 6627 transition_to_camera_mode(c, CAMERA_MODE_RADIAL, 60); 6628 } else { 6629 set_camera_mode_radial(c, 60); 6630 } 6631 } 6632 } 6633 break; 6634 6635 case AREA_WDW_MAIN: 6636 switch (sMarioGeometry.currFloorType) { 6637 case SURFACE_INSTANT_WARP_1B: 6638 c->defMode = CAMERA_MODE_RADIAL; 6639 break; 6640 } 6641 break; 6642 6643 case AREA_WDW_TOWN: 6644 switch (sMarioGeometry.currFloorType) { 6645 case SURFACE_INSTANT_WARP_1C: 6646 c->defMode = CAMERA_MODE_CLOSE; 6647 break; 6648 } 6649 break; 6650 6651 case AREA_DDD_WHIRLPOOL: 6652 //! @bug this does nothing 6653 gLakituState.defMode = CAMERA_MODE_OUTWARD_RADIAL; 6654 break; 6655 6656 case AREA_DDD_SUB: 6657 if ((c->mode != CAMERA_MODE_BEHIND_MARIO) 6658 && (c->mode != CAMERA_MODE_WATER_SURFACE)) { 6659 if (((sMarioCamState->action & ACT_FLAG_ON_POLE) != 0) 6660 || (sMarioGeometry.currFloorHeight > 800.f)) { 6661 transition_to_camera_mode(c, CAMERA_MODE_8_DIRECTIONS, 60); 6662 6663 } else { 6664 if (sMarioCamState->pos[1] < 800.f) { 6665 transition_to_camera_mode(c, CAMERA_MODE_FREE_ROAM, 60); 6666 } 6667 } 6668 } 6669 //! @bug this does nothing 6670 gLakituState.defMode = CAMERA_MODE_FREE_ROAM; 6671 break; 6672 } 6673 } 6674 6675 sStatusFlags &= ~CAM_FLAG_BLOCK_AREA_PROCESSING; 6676 if (oldMode == CAMERA_MODE_C_UP) { 6677 sModeInfo.lastMode = c->mode; 6678 c->mode = oldMode; 6679 } 6680 mode = c->mode; 6681 return mode; 6682 } 6683 6684 /** 6685 * Move `pos` between the nearest floor and ceiling 6686 * @param lastGood unused, passed as the last position the camera was in 6687 */ 6688 void resolve_geometry_collisions(Vec3f pos, UNUSED Vec3f lastGood) { 6689 f32 ceilY, floorY; 6690 struct Surface *surf; 6691 6692 f32_find_wall_collision(&pos[0], &pos[1], &pos[2], 0.f, 100.f); 6693 floorY = find_floor(pos[0], pos[1] + 50.f, pos[2], &surf); 6694 ceilY = find_ceil(pos[0], pos[1] - 50.f, pos[2], &surf); 6695 6696 if ((FLOOR_LOWER_LIMIT != floorY) && (CELL_HEIGHT_LIMIT == ceilY)) { 6697 if (pos[1] < (floorY += 125.f)) { 6698 pos[1] = floorY; 6699 } 6700 } 6701 6702 if ((FLOOR_LOWER_LIMIT == floorY) && (CELL_HEIGHT_LIMIT != ceilY)) { 6703 if (pos[1] > (ceilY -= 125.f)) { 6704 pos[1] = ceilY; 6705 } 6706 } 6707 6708 if ((FLOOR_LOWER_LIMIT != floorY) && (CELL_HEIGHT_LIMIT != ceilY)) { 6709 floorY += 125.f; 6710 ceilY -= 125.f; 6711 6712 if ((pos[1] <= floorY) && (pos[1] < ceilY)) { 6713 pos[1] = floorY; 6714 } 6715 if ((pos[1] > floorY) && (pos[1] >= ceilY)) { 6716 pos[1] = ceilY; 6717 } 6718 if ((pos[1] <= floorY) && (pos[1] >= ceilY)) { 6719 pos[1] = (floorY + ceilY) * 0.5f; 6720 } 6721 } 6722 } 6723 6724 /** 6725 * Checks for any walls obstructing Mario from view, and calculates a new yaw that the camera should 6726 * rotate towards. 6727 * 6728 * @param[out] avoidYaw the angle (from Mario) that the camera should rotate towards to avoid the wall. 6729 * The camera then approaches avoidYaw until Mario is no longer obstructed. 6730 * avoidYaw is always parallel to the wall. 6731 * @param yawRange how wide of an arc to check for walls obscuring Mario. 6732 * 6733 * @return 3 if a wall is covering Mario, 1 if a wall is only near the camera. 6734 */ 6735 s32 rotate_camera_around_walls(struct Camera *c, Vec3f cPos, s16 *avoidYaw, s16 yawRange) { 6736 UNUSED u8 filler1[4]; 6737 struct WallCollisionData colData; 6738 struct Surface *wall; 6739 UNUSED u8 filler2[12]; 6740 f32 dummyDist, checkDist; 6741 UNUSED u8 filler3[4]; 6742 f32 coarseRadius; 6743 f32 fineRadius; 6744 s16 wallYaw, horWallNorm; 6745 UNUSED s16 unused; 6746 s16 dummyPitch; 6747 // The yaw of the vector from Mario to the camera. 6748 s16 yawFromMario; 6749 UNUSED u8 filler4[2]; 6750 s32 status = 0; 6751 /// The current iteration. The algorithm takes 8 equal steps from Mario back to the camera. 6752 s32 step = 0; 6753 UNUSED u8 filler5[4]; 6754 6755 vec3f_get_dist_and_angle(sMarioCamState->pos, cPos, &dummyDist, &dummyPitch, &yawFromMario); 6756 sStatusFlags &= ~CAM_FLAG_CAM_NEAR_WALL; 6757 colData.offsetY = 100.0f; 6758 // The distance from Mario to Lakitu 6759 checkDist = 0.0f; 6760 /// The radius used to find potential walls to avoid. 6761 /// @bug Increases to 250.f, but the max collision radius is 200.f 6762 coarseRadius = 150.0f; 6763 /// This only increases when there is a wall collision found in the coarse pass 6764 fineRadius = 100.0f; 6765 6766 for (step = 0; step < 8; step++) { 6767 // Start at Mario, move backwards to Lakitu's position 6768 colData.x = sMarioCamState->pos[0] + ((cPos[0] - sMarioCamState->pos[0]) * checkDist); 6769 colData.y = sMarioCamState->pos[1] + ((cPos[1] - sMarioCamState->pos[1]) * checkDist); 6770 colData.z = sMarioCamState->pos[2] + ((cPos[2] - sMarioCamState->pos[2]) * checkDist); 6771 colData.radius = coarseRadius; 6772 // Increase the coarse check radius 6773 camera_approach_f32_symmetric_bool(&coarseRadius, 250.f, 30.f); 6774 6775 if (find_wall_collisions(&colData) != 0) { 6776 wall = colData.walls[colData.numWalls - 1]; 6777 6778 // If we're over halfway from Mario to Lakitu, then there's a wall near the camera, but 6779 // not necessarily obstructing Mario 6780 if (step >= 5) { 6781 sStatusFlags |= CAM_FLAG_CAM_NEAR_WALL; 6782 if (status <= 0) { 6783 status = 1; 6784 wall = colData.walls[colData.numWalls - 1]; 6785 // wallYaw is parallel to the wall, not perpendicular 6786 wallYaw = atan2s(wall->normal.z, wall->normal.x) + DEGREES(90); 6787 // Calculate the avoid direction. The function returns the opposite direction so add 180 6788 // degrees. 6789 *avoidYaw = calc_avoid_yaw(yawFromMario, wallYaw) + DEGREES(180); 6790 } 6791 } 6792 6793 colData.x = sMarioCamState->pos[0] + ((cPos[0] - sMarioCamState->pos[0]) * checkDist); 6794 colData.y = sMarioCamState->pos[1] + ((cPos[1] - sMarioCamState->pos[1]) * checkDist); 6795 colData.z = sMarioCamState->pos[2] + ((cPos[2] - sMarioCamState->pos[2]) * checkDist); 6796 colData.radius = fineRadius; 6797 // Increase the fine check radius 6798 camera_approach_f32_symmetric_bool(&fineRadius, 200.f, 20.f); 6799 6800 if (find_wall_collisions(&colData) != 0) { 6801 wall = colData.walls[colData.numWalls - 1]; 6802 horWallNorm = atan2s(wall->normal.z, wall->normal.x); 6803 wallYaw = horWallNorm + DEGREES(90); 6804 // If Mario would be blocked by the surface, then avoid it 6805 if ((is_range_behind_surface(sMarioCamState->pos, cPos, wall, yawRange, SURFACE_WALL_MISC) == 0) 6806 && (is_mario_behind_surface(c, wall) == TRUE) 6807 // Also check if the wall is tall enough to cover Mario 6808 && (is_surf_within_bounding_box(wall, -1.f, 150.f, -1.f) == FALSE)) { 6809 // Calculate the avoid direction. The function returns the opposite direction so add 180 6810 // degrees. 6811 *avoidYaw = calc_avoid_yaw(yawFromMario, wallYaw) + DEGREES(180); 6812 camera_approach_s16_symmetric_bool(avoidYaw, horWallNorm, yawRange); 6813 status = 3; 6814 step = 8; 6815 } 6816 } 6817 } 6818 checkDist += 0.125f; 6819 } 6820 6821 return status; 6822 } 6823 6824 /** 6825 * Stores type and height of the nearest floor and ceiling to Mario in `pg` 6826 * 6827 * Note: Also finds the water level, but waterHeight is unused 6828 */ 6829 void find_mario_floor_and_ceil(struct PlayerGeometry *pg) { 6830 struct Surface *surf; 6831 s16 tempCheckingSurfaceCollisionsForCamera = gCheckingSurfaceCollisionsForCamera; 6832 gCheckingSurfaceCollisionsForCamera = TRUE; 6833 6834 if (find_floor(sMarioCamState->pos[0], sMarioCamState->pos[1] + 10.f, 6835 sMarioCamState->pos[2], &surf) != FLOOR_LOWER_LIMIT) { 6836 pg->currFloorType = surf->type; 6837 } else { 6838 pg->currFloorType = 0; 6839 } 6840 6841 if (find_ceil(sMarioCamState->pos[0], sMarioCamState->pos[1] - 10.f, 6842 sMarioCamState->pos[2], &surf) != CELL_HEIGHT_LIMIT) { 6843 pg->currCeilType = surf->type; 6844 } else { 6845 pg->currCeilType = 0; 6846 } 6847 6848 gCheckingSurfaceCollisionsForCamera = FALSE; 6849 pg->currFloorHeight = find_floor(sMarioCamState->pos[0], 6850 sMarioCamState->pos[1] + 10.f, 6851 sMarioCamState->pos[2], &pg->currFloor); 6852 pg->currCeilHeight = find_ceil(sMarioCamState->pos[0], 6853 sMarioCamState->pos[1] - 10.f, 6854 sMarioCamState->pos[2], &pg->currCeil); 6855 pg->waterHeight = find_water_level(sMarioCamState->pos[0], sMarioCamState->pos[2]); 6856 gCheckingSurfaceCollisionsForCamera = tempCheckingSurfaceCollisionsForCamera; 6857 } 6858 6859 /** 6860 * Start a cutscene focusing on an object 6861 * This will play if nothing else happened in the same frame, like exiting or warping. 6862 */ 6863 void start_object_cutscene(u8 cutscene, struct Object *o) { 6864 sObjectCutscene = cutscene; 6865 gRecentCutscene = 0; 6866 gCutsceneFocus = o; 6867 gObjCutsceneDone = FALSE; 6868 } 6869 6870 /** 6871 * Start a low-priority cutscene without focusing on an object 6872 * This will play if nothing else happened in the same frame, like exiting or warping. 6873 */ 6874 u8 start_object_cutscene_without_focus(u8 cutscene) { 6875 sObjectCutscene = cutscene; 6876 sCutsceneDialogResponse = DIALOG_RESPONSE_NONE; 6877 return 0; 6878 } 6879 6880 s16 unused_dialog_cutscene_response(u8 cutscene) { 6881 // if not in a cutscene, start this one 6882 if ((gCamera->cutscene == 0) && (sObjectCutscene == 0)) { 6883 sObjectCutscene = cutscene; 6884 } 6885 6886 // if playing this cutscene and Mario responded, return the response 6887 if ((gCamera->cutscene == cutscene) && (sCutsceneDialogResponse != DIALOG_RESPONSE_NONE)) { 6888 return sCutsceneDialogResponse; 6889 } else { 6890 return 0; 6891 } 6892 } 6893 6894 s16 cutscene_object_with_dialog(u8 cutscene, struct Object *o, s16 dialogID) { 6895 s16 response = DIALOG_RESPONSE_NONE; 6896 6897 if ((gCamera->cutscene == 0) && (sObjectCutscene == 0)) { 6898 if (gRecentCutscene != cutscene) { 6899 start_object_cutscene(cutscene, o); 6900 if (dialogID != DIALOG_NONE) { 6901 sCutsceneDialogID = dialogID; 6902 } else { 6903 sCutsceneDialogID = DIALOG_001; 6904 } 6905 } else { 6906 response = sCutsceneDialogResponse; 6907 } 6908 6909 gRecentCutscene = 0; 6910 } 6911 return response; 6912 } 6913 6914 s16 cutscene_object_without_dialog(u8 cutscene, struct Object *o) { 6915 s16 response = cutscene_object_with_dialog(cutscene, o, DIALOG_NONE); 6916 return response; 6917 } 6918 6919 /** 6920 * @return 0 if not started, 1 if started, and -1 if finished 6921 */ 6922 s16 cutscene_object(u8 cutscene, struct Object *o) { 6923 s16 status = 0; 6924 6925 if ((gCamera->cutscene == 0) && (sObjectCutscene == 0)) { 6926 if (gRecentCutscene != cutscene) { 6927 start_object_cutscene(cutscene, o); 6928 status = 1; 6929 } else { 6930 status = -1; 6931 } 6932 } 6933 return status; 6934 } 6935 6936 /** 6937 * Update the camera's yaw and nextYaw. This is called from cutscenes to ignore the camera mode's yaw. 6938 */ 6939 void update_camera_yaw(struct Camera *c) { 6940 c->nextYaw = calculate_yaw(c->focus, c->pos); 6941 c->yaw = c->nextYaw; 6942 } 6943 6944 void cutscene_reset_spline(void) { 6945 sCutsceneSplineSegment = 0; 6946 sCutsceneSplineSegmentProgress = 0; 6947 } 6948 6949 void stop_cutscene_and_retrieve_stored_info(struct Camera *c) { 6950 gCutsceneTimer = CUTSCENE_STOP; 6951 c->cutscene = 0; 6952 vec3f_copy(c->focus, sCameraStoreCutscene.focus); 6953 vec3f_copy(c->pos, sCameraStoreCutscene.pos); 6954 } 6955 6956 void cap_switch_save(s16 dummy) { 6957 UNUSED s16 unused = dummy; 6958 save_file_do_save(gCurrSaveFileNum - 1); 6959 } 6960 6961 void init_spline_point(struct CutsceneSplinePoint *splinePoint, s8 index, u8 speed, Vec3s point) { 6962 splinePoint->index = index; 6963 splinePoint->speed = speed; 6964 vec3s_copy(splinePoint->point, point); 6965 } 6966 6967 // TODO: (Scrub C) 6968 void copy_spline_segment(struct CutsceneSplinePoint dst[], struct CutsceneSplinePoint src[]) { 6969 s32 j = 0; 6970 s32 i = 0; 6971 UNUSED u8 filler[8]; 6972 6973 init_spline_point(&dst[i], src[j].index, src[j].speed, src[j].point); 6974 i++; 6975 do { 6976 do { 6977 init_spline_point(&dst[i], src[j].index, src[j].speed, src[j].point); 6978 i++; 6979 j++; 6980 } while ((src[j].index != -1) && (src[j].index != -1)); //! same comparison performed twice 6981 } while (j > 16); 6982 6983 // Create the end of the spline by duplicating the last point 6984 do { init_spline_point(&dst[i], 0, src[j].speed, src[j].point); } while (0); 6985 do { init_spline_point(&dst[i + 1], 0, 0, src[j].point); } while (0); 6986 do { init_spline_point(&dst[i + 2], 0, 0, src[j].point); } while (0); 6987 do { init_spline_point(&dst[i + 3], -1, 0, src[j].point); } while (0); 6988 } 6989 6990 /** 6991 * Triggers Mario to enter a dialog state. This is used to make Mario look at the focus of a cutscene, 6992 * for example, bowser. 6993 * @param state 0 = stop, 1 = start, 2 = start and look up, and 3 = start and look down 6994 * 6995 * @return if Mario left the dialog state, return CUTSCENE_LOOP, else return gCutsceneTimer 6996 */ 6997 s16 cutscene_common_set_dialog_state(s32 state) { 6998 s16 timer = gCutsceneTimer; 6999 // If the dialog ended, return CUTSCENE_LOOP, which would end the cutscene shot 7000 if (set_mario_npc_dialog(state) == MARIO_DIALOG_STATUS_SPEAK) { 7001 timer = CUTSCENE_LOOP; 7002 } 7003 return timer; 7004 } 7005 7006 /// Unused SSL cutscene? 7007 static UNUSED void unused_cutscene_mario_dialog_looking_down(UNUSED struct Camera *c) { 7008 gCutsceneTimer = cutscene_common_set_dialog_state(MARIO_DIALOG_LOOK_DOWN); 7009 } 7010 7011 /** 7012 * Cause Mario to enter the normal dialog state. 7013 */ 7014 static BAD_RETURN(s32) cutscene_mario_dialog(UNUSED struct Camera *c) { 7015 gCutsceneTimer = cutscene_common_set_dialog_state(MARIO_DIALOG_LOOK_FRONT); 7016 } 7017 7018 /// Unused SSL cutscene? 7019 static UNUSED void unused_cutscene_mario_dialog_looking_up(UNUSED struct Camera *c) { 7020 gCutsceneTimer = cutscene_common_set_dialog_state(MARIO_DIALOG_LOOK_UP); 7021 } 7022 7023 /** 7024 * Lower the volume (US only) and start the peach letter background music 7025 */ 7026 BAD_RETURN(s32) cutscene_intro_peach_start_letter_music(UNUSED struct Camera *c) { 7027 #if defined(VERSION_US) || defined(VERSION_SH) || defined(VERSION_CN) 7028 seq_player_lower_volume(SEQ_PLAYER_LEVEL, 60, 40); 7029 #endif 7030 cutscene_intro_peach_play_message_music(); 7031 } 7032 7033 /** 7034 * Raise the volume (not in JP) and start the flying music. 7035 */ 7036 BAD_RETURN(s32) cutscene_intro_peach_start_flying_music(UNUSED struct Camera *c) { 7037 #ifndef VERSION_JP 7038 seq_player_unlower_volume(SEQ_PLAYER_LEVEL, 60); 7039 #endif 7040 cutscene_intro_peach_play_lakitu_flying_music(); 7041 } 7042 7043 #ifdef VERSION_EU 7044 /** 7045 * Lower the volume for the letter background music. In US, this happens on the same frame as the music 7046 * starts. 7047 */ 7048 BAD_RETURN(s32) cutscene_intro_peach_eu_lower_volume(UNUSED struct Camera *c) { 7049 seq_player_lower_volume(SEQ_PLAYER_LEVEL, 60, 40); 7050 } 7051 #endif 7052 7053 void reset_pan_distance(UNUSED struct Camera *c) { 7054 sPanDistance = 0; 7055 } 7056 7057 /** 7058 * Easter egg: the player 2 controller can move the camera's focus in the ending and credits. 7059 */ 7060 void player2_rotate_cam(struct Camera *c, s16 minPitch, s16 maxPitch, s16 minYaw, s16 maxYaw) { 7061 f32 distCamToFocus; 7062 s16 pitch, yaw, pitchCap; 7063 7064 // Change the camera rotation to match the 2nd player's stick 7065 approach_s16_asymptotic_bool(&sCreditsPlayer2Yaw, -(s16)(gPlayer2Controller->stickX * 250.f), 4); 7066 approach_s16_asymptotic_bool(&sCreditsPlayer2Pitch, -(s16)(gPlayer2Controller->stickY * 265.f), 4); 7067 vec3f_get_dist_and_angle(c->pos, c->focus, &distCamToFocus, &pitch, &yaw); 7068 7069 pitchCap = 0x3800 - pitch; if (pitchCap < 0) { 7070 pitchCap = 0; 7071 } 7072 if (maxPitch > pitchCap) { 7073 maxPitch = pitchCap; 7074 } 7075 7076 pitchCap = -0x3800 - pitch; 7077 if (pitchCap > 0) { 7078 pitchCap = 0; 7079 } 7080 if (minPitch < pitchCap) { 7081 minPitch = pitchCap; 7082 } 7083 7084 if (sCreditsPlayer2Pitch > maxPitch) { 7085 sCreditsPlayer2Pitch = maxPitch; 7086 } 7087 if (sCreditsPlayer2Pitch < minPitch) { 7088 sCreditsPlayer2Pitch = minPitch; 7089 } 7090 7091 if (sCreditsPlayer2Yaw > maxYaw) { 7092 sCreditsPlayer2Yaw = maxYaw; 7093 } 7094 if (sCreditsPlayer2Yaw < minYaw) { 7095 sCreditsPlayer2Yaw = minYaw; 7096 } 7097 7098 pitch += sCreditsPlayer2Pitch; 7099 yaw += sCreditsPlayer2Yaw; 7100 vec3f_set_dist_and_angle(c->pos, sPlayer2FocusOffset, distCamToFocus, pitch, yaw); 7101 vec3f_sub(sPlayer2FocusOffset, c->focus); 7102 } 7103 7104 /** 7105 * Store camera info for the cannon opening cutscene 7106 */ 7107 void store_info_cannon(struct Camera *c) { 7108 vec3f_copy(sCameraStoreCutscene.pos, c->pos); 7109 vec3f_copy(sCameraStoreCutscene.focus, c->focus); 7110 sCameraStoreCutscene.panDist = sPanDistance; 7111 sCameraStoreCutscene.cannonYOffset = sCannonYOffset; 7112 } 7113 7114 /** 7115 * Retrieve camera info for the cannon opening cutscene 7116 */ 7117 void retrieve_info_cannon(struct Camera *c) { 7118 vec3f_copy(c->pos, sCameraStoreCutscene.pos); 7119 vec3f_copy(c->focus, sCameraStoreCutscene.focus); 7120 sPanDistance = sCameraStoreCutscene.panDist; 7121 sCannonYOffset = sCameraStoreCutscene.cannonYOffset; 7122 } 7123 7124 /** 7125 * Store camera info for the star spawn cutscene 7126 */ 7127 void store_info_star(struct Camera *c) { 7128 reset_pan_distance(c); 7129 vec3f_copy(sCameraStoreCutscene.pos, c->pos); 7130 sCameraStoreCutscene.focus[0] = sMarioCamState->pos[0]; 7131 sCameraStoreCutscene.focus[1] = c->focus[1]; 7132 sCameraStoreCutscene.focus[2] = sMarioCamState->pos[2]; 7133 } 7134 7135 /** 7136 * Retrieve camera info for the star spawn cutscene 7137 */ 7138 void retrieve_info_star(struct Camera *c) { 7139 vec3f_copy(c->pos, sCameraStoreCutscene.pos); 7140 vec3f_copy(c->focus, sCameraStoreCutscene.focus); 7141 } 7142 7143 static UNUSED void unused_vec3s_to_vec3f(Vec3f dst, Vec3s src) { 7144 dst[0] = src[0]; 7145 dst[1] = src[1]; 7146 dst[2] = src[2]; 7147 } 7148 7149 static UNUSED void unused_vec3f_to_vec3s(Vec3s dst, Vec3f src) { 7150 // note: unlike vec3f_to_vec3s(), this function doesn't round the numbers and instead simply 7151 // truncates them 7152 dst[0] = src[0]; 7153 dst[1] = src[1]; 7154 dst[2] = src[2]; 7155 } 7156 7157 /** 7158 * Rotate the camera's focus around the camera's position by incYaw and incPitch 7159 */ 7160 void pan_camera(struct Camera *c, s16 incPitch, s16 incYaw) { 7161 UNUSED u8 filler[12]; 7162 f32 distCamToFocus; 7163 s16 pitch, yaw; 7164 7165 vec3f_get_dist_and_angle(c->pos, c->focus, &distCamToFocus, &pitch, &yaw); 7166 pitch += incPitch; yaw += incYaw; 7167 vec3f_set_dist_and_angle(c->pos, c->focus, distCamToFocus, pitch, yaw); 7168 } 7169 7170 BAD_RETURN(s32) cutscene_shake_explosion(UNUSED struct Camera *c) { 7171 set_environmental_camera_shake(SHAKE_ENV_EXPLOSION); 7172 cutscene_set_fov_shake_preset(1); 7173 } 7174 7175 static UNUSED void unused_start_bowser_bounce_shake(UNUSED struct Camera *c) { 7176 set_environmental_camera_shake(SHAKE_ENV_BOWSER_THROW_BOUNCE); 7177 } 7178 7179 /** 7180 * Change the spherical coordinates of `to` relative to `from` by `incDist`, `incPitch`, and `incYaw` 7181 * 7182 * @param from the base position 7183 * @param[out] to the destination position 7184 */ 7185 void rotate_and_move_vec3f(Vec3f to, Vec3f from, f32 incDist, s16 incPitch, s16 incYaw) { 7186 f32 dist; 7187 s16 pitch, yaw; 7188 7189 vec3f_get_dist_and_angle(from, to, &dist, &pitch, &yaw); 7190 pitch += incPitch; 7191 yaw += incYaw; 7192 dist += incDist; 7193 vec3f_set_dist_and_angle(from, to, dist, pitch, yaw); 7194 } 7195 7196 void set_flag_post_door(struct Camera *c) { 7197 sStatusFlags |= CAM_FLAG_BEHIND_MARIO_POST_DOOR; 7198 sCameraYawAfterDoorCutscene = calculate_yaw(c->focus, c->pos); 7199 } 7200 7201 void cutscene_soften_music(UNUSED struct Camera *c) { 7202 seq_player_lower_volume(SEQ_PLAYER_LEVEL, 60, 40); 7203 } 7204 7205 void cutscene_unsoften_music(UNUSED struct Camera *c) { 7206 seq_player_unlower_volume(SEQ_PLAYER_LEVEL, 60); 7207 } 7208 7209 UNUSED static void stub_camera_5(UNUSED struct Camera *c) { 7210 } 7211 7212 BAD_RETURN(s32) cutscene_unused_start(UNUSED struct Camera *c) { 7213 } 7214 7215 BAD_RETURN(s32) cutscene_unused_loop(UNUSED struct Camera *c) { 7216 } 7217 7218 /** 7219 * Set the camera position and focus for when Mario falls from the sky. 7220 */ 7221 BAD_RETURN(s32) cutscene_ending_mario_fall_start(struct Camera *c) { 7222 vec3f_set(c->focus, -26.f, 0.f, -137.f); 7223 vec3f_set(c->pos, 165.f, 4725.f, 324.f); 7224 } 7225 7226 /** 7227 * Focus on Mario when he's falling from the sky. 7228 */ 7229 BAD_RETURN(s32) cutscene_ending_mario_fall_focus_mario(struct Camera *c) { 7230 Vec3f offset; 7231 vec3f_set(offset, 0.f, 80.f, 0.f); 7232 7233 offset[2] = ABS(sMarioCamState->pos[1] - c->pos[1]) * -0.1f; 7234 if (offset[2] > -100.f) { 7235 offset[2] = -100.f; 7236 } 7237 7238 offset_rotated(c->focus, sMarioCamState->pos, offset, sMarioCamState->faceAngle); 7239 } 7240 7241 /** 7242 * Mario falls from the sky after the grand star cutscene. 7243 */ 7244 BAD_RETURN(s32) cutscene_ending_mario_fall(struct Camera *c) { 7245 cutscene_event(cutscene_ending_mario_fall_start, c, 0, 0); 7246 cutscene_event(cutscene_ending_mario_fall_focus_mario, c, 0, -1); 7247 player2_rotate_cam(c, -0x2000, 0x2000, -0x2000, 0x2000); 7248 } 7249 7250 /** 7251 * Closeup of Mario as the wing cap fades and Mario looks up. 7252 */ 7253 BAD_RETURN(s32) cutscene_ending_mario_land_closeup(struct Camera *c) { 7254 vec3f_set(c->focus, 85.f, 826.f, 250.f); 7255 vec3f_set(c->pos, -51.f, 988.f, -202.f); 7256 player2_rotate_cam(c, -0x2000, 0x2000, -0x2000, 0x2000); 7257 } 7258 7259 /** 7260 * Reset the spline progress and cvar9. 7261 */ 7262 BAD_RETURN(s32) cutscene_ending_reset_spline(UNUSED struct Camera *c) { 7263 sCutsceneVars[9].point[0] = 0.f; 7264 cutscene_reset_spline(); 7265 } 7266 7267 /** 7268 * Follow sEndingFlyToWindowPos/Focus up to the window. 7269 */ 7270 BAD_RETURN(s32) cutscene_ending_fly_up_to_window(struct Camera *c) { 7271 move_point_along_spline(c->pos, sEndingFlyToWindowPos, &sCutsceneSplineSegment, &sCutsceneSplineSegmentProgress); 7272 move_point_along_spline(c->focus, sEndingFlyToWindowFocus, &sCutsceneSplineSegment, &sCutsceneSplineSegmentProgress); 7273 } 7274 7275 /** 7276 * Move the camera up to the window as the star power frees peach. 7277 */ 7278 BAD_RETURN(s32) cutscene_ending_stars_free_peach(struct Camera *c) { 7279 cutscene_event(cutscene_ending_reset_spline, c, 0, 0); 7280 cutscene_event(cutscene_ending_fly_up_to_window, c, 0, -1); 7281 player2_rotate_cam(c, -0x2000, 0x2000, -0x2000, 0x2000); 7282 } 7283 7284 /** 7285 * Move the camera to the ground as Mario lands. 7286 */ 7287 BAD_RETURN(s32) cutscene_ending_mario_land(struct Camera *c) { 7288 vec3f_set(c->focus, sEndingFlyToWindowFocus[0].point[0], sEndingFlyToWindowFocus[0].point[1] + 80.f, sEndingFlyToWindowFocus[0].point[2]); 7289 vec3f_set(c->pos, sEndingFlyToWindowPos[0].point[0], sEndingFlyToWindowPos[0].point[1], sEndingFlyToWindowPos[0].point[2] + 150.f); 7290 player2_rotate_cam(c, -0x800, 0x2000, -0x2000, 0x2000); 7291 } 7292 7293 /** 7294 * Move the camera closer to peach appearing. 7295 */ 7296 BAD_RETURN(s32) cutscene_ending_peach_appear_closeup(struct Camera *c) { 7297 vec3f_set(c->pos, 179.f, 2463.f, -1216.f); 7298 c->pos[1] = gCutsceneFocus->oPosY + 35.f; 7299 vec3f_set(c->focus, gCutsceneFocus->oPosX, gCutsceneFocus->oPosY + 125.f, gCutsceneFocus->oPosZ); 7300 } 7301 7302 /** 7303 * Peach fades in, the camera focuses on her. 7304 */ 7305 BAD_RETURN(s32) cutscene_ending_peach_appears(struct Camera *c) { 7306 cutscene_event(cutscene_ending_peach_appear_closeup, c, 0, 0); 7307 approach_f32_asymptotic_bool(&c->pos[1], gCutsceneFocus->oPosY + 35.f, 0.02f); 7308 approach_f32_asymptotic_bool(&c->focus[1], gCutsceneFocus->oPosY + 125.f, 0.15f); 7309 player2_rotate_cam(c, -0x2000, 0x2000, -0x2000, 0x2000); 7310 } 7311 7312 /** 7313 * Reset spline progress, set cvar2 y offset. 7314 */ 7315 BAD_RETURN(s32) cutscene_ending_peach_descends_start(UNUSED struct Camera *c) { 7316 cutscene_reset_spline(); 7317 sCutsceneVars[2].point[1] = 150.f; 7318 } 7319 7320 /** 7321 * Follow the sEndingPeachDescentCamPos spline, which rotates around peach. 7322 */ 7323 BAD_RETURN(s32) cutscene_ending_follow_peach_descent(struct Camera *c) { 7324 move_point_along_spline(c->pos, sEndingPeachDescentCamPos, &sCutsceneSplineSegment, &sCutsceneSplineSegmentProgress); 7325 c->pos[1] += gCutsceneFocus->oPosY + sCutsceneVars[3].point[1]; 7326 } 7327 7328 /** 7329 * Decrease cvar2's y offset while the camera flies backwards to Mario. 7330 */ 7331 BAD_RETURN(s32) cutscene_ending_peach_descent_lower_focus(UNUSED struct Camera *c) { 7332 camera_approach_f32_symmetric_bool(&(sCutsceneVars[2].point[1]), 90.f, 0.5f); 7333 } 7334 7335 /** 7336 * Keep following the sEndingPeachDescentCamPos spline, which leads back to Mario. 7337 */ 7338 BAD_RETURN(s32) cutscene_ending_peach_descent_back_to_mario(struct Camera *c) { 7339 Vec3f pos; 7340 7341 move_point_along_spline(pos, sEndingPeachDescentCamPos, &sCutsceneSplineSegment, &sCutsceneSplineSegmentProgress); 7342 c->pos[0] = pos[0]; 7343 c->pos[2] = pos[2]; 7344 approach_f32_asymptotic_bool(&c->pos[1], (pos[1] += gCutsceneFocus->oPosY), 0.07f); 7345 } 7346 7347 /** 7348 * Peach starts floating to the ground. Rotate the camera around her, then fly backwards to Mario when 7349 * she lands. 7350 */ 7351 BAD_RETURN(s32) cutscene_ending_peach_descends(struct Camera *c) { 7352 cutscene_event(cutscene_ending_peach_descends_start, c, 0, 0); 7353 cutscene_event(cutscene_ending_follow_peach_descent, c, 0, 299); 7354 cutscene_event(cutscene_ending_peach_descent_back_to_mario, c, 300, -1); 7355 cutscene_event(cutscene_ending_peach_descent_lower_focus, c, 300, -1); 7356 vec3f_set(c->focus, gCutsceneFocus->oPosX, sCutsceneVars[2].point[1] + gCutsceneFocus->oPosY, 7357 gCutsceneFocus->oPosZ); 7358 player2_rotate_cam(c, -0x2000, 0x2000, -0x2000, 0x2000); 7359 } 7360 7361 /** 7362 * Mario runs across the bridge to peach, and takes off his cap. 7363 * Follow the sEndingMarioToPeach* splines while Mario runs across. 7364 */ 7365 BAD_RETURN(s32) cutscene_ending_mario_to_peach(struct Camera *c) { 7366 cutscene_event(cutscene_ending_reset_spline, c, 0, 0); 7367 move_point_along_spline(c->pos, sEndingMarioToPeachPos, &sCutsceneSplineSegment, &sCutsceneSplineSegmentProgress); 7368 move_point_along_spline(c->focus, sEndingMarioToPeachFocus, &sCutsceneSplineSegment, &sCutsceneSplineSegmentProgress); 7369 player2_rotate_cam(c, -0x2000, 0x2000, -0x2000, 0x2000); 7370 } 7371 7372 /** 7373 * Make the focus follow the sEndingLookUpAtCastle spline. 7374 */ 7375 BAD_RETURN(s32) cutscene_ending_look_up_at_castle(UNUSED struct Camera *c) { 7376 move_point_along_spline(c->focus, sEndingLookUpAtCastle, &sCutsceneSplineSegment, &sCutsceneSplineSegmentProgress); 7377 } 7378 7379 /** 7380 * Peach opens her eyes and the camera looks at the castle window again. 7381 */ 7382 BAD_RETURN(s32) cutscene_ending_peach_wakeup(struct Camera *c) { 7383 cutscene_event(cutscene_ending_reset_spline, c, 0, 0); 7384 cutscene_event(cutscene_ending_look_up_at_castle, c, 0, 0); 7385 #ifdef VERSION_EU 7386 cutscene_event(cutscene_ending_look_up_at_castle, c, 265, -1); 7387 cutscene_spawn_obj(7, 315); 7388 cutscene_spawn_obj(9, 355); 7389 #else 7390 cutscene_event(cutscene_ending_look_up_at_castle, c, 250, -1); 7391 cutscene_spawn_obj(7, 300); 7392 cutscene_spawn_obj(9, 340); 7393 #endif 7394 vec3f_set(c->pos, -163.f, 978.f, -1082.f); 7395 player2_rotate_cam(c, -0x800, 0x2000, -0x2000, 0x2000); 7396 } 7397 7398 /** 7399 * Side view of peach and Mario. Peach thanks Mario for saving her. 7400 */ 7401 BAD_RETURN(s32) cutscene_ending_dialog(struct Camera *c) { 7402 vec3f_set(c->focus, 11.f, 983.f, -1273.f); 7403 vec3f_set(c->pos, -473.f, 970.f, -1152.f); 7404 player2_rotate_cam(c, -0x800, 0x2000, -0x2000, 0x2000); 7405 } 7406 7407 /** 7408 * Zoom in and move the camera close to Mario and peach. 7409 */ 7410 BAD_RETURN(s32) cutscene_ending_kiss_closeup(struct Camera *c) { 7411 set_fov_function(CAM_FOV_SET_29); 7412 vec3f_set(c->focus, 350.f, 1034.f, -1216.f); 7413 vec3f_set(c->pos, -149.f, 1021.f, -1216.f); 7414 } 7415 7416 /** 7417 * Fly back and zoom out for Mario's spin after the kiss. 7418 */ 7419 BAD_RETURN(s32) cutscene_ending_kiss_here_we_go(struct Camera *c) { 7420 Vec3f pos, foc; 7421 7422 set_fov_function(CAM_FOV_DEFAULT); 7423 vec3f_set(foc, 233.f, 1068.f, -1298.f); 7424 vec3f_set(pos, -250.f, 966.f, -1111.f); 7425 //! another double typo 7426 approach_vec3f_asymptotic(c->pos, pos, 0.2, 0.1f, 0.2f); 7427 approach_vec3f_asymptotic(c->focus, foc, 0.2, 0.1f, 0.2f); 7428 } 7429 7430 /** 7431 * Peach kisses Mario on the nose. 7432 */ 7433 BAD_RETURN(s32) cutscene_ending_kiss(struct Camera *c) { 7434 cutscene_event(cutscene_ending_kiss_closeup, c, 0, 0); 7435 #ifdef VERSION_EU 7436 cutscene_event(cutscene_ending_kiss_here_we_go, c, 185, -1); 7437 #else 7438 cutscene_event(cutscene_ending_kiss_here_we_go, c, 155, -1); 7439 #endif 7440 player2_rotate_cam(c, -0x800, 0x2000, -0x2000, 0x2000); 7441 } 7442 7443 /** 7444 * Make the focus follow sEndingLookAtSkyFocus. 7445 */ 7446 BAD_RETURN(s32) cutscene_ending_look_at_sky(struct Camera *c) { 7447 move_point_along_spline(c->focus, sEndingLookAtSkyFocus, &sCutsceneSplineSegment, &sCutsceneSplineSegmentProgress); 7448 vec3f_set(c->pos, 699.f, 1680.f, -703.f); 7449 } 7450 7451 /** 7452 * Zoom in the fov. The fovFunc was just set to default, so it wants to approach 45. But while this is 7453 * called, it will stay at about 37.26f 7454 */ 7455 BAD_RETURN(s32) cutscene_ending_zoom_fov(UNUSED struct Camera *c) { 7456 sFOVState.fov = 37.f; 7457 } 7458 7459 /** 7460 * Peach suggests baking a cake for Mario. Mario looks back at the camera before going inside the castle. 7461 */ 7462 BAD_RETURN(s32) cutscene_ending_cake_for_mario(struct Camera *c) { 7463 cutscene_event(cutscene_ending_reset_spline, c, 0, 0); 7464 cutscene_event(cutscene_ending_look_at_sky, c, 0, 0); 7465 cutscene_event(cutscene_ending_zoom_fov, c, 0, 499); 7466 cutscene_event(cutscene_ending_look_at_sky, c, 500, -1); 7467 cutscene_spawn_obj(8, 600); 7468 cutscene_spawn_obj(8, 608); 7469 cutscene_spawn_obj(8, 624); 7470 cutscene_spawn_obj(8, 710); 7471 } 7472 7473 /** 7474 * Stop the ending cutscene, reset the fov. 7475 */ 7476 BAD_RETURN(s32) cutscene_ending_stop(struct Camera *c) { 7477 set_fov_function(CAM_FOV_SET_45); 7478 c->cutscene = 0; 7479 gCutsceneTimer = CUTSCENE_STOP; 7480 } 7481 7482 /** 7483 * Start the grand star cutscene. 7484 * cvar0 is a relative offset from Mario. 7485 * cvar1 is the is the camera's goal position. 7486 */ 7487 BAD_RETURN(s32) cutscene_grand_star_start(UNUSED struct Camera *c) { 7488 vec3f_set(sCutsceneVars[0].point, 0.f, 150.f, -600.f); 7489 offset_rotated(sCutsceneVars[1].point, sMarioCamState->pos, sCutsceneVars[0].point, sMarioCamState->faceAngle); 7490 sCutsceneVars[1].point[1] = 457.f; 7491 } 7492 7493 /** 7494 * Make the camera fly to the front of Mario. 7495 */ 7496 BAD_RETURN(s32) cutscene_grand_star_front_of_mario(struct Camera *c) { 7497 f32 goalDist; 7498 s16 goalPitch, goalYaw; 7499 f32 dist; 7500 s16 pitch, yaw; 7501 7502 vec3f_get_dist_and_angle(sMarioCamState->pos, sCutsceneVars[1].point, &goalDist, &goalPitch, &goalYaw); 7503 vec3f_get_dist_and_angle(sMarioCamState->pos, c->pos, &dist, &pitch, &yaw); 7504 approach_f32_asymptotic_bool(&dist, goalDist, 0.1f); 7505 approach_s16_asymptotic_bool(&pitch, goalPitch, 32); 7506 approach_s16_asymptotic_bool(&yaw, goalYaw + 0x1200, 20); 7507 vec3f_set_dist_and_angle(sMarioCamState->pos, c->pos, dist, pitch, yaw); 7508 } 7509 7510 /** 7511 * Started shortly after Mario starts the triple jump. Stores Mario's face angle and zeros cvar2. 7512 */ 7513 BAD_RETURN(s32) cutscene_grand_star_mario_jump(UNUSED struct Camera *c) { 7514 vec3s_set(sCutsceneVars[0].angle, 0, sMarioCamState->faceAngle[1], 0); 7515 vec3f_set(sCutsceneVars[2].point, 0.f, 0.f, 0.f); 7516 } 7517 7518 /** 7519 * Accelerate cvar2 to point back and to the left (relative to the camera). 7520 */ 7521 BAD_RETURN(s32) cutscene_grand_star_accel_cvar2(UNUSED struct Camera *c) { 7522 camera_approach_f32_symmetric_bool(&sCutsceneVars[2].point[2], -40.f, 2.0f); 7523 sCutsceneVars[2].point[0] = 5.0f; 7524 } 7525 7526 /** 7527 * Decrease cvar2 offset, follow Mario by directly updating the camera's pos. 7528 */ 7529 BAD_RETURN(s32) cutscene_grand_star_approach_mario(struct Camera *c) { 7530 camera_approach_f32_symmetric_bool(&sCutsceneVars[2].point[2], 0.f, 2.f); 7531 sCutsceneVars[2].point[0] = 0.f; 7532 approach_f32_asymptotic_bool(&c->pos[0], sMarioCamState->pos[0], 0.01f); 7533 approach_f32_asymptotic_bool(&c->pos[2], sMarioCamState->pos[2], 0.01f); 7534 } 7535 7536 /** 7537 * Offset the camera's position by cvar2. Before Mario triple jumps, this moves back and to the left. 7538 * After the triple jump, cvar2 decelerates to 0. 7539 */ 7540 BAD_RETURN(s32) cutscene_grand_star_move_cvar2(struct Camera *c) { 7541 offset_rotated(c->pos, c->pos, sCutsceneVars[2].point, sCutsceneVars[0].angle); 7542 } 7543 7544 BAD_RETURN(s32) cutscene_grand_star_focus_mario(struct Camera *c) { 7545 Vec3f foc; 7546 7547 vec3f_set(foc, sMarioCamState->pos[0], (sMarioCamState->pos[1] - 307.f) * 0.5f + 407.f, sMarioCamState->pos[2]); 7548 approach_vec3f_asymptotic(c->focus, foc, 0.5f, 0.8f, 0.5f); 7549 } 7550 7551 /** 7552 * The first part of the grand star cutscene, after Mario has collected the grand star. 7553 */ 7554 BAD_RETURN(s32) cutscene_grand_star(struct Camera *c) { 7555 sStatusFlags |= CAM_FLAG_SMOOTH_MOVEMENT; 7556 cutscene_event(cutscene_grand_star_start, c, 0, 0); 7557 cutscene_event(cutscene_grand_star_front_of_mario, c, 0, 109); 7558 cutscene_event(cutscene_grand_star_focus_mario, c, 0, -1); 7559 cutscene_event(cutscene_grand_star_mario_jump, c, 110, 110); 7560 cutscene_event(cutscene_grand_star_accel_cvar2, c, 110, 159); 7561 cutscene_event(cutscene_grand_star_approach_mario, c, 160, -1); 7562 cutscene_event(cutscene_grand_star_move_cvar2, c, 110, -1); 7563 } 7564 7565 /** 7566 * Zero the cvars that are used when Mario is flying. 7567 */ 7568 BAD_RETURN(s32) cutscene_grand_star_fly_start(struct Camera *c) { 7569 //! cvar7 is unused in grand star 7570 vec3f_set(sCutsceneVars[7].point, 0.5f, 0.5f, 0.5f); 7571 //! cvar6 is unused in grand star 7572 vec3f_set(sCutsceneVars[6].point, 0.01f, 0.01f, 0.01f); 7573 vec3f_set(sCutsceneVars[4].point, 0.f, 0.f, 0.f); 7574 vec3f_set(sCutsceneVars[5].point, 0.f, c->focus[1] - sMarioCamState->pos[1], 0.f); 7575 sCutsceneVars[8].point[2] = 0.f; 7576 sCutsceneVars[8].point[0] = 0.f; 7577 } 7578 7579 /** 7580 * Decrease the cvar offsets so that Lakitu flies closer to Mario. 7581 */ 7582 BAD_RETURN(s32) cutscene_grand_star_fly_move_to_mario(UNUSED struct Camera *c) { 7583 Vec3f posOff; 7584 7585 vec3f_set(posOff, -600.f, 0.f, -400.f); 7586 approach_vec3f_asymptotic(sCutsceneVars[4].point, posOff, 0.05f, 0.05f, 0.05f); 7587 camera_approach_f32_symmetric_bool(&sCutsceneVars[5].point[1], 0.f, 2.f); 7588 camera_approach_f32_symmetric_bool(&sCutsceneVars[5].point[2], -200.f, 6.f); 7589 } 7590 7591 /** 7592 * Gradually increase the cvar offsets so Lakitu flies away. Mario flies offscreen to the right. 7593 * 7594 * cvar4 is the position offset from Mario. 7595 * cvar5 is the focus offset from Mario. 7596 * cvar8.point[0] is the approach velocity. 7597 */ 7598 BAD_RETURN(s32) cutscene_grand_star_fly_mario_offscreen(UNUSED struct Camera *c) { 7599 camera_approach_f32_symmetric_bool(&sCutsceneVars[8].point[0], 15.f, 0.1f); 7600 7601 camera_approach_f32_symmetric_bool(&sCutsceneVars[4].point[0], -2000.f, sCutsceneVars[8].point[0]); 7602 camera_approach_f32_symmetric_bool(&sCutsceneVars[4].point[1], 1200.f, sCutsceneVars[8].point[0] / 10.f); 7603 camera_approach_f32_symmetric_bool(&sCutsceneVars[4].point[2], 1000.f, sCutsceneVars[8].point[0] / 10.f); 7604 7605 camera_approach_f32_symmetric_bool(&sCutsceneVars[5].point[0], 0.f, sCutsceneVars[8].point[0]); 7606 camera_approach_f32_symmetric_bool(&sCutsceneVars[5].point[1], 1200.f, sCutsceneVars[8].point[0] / 2); 7607 camera_approach_f32_symmetric_bool(&sCutsceneVars[5].point[2], 1000.f, sCutsceneVars[8].point[0] / 1.5f); 7608 } 7609 7610 /** 7611 * Make Lakitu approach the cvars. 7612 * cvar4 is the position offset. 7613 * cvar5 is the focus offset. 7614 */ 7615 BAD_RETURN(s32) cutscene_grand_star_fly_app_cvars(struct Camera *c) { 7616 Vec3f goalPos, goalFoc; 7617 f32 dist; 7618 s16 pitch, yaw; 7619 7620 camera_approach_f32_symmetric_bool(&sCutsceneVars[8].point[2], 90.f, 2.5f); 7621 offset_rotated(goalPos, sMarioCamState->pos, sCutsceneVars[4].point, sMarioCamState->faceAngle); 7622 offset_rotated(goalFoc, sMarioCamState->pos, sCutsceneVars[5].point, sMarioCamState->faceAngle); 7623 7624 // Move towards goalPos by cvar8's Z speed 7625 vec3f_get_dist_and_angle(goalPos, c->pos, &dist, &pitch, &yaw); 7626 camera_approach_f32_symmetric_bool(&dist, 0, sCutsceneVars[8].point[2]); 7627 vec3f_set_dist_and_angle(goalPos, c->pos, dist, pitch, yaw); 7628 7629 approach_vec3f_asymptotic(c->pos, goalPos, 0.01f, 0.01f, 0.01f); 7630 approach_vec3f_asymptotic(c->focus, goalFoc, 0.5f, 0.8f, 0.5f); 7631 } 7632 7633 /** 7634 * Part of the grand star cutscene, starts after Mario is flying. 7635 * 7636 * cvar4 and cvar5 are directions, relative to Mario: 7637 * cvar4 is used as the camera position's offset from Mario. 7638 * cvar5 is used as the camera focus's offset from Mario. 7639 * 7640 * cvar8.point[2] is Lakitu's speed. 7641 */ 7642 BAD_RETURN(s32) cutscene_grand_star_fly(struct Camera *c) { 7643 sStatusFlags |= CAM_FLAG_SMOOTH_MOVEMENT; 7644 cutscene_event(cutscene_grand_star_fly_start, c, 0, 0); 7645 cutscene_event(cutscene_grand_star_fly_move_to_mario, c, 0, 140); 7646 cutscene_event(cutscene_grand_star_fly_mario_offscreen, c, 141, -1); 7647 cutscene_event(cutscene_grand_star_fly_app_cvars, c, 0, -1); 7648 } 7649 7650 /** 7651 * Adjust the camera focus towards a point `dist` units in front of Mario. 7652 * @param dist distance in Mario's forward direction. Note that this is relative to Mario, so a negative 7653 * distance will focus in front of Mario, and a positive distance will focus behind him. 7654 */ 7655 void focus_in_front_of_mario(struct Camera *c, f32 dist, f32 speed) { 7656 Vec3f goalFocus, offset; 7657 7658 offset[0] = 0.f; 7659 offset[2] = dist; 7660 offset[1] = 100.f; 7661 7662 offset_rotated(goalFocus, sMarioCamState->pos, offset, sMarioCamState->faceAngle); 7663 approach_vec3f_asymptotic(c->focus, goalFocus, speed, speed, speed); 7664 } 7665 7666 /** 7667 * Approach Mario and look up. Since Mario faces the camera when he collects the star, there's no need 7668 * to worry about the camera's yaw. 7669 */ 7670 BAD_RETURN(s32) cutscene_dance_move_to_mario(struct Camera *c) { 7671 s16 pitch, yaw; 7672 f32 dist; 7673 7674 vec3f_get_dist_and_angle(sMarioCamState->pos, c->pos, &dist, &pitch, &yaw); 7675 approach_f32_asymptotic_bool(&dist, 600.f, 0.3f); 7676 approach_s16_asymptotic_bool(&pitch, 0x1000, 0x10); 7677 vec3f_set_dist_and_angle(sMarioCamState->pos, c->pos, dist, pitch, yaw); 7678 } 7679 7680 BAD_RETURN(s32) cutscene_dance_rotate(struct Camera *c) { 7681 rotate_and_move_vec3f(c->pos, sMarioCamState->pos, 0, 0, 0x200); 7682 } 7683 7684 BAD_RETURN(s32) cutscene_dance_rotate_move_back(struct Camera *c) { 7685 rotate_and_move_vec3f(c->pos, sMarioCamState->pos, -15.f, 0, 0); 7686 } 7687 7688 BAD_RETURN(s32) cutscene_dance_rotate_move_towards_mario(struct Camera *c) { 7689 rotate_and_move_vec3f(c->pos, sMarioCamState->pos, 20.f, 0, 0); 7690 } 7691 7692 /** 7693 * Speculated to be dance-related due to its proximity to the other dance functions 7694 */ 7695 UNUSED static BAD_RETURN(s32) cutscene_dance_unused(UNUSED struct Camera *c) { 7696 } 7697 7698 /** 7699 * Slowly turn to the point 100 units in front of Mario 7700 */ 7701 BAD_RETURN(s32) cutscene_dance_default_focus_mario(struct Camera *c) { 7702 focus_in_front_of_mario(c, -100.f, 0.2f); 7703 } 7704 7705 /** 7706 * Focus twice as far away as default dance, and move faster. 7707 */ 7708 BAD_RETURN(s32) cutscene_dance_rotate_focus_mario(struct Camera *c) { 7709 focus_in_front_of_mario(c, -200.f, 0.03f); 7710 } 7711 7712 BAD_RETURN(s32) cutscene_dance_shake_fov(UNUSED struct Camera *c) { 7713 set_fov_shake(0x200, 0x28, 0x8000); 7714 } 7715 7716 /** 7717 * Handles both the default and rotate dance cutscenes. 7718 * In the default dance: the camera moves closer to Mario, then stays in place. 7719 * In the rotate dance: the camera moves closer and rotates clockwise around Mario. 7720 */ 7721 BAD_RETURN(s32) cutscene_dance_default_rotate(struct Camera *c) { 7722 sStatusFlags |= CAM_FLAG_SMOOTH_MOVEMENT; 7723 sYawSpeed = 0; 7724 set_fov_function(CAM_FOV_DEFAULT); 7725 cutscene_event(cutscene_dance_default_focus_mario, c, 0, 20); 7726 cutscene_event(cutscene_dance_move_to_mario, c, 0, 39); 7727 // Shake the camera on the 4th beat of the music, when Mario gives the peace sign. 7728 cutscene_event(cutscene_dance_shake_fov, c, 40, 40); 7729 7730 if (c->cutscene != CUTSCENE_DANCE_DEFAULT) { // CUTSCENE_DANCE_ROTATE 7731 cutscene_event(cutscene_dance_rotate_focus_mario, c, 75, 102); 7732 cutscene_event(cutscene_dance_rotate, c, 50, -1); 7733 // These two functions move the camera away and then towards Mario. 7734 cutscene_event(cutscene_dance_rotate_move_back, c, 50, 80); 7735 cutscene_event(cutscene_dance_rotate_move_towards_mario, c, 70, 90); 7736 } else { 7737 // secret star, 100 coin star, or bowser red coin star. 7738 if ((sMarioCamState->action != ACT_STAR_DANCE_NO_EXIT) 7739 && (sMarioCamState->action != ACT_STAR_DANCE_WATER) 7740 && (sMarioCamState->action != ACT_STAR_DANCE_EXIT)) { 7741 gCutsceneTimer = CUTSCENE_STOP; 7742 c->cutscene = 0; 7743 transition_next_state(c, 20); 7744 sStatusFlags |= CAM_FLAG_UNUSED_CUTSCENE_ACTIVE; 7745 } 7746 } 7747 } 7748 7749 /** 7750 * If the camera's yaw is out of the range of `absYaw` +- `yawMax`, then set the yaw to `absYaw` 7751 */ 7752 BAD_RETURN(s32) star_dance_bound_yaw(struct Camera *c, s16 absYaw, s16 yawMax) { 7753 s16 dummyPitch, yaw; 7754 f32 distCamToMario; 7755 s16 yawFromAbs; 7756 7757 vec3f_get_dist_and_angle(sMarioCamState->pos, c->pos, &distCamToMario, &dummyPitch, &yaw); 7758 yawFromAbs = yaw - absYaw; 7759 7760 // Because angles are s16, this checks if yaw is negative 7761 if ((yawFromAbs & 0x8000) != 0) { 7762 yawFromAbs = -yawFromAbs; 7763 } 7764 if (yawFromAbs > yawMax) { 7765 yaw = absYaw; 7766 c->nextYaw = yaw; 7767 c->yaw = yaw; 7768 } 7769 } 7770 7771 /** 7772 * Start the closeup dance cutscene by restricting the camera's yaw in certain areas. 7773 * Store the camera's focus in cvar9. 7774 */ 7775 BAD_RETURN(s32) cutscene_dance_closeup_start(struct Camera *c) { 7776 UNUSED u8 filler[8]; 7777 7778 if ((gLastCompletedStarNum == 4) && (gCurrCourseNum == COURSE_JRB)) { 7779 star_dance_bound_yaw(c, 0x0, 0x4000); 7780 } 7781 if ((gLastCompletedStarNum == 1) && (gCurrCourseNum == COURSE_DDD)) { 7782 star_dance_bound_yaw(c, 0x8000, 0x5000); 7783 } 7784 if ((gLastCompletedStarNum == 5) && (gCurrCourseNum == COURSE_WDW)) { 7785 star_dance_bound_yaw(c, 0x8000, 0x800); 7786 } 7787 7788 vec3f_copy(sCutsceneVars[9].point, c->focus); 7789 //! cvar8 is unused in the closeup cutscene 7790 sCutsceneVars[8].angle[0] = 0x2000; 7791 } 7792 7793 /** 7794 * Focus the camera on Mario eye height. 7795 */ 7796 BAD_RETURN(s32) cutscene_dance_closeup_focus_mario(struct Camera *c) { 7797 Vec3f marioPos; 7798 7799 vec3f_set(marioPos, sMarioCamState->pos[0], sMarioCamState->pos[1] + 125.f, sMarioCamState->pos[2]); 7800 approach_vec3f_asymptotic(sCutsceneVars[9].point, marioPos, 0.2f, 0.2f, 0.2f); 7801 vec3f_copy(c->focus, sCutsceneVars[9].point); 7802 } 7803 7804 /** 7805 * Fly above Mario, looking down. 7806 */ 7807 BAD_RETURN(s32) cutscene_dance_closeup_fly_above(struct Camera *c) { 7808 s16 pitch, yaw; 7809 f32 dist; 7810 s16 goalPitch = 0x1800; 7811 7812 if ((gLastCompletedStarNum == 6 && gCurrCourseNum == COURSE_SL) || 7813 (gLastCompletedStarNum == 4 && gCurrCourseNum == COURSE_TTC)) { 7814 goalPitch = 0x800; 7815 } 7816 7817 vec3f_get_dist_and_angle(sMarioCamState->pos, c->pos, &dist, &pitch, &yaw); 7818 approach_f32_asymptotic_bool(&dist, 800.f, 0.05f); 7819 approach_s16_asymptotic_bool(&pitch, goalPitch, 16); 7820 approach_s16_asymptotic_bool(&yaw, c->yaw, 8); 7821 vec3f_set_dist_and_angle(sMarioCamState->pos, c->pos, dist, pitch, yaw); 7822 } 7823 7824 /** 7825 * Fly closer right when Mario gives the peace sign. 7826 */ 7827 BAD_RETURN(s32) cutscene_dance_closeup_fly_closer(struct Camera *c) { 7828 s16 pitch, yaw; 7829 f32 dist; 7830 7831 vec3f_get_dist_and_angle(sMarioCamState->pos, c->pos, &dist, &pitch, &yaw); 7832 approach_f32_asymptotic_bool(&dist, 240.f, 0.4f); 7833 approach_s16_asymptotic_bool(&yaw, c->yaw, 8); 7834 approach_s16_asymptotic_bool(&pitch, 0x1000, 5); 7835 vec3f_set_dist_and_angle(sMarioCamState->pos, c->pos, dist, pitch, yaw); 7836 } 7837 7838 /** 7839 * Zoom in by increasing fov to 80 degrees. Most dramatic zoom in the game. 7840 */ 7841 BAD_RETURN(s32) cutscene_dance_closeup_zoom(UNUSED struct Camera *c) { 7842 set_fov_function(CAM_FOV_APP_80); 7843 } 7844 7845 /** 7846 * Shake fov, starts on the first frame Mario has the peace sign up. 7847 */ 7848 BAD_RETURN(s32) cutscene_dance_closeup_shake_fov(UNUSED struct Camera *c) { 7849 set_fov_shake(0x300, 0x30, 0x8000); 7850 } 7851 7852 /** 7853 * The camera moves in for a closeup on Mario. Used for stars that are underwater or in tight places. 7854 */ 7855 BAD_RETURN(s32) cutscene_dance_closeup(struct Camera *c) { 7856 sStatusFlags |= CAM_FLAG_SMOOTH_MOVEMENT; 7857 7858 if (sMarioCamState->action == ACT_STAR_DANCE_WATER) { 7859 cutscene_event(cutscene_dance_closeup_start, c, 0, 0); 7860 cutscene_event(cutscene_dance_closeup_focus_mario, c, 0, -1); 7861 cutscene_event(cutscene_dance_closeup_fly_above, c, 0, 62); 7862 cutscene_event(cutscene_dance_closeup_fly_closer, c, 63, -1); 7863 cutscene_event(cutscene_dance_closeup_zoom, c, 63, 63); 7864 cutscene_event(cutscene_dance_closeup_shake_fov, c, 70, 70); 7865 } else { 7866 cutscene_event(cutscene_dance_closeup_start, c, 0, 0); 7867 cutscene_event(cutscene_dance_closeup_focus_mario, c, 0, -1); 7868 // Almost twice as fast as under water 7869 cutscene_event(cutscene_dance_closeup_fly_above, c, 0, 32); 7870 cutscene_event(cutscene_dance_closeup_fly_closer, c, 33, -1); 7871 cutscene_event(cutscene_dance_closeup_zoom, c, 33, 33); 7872 cutscene_event(cutscene_dance_closeup_shake_fov, c, 40, 40); 7873 } 7874 set_handheld_shake(HAND_CAM_SHAKE_CUTSCENE); 7875 } 7876 7877 /** 7878 * cvar8.point[2] is the amount to increase distance from Mario 7879 */ 7880 BAD_RETURN(s32) cutscene_dance_fly_away_start(struct Camera *c) { 7881 Vec3f areaCenter; 7882 7883 vec3f_copy(sCutsceneVars[9].point, c->focus); 7884 sCutsceneVars[8].point[2] = 65.f; 7885 7886 if (c->mode == CAMERA_MODE_RADIAL) { 7887 vec3f_set(areaCenter, c->areaCenX, c->areaCenY, c->areaCenZ); 7888 c->yaw = calculate_yaw(areaCenter, c->pos); 7889 c->nextYaw = c->yaw; 7890 } 7891 7892 // Restrict the camera yaw in tight spaces 7893 if ((gLastCompletedStarNum == 6) && (gCurrCourseNum == COURSE_CCM)) { 7894 star_dance_bound_yaw(c, 0x5600, 0x800); 7895 } 7896 if ((gLastCompletedStarNum == 2) && (gCurrCourseNum == COURSE_TTM)) { 7897 star_dance_bound_yaw(c, 0x0, 0x800); 7898 } 7899 if ((gLastCompletedStarNum == 1) && (gCurrCourseNum == COURSE_SL)) { 7900 star_dance_bound_yaw(c, 0x2000, 0x800); 7901 } 7902 if ((gLastCompletedStarNum == 3) && (gCurrCourseNum == COURSE_RR)) { 7903 star_dance_bound_yaw(c, 0x0, 0x800); 7904 } 7905 } 7906 7907 BAD_RETURN(s32) cutscene_dance_fly_away_approach_mario(struct Camera *c) { 7908 s16 pitch, yaw; 7909 f32 dist; 7910 7911 vec3f_get_dist_and_angle(sMarioCamState->pos, c->pos, &dist, &pitch, &yaw); 7912 approach_f32_asymptotic_bool(&dist, 600.f, 0.3f); 7913 approach_s16_asymptotic_bool(&pitch, 0x1000, 16); 7914 approach_s16_asymptotic_bool(&yaw, c->yaw, 8); 7915 vec3f_set_dist_and_angle(sMarioCamState->pos, c->pos, dist, pitch, yaw); 7916 } 7917 7918 BAD_RETURN(s32) cutscene_dance_fly_away_focus_mario(struct Camera *c) { 7919 Vec3f marioPos; 7920 7921 vec3f_set(marioPos, sMarioCamState->pos[0], sMarioCamState->pos[1] + 125.f, sMarioCamState->pos[2]); 7922 approach_vec3f_asymptotic(sCutsceneVars[9].point, marioPos, 0.2f, 0.2f, 0.2f); 7923 vec3f_copy(c->focus, sCutsceneVars[9].point); 7924 } 7925 7926 /** 7927 * Slowly pan the camera downwards and to the camera's right, using cvar9's angle. 7928 */ 7929 void cutscene_pan_cvar9(struct Camera *c) { 7930 vec3f_copy(c->focus, sCutsceneVars[9].point); 7931 sCutsceneVars[9].angle[0] -= 29; 7932 sCutsceneVars[9].angle[1] += 29; 7933 pan_camera(c, sCutsceneVars[9].angle[0], sCutsceneVars[9].angle[1]); 7934 } 7935 7936 /** 7937 * Move backwards and rotate slowly around Mario. 7938 */ 7939 BAD_RETURN(s32) cutscene_dance_fly_rotate_around_mario(struct Camera *c) { 7940 cutscene_pan_cvar9(c); 7941 rotate_and_move_vec3f(c->pos, sMarioCamState->pos, sCutsceneVars[8].point[2], 0, 0); 7942 } 7943 7944 /** 7945 * Rotate quickly while Lakitu flies up. 7946 */ 7947 BAD_RETURN(s32) cutscene_dance_fly_away_rotate_while_flying(struct Camera *c) { 7948 rotate_and_move_vec3f(c->pos, sMarioCamState->pos, 0, 0, 0x80); 7949 } 7950 7951 BAD_RETURN(s32) cutscene_dance_fly_away_shake_fov(UNUSED struct Camera *c) { 7952 set_fov_shake(0x400, 0x30, 0x8000); 7953 } 7954 7955 /** 7956 * After collecting the star, Lakitu flies upwards out of the course. 7957 */ 7958 BAD_RETURN(s32) cutscene_dance_fly_away(struct Camera *c) { 7959 sStatusFlags |= CAM_FLAG_SMOOTH_MOVEMENT; 7960 cutscene_event(cutscene_dance_fly_away_start, c, 0, 0); 7961 cutscene_event(cutscene_dance_fly_away_focus_mario, c, 0, 30); 7962 cutscene_event(cutscene_dance_fly_away_approach_mario, c, 0, 30); 7963 cutscene_event(cutscene_dance_fly_rotate_around_mario, c, 55, 124); 7964 cutscene_event(cutscene_dance_fly_away_rotate_while_flying, c, 55, 124); 7965 cutscene_event(cutscene_dance_fly_away_shake_fov, c, 40, 40); 7966 set_fov_function(CAM_FOV_DEFAULT); 7967 set_handheld_shake(HAND_CAM_SHAKE_STAR_DANCE); 7968 } 7969 7970 /** 7971 * Jump the camera pos and focus to cvar 8 and 7. 7972 * Called every frame, starting after 10, so when these cvars are updated, the camera will jump. 7973 */ 7974 BAD_RETURN(s32) cutscene_key_dance_jump_cvar(struct Camera *c) { 7975 offset_rotated(c->pos, sMarioCamState->pos, sCutsceneVars[8].point, sMarioCamState->faceAngle); 7976 offset_rotated(c->focus, sMarioCamState->pos, sCutsceneVars[7].point, sMarioCamState->faceAngle); 7977 } 7978 7979 /** 7980 * Jump to a closeup view of Mario and the key. 7981 */ 7982 BAD_RETURN(s32) cutscene_key_dance_jump_closeup(UNUSED struct Camera *c) { 7983 vec3f_set(sCutsceneVars[8].point, 38.f, 171.f, -248.f); 7984 vec3f_set(sCutsceneVars[7].point, -57.f, 51.f, 187.f); 7985 } 7986 7987 /** 7988 * Jump to a view from the lower left (Mario's right). 7989 */ 7990 BAD_RETURN(s32) cutscene_key_dance_jump_lower_left(UNUSED struct Camera *c) { 7991 vec3f_set(sCutsceneVars[8].point, -178.f, 62.f, -132.f); 7992 vec3f_set(sCutsceneVars[7].point, 299.f, 91.f, 58.f); 7993 } 7994 7995 /** 7996 * Jump to a rotated view from above. 7997 */ 7998 BAD_RETURN(s32) cutscene_key_dance_jump_above(UNUSED struct Camera *c) { 7999 gLakituState.keyDanceRoll = 0x2800; 8000 vec3f_set(sCutsceneVars[8].point, 89.f, 373.f, -304.f); 8001 vec3f_set(sCutsceneVars[7].point, 0.f, 127.f, 0.f); 8002 } 8003 8004 /** 8005 * Finally, jump to a further view, slightly to Mario's left. 8006 */ 8007 BAD_RETURN(s32) cutscene_key_dance_jump_last(UNUSED struct Camera *c) { 8008 gLakituState.keyDanceRoll = 0; 8009 vec3f_set(sCutsceneVars[8].point, 135.f, 158.f, -673.f); 8010 vec3f_set(sCutsceneVars[7].point, -20.f, 135.f, -198.f); 8011 } 8012 8013 BAD_RETURN(s32) cutscene_key_dance_shake_fov(UNUSED struct Camera *c) { 8014 set_fov_shake(0x180, 0x30, 0x8000); 8015 } 8016 8017 BAD_RETURN(s32) cutscene_key_dance_handheld_shake(UNUSED struct Camera *c) { 8018 set_handheld_shake(HAND_CAM_SHAKE_CUTSCENE); 8019 } 8020 8021 BAD_RETURN(s32) cutscene_key_dance_focus_mario(struct Camera *c) { 8022 focus_in_front_of_mario(c, 0, 0.2f); 8023 } 8024 8025 /** 8026 * Cutscene that plays when Mario collects a key from bowser. It's basically a sequence of four jump 8027 * cuts. 8028 */ 8029 BAD_RETURN(s32) cutscene_key_dance(struct Camera *c) { 8030 cutscene_event(cutscene_dance_move_to_mario, c, 0, 10); 8031 cutscene_event(cutscene_key_dance_focus_mario, c, 0, 10); 8032 cutscene_event(cutscene_key_dance_jump_closeup, c, 0, 0); 8033 cutscene_event(cutscene_key_dance_jump_lower_left, c, 20, 20); 8034 cutscene_event(cutscene_key_dance_jump_above, c, 35, 35); 8035 cutscene_event(cutscene_key_dance_jump_last, c, 52, 52); 8036 cutscene_event(cutscene_key_dance_jump_cvar, c, 11, -1); 8037 cutscene_event(cutscene_key_dance_shake_fov, c, 54, 54); 8038 cutscene_event(cutscene_key_dance_handheld_shake, c, 52, -1); 8039 } 8040 8041 BAD_RETURN(s32) cutscene_bowser_area_shake_fov(UNUSED struct Camera *c) { 8042 cutscene_set_fov_shake_preset(2); 8043 } 8044 8045 /** 8046 * Set oBowserCamAct to 1, which causes bowser to start walking. 8047 */ 8048 BAD_RETURN(s32) cutscene_bowser_area_start_bowser_walking(UNUSED struct Camera *c) { 8049 gSecondCameraFocus->oBowserCamAct = BOWSER_CAM_ACT_WALK; 8050 } 8051 8052 /** 8053 * Offset the camera from bowser using cvar2 and cvar3 8054 * @bug cvar2.point is (0,0,0) on the first frame, but because of the warp transition, this behavior 8055 * isn't seen. After the first frame, cvar2.point is bowser's position. 8056 */ 8057 BAD_RETURN(s32) cutscene_bowser_arena_set_pos(struct Camera *c) { 8058 vec3f_set_dist_and_angle(sCutsceneVars[2].point, c->pos, sCutsceneVars[3].point[2], 8059 sCutsceneVars[3].angle[0], sCutsceneVars[3].angle[1]); 8060 vec3f_set(sCutsceneVars[2].point, gSecondCameraFocus->oPosX, gSecondCameraFocus->oPosY, 8061 gSecondCameraFocus->oPosZ); 8062 } 8063 8064 /** 8065 * Apply a sine wave to the focus's y coordinate. 8066 * The y offset starts at 120, then decreases to 0 before reaching ~240 on the last frame. 8067 */ 8068 BAD_RETURN(s32) cutscene_bowser_arena_focus_sine(UNUSED struct Camera *c) { 8069 //! unused initialization 8070 f32 yOff = 150.0f; 8071 8072 // cvar4 was zeroed when the cutscene started. 8073 yOff = sins(sCutsceneVars[4].angle[1]) * 120.0f + 120.0f; 8074 sCutsceneVars[4].angle[1] -= 0x200; 8075 approach_f32_asymptotic_bool(&sCutsceneVars[0].point[1], yOff, 0.5f); 8076 } 8077 8078 /** 8079 * Set the camera focus according to cvar0 and cvar2. 8080 */ 8081 BAD_RETURN(s32) cutscene_bowser_arena_set_focus(struct Camera *c) { 8082 offset_rotated(c->focus, sCutsceneVars[2].point, sCutsceneVars[0].point, sCutsceneVars[2].angle); 8083 } 8084 8085 /** 8086 * Adjust the cvar offsets, making the camera look up, move slightly further back, and focus a little 8087 * further in front of bowser. 8088 */ 8089 BAD_RETURN(s32) cutscene_bowser_arena_adjust_offsets(UNUSED struct Camera *c) { 8090 approach_s16_asymptotic_bool(&sCutsceneVars[3].angle[0], 0x6C8, 30); 8091 approach_f32_asymptotic_bool(&sCutsceneVars[0].point[2], -200.f, 0.02f); 8092 approach_f32_asymptotic_bool(&sCutsceneVars[3].point[2], 550.f, 0.02f); 8093 } 8094 8095 /** 8096 * Decrease cvar0's z offset, making the camera focus pan left towards bowser. 8097 */ 8098 BAD_RETURN(s32) cutscene_bowser_arena_pan_left(UNUSED struct Camera *c) { 8099 approach_f32_asymptotic_bool(&sCutsceneVars[0].point[2], 0.f, 0.05f); 8100 } 8101 8102 /** 8103 * Duplicate of cutscene_mario_dialog(). 8104 */ 8105 BAD_RETURN(s32) cutscene_bowser_arena_mario_dialog(UNUSED struct Camera *c) { 8106 cutscene_common_set_dialog_state(MARIO_DIALOG_LOOK_FRONT); 8107 } 8108 8109 void cutscene_stop_dialog(UNUSED struct Camera *c) { 8110 cutscene_common_set_dialog_state(MARIO_DIALOG_STOP); 8111 } 8112 8113 /** 8114 * Active for the first 5 frames of the cutscene. 8115 * cvar3 is the camera's polar offset from bowser 8116 * cvar2.angle is bowser's move angle 8117 * 8118 * cvar0 is the focus offset from bowser 8119 */ 8120 BAD_RETURN(s32) cutscene_bowser_arena_start(struct Camera *c) { 8121 sCutsceneVars[3].point[2] = 430.f; 8122 sCutsceneVars[3].angle[1] = gSecondCameraFocus->oMoveAngleYaw - DEGREES(45); 8123 sCutsceneVars[3].angle[0] = 0xD90; 8124 8125 //! Tricky math: Bowser starts at (0, 307, -1000), with a moveAngle of (0,0,0). A sane person would 8126 //! expect this offset to move the focus to (0, 427, -1800). 8127 //! BUT because offset_rotated() flips the Z direction (to match sm64's coordinate system), this 8128 //! offset actually moves the focus to (0, 427, -200) 8129 vec3f_set(sCutsceneVars[0].point, 0.f, 120.f, -800.f); 8130 vec3s_set(sCutsceneVars[2].angle, gSecondCameraFocus->oMoveAnglePitch, 8131 gSecondCameraFocus->oMoveAngleYaw, gSecondCameraFocus->oMoveAngleRoll); 8132 8133 // Set the camera's position and focus. 8134 cutscene_bowser_arena_set_pos(c); 8135 cutscene_bowser_arena_set_focus(c); 8136 } 8137 8138 /** 8139 * Create the dialog box depending on which bowser fight Mario is in. 8140 */ 8141 BAD_RETURN(s32) bowser_fight_intro_dialog(UNUSED struct Camera *c) { 8142 s16 dialog; 8143 8144 switch (gCurrLevelNum) { 8145 case LEVEL_BOWSER_1: 8146 dialog = DIALOG_067; 8147 break; 8148 case LEVEL_BOWSER_2: 8149 dialog = DIALOG_092; 8150 break; 8151 default: // LEVEL_BOWSER_3 8152 dialog = DIALOG_093; 8153 } 8154 8155 create_dialog_box(dialog); 8156 } 8157 8158 /** 8159 * Create the dialog box and wait until it's gone. 8160 */ 8161 BAD_RETURN(s32) cutscene_bowser_arena_dialog(struct Camera *c) { 8162 cutscene_event(bowser_fight_intro_dialog, c, 0, 0); 8163 8164 if (get_dialog_id() == DIALOG_NONE) { 8165 gCutsceneTimer = CUTSCENE_LOOP; 8166 } 8167 } 8168 8169 /** 8170 * End the bowser arena cutscene. 8171 */ 8172 BAD_RETURN(s32) cutscene_bowser_arena_end(struct Camera *c) { 8173 cutscene_stop_dialog(c); 8174 c->cutscene = 0; 8175 transition_next_state(c, 20); 8176 sStatusFlags |= CAM_FLAG_UNUSED_CUTSCENE_ACTIVE; 8177 sModeOffsetYaw = sMarioCamState->faceAngle[1] + DEGREES(90); 8178 gSecondCameraFocus->oBowserCamAct = BOWSER_CAM_ACT_END; 8179 } 8180 8181 /** 8182 * Cutscene that plays when Mario enters a bowser fight. 8183 */ 8184 BAD_RETURN(s32) cutscene_bowser_arena(struct Camera *c) { 8185 //! This does nothing, but may have been used in development 8186 cutscene_spawn_obj(2, 0); 8187 8188 if (gSecondCameraFocus != NULL) { 8189 cutscene_event(cutscene_bowser_arena_mario_dialog, c, 0, -1); 8190 cutscene_event(cutscene_bowser_arena_start, c, 0, 5); 8191 cutscene_event(cutscene_bowser_area_start_bowser_walking, c, 40, 40); 8192 cutscene_event(cutscene_bowser_area_shake_fov, c, 145, 145); 8193 cutscene_event(cutscene_bowser_arena_set_pos, c, 40, -1); 8194 cutscene_event(cutscene_bowser_arena_pan_left, c, 40, 99); 8195 cutscene_event(cutscene_bowser_arena_adjust_offsets, c, 100, -1); 8196 cutscene_event(cutscene_bowser_arena_focus_sine, c, 40, 140); 8197 cutscene_event(cutscene_bowser_arena_set_focus, c, 40, -1); 8198 cutscene_event(cutscene_shake_explosion, c, 60, 60); 8199 cutscene_event(cutscene_shake_explosion, c, 82, 82); 8200 cutscene_event(cutscene_shake_explosion, c, 109, 109); 8201 cutscene_event(cutscene_shake_explosion, c, 127, 127); 8202 } 8203 } 8204 8205 BAD_RETURN(s32) cutscene_star_spawn_store_info(struct Camera *c) { 8206 store_info_star(c); 8207 } 8208 8209 /** 8210 * Focus on the top of the star. 8211 */ 8212 BAD_RETURN(s32) cutscene_star_spawn_focus_star(struct Camera *c) { 8213 UNUSED u8 filler1[4]; // hMul? 8214 Vec3f starPos; 8215 UNUSED u8 filler2[4]; // vMul? 8216 8217 if (gCutsceneFocus != NULL) { 8218 object_pos_to_vec3f(starPos, gCutsceneFocus); 8219 starPos[1] += gCutsceneFocus->hitboxHeight; 8220 approach_vec3f_asymptotic(c->focus, starPos, 0.1f, 0.1f, 0.1f); 8221 } 8222 } 8223 8224 /** 8225 * Use boss fight mode's update function to move the focus back. 8226 */ 8227 BAD_RETURN(s32) cutscene_star_spawn_update_boss_fight(struct Camera *c) { 8228 Vec3f pos, focus; 8229 8230 update_boss_fight_camera(c, focus, pos); 8231 approach_vec3f_asymptotic(c->focus, focus, 0.2f, 0.2f, 0.2f); 8232 approach_vec3f_asymptotic(c->pos, pos, 0.2f, 0.2f, 0.2f); 8233 } 8234 8235 /** 8236 * Fly back to the camera's previous pos and focus. 8237 */ 8238 BAD_RETURN(s32) cutscene_star_spawn_fly_back(struct Camera *c) { 8239 retrieve_info_star(c); 8240 transition_next_state(c, 15); 8241 } 8242 8243 /** 8244 * Plays when a star spawns (ie from a box). 8245 */ 8246 BAD_RETURN(s32) cutscene_star_spawn(struct Camera *c) { 8247 cutscene_event(cutscene_star_spawn_store_info, c, 0, 0); 8248 cutscene_event(cutscene_star_spawn_focus_star, c, 0, -1); 8249 sStatusFlags |= CAM_FLAG_SMOOTH_MOVEMENT; 8250 8251 if (gObjCutsceneDone) { 8252 // Set the timer to CUTSCENE_LOOP, which start the next shot. 8253 gCutsceneTimer = CUTSCENE_LOOP; 8254 } 8255 } 8256 8257 /** 8258 * Move the camera back to Mario. 8259 */ 8260 BAD_RETURN(s32) cutscene_star_spawn_back(struct Camera *c) { 8261 if ((c->mode == CAMERA_MODE_BOSS_FIGHT) && (set_cam_angle(0) == CAM_ANGLE_LAKITU)) { 8262 cutscene_event(cutscene_star_spawn_update_boss_fight, c, 0, -1); 8263 } else { 8264 cutscene_event(cutscene_star_spawn_fly_back, c, 0, 0); 8265 } 8266 8267 sStatusFlags |= CAM_FLAG_SMOOTH_MOVEMENT; 8268 sStatusFlags |= CAM_FLAG_UNUSED_CUTSCENE_ACTIVE; 8269 } 8270 8271 BAD_RETURN(s32) cutscene_star_spawn_end(struct Camera *c) { 8272 sStatusFlags |= CAM_FLAG_SMOOTH_MOVEMENT; 8273 gCutsceneTimer = CUTSCENE_STOP; 8274 c->cutscene = 0; 8275 } 8276 8277 BAD_RETURN(s32) cutscene_exit_waterfall_warp(struct Camera *c) { 8278 //! hardcoded position 8279 vec3f_set(c->pos, -3899.f, 39.f, -5671.f); 8280 } 8281 8282 /** 8283 * Look at Mario, used by cutscenes that play when Mario exits a course to castle grounds. 8284 */ 8285 BAD_RETURN(s32) cutscene_exit_to_castle_grounds_focus_mario(struct Camera *c) { 8286 vec3f_copy(c->focus, sMarioCamState->pos); 8287 c->focus[1] = c->pos[1] + (sMarioCamState->pos[1] + 125.f - c->pos[1]) * 0.5f; 8288 approach_vec3f_asymptotic(c->focus, sMarioCamState->pos, 0.05f, 0.4f, 0.05f); 8289 } 8290 8291 /** 8292 * Cutscene that plays when Mario leaves CotMC through the waterfall. 8293 */ 8294 BAD_RETURN(s32) cutscene_exit_waterfall(struct Camera *c) { 8295 cutscene_event(cutscene_exit_waterfall_warp, c, 0, 0); 8296 cutscene_event(cutscene_exit_to_castle_grounds_focus_mario, c, 0, -1); 8297 update_camera_yaw(c); 8298 } 8299 8300 /** 8301 * End the cutscene, used by cutscenes that play when Mario exits a course to castle grounds. 8302 */ 8303 BAD_RETURN(s32) cutscene_exit_to_castle_grounds_end(struct Camera *c) { 8304 sStatusFlags |= CAM_FLAG_SMOOTH_MOVEMENT; 8305 gCutsceneTimer = CUTSCENE_STOP; 8306 c->cutscene = 0; 8307 update_camera_yaw(c); 8308 } 8309 8310 BAD_RETURN(s32) cutscene_exit_fall_to_castle_grounds_warp(struct Camera *c) { 8311 //! hardcoded position 8312 vec3f_set(c->pos, 5830.f, 32.f, 3985.f); 8313 } 8314 8315 /** 8316 * Cutscene that plays when Mario falls from WMotR. 8317 */ 8318 BAD_RETURN(s32) cutscene_exit_fall_to_castle_grounds(struct Camera *c) { 8319 cutscene_event(cutscene_exit_fall_to_castle_grounds_warp, c, 0, 0); 8320 cutscene_event(cutscene_exit_to_castle_grounds_focus_mario, c, 0, -1); 8321 update_camera_yaw(c); 8322 } 8323 8324 /** 8325 * Start the red coin star spawning cutscene. 8326 */ 8327 BAD_RETURN(s32) cutscene_red_coin_star_start(struct Camera *c) { 8328 object_pos_to_vec3f(sCutsceneVars[1].point, gCutsceneFocus); 8329 store_info_star(c); 8330 // Store the default fov for after the cutscene 8331 sCutsceneVars[2].point[2] = sFOVState.fov; 8332 } 8333 8334 /** 8335 * Look towards the star's x and z position 8336 */ 8337 BAD_RETURN(s32) cutscene_red_coin_star_focus_xz(struct Camera *c) { 8338 approach_f32_asymptotic_bool(&c->focus[0], gCutsceneFocus->oPosX, 0.15f); 8339 approach_f32_asymptotic_bool(&c->focus[2], gCutsceneFocus->oPosZ, 0.15f); 8340 } 8341 8342 /** 8343 * Look towards the star's y position. Only active before the camera warp. 8344 */ 8345 BAD_RETURN(s32) cutscene_red_coin_star_focus_y(struct Camera *c) { 8346 approach_f32_asymptotic_bool(&c->focus[1], gCutsceneFocus->oPosY, 0.1f); 8347 } 8348 8349 /** 8350 * Look 80% up towards the star. Only active after the camera warp. 8351 */ 8352 BAD_RETURN(s32) cutscene_red_coin_star_look_up_at_star(struct Camera *c) { 8353 c->focus[1] = sCutsceneVars[1].point[1] + (gCutsceneFocus->oPosY - sCutsceneVars[1].point[1]) * 0.8f; 8354 } 8355 8356 /** 8357 * Warp the camera near the star's spawn point 8358 */ 8359 BAD_RETURN(s32) cutscene_red_coin_star_warp(struct Camera *c) { 8360 f32 dist; 8361 s16 pitch, yaw, posYaw; 8362 struct Object *o = gCutsceneFocus; 8363 8364 vec3f_set(sCutsceneVars[1].point, o->oHomeX, o->oHomeY, o->oHomeZ); 8365 vec3f_get_dist_and_angle(sCutsceneVars[1].point, c->pos, &dist, &pitch, &yaw); 8366 posYaw = calculate_yaw(sCutsceneVars[1].point, c->pos); 8367 yaw = calculate_yaw(sCutsceneVars[1].point, sMarioCamState->pos); 8368 8369 if (ABS(yaw - posYaw + DEGREES(90)) < ABS(yaw - posYaw - DEGREES(90))) { 8370 yaw += DEGREES(90); 8371 } else { 8372 yaw -= DEGREES(90); 8373 } 8374 8375 vec3f_set_dist_and_angle(sCutsceneVars[1].point, c->pos, 400.f, 0x1000, yaw); 8376 sStatusFlags &= ~CAM_FLAG_SMOOTH_MOVEMENT; 8377 } 8378 8379 /** 8380 * Zoom out while looking at the star. 8381 */ 8382 BAD_RETURN(s32) cutscene_red_coin_star_set_fov(UNUSED struct Camera *c) { 8383 sFOVState.fov = 60.f; 8384 } 8385 8386 BAD_RETURN(s32) cutscene_red_coin_star(struct Camera *c) { 8387 sStatusFlags |= CAM_FLAG_SMOOTH_MOVEMENT; 8388 cutscene_event(cutscene_red_coin_star_start, c, 0, 0); 8389 cutscene_event(cutscene_red_coin_star_warp, c, 30, 30); 8390 cutscene_event(cutscene_red_coin_star_focus_xz, c, 0, -1); 8391 cutscene_event(cutscene_red_coin_star_focus_y, c, 0, 29); 8392 cutscene_event(cutscene_red_coin_star_look_up_at_star, c, 30, -1); 8393 cutscene_event(cutscene_red_coin_star_set_fov, c, 30, -1); 8394 8395 if (gObjCutsceneDone) { 8396 // Set the timer to CUTSCENE_LOOP, which start the next shot. 8397 gCutsceneTimer = CUTSCENE_LOOP; 8398 } 8399 } 8400 8401 /** 8402 * End the red coin star spawning cutscene 8403 */ 8404 BAD_RETURN(s32) cutscene_red_coin_star_end(struct Camera *c) { 8405 retrieve_info_star(c); 8406 gCutsceneTimer = CUTSCENE_STOP; 8407 c->cutscene = 0; 8408 // Restore the default fov 8409 sFOVState.fov = sCutsceneVars[2].point[2]; 8410 } 8411 8412 /** 8413 * Moves the camera towards the cutscene's focus, stored in sCutsceneVars[3].point 8414 * 8415 * sCutsceneVars[3].point is used as the target point 8416 * sCutsceneVars[0].point is used as the current camera focus during the transition 8417 * 8418 * @param rotPitch constant pitch offset to add to the camera's focus 8419 * @param rotYaw constant yaw offset to add to the camera's focus 8420 */ 8421 void cutscene_goto_cvar_pos(struct Camera *c, f32 goalDist, s16 goalPitch, s16 rotPitch, s16 rotYaw) { 8422 UNUSED u8 filler[4]; 8423 f32 nextDist; 8424 s16 nextPitch, nextYaw; 8425 // The next 2 polar coord points are only used in CUTSCENE_PREPARE_CANNON 8426 f32 cannonDist; 8427 s16 cannonPitch, cannonYaw; 8428 f32 curDist; 8429 s16 curPitch, curYaw; 8430 UNUSED f64 unused; 8431 8432 vec3f_get_dist_and_angle(sCutsceneVars[3].point, c->pos, &nextDist, &nextPitch, &nextYaw); 8433 8434 // If over 8000 units away from the cannon, just teleport there 8435 if ((nextDist > 8000.f) && (c->cutscene == CUTSCENE_PREPARE_CANNON)) { 8436 nextDist = goalDist * 4.f; 8437 nextPitch = goalPitch; 8438 vec3f_copy(sCutsceneVars[0].point, sCutsceneVars[3].point); 8439 sStatusFlags &= ~CAM_FLAG_SMOOTH_MOVEMENT; 8440 8441 if (gCurrLevelNum == LEVEL_TTM) { 8442 nextYaw = atan2s(sCutsceneVars[3].point[2] - c->areaCenZ, 8443 sCutsceneVars[3].point[0] - c->areaCenX); 8444 } 8445 } else { 8446 if (c->cutscene == CUTSCENE_PREPARE_CANNON) { 8447 vec3f_get_dist_and_angle(c->pos, sCutsceneVars[0].point, &curDist, &curPitch, &curYaw); 8448 vec3f_get_dist_and_angle(c->pos, sCutsceneVars[3].point, &cannonDist, &cannonPitch, &cannonYaw); 8449 approach_f32_asymptotic_bool(&curDist, cannonDist, 0.1f); 8450 approach_s16_asymptotic_bool(&curPitch, cannonPitch, 15); 8451 approach_s16_asymptotic_bool(&curYaw, cannonYaw, 15); 8452 // Move the current focus, sCutsceneVars[0].point, in the direction towards the cannon 8453 vec3f_set_dist_and_angle(c->pos, sCutsceneVars[0].point, curDist, curPitch, curYaw); 8454 } else { 8455 approach_vec3f_asymptotic(sCutsceneVars[0].point, sCutsceneVars[3].point, 0.1f, 0.1f, 0.1f); 8456 } 8457 } 8458 8459 approach_f32_asymptotic_bool(&nextDist, goalDist, 0.05f); 8460 approach_s16_asymptotic_bool(&nextPitch, goalPitch, 0x20); 8461 8462 vec3f_set_dist_and_angle(sCutsceneVars[3].point, c->pos, nextDist, nextPitch, nextYaw); 8463 vec3f_copy(c->focus, sCutsceneVars[0].point); 8464 8465 // Apply the constant rotation given 8466 pan_camera(c, rotPitch, rotYaw); 8467 vec3f_get_dist_and_angle(c->pos, c->focus, &nextDist, &nextPitch, &nextYaw); 8468 8469 if (nextPitch < -0x3000) { 8470 nextPitch = -0x3000; 8471 } 8472 if (nextPitch > 0x3000) { 8473 nextPitch = 0x3000; 8474 } 8475 8476 vec3f_set_dist_and_angle(c->pos, c->focus, nextDist, nextPitch, nextYaw); 8477 } 8478 8479 /** 8480 * Store the camera's pos and focus, and copy the cannon's position to cvars. 8481 */ 8482 BAD_RETURN(s32) cutscene_prepare_cannon_start(struct Camera *c) { 8483 store_info_cannon(c); 8484 vec3f_copy(sCutsceneVars[0].point, c->focus); 8485 sCutsceneVars[2].point[0] = 30.f; 8486 // Store the cannon door's position in sCutsceneVars[3]'s point 8487 object_pos_to_vec3f(sCutsceneVars[3].point, gCutsceneFocus); 8488 vec3s_set(sCutsceneVars[5].angle, 0, 0, 0); 8489 } 8490 8491 /** 8492 * Fly towards the cannon door. 8493 */ 8494 BAD_RETURN(s32) cutscene_prepare_cannon_fly_to_cannon(struct Camera *c) { 8495 cutscene_goto_cvar_pos(c, 300.f, 0x2000, 0, sCutsceneVars[5].angle[1]); 8496 camera_approach_s16_symmetric_bool(&sCutsceneVars[5].angle[1], 0x400, 17); 8497 set_handheld_shake(HAND_CAM_SHAKE_CUTSCENE); 8498 } 8499 8500 /** 8501 * Used in the cannon opening cutscene to fly back to the camera's last position and focus 8502 */ 8503 void cannon_approach_prev(f32 *value, f32 target) { 8504 f32 inc = ABS(target - *value) / sCutsceneVars[2].point[0]; 8505 camera_approach_f32_symmetric_bool(value, target, inc); 8506 } 8507 8508 /** 8509 * Fly or warp back to the previous pos and focus, stored in sCameraStoreCutscene. 8510 */ 8511 BAD_RETURN(s32) cutscene_prepare_cannon_fly_back(struct Camera *c) { 8512 f32 distToPrevPos = calc_abs_dist(c->pos, sCameraStoreCutscene.pos); 8513 8514 if (distToPrevPos < 8000.f) { 8515 cannon_approach_prev(&c->pos[0], sCameraStoreCutscene.pos[0]); 8516 cannon_approach_prev(&c->pos[1], sCameraStoreCutscene.pos[1]); 8517 cannon_approach_prev(&c->pos[2], sCameraStoreCutscene.pos[2]); 8518 cannon_approach_prev(&c->focus[0], sCameraStoreCutscene.focus[0]); 8519 cannon_approach_prev(&c->focus[1], sCameraStoreCutscene.focus[1]); 8520 cannon_approach_prev(&c->focus[2], sCameraStoreCutscene.focus[2]); 8521 } else { 8522 // If too far away, just warp back 8523 vec3f_copy(c->focus, sCameraStoreCutscene.focus); 8524 vec3f_copy(c->pos, sCameraStoreCutscene.pos); 8525 sStatusFlags &= ~CAM_FLAG_SMOOTH_MOVEMENT; 8526 } 8527 if (sCutsceneVars[2].point[0] > 1.f) { 8528 sCutsceneVars[2].point[0] -= 1.f; 8529 } 8530 } 8531 8532 /** 8533 * Cutscene that plays when the cannon is opened. 8534 */ 8535 BAD_RETURN(s32) cutscene_prepare_cannon(struct Camera *c) { 8536 sStatusFlags |= CAM_FLAG_SMOOTH_MOVEMENT; 8537 cutscene_event(cutscene_prepare_cannon_start, c, 0, 0); 8538 cutscene_event(cutscene_prepare_cannon_fly_to_cannon, c, 0, 140); 8539 cutscene_event(cutscene_prepare_cannon_fly_back, c, 141, -1); 8540 } 8541 8542 /** 8543 * Stop the cannon opening cutscene. 8544 */ 8545 BAD_RETURN(s32) cutscene_prepare_cannon_end(struct Camera *c) { 8546 gCutsceneTimer = CUTSCENE_STOP; 8547 c->cutscene = 0; 8548 retrieve_info_cannon(c); 8549 sStatusFlags |= CAM_FLAG_SMOOTH_MOVEMENT; 8550 } 8551 8552 /** 8553 * Moves the camera to Mario's side when Mario starts ACT_WATER_DEATH 8554 * Note that ACT_WATER_DEATH only starts when Mario gets hit by an enemy under water. It does not start 8555 * when Mario drowns. 8556 */ 8557 void water_death_move_to_mario_side(struct Camera *c) { 8558 f32 dist; 8559 s16 pitch, yaw; 8560 8561 vec3f_get_dist_and_angle(sMarioCamState->pos, c->pos, &dist, &pitch, &yaw); 8562 approach_s16_asymptotic_bool(&yaw, (sMarioCamState->faceAngle[1] - 0x3000), 8); 8563 vec3f_set_dist_and_angle(sMarioCamState->pos, c->pos, dist, pitch, yaw); 8564 } 8565 8566 /** 8567 * Unnecessary, only used in cutscene_death_standing_goto_mario() 8568 */ 8569 void death_goto_mario(struct Camera *c) { 8570 cutscene_goto_cvar_pos(c, 400.f, 0x1000, 0x300, 0); 8571 } 8572 8573 BAD_RETURN(s32) cutscene_death_standing_start(struct Camera *c) { 8574 vec3f_copy(sCutsceneVars[0].point, c->focus); 8575 vec3f_copy(sCutsceneVars[3].point, sMarioCamState->pos); 8576 sCutsceneVars[3].point[1] += 70.f; 8577 } 8578 8579 /** 8580 * Fly to Mario and turn on handheld shake. 8581 */ 8582 BAD_RETURN(s32) cutscene_death_standing_goto_mario(struct Camera *c) { 8583 death_goto_mario(c); 8584 set_handheld_shake(HAND_CAM_SHAKE_HIGH); 8585 } 8586 8587 /** 8588 * Cutscene that plays when Mario dies while standing. 8589 */ 8590 BAD_RETURN(s32) cutscene_death_standing(struct Camera *c) { 8591 cutscene_event(cutscene_death_standing_start, c, 0, 0); 8592 cutscene_event(cutscene_death_standing_goto_mario, c, 0, -1); 8593 sStatusFlags |= CAM_FLAG_SMOOTH_MOVEMENT; 8594 } 8595 8596 BAD_RETURN(s32) cutscene_death_stomach_start(struct Camera *c) { 8597 Vec3f offset = { 0, 40.f, -60.f }; 8598 8599 offset_rotated(sCutsceneVars[3].point, sMarioCamState->pos, offset, sMarioCamState->faceAngle); 8600 vec3f_copy(sCutsceneVars[0].point, c->focus); 8601 } 8602 8603 BAD_RETURN(s32) cutscene_death_stomach_goto_mario(struct Camera *c) { 8604 cutscene_goto_cvar_pos(c, 400.f, 0x1800, 0, -0x400); 8605 } 8606 8607 /** 8608 * Ah, yes 8609 */ 8610 UNUSED static void unused_water_death_move_to_side_of_mario(struct Camera *c) { 8611 water_death_move_to_mario_side(c); 8612 } 8613 8614 /** 8615 * Cutscene that plays when Mario dies on his stomach. 8616 */ 8617 BAD_RETURN(s32) cutscene_death_stomach(struct Camera *c) { 8618 cutscene_event(cutscene_death_stomach_start, c, 0, 0); 8619 cutscene_event(cutscene_death_stomach_goto_mario, c, 0, -1); 8620 sStatusFlags |= CAM_FLAG_SMOOTH_MOVEMENT; 8621 set_handheld_shake(HAND_CAM_SHAKE_CUTSCENE); 8622 } 8623 8624 BAD_RETURN(s32) cutscene_bbh_death_start(struct Camera *c) { 8625 Vec3f dir = { 0, 40.f, 60.f }; 8626 8627 offset_rotated(sCutsceneVars[3].point, sMarioCamState->pos, dir, sMarioCamState->faceAngle); 8628 vec3f_copy(sCutsceneVars[0].point, c->focus); 8629 } 8630 8631 BAD_RETURN(s32) cutscene_bbh_death_goto_mario(struct Camera *c) { 8632 cutscene_goto_cvar_pos(c, 400.f, 0x1800, 0, 0x400); 8633 } 8634 8635 /** 8636 * Cutscene that plays when Mario dies in BBH. 8637 */ 8638 BAD_RETURN(s32) cutscene_bbh_death(struct Camera *c) { 8639 cutscene_event(cutscene_bbh_death_start, c, 0, 0); 8640 cutscene_event(cutscene_bbh_death_goto_mario, c, 0, -1); 8641 sStatusFlags |= CAM_FLAG_SMOOTH_MOVEMENT; 8642 set_handheld_shake(HAND_CAM_SHAKE_CUTSCENE); 8643 } 8644 8645 /** 8646 * Copy the camera's focus to cvar0 8647 */ 8648 BAD_RETURN(s32) cutscene_quicksand_death_start(struct Camera *c) { 8649 vec3f_copy(sCutsceneVars[0].point, c->focus); 8650 } 8651 8652 /** 8653 * Fly closer to Mario. In WATER_DEATH, move to Mario's side. 8654 */ 8655 BAD_RETURN(s32) cutscene_quicksand_death_goto_mario(struct Camera *c) { 8656 cutscene_goto_cvar_pos(c, 400.f, 0x2800, 0x200, 0); 8657 8658 if (c->cutscene == CUTSCENE_WATER_DEATH) { 8659 water_death_move_to_mario_side(c); 8660 } 8661 } 8662 8663 /** 8664 * Cutscene that plays when Mario dies in quicksand. 8665 */ 8666 BAD_RETURN(s32) cutscene_quicksand_death(struct Camera *c) { 8667 sCutsceneVars[3].point[0] = sMarioCamState->pos[0]; 8668 sCutsceneVars[3].point[1] = sMarioCamState->pos[1] + 20.f; 8669 sCutsceneVars[3].point[2] = sMarioCamState->pos[2]; 8670 8671 cutscene_event(cutscene_quicksand_death_start, c, 0, 0); 8672 cutscene_event(cutscene_quicksand_death_goto_mario, c, 0, -1); 8673 sStatusFlags |= CAM_FLAG_SMOOTH_MOVEMENT; 8674 set_handheld_shake(HAND_CAM_SHAKE_HIGH); 8675 } 8676 8677 /** 8678 * Fly away from Mario near the end of the cutscene. 8679 */ 8680 BAD_RETURN(s32) cutscene_suffocation_fly_away(UNUSED struct Camera *c) { 8681 Vec3f target; 8682 Vec3f offset = { 0, 20.f, 120.f }; 8683 8684 offset_rotated(target, sMarioCamState->pos, offset, sMarioCamState->faceAngle); 8685 approach_vec3f_asymptotic(sCutsceneVars[3].point, target, 0.1f, 0.1f, 0.1f); 8686 } 8687 8688 /** 8689 * Keep Lakitu above the gas level. 8690 */ 8691 BAD_RETURN(s32) cutscene_suffocation_stay_above_gas(struct Camera *c) { 8692 UNUSED u8 filler1[4]; 8693 f32 gasLevel; 8694 UNUSED u8 filler2[4]; 8695 8696 cutscene_goto_cvar_pos(c, 400.f, 0x2800, 0x200, 0); 8697 gasLevel = find_poison_gas_level(sMarioCamState->pos[0], sMarioCamState->pos[2]); 8698 8699 if (gasLevel != FLOOR_LOWER_LIMIT) { 8700 if ((gasLevel += 130.f) > c->pos[1]) { 8701 c->pos[1] = gasLevel; 8702 } 8703 } 8704 } 8705 8706 /** 8707 * Quickly rotate around Mario. 8708 */ 8709 BAD_RETURN(s32) cutscene_suffocation_rotate(struct Camera *c) { 8710 f32 dist; 8711 s16 pitch, yaw; 8712 8713 vec3f_get_dist_and_angle(sMarioCamState->pos, c->pos, &dist, &pitch, &yaw); 8714 yaw += 0x100; 8715 vec3f_set_dist_and_angle(sMarioCamState->pos, c->pos, dist, pitch, yaw); 8716 } 8717 8718 /** 8719 * Cutscene that plays when Mario dies from suffocation (ie due to HMC gas). 8720 */ 8721 BAD_RETURN(s32) cutscene_suffocation(struct Camera *c) { 8722 cutscene_event(cutscene_death_stomach_start, c, 0, 0); 8723 cutscene_event(cutscene_suffocation_rotate, c, 0, -1); 8724 cutscene_event(cutscene_suffocation_stay_above_gas, c, 0, -1); 8725 cutscene_event(cutscene_suffocation_fly_away, c, 50, -1); 8726 sStatusFlags |= CAM_FLAG_SMOOTH_MOVEMENT; 8727 set_handheld_shake(HAND_CAM_SHAKE_HIGH); 8728 } 8729 8730 BAD_RETURN(s32) cutscene_enter_pool_start(struct Camera *c) { 8731 vec3f_copy(sCutsceneVars[3].point, sMarioCamState->pos); 8732 8733 if (gCurrLevelNum == LEVEL_CASTLE) { // entering HMC 8734 vec3f_set(sCutsceneVars[3].point, 2485.f, -1589.f, -2659.f); 8735 } 8736 if (gCurrLevelNum == LEVEL_HMC) { // entering CotMC 8737 vec3f_set(sCutsceneVars[3].point, 3350.f, -4589.f, 4800.f); 8738 } 8739 8740 vec3f_copy(sCutsceneVars[0].point, c->focus); 8741 } 8742 8743 BAD_RETURN(s32) cutscene_enter_pool_loop(struct Camera *c) { 8744 UNUSED u8 filler[8]; 8745 8746 cutscene_goto_cvar_pos(c, 1200.f, 0x2000, 0x200, 0); 8747 } 8748 8749 BAD_RETURN(s32) cutscene_enter_pool(struct Camera *c) { 8750 cutscene_event(cutscene_enter_pool_start, c, 0, 0); 8751 cutscene_event(cutscene_enter_pool_loop, c, 0, -1); 8752 sStatusFlags |= CAM_FLAG_SMOOTH_MOVEMENT; 8753 } 8754 8755 /** 8756 * Store the camera focus in cvar1. 8757 * Store the area's center position (which happens to be the pyramid, in SSL) in cvar3. 8758 */ 8759 BAD_RETURN(s32) cutscene_pyramid_top_explode_start(struct Camera *c) { 8760 reset_pan_distance(c); 8761 store_info_cannon(c); 8762 8763 vec3f_copy(sCutsceneVars[1].point, c->focus); 8764 vec3f_set(sCutsceneVars[3].point, c->areaCenX, 1280.f, c->areaCenZ); 8765 } 8766 8767 /** 8768 * Zoom in on the pyramid. 8769 */ 8770 BAD_RETURN(s32) cutscene_pyramid_top_explode_zoom_in(UNUSED struct Camera *c) { 8771 set_fov_function(CAM_FOV_APP_30); 8772 } 8773 8774 /** 8775 * Look at the pyramid top. 8776 */ 8777 BAD_RETURN(s32) cutscene_pyramid_top_explode_focus(struct Camera *c) { 8778 approach_vec3f_asymptotic(c->focus, sCutsceneVars[3].point, 0.02f, 0.02f, 0.02f); 8779 sStatusFlags |= CAM_FLAG_SMOOTH_MOVEMENT; 8780 } 8781 8782 /** 8783 * Store the old pos and focus, then warp to the pyramid top. 8784 */ 8785 BAD_RETURN(s32) cutscene_pyramid_top_explode_warp(struct Camera *c) { 8786 s16 pitch, yaw; 8787 f32 dist; 8788 8789 set_fov_function(CAM_FOV_DEFAULT); 8790 sFOVState.fov = 45.f; 8791 8792 vec3f_copy(sCutsceneVars[4].point, c->pos); 8793 vec3f_copy(sCutsceneVars[5].point, c->focus); 8794 vec3f_copy(c->focus, sCutsceneVars[3].point); 8795 8796 vec3f_get_dist_and_angle(sCutsceneVars[3].point, sMarioCamState[0].pos, &dist, &pitch, &yaw); 8797 vec3f_set_dist_and_angle(sCutsceneVars[3].point, c->pos, 2000.f, 0, yaw); 8798 c->pos[1] += 500.f; 8799 } 8800 8801 /** 8802 * Close up view of the spinning pyramid top as it rises. 8803 */ 8804 BAD_RETURN(s32) cutscene_pyramid_top_explode_closeup(struct Camera *c) { 8805 s16 pitch, yaw; 8806 f32 dist; 8807 8808 vec3f_get_dist_and_angle(sCutsceneVars[3].point, c->pos, &dist, &pitch, &yaw); 8809 approach_f32_asymptotic_bool(&dist, 2000.f, 0.1f); 8810 vec3f_set_dist_and_angle(sCutsceneVars[3].point, c->pos, dist, pitch, yaw); 8811 8812 c->focus[1] += 4.f; 8813 c->pos[1] -= 5.f; 8814 sFOVState.fov = 45.f; 8815 set_handheld_shake(HAND_CAM_SHAKE_CUTSCENE); 8816 } 8817 8818 /** 8819 * Shake the camera during the closeup. 8820 */ 8821 BAD_RETURN(s32) cutscene_pyramid_top_explode_cam_shake(UNUSED struct Camera *c) { 8822 set_environmental_camera_shake(SHAKE_ENV_PYRAMID_EXPLODE); 8823 } 8824 8825 /** 8826 * Warp back to the old position, and start a heavy camera shake. 8827 */ 8828 BAD_RETURN(s32) cutscene_pyramid_top_explode_warp_back(struct Camera *c) { 8829 UNUSED u8 filler[8]; 8830 8831 vec3f_copy(c->pos, sCutsceneVars[4].point); 8832 vec3f_copy(c->focus, sCutsceneVars[5].point); 8833 set_environmental_camera_shake(SHAKE_ENV_BOWSER_JUMP); 8834 } 8835 8836 /** 8837 * An unused cutscene for when the pyramid explodes. 8838 */ 8839 BAD_RETURN(s32) cutscene_pyramid_top_explode(struct Camera *c) { 8840 cutscene_event(cutscene_pyramid_top_explode_start, c, 0, 0); 8841 cutscene_event(cutscene_pyramid_top_explode_focus, c, 0, 30); 8842 cutscene_event(cutscene_pyramid_top_explode_warp, c, 31, 31); 8843 cutscene_event(cutscene_pyramid_top_explode_closeup, c, 31, 139); 8844 cutscene_event(cutscene_pyramid_top_explode_zoom_in, c, 23, 23); 8845 cutscene_event(cutscene_pyramid_top_explode_warp_back, c, 140, 140); 8846 cutscene_event(cutscene_pyramid_top_explode_cam_shake, c, 31, 139); 8847 } 8848 8849 /** 8850 * End the pyramid top explosion cutscene. 8851 */ 8852 BAD_RETURN(s32) cutscene_pyramid_top_explode_end(struct Camera *c) { 8853 cutscene_stop_dialog(c); 8854 stop_cutscene_and_retrieve_stored_info(c); 8855 // Move the camera back to Mario 8856 transition_next_state(c, 30); 8857 } 8858 8859 /** 8860 * Store the camera focus in cvar0, and store the top of the pyramid in cvar3. 8861 */ 8862 BAD_RETURN(s32) cutscene_enter_pyramid_top_start(struct Camera *c) { 8863 vec3f_copy(sCutsceneVars[0].point, c->focus); 8864 vec3f_set(sCutsceneVars[3].point, c->areaCenX, 1280.f, c->areaCenZ); 8865 } 8866 8867 /** 8868 * Cutscene that plays when Mario enters the top of the pyramid. 8869 */ 8870 BAD_RETURN(s32) cutscene_enter_pyramid_top(struct Camera *c) { 8871 cutscene_event(cutscene_enter_pyramid_top_start, c, 0, 0); 8872 // Move to cvar3 8873 cutscene_goto_cvar_pos(c, 200.f, 0x3000, 0, 0); 8874 sStatusFlags |= CAM_FLAG_SMOOTH_MOVEMENT; 8875 set_handheld_shake(HAND_CAM_SHAKE_CUTSCENE); 8876 8877 if (sMarioCamState->pos[1] > 1250.f) { 8878 // End the cutscene early if Mario ledge-grabbed. 8879 // This only works because of the janky way that ledge-grabbing is implemented. 8880 cutscene_exit_to_castle_grounds_end(c); 8881 } 8882 } 8883 8884 UNUSED static void unused_cutscene_goto_cvar(struct Camera *c) { 8885 f32 dist; 8886 8887 dist = calc_abs_dist(sCutsceneVars[3].point, sMarioCamState->pos); 8888 dist = calc_abs_dist(sCutsceneVars[9].point, sMarioCamState->pos) + 200.f; 8889 cutscene_goto_cvar_pos(c, dist, 0x1000, 0x300, 0); 8890 } 8891 8892 /** 8893 * cvar8 is Mario's position and faceAngle 8894 * 8895 * cvar9.point is gCutsceneFocus's position 8896 * cvar9.angle[1] is the yaw between Mario and the gCutsceneFocus 8897 */ 8898 BAD_RETURN(s32) cutscene_dialog_start(struct Camera *c) { 8899 UNUSED u8 filler[4]; 8900 UNUSED s16 unused; 8901 s16 yaw; 8902 8903 cutscene_soften_music(c); 8904 set_time_stop_flags(TIME_STOP_ENABLED | TIME_STOP_DIALOG); 8905 8906 #ifndef VERSION_JP 8907 if (c->mode == CAMERA_MODE_BOSS_FIGHT) { 8908 vec3f_copy(sCameraStoreCutscene.focus, c->focus); 8909 vec3f_copy(sCameraStoreCutscene.pos, c->pos); 8910 } else { 8911 #endif 8912 store_info_star(c); 8913 #ifndef VERSION_JP 8914 } 8915 #endif 8916 8917 // Store Mario's position and faceAngle 8918 sCutsceneVars[8].angle[0] = 0; 8919 vec3f_copy(sCutsceneVars[8].point, sMarioCamState->pos); 8920 sCutsceneVars[8].point[1] += 125.f; 8921 8922 // Store gCutsceneFocus's position and yaw 8923 object_pos_to_vec3f(sCutsceneVars[9].point, gCutsceneFocus); 8924 sCutsceneVars[9].point[1] += gCutsceneFocus->hitboxHeight + 200.f; 8925 sCutsceneVars[9].angle[1] = calculate_yaw(sCutsceneVars[8].point, sCutsceneVars[9].point); 8926 8927 yaw = calculate_yaw(sMarioCamState->pos, gLakituState.curPos); 8928 if ((yaw - sCutsceneVars[9].angle[1]) & 0x8000) { 8929 sCutsceneVars[9].angle[1] -= 0x6000; 8930 } else { 8931 sCutsceneVars[9].angle[1] += 0x6000; 8932 } 8933 } 8934 8935 /** 8936 * Move closer to Mario and the object, adjusting to their difference in height. 8937 * The camera's generally ends up looking over Mario's shoulder. 8938 */ 8939 BAD_RETURN(s32) cutscene_dialog_move_mario_shoulder(struct Camera *c) { 8940 f32 dist; 8941 s16 pitch, yaw; 8942 Vec3f focus, pos; 8943 8944 scale_along_line(focus, sCutsceneVars[9].point, sMarioCamState->pos, 0.7f); 8945 vec3f_get_dist_and_angle(c->pos, focus, &dist, &pitch, &yaw); 8946 pitch = calculate_pitch(c->pos, sCutsceneVars[9].point); 8947 vec3f_set_dist_and_angle(c->pos, pos, dist, pitch, yaw); 8948 8949 focus[1] = focus[1] + (sCutsceneVars[9].point[1] - focus[1]) * 0.1f; 8950 approach_vec3f_asymptotic(c->focus, focus, 0.2f, 0.2f, 0.2f); 8951 8952 vec3f_copy(pos, c->pos); 8953 8954 // Set y pos to cvar8's y (top of focus object) 8955 pos[1] = sCutsceneVars[8].point[1]; 8956 vec3f_get_dist_and_angle(sCutsceneVars[8].point, pos, &dist, &pitch, &yaw); 8957 approach_s16_asymptotic_bool(&yaw, sCutsceneVars[9].angle[1], 0x10); 8958 approach_f32_asymptotic_bool(&dist, 180.f, 0.05f); 8959 vec3f_set_dist_and_angle(sCutsceneVars[8].point, pos, dist, pitch, yaw); 8960 8961 // Move up if Mario is below the focus object, down is Mario is above 8962 pos[1] = sCutsceneVars[8].point[1] 8963 + sins(calculate_pitch(sCutsceneVars[9].point, sCutsceneVars[8].point)) * 100.f; 8964 8965 approach_f32_asymptotic_bool(&c->pos[1], pos[1], 0.05f); 8966 c->pos[0] = pos[0]; 8967 c->pos[2] = pos[2]; 8968 } 8969 8970 /** 8971 * Create the dialog with sCutsceneDialogID 8972 */ 8973 BAD_RETURN(s32) cutscene_dialog_create_dialog_box(struct Camera *c) { 8974 if (c->cutscene == CUTSCENE_RACE_DIALOG) { 8975 create_dialog_box_with_response(sCutsceneDialogID); 8976 } else { 8977 create_dialog_box(sCutsceneDialogID); 8978 } 8979 8980 //! Unused. This may have been used before sCutsceneDialogResponse was implemented. 8981 sCutsceneVars[8].angle[0] = DIALOG_RESPONSE_NOT_DEFINED; 8982 } 8983 8984 /** 8985 * Cutscene that plays when Mario talks to an object. 8986 */ 8987 BAD_RETURN(s32) cutscene_dialog(struct Camera *c) { 8988 cutscene_event(cutscene_dialog_start, c, 0, 0); 8989 cutscene_event(cutscene_dialog_move_mario_shoulder, c, 0, -1); 8990 cutscene_event(cutscene_dialog_create_dialog_box, c, 10, 10); 8991 sStatusFlags |= CAM_FLAG_SMOOTH_MOVEMENT; 8992 8993 if (gDialogResponse != DIALOG_RESPONSE_NONE) { 8994 sCutsceneDialogResponse = gDialogResponse; 8995 } 8996 8997 if ((get_dialog_id() == DIALOG_NONE) && (sCutsceneVars[8].angle[0] != 0)) { 8998 if (c->cutscene != CUTSCENE_RACE_DIALOG) { 8999 sCutsceneDialogResponse = DIALOG_RESPONSE_NOT_DEFINED; 9000 } 9001 9002 gCutsceneTimer = CUTSCENE_LOOP; 9003 retrieve_info_star(c); 9004 transition_next_state(c, 15); 9005 sStatusFlags |= CAM_FLAG_UNUSED_CUTSCENE_ACTIVE; 9006 cutscene_unsoften_music(c); 9007 } 9008 } 9009 9010 /** 9011 * Sets the CAM_FLAG_UNUSED_CUTSCENE_ACTIVE flag, which does nothing. 9012 */ 9013 BAD_RETURN(s32) cutscene_dialog_set_flag(UNUSED struct Camera *c) { 9014 sStatusFlags |= CAM_FLAG_UNUSED_CUTSCENE_ACTIVE; 9015 } 9016 9017 /** 9018 * Ends the dialog cutscene. 9019 */ 9020 BAD_RETURN(s32) cutscene_dialog_end(struct Camera *c) { 9021 sStatusFlags |= CAM_FLAG_UNUSED_CUTSCENE_ACTIVE; 9022 c->cutscene = 0; 9023 clear_time_stop_flags(TIME_STOP_ENABLED | TIME_STOP_DIALOG); 9024 } 9025 9026 /** 9027 * Soften the music, clear cvar0 9028 * 9029 * In this cutscene, cvar0.angle[0] is used as a state variable. 9030 */ 9031 BAD_RETURN(s32) cutscene_read_message_start(struct Camera *c) { 9032 cutscene_soften_music(c); 9033 transition_next_state(c, 30); 9034 reset_pan_distance(c); 9035 store_info_star(c); 9036 9037 sCutsceneVars[1].angle[0] = sCUpCameraPitch; 9038 sCutsceneVars[1].angle[1] = sModeOffsetYaw; 9039 sCUpCameraPitch = -0x830; 9040 sModeOffsetYaw = 0; 9041 sCutsceneVars[0].angle[0] = 0; 9042 } 9043 9044 UNUSED static void unused_cam_to_mario(struct Camera *c) { 9045 Vec3s dir; 9046 9047 vec3s_set(dir, 0, sMarioCamState->faceAngle[1], 0); 9048 offset_rotated_coords(c->pos, sMarioCamState->pos, dir, 0, 100.f, 190.f); 9049 offset_rotated_coords(c->focus, sMarioCamState->pos, dir, 0, 70.f, -20.f); 9050 } 9051 9052 /** 9053 * Cutscene that plays when Mario is reading a message (a sign or message on the wall) 9054 */ 9055 BAD_RETURN(s32) cutscene_read_message(struct Camera *c) { 9056 UNUSED u8 filler[8]; 9057 9058 cutscene_event(cutscene_read_message_start, c, 0, 0); 9059 sStatusFlags |= CAM_FLAG_SMOOTH_MOVEMENT; 9060 9061 switch (sCutsceneVars[0].angle[0]) { 9062 // Do nothing until message is gone. 9063 case 0: 9064 if (get_dialog_id() != DIALOG_NONE) { 9065 sCutsceneVars[0].angle[0]++; 9066 set_time_stop_flags(TIME_STOP_ENABLED | TIME_STOP_DIALOG); 9067 } 9068 break; 9069 // Leave the dialog. 9070 case 1: 9071 move_mario_head_c_up(c); 9072 update_c_up(c, c->focus, c->pos); 9073 9074 // This could cause softlocks. If a message starts one frame after another one closes, the 9075 // cutscene will never end. 9076 if (get_dialog_id() == DIALOG_NONE) { 9077 gCutsceneTimer = CUTSCENE_LOOP; 9078 retrieve_info_star(c); 9079 transition_next_state(c, 15); 9080 sStatusFlags |= CAM_FLAG_UNUSED_CUTSCENE_ACTIVE; 9081 clear_time_stop_flags(TIME_STOP_ENABLED | TIME_STOP_DIALOG); 9082 // Retrieve previous state 9083 sCUpCameraPitch = sCutsceneVars[1].angle[0]; 9084 sModeOffsetYaw = sCutsceneVars[1].angle[1]; 9085 cutscene_unsoften_music(c); 9086 } 9087 } 9088 sStatusFlags |= CAM_FLAG_UNUSED_CUTSCENE_ACTIVE; 9089 } 9090 9091 /** 9092 * Set CAM_FLAG_UNUSED_CUTSCENE_ACTIVE, which does nothing. 9093 */ 9094 BAD_RETURN(s32) cutscene_read_message_set_flag(UNUSED struct Camera *c) { 9095 sStatusFlags |= CAM_FLAG_UNUSED_CUTSCENE_ACTIVE; 9096 } 9097 9098 /** 9099 * End the message cutscene. 9100 */ 9101 BAD_RETURN(s32) cutscene_read_message_end(struct Camera *c) { 9102 sStatusFlags |= CAM_FLAG_UNUSED_CUTSCENE_ACTIVE; 9103 c->cutscene = 0; 9104 } 9105 9106 /** 9107 * Set cvars: 9108 * cvar7 is Mario's pos and angle 9109 * cvar6 is the focus offset 9110 * cvar5 is the position offset 9111 */ 9112 BAD_RETURN(s32) cutscene_exit_succ_start(UNUSED struct Camera *c) { 9113 vec3f_copy(sCutsceneVars[7].point, sMarioCamState->pos); 9114 vec3s_copy(sCutsceneVars[7].angle, sMarioCamState->faceAngle); 9115 vec3f_set(sCutsceneVars[6].point, 6.f, 363.f, 543.f); 9116 vec3f_set(sCutsceneVars[5].point, 137.f, 226.f, 995.f); 9117 } 9118 9119 /** 9120 * Set the camera pos depending on which level Mario exited. 9121 */ 9122 BAD_RETURN(s32) cutscene_non_painting_set_cam_pos(struct Camera *c) { 9123 UNUSED u8 filler1[4]; 9124 struct Surface *floor; 9125 UNUSED u8 filler2[12]; 9126 9127 switch (gPrevLevel) { 9128 case LEVEL_HMC: 9129 vec3f_set(c->pos, 3465.f, -1008.f, -2961.f); 9130 break; 9131 9132 case LEVEL_COTMC: 9133 vec3f_set(c->pos, 3465.f, -1008.f, -2961.f); 9134 break; 9135 9136 case LEVEL_RR: 9137 vec3f_set(c->pos, -3741.f, 3151.f, 6065.f); 9138 break; 9139 9140 case LEVEL_WMOTR: 9141 vec3f_set(c->pos, 1972.f, 3230.f, 5891.f); 9142 break; 9143 9144 default: 9145 offset_rotated(c->pos, sCutsceneVars[7].point, sCutsceneVars[5].point, sCutsceneVars[7].angle); 9146 c->pos[1] = find_floor(c->pos[0], c->pos[1] + 1000.f, c->pos[2], &floor) + 125.f; 9147 break; 9148 } 9149 } 9150 9151 /** 9152 * Update the camera focus depending on which level Mario exited. 9153 */ 9154 BAD_RETURN(s32) cutscene_non_painting_set_cam_focus(struct Camera *c) { 9155 offset_rotated(c->focus, sCutsceneVars[7].point, sCutsceneVars[6].point, sCutsceneVars[7].angle); 9156 9157 if ((gPrevLevel == LEVEL_COTMC) || (gPrevLevel == LEVEL_HMC) || (gPrevLevel == LEVEL_RR) 9158 || (gPrevLevel == LEVEL_WMOTR)) { 9159 c->focus[0] = c->pos[0] + (sMarioCamState->pos[0] - c->pos[0]) * 0.7f; 9160 c->focus[1] = c->pos[1] + (sMarioCamState->pos[1] - c->pos[1]) * 0.4f; 9161 c->focus[2] = c->pos[2] + (sMarioCamState->pos[2] - c->pos[2]) * 0.7f; 9162 } else { 9163 c->focus[1] = c->pos[1] + (sMarioCamState->pos[1] - c->pos[1]) * 0.2f; 9164 } 9165 } 9166 9167 /** 9168 * Focus slightly left of Mario. Perhaps to keep the bowser painting in view? 9169 */ 9170 BAD_RETURN(s32) cutscene_exit_bowser_succ_focus_left(UNUSED struct Camera *c) { 9171 approach_f32_asymptotic_bool(&sCutsceneVars[6].point[0], -24.f, 0.05f); 9172 } 9173 9174 /** 9175 * Instead of focusing on the key, just start a pitch shake. Clever! 9176 * The shake lasts 32 frames. 9177 */ 9178 BAD_RETURN(s32) cutscene_exit_bowser_key_toss_shake(struct Camera *c) { 9179 //! Unnecessary check. 9180 if (c->cutscene == CUTSCENE_EXIT_BOWSER_SUCC) { 9181 set_camera_pitch_shake(0x800, 0x40, 0x800); 9182 } 9183 } 9184 9185 /** 9186 * Start a camera shake when Mario lands on the ground. 9187 */ 9188 BAD_RETURN(s32) cutscene_exit_succ_shake_landing(UNUSED struct Camera *c) { 9189 set_environmental_camera_shake(SHAKE_ENV_EXPLOSION); 9190 } 9191 9192 /** 9193 * Cutscene that plays when Mario beats bowser and exits the level. 9194 */ 9195 BAD_RETURN(s32) cutscene_exit_bowser_succ(struct Camera *c) { 9196 cutscene_event(cutscene_exit_succ_start, c, 0, 0); 9197 cutscene_event(cutscene_non_painting_set_cam_pos, c, 0, -1); 9198 cutscene_event(cutscene_exit_bowser_succ_focus_left, c, 18, -1); 9199 cutscene_event(cutscene_non_painting_set_cam_focus, c, 0, -1); 9200 cutscene_event(cutscene_exit_bowser_key_toss_shake, c, 125, 125); 9201 cutscene_event(cutscene_exit_succ_shake_landing, c, 41, 41); 9202 } 9203 9204 /** 9205 * End a non-painting exit cutscene. Used by BBH and bowser courses. 9206 */ 9207 BAD_RETURN(s32) cutscene_non_painting_end(struct Camera *c) { 9208 c->cutscene = 0; 9209 9210 if (c->defMode == CAMERA_MODE_CLOSE) { 9211 c->mode = CAMERA_MODE_CLOSE; 9212 } else { 9213 c->mode = CAMERA_MODE_FREE_ROAM; 9214 } 9215 9216 sStatusFlags |= CAM_FLAG_UNUSED_CUTSCENE_ACTIVE; 9217 sStatusFlags |= CAM_FLAG_SMOOTH_MOVEMENT; 9218 transition_next_state(c, 60); 9219 update_camera_yaw(c); 9220 } 9221 9222 /** 9223 * Override the position offset. 9224 */ 9225 BAD_RETURN(s32) cutscene_exit_non_painting_succ_override_cvar(UNUSED struct Camera *c) { 9226 vec3f_set(sCutsceneVars[5].point, 137.f, 246.f, 1115.f); 9227 } 9228 9229 /** 9230 * Cutscene that plays when Mario collects a star and leaves a non-painting course, like HMC or BBH. 9231 */ 9232 BAD_RETURN(s32) cutscene_exit_non_painting_succ(struct Camera *c) { 9233 cutscene_event(cutscene_exit_succ_start, c, 0, 0); 9234 cutscene_event(cutscene_exit_non_painting_succ_override_cvar, c, 0, 0); 9235 cutscene_event(cutscene_non_painting_set_cam_pos, c, 0, -1); 9236 cutscene_event(cutscene_exit_bowser_succ_focus_left, c, 18, -1); 9237 cutscene_event(cutscene_non_painting_set_cam_focus, c, 0, -1); 9238 cutscene_event(cutscene_exit_succ_shake_landing, c, 41, 41); 9239 update_camera_yaw(c); 9240 } 9241 9242 /** 9243 * Set cvar7 to Mario's pos and faceAngle 9244 * Set cvar6 to the focus offset from Mario. 9245 * set cvar5 to the pos offset from Mario. (This is always overwritten) 9246 */ 9247 BAD_RETURN(s32) cutscene_non_painting_death_start(UNUSED struct Camera *c) { 9248 vec3f_copy(sCutsceneVars[7].point, sMarioCamState->pos); 9249 vec3s_copy(sCutsceneVars[7].angle, sMarioCamState->faceAngle); 9250 vec3f_set(sCutsceneVars[6].point, -42.f, 350.f, 727.f); 9251 // This is always overwritten, except in the unused cutscene_exit_bowser_death() 9252 vec3f_set(sCutsceneVars[5].point, 107.f, 226.f, 1187.f); 9253 } 9254 9255 /** 9256 * This cutscene is the same as non_painting_death, but the camera is closer to Mario and lower. 9257 * Because it it doesn't call cutscene_non_painting_death_override_offset, the value from 9258 * cutscene_non_painting_death_start is used. 9259 * 9260 * This cutscene is unused, dying in bowser's arena spawns Mario near the warp pipe, not back in the 9261 * hub. 9262 */ 9263 BAD_RETURN(s32) cutscene_exit_bowser_death(struct Camera *c) { 9264 cutscene_event(cutscene_non_painting_death_start, c, 0, 0); 9265 cutscene_event(cutscene_non_painting_set_cam_pos, c, 0, -1); 9266 cutscene_event(cutscene_non_painting_set_cam_focus, c, 0, -1); 9267 } 9268 9269 /** 9270 * Set the offset from Mario depending on the course Mario exited. 9271 * This overrides cutscene_non_painting_death_start() 9272 */ 9273 BAD_RETURN(s32) cutscene_non_painting_death_override_offset(UNUSED struct Camera *c) { 9274 switch (gPrevLevel) { 9275 case LEVEL_HMC: 9276 vec3f_set(sCutsceneVars[5].point, 187.f, 369.f, -197.f); 9277 break; 9278 case LEVEL_COTMC: 9279 vec3f_set(sCutsceneVars[5].point, 187.f, 369.f, -197.f); 9280 break; 9281 default: 9282 vec3f_set(sCutsceneVars[5].point, 107.f, 246.f, 1307.f); 9283 break; 9284 } 9285 } 9286 9287 /** 9288 * Cutscene played when Mario dies in a non-painting course, like HMC or BBH. 9289 */ 9290 BAD_RETURN(s32) cutscene_non_painting_death(struct Camera *c) { 9291 cutscene_event(cutscene_non_painting_death_start, c, 0, 0); 9292 cutscene_event(cutscene_non_painting_death_override_offset, c, 0, 0); 9293 cutscene_event(cutscene_non_painting_set_cam_pos, c, 0, -1); 9294 cutscene_event(cutscene_non_painting_set_cam_focus, c, 0, -1); 9295 sStatusFlags |= CAM_FLAG_UNUSED_CUTSCENE_ACTIVE; 9296 } 9297 9298 /** 9299 * Set cvars: 9300 * cvar3 is an offset applied to the camera's rotation around Mario. It starts at 0x1200 9301 * cvar 1 is more complicated: 9302 * First the yaw from Mario to the camera is calculated. cvar1 is the high byte of the difference 9303 * between that yaw and Mario's faceAngle plus 0x1200. The reason for taking the high byte is 9304 * because cvar1 rotates until is reaches 0, so it's important that it's a multiple of 0x100. 9305 */ 9306 BAD_RETURN(s32) cutscene_cap_switch_press_start(struct Camera *c) { 9307 UNUSED s16 unused; 9308 s16 yaw; 9309 UNUSED u8 filler[8]; 9310 9311 store_info_star(c); 9312 yaw = calculate_yaw(sMarioCamState->pos, c->pos); 9313 sCutsceneVars[3].angle[1] = 0x1200; 9314 // Basically the amount of rotation to get from behind Mario to in front of Mario 9315 sCutsceneVars[1].angle[1] = (yaw - (sMarioCamState->faceAngle[1] + sCutsceneVars[3].angle[1])) & 0xFF00; 9316 } 9317 9318 /** 9319 * Rotate around Mario. As each cvar stops updating, the rotation slows until the camera ends up in 9320 * front of Mario. 9321 */ 9322 BAD_RETURN(s32) cutscene_cap_switch_press_rotate_around_mario(struct Camera *c) { 9323 f32 dist; 9324 s16 pitch, yaw; 9325 UNUSED s16 unusedYaw = sMarioCamState->faceAngle[1] + 0x1000; 9326 UNUSED u8 filler[2]; 9327 UNUSED s32 cvar1Yaw = sCutsceneVars[1].angle[1]; 9328 9329 vec3f_get_dist_and_angle(sMarioCamState->pos, c->pos, &dist, &pitch, &yaw); 9330 9331 // cvar3 wraps around until it reaches 0x1000 9332 if (sCutsceneVars[3].angle[1] != 0x1000) { 9333 sCutsceneVars[3].angle[1] += 0x100; 9334 } 9335 9336 // cvar1 wraps until 0 9337 if (sCutsceneVars[1].angle[1] != 0) { 9338 sCutsceneVars[1].angle[1] += 0x100; 9339 } 9340 9341 yaw = sMarioCamState->faceAngle[1] + sCutsceneVars[3].angle[1] + sCutsceneVars[1].angle[1]; 9342 vec3f_set_dist_and_angle(sMarioCamState->pos, c->pos, dist, pitch, yaw); 9343 } 9344 9345 /** 9346 * Move the camera slightly downwards. 9347 */ 9348 BAD_RETURN(s32) cutscene_cap_switch_press_lower_cam(struct Camera *c) { 9349 rotate_and_move_vec3f(c->pos, sMarioCamState->pos, 0, -0x20, 0); 9350 } 9351 9352 /** 9353 * Move the camera closer to Mario. 9354 */ 9355 BAD_RETURN(s32) cutscene_cap_switch_press_approach_mario(struct Camera *c) { 9356 s16 pitch, yaw; 9357 f32 dist; 9358 9359 vec3f_get_dist_and_angle(sMarioCamState->pos, c->pos, &dist, &pitch, &yaw); 9360 approach_f32_asymptotic_bool(&dist, 195.f, 0.2f); 9361 approach_s16_asymptotic_bool(&pitch, 0, 0x10); 9362 vec3f_set_dist_and_angle(sMarioCamState->pos, c->pos, dist, pitch, yaw); 9363 9364 approach_f32_asymptotic_bool(&c->focus[0], sMarioCamState->pos[0], 0.1f); 9365 approach_f32_asymptotic_bool(&c->focus[1], sMarioCamState->pos[1] + 110.f, 0.1f); 9366 approach_f32_asymptotic_bool(&c->focus[2], sMarioCamState->pos[2], 0.1f); 9367 } 9368 9369 /** 9370 * Pan the camera left so that Mario is on the right side of the screen when the camera stops spinning. 9371 */ 9372 BAD_RETURN(s32) cutscene_cap_switch_press_pan_left(struct Camera *c) { 9373 vec3f_copy(c->focus, sMarioCamState->pos); 9374 c->focus[1] += 110.f; 9375 camera_approach_s16_symmetric_bool(&sCutsceneVars[0].angle[1], 0x800, 0x20); 9376 pan_camera(c, sCutsceneVars[0].angle[0], sCutsceneVars[0].angle[1]); 9377 } 9378 9379 /** 9380 * Create a dialog box with the cap switch's text. 9381 */ 9382 BAD_RETURN(s32) cutscene_cap_switch_press_create_dialog(UNUSED struct Camera *c) { 9383 create_dialog_box_with_response(gCutsceneFocus->oBhvParams2ndByte + DIALOG_010); 9384 } 9385 9386 static UNUSED BAD_RETURN(s32) unused_cap_switch_retrieve_info(struct Camera *c) { 9387 retrieve_info_star(c); 9388 transition_next_state(c, 30); 9389 } 9390 9391 /** 9392 * Cutscene that plays when Mario presses a cap switch. 9393 */ 9394 BAD_RETURN(s32) cutscene_cap_switch_press(struct Camera *c) { 9395 f32 dist; 9396 s16 pitch, yaw; 9397 9398 sStatusFlags |= CAM_FLAG_SMOOTH_MOVEMENT; 9399 sStatusFlags |= CAM_FLAG_UNUSED_CUTSCENE_ACTIVE; 9400 9401 cutscene_event(cutscene_cap_switch_press_start, c, 0, 0); 9402 cutscene_event(cutscene_cap_switch_press_approach_mario, c, 0, 30); 9403 cutscene_event(cutscene_cap_switch_press_pan_left, c, 0, -1); 9404 cutscene_event(cutscene_cap_switch_press_rotate_around_mario, c, 30, -1); 9405 cutscene_event(cutscene_cap_switch_press_lower_cam, c, 10, 70); 9406 cutscene_event(cutscene_cap_switch_press_create_dialog, c, 10, 10); 9407 vec3f_get_dist_and_angle(sMarioCamState->pos, c->pos, &dist, &pitch, &yaw); 9408 9409 if (gDialogResponse != DIALOG_RESPONSE_NONE) { 9410 sCutsceneVars[4].angle[0] = gDialogResponse; 9411 } 9412 9413 if ((get_dialog_id() == DIALOG_NONE) && (sCutsceneVars[4].angle[0] != 0)) { 9414 sCutsceneDialogResponse = sCutsceneVars[4].angle[0]; 9415 if (sCutsceneVars[4].angle[0] == 1) { 9416 cap_switch_save(gCutsceneFocus->oBhvParams2ndByte); 9417 } 9418 stop_cutscene_and_retrieve_stored_info(c); 9419 transition_next_state(c, 30); 9420 } 9421 } 9422 9423 /** 9424 * Sets cvars: 9425 * cvar0 is the camera's position 9426 * cvar1 is the camera's focus 9427 * cvar2 is the goal position 9428 * cvar3 is the goal focus 9429 */ 9430 BAD_RETURN(s32) cutscene_unlock_key_door_start(struct Camera *c) { 9431 Vec3f posOff, focusOff; 9432 9433 vec3f_copy(sCutsceneVars[0].point, c->pos); 9434 vec3f_copy(sCutsceneVars[1].point, c->focus); 9435 vec3f_set(posOff, -206.f, 108.f, 234.f); 9436 vec3f_set(focusOff, 48.f, 104.f, -193.f); 9437 offset_rotated(sCutsceneVars[2].point, sMarioCamState->pos, posOff, sMarioCamState->faceAngle); 9438 offset_rotated(sCutsceneVars[3].point, sMarioCamState->pos, focusOff, sMarioCamState->faceAngle); 9439 } 9440 9441 /** 9442 * Move the camera to the cvars position and focus, closer to Mario. 9443 * Gives a better view of the key. 9444 */ 9445 BAD_RETURN(s32) cutscene_unlock_key_door_approach_mario(struct Camera *c) { 9446 approach_vec3f_asymptotic(c->pos, sCutsceneVars[2].point, 0.1f, 0.1f, 0.1f); 9447 approach_vec3f_asymptotic(c->focus, sCutsceneVars[3].point, 0.1f, 0.1f, 0.1f); 9448 } 9449 9450 /** 9451 * Move the camera focus up a bit, focusing on the key in the lock. 9452 */ 9453 BAD_RETURN(s32) cutscene_unlock_key_door_focus_lock(UNUSED struct Camera *c) { 9454 approach_f32_asymptotic_bool(&sCutsceneVars[3].point[1], sMarioCamState->pos[1] + 140.f, 0.07f); 9455 } 9456 9457 BAD_RETURN(s32) cutscene_unlock_key_door_stub(UNUSED struct Camera *c) { 9458 } 9459 9460 /** 9461 * Move back to the previous pos and focus, stored in cvar0 and cvar1. 9462 */ 9463 BAD_RETURN(s32) cutscene_unlock_key_door_fly_back(struct Camera *c) { 9464 approach_vec3f_asymptotic(c->pos, sCutsceneVars[0].point, 0.1f, 0.1f, 0.1f); 9465 approach_vec3f_asymptotic(c->focus, sCutsceneVars[1].point, 0.1f, 0.1f, 0.1f); 9466 } 9467 9468 /** 9469 * Shake the camera's fov when the key is put in the lock. 9470 */ 9471 BAD_RETURN(s32) cutscene_unlock_key_door_fov_shake(UNUSED struct Camera *c) { 9472 cutscene_set_fov_shake_preset(1); 9473 } 9474 9475 /** 9476 * Cutscene that plays when Mario unlocks a key door. 9477 */ 9478 BAD_RETURN(s32) cutscene_unlock_key_door(UNUSED struct Camera *c) { 9479 cutscene_event(cutscene_unlock_key_door_start, c, 0, 0); 9480 cutscene_event(cutscene_unlock_key_door_approach_mario, c, 0, 123); 9481 cutscene_event(cutscene_unlock_key_door_fly_back, c, 124, -1); 9482 cutscene_event(cutscene_unlock_key_door_fov_shake, c, 79, 79); 9483 cutscene_event(cutscene_unlock_key_door_focus_lock, c, 70, 110); 9484 cutscene_event(cutscene_unlock_key_door_stub, c, 112, 112); 9485 } 9486 9487 /** 9488 * Move the camera along `positionSpline` and point its focus at the corresponding point along 9489 * `focusSpline`. sCutsceneSplineSegmentProgress is updated after pos and focus are calculated. 9490 */ 9491 s32 intro_peach_move_camera_start_to_pipe(struct Camera *c, struct CutsceneSplinePoint positionSpline[], 9492 struct CutsceneSplinePoint focusSpline[]) { 9493 Vec3f offset; 9494 s32 posReturn = 0; 9495 s32 focusReturn = 0; 9496 9497 /** 9498 * The position spline's speed parameters are all 0, so sCutsceneSplineSegmentProgress doesn't get 9499 * updated. Otherwise position would move two frames ahead, and c->focus would always be one frame 9500 * further along the spline than c->pos. 9501 */ 9502 posReturn = move_point_along_spline(c->pos, positionSpline, &sCutsceneSplineSegment, &sCutsceneSplineSegmentProgress); 9503 focusReturn = move_point_along_spline(c->focus, focusSpline, &sCutsceneSplineSegment, &sCutsceneSplineSegmentProgress); 9504 9505 // The two splines used by this function are reflected in the horizontal plane for some reason, 9506 // so they are rotated every frame. Why do this, Nintendo? 9507 rotate_in_xz(c->focus, c->focus, DEGREES(-180)); 9508 rotate_in_xz(c->pos, c->pos, DEGREES(-180)); 9509 9510 vec3f_set(offset, -1328.f, 260.f, 4664.f); 9511 vec3f_add(c->focus, offset); 9512 vec3f_add(c->pos, offset); 9513 9514 posReturn += focusReturn; // Unused 9515 return focusReturn; 9516 } 9517 9518 /** 9519 * Create a dialog box with the letter text 9520 */ 9521 BAD_RETURN(s32) peach_letter_text(UNUSED struct Camera *c) { 9522 create_dialog_box(DIALOG_020); 9523 } 9524 9525 #ifndef VERSION_JP 9526 BAD_RETURN(s32) play_sound_peach_reading_letter(UNUSED struct Camera *c) { 9527 play_sound(SOUND_PEACH_DEAR_MARIO, gGlobalSoundSource); 9528 } 9529 #endif 9530 9531 /** 9532 * Move the camera from peach reading the letter all the way to Mario's warp pipe. Follow the 9533 * sIntroStartToPipe splines. 9534 */ 9535 BAD_RETURN(s32) cutscene_intro_peach_start_to_pipe_spline(struct Camera *c) { 9536 if (intro_peach_move_camera_start_to_pipe(c, sIntroStartToPipePosition, sIntroStartToPipeFocus) != 0) { 9537 gCameraMovementFlags &= ~CAM_MOVE_C_UP_MODE; 9538 gCutsceneTimer = CUTSCENE_LOOP; 9539 } 9540 } 9541 9542 /** 9543 * Loop the cutscene until Mario exits the dialog. 9544 */ 9545 BAD_RETURN(s32) cutscene_intro_peach_dialog(struct Camera *c) { 9546 if (get_dialog_id() == DIALOG_NONE) { 9547 vec3f_copy(gLakituState.goalPos, c->pos); 9548 vec3f_copy(gLakituState.goalFocus, c->focus); 9549 sStatusFlags |= (CAM_FLAG_SMOOTH_MOVEMENT | CAM_FLAG_UNUSED_CUTSCENE_ACTIVE); 9550 gCutsceneTimer = CUTSCENE_STOP; 9551 c->cutscene = 0; 9552 } 9553 } 9554 9555 BAD_RETURN(s32) cutscene_intro_peach_follow_pipe_spline(struct Camera *c) { 9556 move_point_along_spline(c->pos, sIntroPipeToDialogPosition, &sCutsceneSplineSegment, &sCutsceneSplineSegmentProgress); 9557 move_point_along_spline(c->focus, sIntroPipeToDialogFocus, &sCutsceneSplineSegment, &sCutsceneSplineSegmentProgress); 9558 } 9559 9560 BAD_RETURN(s32) cutscene_intro_peach_clear_cutscene_status(UNUSED struct Camera *c) { 9561 sMarioCamState->cameraEvent = 0; 9562 } 9563 9564 /** 9565 * Set fov to 8 degrees, then zoom out to 30. 9566 */ 9567 BAD_RETURN(s32) cutscene_intro_peach_zoom_fov(UNUSED struct Camera *c) { 9568 sFOVState.fov = 8.f; 9569 set_fov_function(CAM_FOV_ZOOM_30); 9570 } 9571 9572 /** 9573 * Reset the spline progress, turn on handheld shake. 9574 */ 9575 BAD_RETURN(s32) cutscene_intro_peach_reset_spline(UNUSED struct Camera *c) { 9576 sCutsceneSplineSegment = 0; 9577 sCutsceneSplineSegmentProgress = 0.1f; 9578 //! @bug since this event is only called for one frame, this handheld shake is turned off on the 9579 //! next frame. 9580 set_handheld_shake(HAND_CAM_SHAKE_HIGH); 9581 } 9582 9583 /** 9584 * Turn off handheld shake. This was likely written before handheld shake was changed to turn off every 9585 * frame, as it's the only instance of HAND_CAM_SHAKE_OFF. 9586 */ 9587 BAD_RETURN(s32) cutscene_intro_peach_handheld_shake_off(UNUSED struct Camera *c) { 9588 set_handheld_shake(HAND_CAM_SHAKE_OFF); 9589 } 9590 9591 BAD_RETURN(s32) intro_pipe_exit_text(UNUSED struct Camera *c) { 9592 create_dialog_box(DIALOG_033); 9593 } 9594 9595 #ifndef VERSION_JP 9596 BAD_RETURN(s32) play_sound_intro_turn_on_hud(UNUSED struct Camera *c) { 9597 play_sound_rbutton_changed(); 9598 } 9599 #endif 9600 9601 /** 9602 * Fly to the pipe. Near the end, the camera jumps to Lakitu's position and the hud turns on. 9603 */ 9604 BAD_RETURN(s32) cutscene_intro_peach_fly_to_pipe(struct Camera *c) { 9605 #if defined(VERSION_US) || defined(VERSION_SH) || defined(VERSION_CN) 9606 cutscene_event(play_sound_intro_turn_on_hud, c, 818, 818); 9607 #elif defined(VERSION_EU) 9608 cutscene_event(play_sound_intro_turn_on_hud, c, 673, 673); 9609 #endif 9610 cutscene_spawn_obj(6, 1); 9611 cutscene_event(cutscene_intro_peach_start_flying_music, c, 0, 0); 9612 cutscene_event(cutscene_intro_peach_start_to_pipe_spline, c, 0, -1); 9613 #ifdef VERSION_EU 9614 cutscene_event(cutscene_intro_peach_clear_cutscene_status, c, 572, 572); 9615 #else 9616 cutscene_event(cutscene_intro_peach_clear_cutscene_status, c, 717, 717); 9617 #endif 9618 clamp_pitch(c->pos, c->focus, 0x3B00, -0x3B00); 9619 sCutsceneVars[1].point[1] = 400.f; 9620 } 9621 9622 /** 9623 * Lakitu flies around the warp pipe, then Mario jumps out. 9624 */ 9625 BAD_RETURN(s32) cutscene_intro_peach_mario_appears(struct Camera *c) { 9626 UNUSED u8 filler[8]; 9627 9628 sMarioCamState->cameraEvent = 0; 9629 cutscene_event(cutscene_intro_peach_reset_spline, c, 0, 0); 9630 cutscene_event(cutscene_intro_peach_follow_pipe_spline, c, 0, -1); 9631 cutscene_event(cutscene_intro_peach_handheld_shake_off, c, 70, 70); 9632 cutscene_event(intro_pipe_exit_text, c, 250, 250); 9633 9634 approach_f32_asymptotic_bool(&sCutsceneVars[1].point[1], 80.f + sMarioGeometry.currFloorHeight + 9635 (sMarioCamState->pos[1] - sMarioGeometry.currFloorHeight) * 1.1f, 0.4f); 9636 9637 // Make the camera look up as Mario jumps out of the pipe 9638 if (c->focus[1] < sCutsceneVars[1].point[1]) { 9639 c->focus[1] = sCutsceneVars[1].point[1]; 9640 } 9641 9642 sStatusFlags |= CAM_FLAG_UNUSED_CUTSCENE_ACTIVE; 9643 } 9644 9645 /** 9646 * Reset the fov. This gives the effect of peach zooming out as she fades. 9647 */ 9648 BAD_RETURN(s32) cutscene_intro_peach_reset_fov(UNUSED struct Camera *c) { 9649 set_fov_function(CAM_FOV_DEFAULT); 9650 } 9651 9652 /** 9653 * Peach reads the letter to Mario. 9654 */ 9655 BAD_RETURN(s32) cutscene_intro_peach_letter(struct Camera *c) { 9656 cutscene_spawn_obj(5, 0); 9657 cutscene_event(cutscene_intro_peach_zoom_fov, c, 0, 0); 9658 cutscene_event(cutscene_intro_peach_start_letter_music, c, 65, 65); 9659 #ifdef VERSION_EU 9660 cutscene_event(cutscene_intro_peach_eu_lower_volume, c, 68, 68); 9661 #endif 9662 cutscene_event(cutscene_intro_peach_start_to_pipe_spline, c, 0, 0); 9663 cutscene_event(peach_letter_text, c, 65, 65); 9664 #ifndef VERSION_JP 9665 cutscene_event(play_sound_peach_reading_letter, c, 83, 83); 9666 #endif 9667 9668 if ((gCutsceneTimer > 120) && (get_dialog_id() == DIALOG_NONE)) { 9669 // Start the next scene 9670 gCutsceneTimer = CUTSCENE_LOOP; 9671 } 9672 9673 clamp_pitch(c->pos, c->focus, 0x3B00, -0x3B00); 9674 } 9675 9676 /** 9677 * Reset the spline progress. 9678 */ 9679 BAD_RETURN(s32) cutscene_end_waving_start(UNUSED struct Camera *c) { 9680 cutscene_reset_spline(); 9681 } 9682 9683 // 3rd part of data 9684 struct CutsceneSplinePoint gIntroLakituStartToPipeFocus[] = { 9685 { 0, 32, { 58, -250, 346 } }, { 1, 50, { -159, -382, 224 } }, { 2, 37, { 0, -277, 237 } }, 9686 { 3, 15, { 1, -44, 245 } }, { 4, 35, { 0, -89, 228 } }, { 5, 15, { 28, 3, 259 } }, 9687 { 6, 25, { -38, -201, 371 } }, { 7, 20, { -642, 118, 652 } }, { 8, 25, { 103, -90, 861 } }, 9688 { 9, 25, { 294, 145, 579 } }, { 10, 30, { 220, -42, 500 } }, { 11, 20, { 10, -134, 200 } }, 9689 { 12, 20, { -143, -145, 351 } }, { 13, 14, { -256, -65, 528 } }, { 14, 20, { -251, -52, 459 } }, 9690 { 15, 25, { -382, 520, 395 } }, { 16, 25, { -341, 240, 653 } }, { 17, 5, { -262, 700, 143 } }, 9691 { 18, 15, { -760, 32, 27 } }, { 19, 20, { -756, -6, -26 } }, { 20, 20, { -613, 5, 424 } }, 9692 { 21, 20, { -22, -100, 312 } }, { 22, 25, { 212, 80, 61 } }, { 23, 20, { 230, -28, 230 } }, 9693 { 24, 35, { -83, -51, 303 } }, { 25, 17, { 126, 90, 640 } }, { 26, 9, { 158, 95, 763 } }, 9694 { 27, 8, { 113, -25, 1033 } }, { 28, 20, { 57, -53, 1291 } }, { 29, 15, { 73, -34, 1350 } }, 9695 { 30, 7, { 0, 96, 1400 } }, { 31, 8, { -59, 269, 1450 } }, { 32, 15, { 57, 1705, 1500 } }, 9696 { 0, 15, { -227, 511, 1550 } }, { -1, 15, { -227, 511, 1600 } } 9697 }; 9698 9699 struct CutsceneSplinePoint gIntroLakituStartToPipeOffsetFromCamera[] = { 9700 { 0, 0, { -46, 87, -15 } }, { 1, 0, { -38, 91, -11 } }, { 2, 0, { -31, 93, -13 } }, 9701 { 3, 0, { -50, 84, -16 } }, { 4, 0, { -52, 83, -17 } }, { 5, 0, { -10, 99, 3 } }, 9702 { 6, 0, { -54, 83, -10 } }, { 7, 0, { -31, 85, -40 } }, { 8, 0, { -34, 91, 19 } }, 9703 { 9, 0, { -9, 95, 28 } }, { 10, 0, { 17, 72, 66 } }, { 11, 0, { 88, -7, 45 } }, 9704 { 12, 0, { 96, -6, -26 } }, { 13, 0, { 56, -1, -82 } }, { 14, 0, { 40, 65, -63 } }, 9705 { 15, 0, { -26, -3, -96 } }, { 16, 0, { 92, 82, 19 } }, { 17, 0, { 92, 32, 19 } }, 9706 { 18, 0, { 92, 32, 19 } }, { 19, 0, { 92, 102, 19 } }, { 20, 0, { -69, 59, -70 } }, 9707 { 21, 0, { -77, 109, -61 } }, { 22, 0, { -87, 59, -46 } }, { 23, 0, { -99, -3, 11 } }, 9708 { 24, 0, { -99, -11, 5 } }, { 25, 0, { -97, -6, 19 } }, { 26, 0, { -97, 22, -7 } }, 9709 { 27, 0, { -98, -11, -13 } }, { 28, 0, { -97, -11, 19 } }, { 29, 0, { -91, -11, 38 } }, 9710 { 30, 0, { -76, -11, 63 } }, { 31, 0, { -13, 33, 93 } }, { 32, 0, { 51, -11, 84 } }, 9711 { 33, 0, { 51, -11, 84 } }, { -1, 0, { 51, -11, 84 } } 9712 }; 9713 9714 struct CutsceneSplinePoint gEndWavingPos[] = { 9715 { 0, 0, { -5, 975, -917 } }, { 0, 0, { -5, 975, -917 } }, { 0, 0, { -5, 975, -917 } }, 9716 { 0, 0, { -76, 1067, 742 } }, { 0, 0, { -105, 1576, 3240 } }, { 0, 0, { -177, 1709, 5586 } }, 9717 { 0, 0, { -177, 1709, 5586 } }, { 0, 0, { -177, 1709, 5586 } }, { 0, 0, { -177, 1709, 5586 } } 9718 }; 9719 9720 struct CutsceneSplinePoint gEndWavingFocus[] = { 9721 { 0, 50, { 18, 1013, -1415 } }, { 0, 100, { 17, 1037, -1412 } }, { 0, 100, { 16, 1061, -1408 } }, 9722 { 0, 100, { -54, 1053, 243 } }, { 0, 100, { -84, 1575, 2740 } }, { 0, 50, { -156, 1718, 5086 } }, 9723 { 0, 0, { -156, 1718, 5086 } }, { 0, 0, { -156, 1718, 5086 } }, { 0, 0, { -156, 1718, 5086 } } 9724 }; 9725 9726 BAD_RETURN(s32) cutscene_end_waving(struct Camera *c) { 9727 cutscene_event(cutscene_end_waving_start, c, 0, 0); 9728 move_point_along_spline(c->pos, gEndWavingPos, &sCutsceneSplineSegment, &sCutsceneSplineSegmentProgress); 9729 move_point_along_spline(c->focus, gEndWavingFocus, &sCutsceneSplineSegment, &sCutsceneSplineSegmentProgress); 9730 cutscene_spawn_obj(6, 120); 9731 } 9732 9733 /** 9734 * Called on the first frame of the credits. Resets the spline progress. 9735 */ 9736 BAD_RETURN(s32) cutscene_credits_reset_spline(UNUSED struct Camera *c) { 9737 cutscene_reset_spline(); 9738 } 9739 9740 extern struct CutsceneSplinePoint sBoBCreditsSplinePositions[]; 9741 extern struct CutsceneSplinePoint sBoBCreditsSplineFocus[]; 9742 extern struct CutsceneSplinePoint sWFCreditsSplinePositions[]; 9743 extern struct CutsceneSplinePoint sWFCreditsSplineFocus[]; 9744 extern struct CutsceneSplinePoint sJRBCreditsSplinePositions[]; 9745 extern struct CutsceneSplinePoint sJRBCreditsSplineFocus[]; 9746 extern struct CutsceneSplinePoint sCCMSlideCreditsSplinePositions[]; 9747 extern struct CutsceneSplinePoint sCCMSlideCreditsSplineFocus[]; 9748 extern struct CutsceneSplinePoint sBBHCreditsSplinePositions[]; 9749 extern struct CutsceneSplinePoint sBBHCreditsSplineFocus[]; 9750 extern struct CutsceneSplinePoint sHMCCreditsSplinePositions[]; 9751 extern struct CutsceneSplinePoint sHMCCreditsSplineFocus[]; 9752 extern struct CutsceneSplinePoint sTHIWigglerCreditsSplinePositions[]; 9753 extern struct CutsceneSplinePoint sTHIWigglerCreditsSplineFocus[]; 9754 extern struct CutsceneSplinePoint sVolcanoCreditsSplinePositions[]; 9755 extern struct CutsceneSplinePoint sVolcanoCreditsSplineFocus[]; 9756 extern struct CutsceneSplinePoint sSSLCreditsSplinePositions[]; 9757 extern struct CutsceneSplinePoint sSSLCreditsSplineFocus[]; 9758 extern struct CutsceneSplinePoint sDDDCreditsSplinePositions[]; 9759 extern struct CutsceneSplinePoint sDDDCreditsSplineFocus[]; 9760 extern struct CutsceneSplinePoint sSLCreditsSplinePositions[]; 9761 extern struct CutsceneSplinePoint sSLCreditsSplineFocus[]; 9762 extern struct CutsceneSplinePoint sWDWCreditsSplinePositions[]; 9763 extern struct CutsceneSplinePoint sWDWCreditsSplineFocus[]; 9764 extern struct CutsceneSplinePoint sTTMCreditsSplinePositions[]; 9765 extern struct CutsceneSplinePoint sTTMCreditsSplineFocus[]; 9766 extern struct CutsceneSplinePoint sTHIHugeCreditsSplinePositions[]; 9767 extern struct CutsceneSplinePoint sTHIHugeCreditsSplineFocus[]; 9768 extern struct CutsceneSplinePoint sTTCCreditsSplinePositions[]; 9769 extern struct CutsceneSplinePoint sTTCCreditsSplineFocus[]; 9770 extern struct CutsceneSplinePoint sRRCreditsSplinePositions[]; 9771 extern struct CutsceneSplinePoint sRRCreditsSplineFocus[]; 9772 extern struct CutsceneSplinePoint sSACreditsSplinePositions[]; 9773 extern struct CutsceneSplinePoint sSACreditsSplineFocus[]; 9774 extern struct CutsceneSplinePoint sCotMCCreditsSplinePositions[]; 9775 extern struct CutsceneSplinePoint sCotMCCreditsSplineFocus[]; 9776 extern struct CutsceneSplinePoint sDDDSubCreditsSplinePositions[]; 9777 extern struct CutsceneSplinePoint sDDDSubCreditsSplineFocus[]; 9778 extern struct CutsceneSplinePoint sCCMOutsideCreditsSplinePositions[]; 9779 extern struct CutsceneSplinePoint sCCMOutsideCreditsSplineFocus[]; 9780 9781 /** 9782 * Follow splines through the courses of the game. 9783 */ 9784 BAD_RETURN(s32) cutscene_credits(struct Camera *c) { 9785 struct CutsceneSplinePoint *focus, *pos; 9786 9787 cutscene_event(cutscene_credits_reset_spline, c, 0, 0); 9788 9789 switch (gCurrLevelArea) { 9790 case AREA_BOB: 9791 pos = sBoBCreditsSplinePositions; 9792 focus = sBoBCreditsSplineFocus; 9793 break; 9794 case AREA_WF: 9795 pos = sWFCreditsSplinePositions; 9796 focus = sWFCreditsSplineFocus; 9797 break; 9798 case AREA_JRB_MAIN: 9799 pos = sJRBCreditsSplinePositions; 9800 focus = sJRBCreditsSplineFocus; 9801 break; 9802 case AREA_CCM_SLIDE: 9803 pos = sCCMSlideCreditsSplinePositions; 9804 focus = sCCMSlideCreditsSplineFocus; 9805 break; 9806 case AREA_BBH: 9807 pos = sBBHCreditsSplinePositions; 9808 focus = sBBHCreditsSplineFocus; 9809 break; 9810 case AREA_HMC: 9811 pos = sHMCCreditsSplinePositions; 9812 focus = sHMCCreditsSplineFocus; 9813 break; 9814 case AREA_THI_WIGGLER: 9815 pos = sTHIWigglerCreditsSplinePositions; 9816 focus = sTHIWigglerCreditsSplineFocus; 9817 break; 9818 case AREA_LLL_VOLCANO: 9819 pos = sVolcanoCreditsSplinePositions; 9820 focus = sVolcanoCreditsSplineFocus; 9821 break; 9822 case AREA_SSL_OUTSIDE: 9823 pos = sSSLCreditsSplinePositions; 9824 focus = sSSLCreditsSplineFocus; 9825 break; 9826 case AREA_DDD_WHIRLPOOL: 9827 pos = sDDDCreditsSplinePositions; 9828 focus = sDDDCreditsSplineFocus; 9829 break; 9830 case AREA_SL_OUTSIDE: 9831 pos = sSLCreditsSplinePositions; 9832 focus = sSLCreditsSplineFocus; 9833 break; 9834 case AREA_WDW_MAIN: 9835 pos = sWDWCreditsSplinePositions; 9836 focus = sWDWCreditsSplineFocus; 9837 break; 9838 case AREA_TTM_OUTSIDE: 9839 pos = sTTMCreditsSplinePositions; 9840 focus = sTTMCreditsSplineFocus; 9841 break; 9842 case AREA_THI_HUGE: 9843 pos = sTHIHugeCreditsSplinePositions; 9844 focus = sTHIHugeCreditsSplineFocus; 9845 break; 9846 case AREA_TTC: 9847 pos = sTTCCreditsSplinePositions; 9848 focus = sTTCCreditsSplineFocus; 9849 break; 9850 case AREA_RR: 9851 pos = sRRCreditsSplinePositions; 9852 focus = sRRCreditsSplineFocus; 9853 break; 9854 case AREA_SA: 9855 pos = sSACreditsSplinePositions; 9856 focus = sSACreditsSplineFocus; 9857 break; 9858 case AREA_COTMC: 9859 pos = sCotMCCreditsSplinePositions; 9860 focus = sCotMCCreditsSplineFocus; 9861 break; 9862 case AREA_DDD_SUB: 9863 pos = sDDDSubCreditsSplinePositions; 9864 focus = sDDDSubCreditsSplineFocus; 9865 break; 9866 case AREA_CCM_OUTSIDE: 9867 //! Checks if the "Snowman's Lost His Head" star was collected. The credits likely would 9868 //! have avoided the snowman if the player didn't collect that star, but in the end the 9869 //! developers decided against it. 9870 if (save_file_get_star_flags(gCurrSaveFileNum - 1, COURSE_NUM_TO_INDEX(gCurrCourseNum)) & (1 << 4)) { 9871 pos = sCCMOutsideCreditsSplinePositions; 9872 focus = sCCMOutsideCreditsSplineFocus; 9873 } else { 9874 pos = sCCMOutsideCreditsSplinePositions; 9875 focus = sCCMOutsideCreditsSplineFocus; 9876 } 9877 break; 9878 default: 9879 pos = sCCMOutsideCreditsSplinePositions; 9880 focus = sCCMOutsideCreditsSplineFocus; 9881 } 9882 9883 copy_spline_segment(sCurCreditsSplinePos, pos); 9884 copy_spline_segment(sCurCreditsSplineFocus, focus); 9885 move_point_along_spline(c->pos, sCurCreditsSplinePos, &sCutsceneSplineSegment, &sCutsceneSplineSegmentProgress); 9886 move_point_along_spline(c->focus, sCurCreditsSplineFocus, &sCutsceneSplineSegment, &sCutsceneSplineSegmentProgress); 9887 player2_rotate_cam(c, -0x2000, 0x2000, -0x4000, 0x4000); 9888 } 9889 9890 /** 9891 * Set the camera pos relative to Mario. 9892 */ 9893 BAD_RETURN(s32) cutscene_sliding_doors_open_start(struct Camera *c) { 9894 f32 dist; 9895 s16 pitch, yaw; 9896 9897 vec3f_get_dist_and_angle(sMarioCamState->pos, c->pos, &dist, &pitch, &yaw); 9898 9899 // If the camera is too close, warp it backwards set it to a better angle. 9900 if (dist < 500.f) { 9901 dist = 500.f; 9902 yaw = sMarioCamState->faceAngle[1] + 0x8800; 9903 pitch = 0x800; 9904 } 9905 9906 vec3f_set_dist_and_angle(sMarioCamState->pos, c->pos, dist, pitch, yaw); 9907 } 9908 9909 /** 9910 * cvar1: Mario's position 9911 * cvar0.angle: Mario's angle 9912 * cvar0.point: offset from Mario 9913 */ 9914 BAD_RETURN(s32) cutscene_sliding_doors_open_set_cvars(UNUSED struct Camera *c) { 9915 vec3f_copy(sCutsceneVars[1].point, sMarioCamState->pos); 9916 vec3s_copy(sCutsceneVars[0].angle, sMarioCamState->faceAngle); 9917 vec3f_set(sCutsceneVars[0].point, 80.f, 325.f, 200.f); 9918 } 9919 9920 /** 9921 * Decrease the cvar0 y offset to 75, which would simulate Lakitu flying under the doorway. 9922 * However, the initial y offset is too high for Lakitu to reach 75 in time. 9923 */ 9924 BAD_RETURN(s32) cutscene_sliding_doors_go_under_doorway(UNUSED struct Camera *c) { 9925 camera_approach_f32_symmetric_bool(&sCutsceneVars[0].point[1], 75.f, 10.f); 9926 } 9927 9928 /** 9929 * Approach a y offset of 125 again. 9930 */ 9931 BAD_RETURN(s32) cutscene_sliding_doors_fly_back_up(UNUSED struct Camera *c) { 9932 camera_approach_f32_symmetric_bool(&sCutsceneVars[0].point[1], 125.f, 10.f); 9933 } 9934 9935 /** 9936 * Follow Mario through the door, by approaching cvar1.point. 9937 */ 9938 BAD_RETURN(s32) cutscene_sliding_doors_follow_mario(struct Camera *c) { 9939 Vec3f pos; 9940 UNUSED u8 filler[20]; 9941 9942 vec3f_copy(pos, c->pos); 9943 // Update cvar1 with Mario's position (the y value doesn't change) 9944 sCutsceneVars[1].point[0] = sMarioCamState->pos[0]; 9945 sCutsceneVars[1].point[2] = sMarioCamState->pos[2]; 9946 9947 // Decrease cvar0's offsets, moving the camera behind Mario at his eye height. 9948 approach_f32_asymptotic_bool(&sCutsceneVars[0].point[0], 0, 0.1f); 9949 camera_approach_f32_symmetric_bool(&sCutsceneVars[0].point[2], 125.f, 50.f); 9950 // Update cvar0's angle 9951 approach_vec3s_asymptotic(sCutsceneVars[0].angle, sMarioCamState->faceAngle, 16, 16, 16); 9952 9953 // Apply the offset to the camera's position 9954 offset_rotated(pos, sCutsceneVars[1].point, sCutsceneVars[0].point, sCutsceneVars[0].angle); 9955 approach_vec3f_asymptotic(c->pos, pos, 0.15f, 0.05f, 0.15f); 9956 9957 // Focus on Mario's eye height 9958 set_focus_rel_mario(c, 0, 125.f, 0, 0); 9959 } 9960 9961 /** 9962 * Plays when Mario opens the sliding doors. 9963 * Note: the star door unlocking event is not a cutscene, it's handled by Mario separately. 9964 */ 9965 BAD_RETURN(s32) cutscene_sliding_doors_open(struct Camera *c) { 9966 UNUSED u8 filler[8]; 9967 9968 reset_pan_distance(c); 9969 cutscene_event(cutscene_sliding_doors_open_start, c, 0, 8); 9970 cutscene_event(cutscene_sliding_doors_open_set_cvars, c, 8, 8); 9971 cutscene_event(cutscene_sliding_doors_go_under_doorway, c, 8, 28); 9972 cutscene_event(cutscene_sliding_doors_fly_back_up, c, 29, -1); 9973 cutscene_event(cutscene_sliding_doors_follow_mario, c, 8, -1); 9974 } 9975 9976 /** 9977 * Ends the double door cutscene. 9978 */ 9979 BAD_RETURN(s32) cutscene_double_doors_end(struct Camera *c) { 9980 set_flag_post_door(c); 9981 c->cutscene = 0; 9982 sStatusFlags |= CAM_FLAG_SMOOTH_MOVEMENT; 9983 } 9984 9985 BAD_RETURN(s32) cutscene_enter_painting_stub(UNUSED struct Camera *c) { 9986 } 9987 9988 /** 9989 * Plays when Mario enters a painting. The camera flies up to the painting's center, then it slowly 9990 * zooms in until the star select screen appears. 9991 */ 9992 BAD_RETURN(s32) cutscene_enter_painting(struct Camera *c) { 9993 struct Surface *floor, *highFloor; 9994 Vec3f paintingPos, focus, focusOffset; 9995 Vec3s paintingAngle; 9996 f32 floorHeight; 9997 9998 cutscene_event(cutscene_enter_painting_stub, c, 0, 0); 9999 // Zoom in 10000 set_fov_function(CAM_FOV_APP_20); 10001 sStatusFlags |= CAM_FLAG_SMOOTH_MOVEMENT; 10002 10003 if (gRipplingPainting != NULL) { 10004 paintingAngle[0] = 0; 10005 paintingAngle[1] = (s32)((gRipplingPainting->yaw / 360.f) * 65536.f); // convert degrees to IAU 10006 paintingAngle[2] = 0; 10007 10008 focusOffset[0] = gRipplingPainting->size / 2; 10009 focusOffset[1] = focusOffset[0]; 10010 focusOffset[2] = 0; 10011 10012 paintingPos[0] = gRipplingPainting->posX; 10013 paintingPos[1] = gRipplingPainting->posY; 10014 paintingPos[2] = gRipplingPainting->posZ; 10015 10016 offset_rotated(focus, paintingPos, focusOffset, paintingAngle); 10017 approach_vec3f_asymptotic(c->focus, focus, 0.1f, 0.1f, 0.1f); 10018 focusOffset[2] = -(((gRipplingPainting->size * 1000.f) / 2) / 307.f); 10019 offset_rotated(focus, paintingPos, focusOffset, paintingAngle); 10020 floorHeight = find_floor(focus[0], focus[1] + 500.f, focus[2], &highFloor) + 125.f; 10021 10022 if (focus[1] < floorHeight) { 10023 focus[1] = floorHeight; 10024 } 10025 10026 if (c->cutscene == CUTSCENE_ENTER_PAINTING) { 10027 approach_vec3f_asymptotic(c->pos, focus, 0.2f, 0.1f, 0.2f); 10028 } else { 10029 approach_vec3f_asymptotic(c->pos, focus, 0.9f, 0.9f, 0.9f); 10030 } 10031 10032 find_floor(sMarioCamState->pos[0], sMarioCamState->pos[1] + 50.f, sMarioCamState->pos[2], &floor); 10033 10034 if ((floor->type < SURFACE_PAINTING_WOBBLE_A6) || (floor->type > SURFACE_PAINTING_WARP_F9)) { 10035 c->cutscene = 0; 10036 gCutsceneTimer = CUTSCENE_STOP; 10037 sStatusFlags |= CAM_FLAG_SMOOTH_MOVEMENT; 10038 } 10039 } 10040 c->mode = CAMERA_MODE_CLOSE; 10041 } 10042 10043 /** 10044 * Warp the camera to Mario, then use his faceAngle to calculate the right relative position. 10045 * 10046 * cvar0.point is Mario's position 10047 * cvar0.angle is Mario's faceAngle 10048 * 10049 * cvar1 is the camera's position relative to Mario 10050 * cvar2 is the camera's focus relative to Mario 10051 */ 10052 BAD_RETURN(s32) cutscene_exit_painting_start(struct Camera *c) { 10053 struct Surface *floor; 10054 f32 floorHeight; 10055 10056 vec3f_set(sCutsceneVars[2].point, 258.f, -352.f, 1189.f); 10057 vec3f_set(sCutsceneVars[1].point, 65.f, -155.f, 444.f); 10058 10059 if (gPrevLevel == LEVEL_TTM) { 10060 sCutsceneVars[1].point[1] = 0.f; 10061 sCutsceneVars[1].point[2] = 0.f; 10062 } 10063 vec3f_copy(sCutsceneVars[0].point, sMarioCamState->pos); 10064 sCutsceneVars[0].angle[0] = 0; 10065 sCutsceneVars[0].angle[1] = sMarioCamState->faceAngle[1]; 10066 sCutsceneVars[0].angle[2] = 0; 10067 offset_rotated(c->focus, sCutsceneVars[0].point, sCutsceneVars[1].point, sCutsceneVars[0].angle); 10068 offset_rotated(c->pos, sCutsceneVars[0].point, sCutsceneVars[2].point, sCutsceneVars[0].angle); 10069 floorHeight = find_floor(c->pos[0], c->pos[1] + 10.f, c->pos[2], &floor); 10070 10071 if (floorHeight != FLOOR_LOWER_LIMIT) { 10072 if (c->pos[1] < (floorHeight += 60.f)) { 10073 c->pos[1] = floorHeight; 10074 } 10075 } 10076 } 10077 10078 /** 10079 * Decrease cvar2's x and z offset, moving closer to Mario. 10080 */ 10081 BAD_RETURN(s32) cutscene_exit_painting_move_to_mario(struct Camera *c) { 10082 Vec3f pos; 10083 10084 //! Tricky math: Since offset_rotated() flips Z offsets, you'd expect a positive Z offset to move 10085 //! the camera into the wall. However, Mario's faceAngle always points into the painting, so a 10086 //! positive Z offset moves the camera "behind" Mario, away from the painting. 10087 //! 10088 //! In the success cutscene, when Mario jumps out face-first, only his gfx angle is updated. His 10089 //! actual face angle isn't updated until after the cutscene. 10090 approach_f32_asymptotic_bool(&sCutsceneVars[2].point[0], 178.f, 0.05f); 10091 approach_f32_asymptotic_bool(&sCutsceneVars[2].point[2], 889.f, 0.05f); 10092 offset_rotated(pos, sCutsceneVars[0].point, sCutsceneVars[2].point, sCutsceneVars[0].angle); 10093 c->pos[0] = pos[0]; 10094 c->pos[2] = pos[2]; 10095 } 10096 10097 /** 10098 * Move the camera down to the floor Mario lands on. 10099 */ 10100 BAD_RETURN(s32) cutscene_exit_painting_move_to_floor(struct Camera *c) { 10101 struct Surface *floor; 10102 Vec3f floorHeight; 10103 10104 vec3f_copy(floorHeight, sMarioCamState->pos); 10105 floorHeight[1] = find_floor(sMarioCamState->pos[0], sMarioCamState->pos[1] + 10.f, sMarioCamState->pos[2], &floor); 10106 10107 if (floor != NULL) { 10108 floorHeight[1] = floorHeight[1] + (sMarioCamState->pos[1] - floorHeight[1]) * 0.7f + 125.f; 10109 approach_vec3f_asymptotic(c->focus, floorHeight, 0.2f, 0.2f, 0.2f); 10110 10111 if (floorHeight[1] < c->pos[1]) { 10112 approach_f32_asymptotic_bool(&c->pos[1], floorHeight[1], 0.05f); 10113 } 10114 } 10115 } 10116 10117 /** 10118 * Cutscene played when Mario leaves a painting, either due to death or collecting a star. 10119 */ 10120 BAD_RETURN(s32) cutscene_exit_painting(struct Camera *c) { 10121 cutscene_event(cutscene_exit_painting_start, c, 0, 0); 10122 cutscene_event(cutscene_exit_painting_move_to_mario, c, 5, -1); 10123 cutscene_event(cutscene_exit_painting_move_to_floor, c, 5, -1); 10124 10125 //! Hardcoded position. TTM's painting is close to an opposite wall, so just fix the pos. 10126 if (gPrevLevel == LEVEL_TTM) { 10127 vec3f_set(c->pos, -296.f, 1261.f, 3521.f); 10128 } 10129 10130 update_camera_yaw(c); 10131 } 10132 10133 /** 10134 * Unused. Warp the camera to Mario. 10135 */ 10136 BAD_RETURN(s32) cutscene_unused_exit_start(struct Camera *c) { 10137 UNUSED u8 filler[18]; 10138 Vec3f offset; 10139 Vec3s marioAngle; 10140 10141 vec3f_set(offset, 200.f, 300.f, 200.f); 10142 vec3s_set(marioAngle, 0, sMarioCamState->faceAngle[1], 0); 10143 offset_rotated(c->pos, sMarioCamState->pos, offset, marioAngle); 10144 set_focus_rel_mario(c, 0.f, 125.f, 0.f, 0); 10145 } 10146 10147 /** 10148 * Unused. Focus on Mario as he exits. 10149 */ 10150 BAD_RETURN(s32) cutscene_unused_exit_focus_mario(struct Camera *c) { 10151 Vec3f focus; 10152 10153 vec3f_set(focus, sMarioCamState->pos[0], sMarioCamState->pos[1] + 125.f, sMarioCamState->pos[2]); 10154 set_focus_rel_mario(c, 0.f, 125.f, 0.f, 0); 10155 approach_vec3f_asymptotic(c->focus, focus, 0.02f, 0.001f, 0.02f); 10156 update_camera_yaw(c); 10157 } 10158 10159 /** 10160 * Give control back to the player. 10161 */ 10162 BAD_RETURN(s32) cutscene_exit_painting_end(struct Camera *c) { 10163 c->mode = CAMERA_MODE_CLOSE; 10164 c->cutscene = 0; 10165 gCutsceneTimer = CUTSCENE_STOP; 10166 sStatusFlags |= CAM_FLAG_SMOOTH_MOVEMENT; 10167 sStatusFlags &= ~CAM_FLAG_BLOCK_SMOOTH_MOVEMENT; 10168 update_camera_yaw(c); 10169 } 10170 10171 /** 10172 * End the cutscene, starting cannon mode. 10173 */ 10174 BAD_RETURN(s32) cutscene_enter_cannon_end(struct Camera *c) { 10175 sStatusFlags &= ~CAM_FLAG_SMOOTH_MOVEMENT; 10176 sStatusFlags |= CAM_FLAG_BLOCK_SMOOTH_MOVEMENT; 10177 c->mode = CAMERA_MODE_INSIDE_CANNON; 10178 c->cutscene = 0; 10179 sCannonYOffset = 800.f; 10180 } 10181 10182 /** 10183 * Rotate around the cannon as it rises out of the hole. 10184 */ 10185 BAD_RETURN(s32) cutscene_enter_cannon_raise(struct Camera *c) { 10186 struct Object *o; 10187 UNUSED u8 filler[8]; 10188 f32 floorHeight; 10189 struct Surface *floor; 10190 Vec3f cannonFocus; 10191 Vec3s cannonAngle; 10192 10193 // Shake the camera when the cannon is fully raised 10194 cutscene_event(cutscene_shake_explosion, c, 70, 70); 10195 sStatusFlags |= CAM_FLAG_SMOOTH_MOVEMENT; 10196 camera_approach_s16_symmetric_bool(&sCutsceneVars[1].angle[0], 0, 0x80); 10197 camera_approach_s16_symmetric_bool(&sCutsceneVars[2].angle[0], 0, 0x80); 10198 // Move the camera around the cannon, gradually rotating and moving closer 10199 vec3f_set_dist_and_angle(sCutsceneVars[0].point, c->pos, sCutsceneVars[1].point[2], sCutsceneVars[1].angle[0], 10200 sCutsceneVars[1].angle[1]); 10201 sCutsceneVars[1].point[2] = approach_f32(sCutsceneVars[1].point[2], 400.f, 5.f, 5.f); 10202 sCutsceneVars[1].angle[1] += 0x40; 10203 sCutsceneVars[3].point[1] += 2.f; 10204 c->pos[1] += sCutsceneVars[3].point[1]; 10205 10206 if ((o = sMarioCamState->usedObj) != NULL) { 10207 sCutsceneVars[0].point[1] = o->oPosY; 10208 cannonAngle[0] = o->oMoveAnglePitch; 10209 cannonAngle[1] = o->oMoveAngleYaw; 10210 cannonAngle[2] = o->oMoveAngleRoll; 10211 c->focus[0] = o->oPosX; 10212 c->focus[1] = o->oPosY; 10213 c->focus[2] = o->oPosZ; 10214 cannonFocus[0] = 0.f; 10215 cannonFocus[1] = 100.f; 10216 cannonFocus[2] = 0.f; 10217 offset_rotated(c->focus, c->focus, cannonFocus, cannonAngle); 10218 } 10219 10220 floorHeight = find_floor(c->pos[0], c->pos[1] + 500.f, c->pos[2], &floor) + 100.f; 10221 10222 if (c->pos[1] < floorHeight) { 10223 c->pos[1] = floorHeight; 10224 } 10225 } 10226 10227 /** 10228 * Start the cannon entering cutscene 10229 */ 10230 BAD_RETURN(s32) cutscene_enter_cannon_start(struct Camera *c) { 10231 UNUSED u8 filler[8]; // cvar3Start, cvar4Start? 10232 struct Object *o; 10233 10234 sStatusFlags |= CAM_FLAG_SMOOTH_MOVEMENT; 10235 sMarioCamState->cameraEvent = 0; 10236 10237 // Store the cannon's position and angle in cvar0 10238 if ((o = sMarioCamState->usedObj) != NULL) { 10239 sCutsceneVars[0].point[0] = o->oPosX; 10240 sCutsceneVars[0].point[1] = o->oPosY; 10241 sCutsceneVars[0].point[2] = o->oPosZ; 10242 sCutsceneVars[0].angle[0] = o->oMoveAnglePitch; 10243 sCutsceneVars[0].angle[1] = o->oMoveAngleYaw; 10244 sCutsceneVars[0].angle[2] = o->oMoveAngleRoll; 10245 } 10246 10247 // Store the camera's polar offset from the cannon in cvar1 10248 vec3f_get_dist_and_angle(sCutsceneVars[0].point, c->pos, &sCutsceneVars[1].point[2], 10249 &sCutsceneVars[1].angle[0], &sCutsceneVars[1].angle[1]); 10250 sCutsceneVars[3].point[1] = 0.f; 10251 //! cvar4 is unused in this cutscene 10252 sCutsceneVars[4].point[1] = 0.f; 10253 } 10254 10255 /** 10256 * Store the camera's pos and focus for the door cutscene 10257 */ 10258 BAD_RETURN(s32) cutscene_door_start(struct Camera *c) { 10259 vec3f_copy(sCutsceneVars[0].point, c->pos); 10260 vec3f_copy(sCutsceneVars[1].point, c->focus); 10261 } 10262 10263 /** 10264 * Fix the camera in place while the door opens. 10265 */ 10266 BAD_RETURN(s32) cutscene_door_fix_cam(struct Camera *c) { 10267 vec3f_copy(c->pos, sCutsceneVars[0].point); 10268 vec3f_copy(c->focus, sCutsceneVars[1].point); 10269 } 10270 10271 /** 10272 * Loop until Mario is no longer using the door. 10273 */ 10274 BAD_RETURN(s32) cutscene_door_loop(struct Camera *c) { 10275 //! bitwise AND instead of boolean 10276 if ((sMarioCamState->action != ACT_PULLING_DOOR) & (sMarioCamState->action != ACT_PUSHING_DOOR)) { 10277 gCutsceneTimer = CUTSCENE_STOP; 10278 c->cutscene = 0; 10279 } 10280 } 10281 10282 /** 10283 * Warp the camera behind Mario. 10284 */ 10285 BAD_RETURN(s32) cutscene_door_move_behind_mario(struct Camera *c) { 10286 Vec3f camOffset; 10287 s16 doorRotation; 10288 10289 reset_pan_distance(c); 10290 determine_pushing_or_pulling_door(&doorRotation); 10291 set_focus_rel_mario(c, 0.f, 125.f, 0.f, 0); 10292 vec3s_set(sCutsceneVars[0].angle, 0, sMarioCamState->faceAngle[1] + doorRotation, 0); 10293 vec3f_set(camOffset, 0.f, 125.f, 250.f); 10294 10295 if (doorRotation == 0) { //! useless code 10296 camOffset[0] = 0.f; 10297 } else { 10298 camOffset[0] = 0.f; 10299 } 10300 10301 offset_rotated(c->pos, sMarioCamState->pos, camOffset, sCutsceneVars[0].angle); 10302 } 10303 10304 /** 10305 * Follow Mario through the door. 10306 */ 10307 BAD_RETURN(s32) cutscene_door_follow_mario(struct Camera *c) { 10308 s16 pitch, yaw; 10309 f32 dist; 10310 10311 set_focus_rel_mario(c, 0.f, 125.f, 0.f, 0); 10312 vec3f_get_dist_and_angle(c->focus, c->pos, &dist, &pitch, &yaw); 10313 camera_approach_f32_symmetric_bool(&dist, 150.f, 7.f); 10314 vec3f_set_dist_and_angle(c->focus, c->pos, dist, pitch, yaw); 10315 update_camera_yaw(c); 10316 } 10317 10318 /** 10319 * Ends the door cutscene. Sets the camera mode to close mode unless the default is free roam. 10320 */ 10321 BAD_RETURN(s32) cutscene_door_end(struct Camera *c) { 10322 if (c->defMode == CAMERA_MODE_FREE_ROAM) { 10323 c->mode = CAMERA_MODE_FREE_ROAM; 10324 } else { 10325 c->mode = CAMERA_MODE_CLOSE; 10326 } 10327 10328 c->cutscene = 0; 10329 gCutsceneTimer = CUTSCENE_STOP; 10330 sStatusFlags |= CAM_FLAG_SMOOTH_MOVEMENT; 10331 sStatusFlags &= ~CAM_FLAG_BLOCK_SMOOTH_MOVEMENT; 10332 set_flag_post_door(c); 10333 update_camera_yaw(c); 10334 } 10335 10336 /** 10337 * Used for entering a room that uses a specific camera mode, like the castle lobby or BBH 10338 */ 10339 BAD_RETURN(s32) cutscene_door_mode(struct Camera *c) { 10340 UNUSED u8 filler[8]; 10341 10342 reset_pan_distance(c); 10343 camera_course_processing(c); 10344 10345 if (c->mode == CAMERA_MODE_FIXED) { 10346 c->nextYaw = update_fixed_camera(c, c->focus, c->pos); 10347 } 10348 if (c->mode == CAMERA_MODE_PARALLEL_TRACKING) { 10349 c->nextYaw = update_parallel_tracking_camera(c, c->focus, c->pos); 10350 } 10351 10352 c->yaw = c->nextYaw; 10353 10354 // Loop until Mario is no longer using the door 10355 if (sMarioCamState->action != ACT_ENTERING_STAR_DOOR && 10356 sMarioCamState->action != ACT_PULLING_DOOR && 10357 sMarioCamState->action != ACT_PUSHING_DOOR) { 10358 gCutsceneTimer = CUTSCENE_STOP; 10359 c->cutscene = 0; 10360 } 10361 } 10362 10363 /****************************************************************************************************** 10364 * Cutscenes 10365 ******************************************************************************************************/ 10366 10367 /** 10368 * Cutscene that plays when Mario beats the game. 10369 */ 10370 struct Cutscene sCutsceneEnding[] = { 10371 { cutscene_ending_mario_fall, 170 }, 10372 { cutscene_ending_mario_land, 70 }, 10373 #ifdef VERSION_EU 10374 { cutscene_ending_mario_land_closeup, 0x44 }, 10375 { cutscene_ending_stars_free_peach, 0x15c }, 10376 { cutscene_ending_peach_appears, 0x6d }, 10377 { cutscene_ending_peach_descends, 0x212 }, 10378 { cutscene_ending_mario_to_peach, 0x69 }, 10379 { cutscene_ending_peach_wakeup, 0x1a4 }, 10380 { cutscene_ending_dialog, 0x114 }, 10381 { cutscene_ending_kiss, 0x10b }, 10382 #else 10383 { cutscene_ending_mario_land_closeup, 75 }, 10384 #if defined(VERSION_SH) || defined(VERSION_CN) 10385 { cutscene_ending_stars_free_peach, 431 }, 10386 #else 10387 { cutscene_ending_stars_free_peach, 386 }, 10388 #endif 10389 { cutscene_ending_peach_appears, 139 }, 10390 { cutscene_ending_peach_descends, 590 }, 10391 { cutscene_ending_mario_to_peach, 95 }, 10392 #if defined(VERSION_SH) || defined(VERSION_CN) 10393 { cutscene_ending_peach_wakeup, 455 }, 10394 { cutscene_ending_dialog, 286 }, 10395 #else 10396 { cutscene_ending_peach_wakeup, 425 }, 10397 { cutscene_ending_dialog, 236 }, 10398 #endif 10399 { cutscene_ending_kiss, 245 }, 10400 #endif 10401 { cutscene_ending_cake_for_mario, CUTSCENE_LOOP }, 10402 { cutscene_ending_stop, 0 } 10403 }; 10404 10405 /** 10406 * Cutscene that plays when Mario collects the grand star from bowser. 10407 */ 10408 struct Cutscene sCutsceneGrandStar[] = { 10409 { cutscene_grand_star, 360 }, 10410 { cutscene_grand_star_fly, CUTSCENE_LOOP } 10411 }; 10412 10413 struct Cutscene sCutsceneUnused[] = { 10414 { cutscene_unused_start, 1 }, 10415 { cutscene_unused_loop, CUTSCENE_LOOP } 10416 }; 10417 10418 /** 10419 * Cutscene that plays when Mario enters a door that warps to another area. 10420 */ 10421 struct Cutscene sCutsceneDoorWarp[] = { 10422 { cutscene_door_start, 1 }, 10423 { cutscene_door_loop, CUTSCENE_LOOP } 10424 }; 10425 10426 /** 10427 * Cutscene that plays after the credits, when Lakitu is flying away from the castle. 10428 */ 10429 struct Cutscene sCutsceneEndWaving[] = { 10430 { cutscene_end_waving, CUTSCENE_LOOP } 10431 }; 10432 10433 /** 10434 * The game's credits. 10435 */ 10436 struct Cutscene sCutsceneCredits[] = { 10437 { cutscene_credits, CUTSCENE_LOOP } 10438 }; 10439 10440 /** 10441 * Cutscene that plays when Mario pulls open a door. 10442 */ 10443 struct Cutscene sCutsceneDoorPull[] = { 10444 { cutscene_door_start, 1 }, 10445 { cutscene_door_fix_cam, 30 }, 10446 { cutscene_door_move_behind_mario, 1 }, 10447 { cutscene_door_follow_mario, 50 }, 10448 { cutscene_door_end, 0 } 10449 }; 10450 10451 /** 10452 * Cutscene that plays when Mario pushes open a door. 10453 */ 10454 struct Cutscene sCutsceneDoorPush[] = { 10455 { cutscene_door_start, 1 }, 10456 { cutscene_door_fix_cam, 20 }, 10457 { cutscene_door_move_behind_mario, 1 }, 10458 { cutscene_door_follow_mario, 50 }, 10459 { cutscene_door_end, 0 } 10460 }; 10461 10462 /** 10463 * Cutscene that plays when Mario pulls open a door that has some special mode requirement on the other 10464 * side. 10465 */ 10466 struct Cutscene sCutsceneDoorPullMode[] = { 10467 { cutscene_door_start, 1 }, 10468 { cutscene_door_fix_cam, 30 }, 10469 { cutscene_door_mode, CUTSCENE_LOOP } 10470 }; 10471 10472 /** 10473 * Cutscene that plays when Mario pushes open a door that has some special mode requirement on the other 10474 * side. 10475 */ 10476 struct Cutscene sCutsceneDoorPushMode[] = { 10477 { cutscene_door_start, 1 }, 10478 { cutscene_door_fix_cam, 20 }, 10479 { cutscene_door_mode, CUTSCENE_LOOP } 10480 }; 10481 10482 /** 10483 * Cutscene that plays when Mario enters the cannon and it rises out of the hole. 10484 */ 10485 struct Cutscene sCutsceneEnterCannon[] = { 10486 { cutscene_enter_cannon_start, 1 }, 10487 { cutscene_enter_cannon_raise, 121 }, 10488 { cutscene_enter_cannon_end, 0 } 10489 }; 10490 10491 /** 10492 * Cutscene that plays when a star spawns from ie a box or after a boss fight. 10493 */ 10494 struct Cutscene sCutsceneStarSpawn[] = { 10495 { cutscene_star_spawn, CUTSCENE_LOOP }, 10496 { cutscene_star_spawn_back, 15 }, 10497 { cutscene_star_spawn_end, 0 } 10498 }; 10499 10500 /** 10501 * Cutscene for the red coin star spawning. Compared to a regular star, this cutscene can warp long 10502 * distances. 10503 */ 10504 struct Cutscene sCutsceneRedCoinStarSpawn[] = { 10505 { cutscene_red_coin_star, CUTSCENE_LOOP }, 10506 { cutscene_red_coin_star_end, 0 } 10507 }; 10508 10509 /** 10510 * Cutscene that plays when Mario enters a course painting. 10511 */ 10512 struct Cutscene sCutsceneEnterPainting[] = { 10513 { cutscene_enter_painting, CUTSCENE_LOOP } 10514 }; 10515 10516 /** 10517 * Cutscene that plays when Mario dies and warps back to the castle. 10518 */ 10519 struct Cutscene sCutsceneDeathExit[] = { 10520 { cutscene_exit_painting, 118 }, 10521 { cutscene_exit_painting_end, 0 } 10522 }; 10523 10524 /** 10525 * Cutscene that plays when Mario warps to the castle after collecting a star. 10526 */ 10527 struct Cutscene sCutsceneExitPaintingSuccess[] = { 10528 { cutscene_exit_painting, 180 }, 10529 { cutscene_exit_painting_end, 0 } 10530 }; 10531 10532 struct Cutscene sCutsceneUnusedExit[] = { 10533 { cutscene_unused_exit_start, 1 }, 10534 { cutscene_unused_exit_focus_mario, 60 }, 10535 { cutscene_exit_painting_end, 0 } 10536 }; 10537 10538 /** 10539 * The intro of the game. Peach reads her letter and Lakitu flies down to Mario's warp pipe. 10540 */ 10541 struct Cutscene sCutsceneIntroPeach[] = { 10542 { cutscene_intro_peach_letter, CUTSCENE_LOOP }, 10543 { cutscene_intro_peach_reset_fov, 35 }, 10544 #ifdef VERSION_EU 10545 { cutscene_intro_peach_fly_to_pipe, 675 }, 10546 #else 10547 { cutscene_intro_peach_fly_to_pipe, 820 }, 10548 #endif 10549 { cutscene_intro_peach_mario_appears, 270 }, 10550 { cutscene_intro_peach_dialog, CUTSCENE_LOOP } 10551 }; 10552 10553 /** 10554 * Cutscene that plays when a cannon door is opened. 10555 */ 10556 struct Cutscene sCutscenePrepareCannon[] = { 10557 { cutscene_prepare_cannon, 170 }, 10558 { cutscene_prepare_cannon_end, 0 } 10559 }; 10560 10561 /** 10562 * Cutscene that plays when Mario enters the castle grounds after leaving CotMC through the waterfall. 10563 */ 10564 struct Cutscene sCutsceneExitWaterfall[] = { 10565 { cutscene_exit_waterfall, 52 }, 10566 { cutscene_exit_to_castle_grounds_end, 0 } 10567 }; 10568 10569 /** 10570 * Cutscene that plays when Mario falls from WMotR. 10571 */ 10572 struct Cutscene sCutsceneFallToCastleGrounds[] = { 10573 { cutscene_exit_fall_to_castle_grounds, 73 }, 10574 { cutscene_exit_to_castle_grounds_end, 0 } 10575 }; 10576 10577 /** 10578 * Cutscene that plays when Mario enters the pyramid through the hole at the top. 10579 */ 10580 struct Cutscene sCutsceneEnterPyramidTop[] = { 10581 { cutscene_enter_pyramid_top, 90 }, 10582 { cutscene_exit_to_castle_grounds_end, 0 } 10583 }; 10584 10585 /** 10586 * Unused cutscene for when the pyramid explodes. 10587 */ 10588 struct Cutscene sCutscenePyramidTopExplode[] = { 10589 { cutscene_mario_dialog, CUTSCENE_LOOP }, 10590 { cutscene_pyramid_top_explode, 150 }, 10591 { cutscene_pyramid_top_explode_end, 0 } 10592 }; 10593 10594 /** 10595 * Cutscene that plays when Mario dies while standing, or from electrocution. 10596 */ 10597 struct Cutscene sCutsceneStandingDeath[] = { 10598 { cutscene_death_standing, CUTSCENE_LOOP } 10599 }; 10600 10601 /** 10602 * Cutscene that plays when Mario enters HMC or CotMC. 10603 */ 10604 struct Cutscene sCutsceneEnterPool[] = { 10605 { cutscene_enter_pool, 100 }, 10606 { cutscene_exit_to_castle_grounds_end, 0 } 10607 }; 10608 10609 /** 10610 * Cutscene that plays when Mario dies on his stomach. 10611 */ 10612 struct Cutscene sCutsceneDeathStomach[] = { 10613 { cutscene_death_stomach, CUTSCENE_LOOP } 10614 }; 10615 10616 /** 10617 * Cutscene that plays when Mario dies on his back. 10618 */ 10619 struct Cutscene sCutsceneDeathOnBack[] = { 10620 { cutscene_bbh_death, CUTSCENE_LOOP } 10621 }; 10622 10623 /** 10624 * Cutscene that plays when Mario dies in quicksand. 10625 */ 10626 struct Cutscene sCutsceneQuicksandDeath[] = { 10627 { cutscene_quicksand_death, CUTSCENE_LOOP }, 10628 }; 10629 10630 /** 10631 * Unused cutscene for ACT_WATER_DEATH, which happens when Mario gets hit by an enemy under water. 10632 */ 10633 struct Cutscene sCutsceneWaterDeath[] = { 10634 { cutscene_quicksand_death, CUTSCENE_LOOP } 10635 }; 10636 10637 /** 10638 * Cutscene that plays when Mario suffocates. 10639 */ 10640 struct Cutscene sCutsceneSuffocation[] = { 10641 { cutscene_suffocation, CUTSCENE_LOOP } 10642 }; 10643 10644 /** 10645 * Cutscene that plays when entering bowser's arenas. 10646 */ 10647 struct Cutscene sCutsceneEnterBowserArena[] = { 10648 { cutscene_bowser_arena, 180 }, 10649 { cutscene_bowser_arena_dialog, CUTSCENE_LOOP }, 10650 { cutscene_bowser_arena_end, 0 } 10651 }; 10652 10653 // The dance cutscenes are automatically stopped since reset_camera() is called after Mario warps. 10654 10655 /** 10656 * Star dance cutscene. 10657 * For the default dance, the camera moves closer to Mario, then stays in place. 10658 * For the rotate dance, the camera moves closer and rotates clockwise around Mario. 10659 */ 10660 struct Cutscene sCutsceneDanceDefaultRotate[] = { 10661 { cutscene_dance_default_rotate, CUTSCENE_LOOP } 10662 }; 10663 10664 /** 10665 * Star dance cutscene. 10666 * The camera moves closer and rotates clockwise around Mario. 10667 */ 10668 struct Cutscene sCutsceneDanceFlyAway[] = { 10669 { cutscene_dance_fly_away, CUTSCENE_LOOP } 10670 }; 10671 10672 /** 10673 * Star dance cutscene. 10674 * The camera moves in for a closeup on Mario. Used in tight spaces and underwater. 10675 */ 10676 struct Cutscene sCutsceneDanceCloseup[] = { 10677 { cutscene_dance_closeup, CUTSCENE_LOOP } 10678 }; 10679 10680 /** 10681 * Star dance cutscene. 10682 * The camera moves closer and rotates clockwise around Mario. 10683 */ 10684 struct Cutscene sCutsceneKeyDance[] = { 10685 { cutscene_key_dance, CUTSCENE_LOOP } 10686 }; 10687 10688 /** 10689 * Cutscene that plays when Mario presses a cap switch. 10690 */ 10691 struct Cutscene sCutsceneCapSwitchPress[] = { 10692 { cutscene_cap_switch_press, CUTSCENE_LOOP } 10693 }; 10694 10695 /** 10696 * Cutscene that plays when Mario opens a sliding star door. 10697 */ 10698 struct Cutscene sCutsceneSlidingDoorsOpen[] = { 10699 { cutscene_sliding_doors_open, 50 }, 10700 { cutscene_double_doors_end, 0 } 10701 }; 10702 10703 /** 10704 * Cutscene that plays when Mario unlocks the basement or upstairs key door. 10705 */ 10706 struct Cutscene sCutsceneUnlockKeyDoor[] = { 10707 { cutscene_unlock_key_door, 200 }, 10708 { cutscene_double_doors_end, 0 } 10709 }; 10710 10711 /** 10712 * Cutscene that plays when Mario exits bowser's arena after getting the key. 10713 */ 10714 struct Cutscene sCutsceneExitBowserSuccess[] = { 10715 { cutscene_exit_bowser_succ, 190 }, 10716 { cutscene_non_painting_end, 0 } 10717 }; 10718 10719 /** 10720 * Unused cutscene for when Mario dies in bowser's arena. Instead, Mario just respawns at the warp pipe. 10721 */ 10722 struct Cutscene sCutsceneExitBowserDeath[] = { 10723 { cutscene_exit_bowser_death, 120 }, 10724 { cutscene_non_painting_end, 0 } 10725 }; 10726 10727 /** 10728 * Cutscene that plays when Mario exits a non-painting course, like HMC. 10729 */ 10730 struct Cutscene sCutsceneExitSpecialSuccess[] = { 10731 { cutscene_exit_non_painting_succ, 163 }, 10732 { cutscene_non_painting_end, 0 } 10733 }; 10734 10735 /** 10736 * Cutscene that plays when Mario exits from dying in a non-painting course, like HMC. 10737 */ 10738 struct Cutscene sCutsceneNonPaintingDeath[] = { 10739 { cutscene_non_painting_death, 120 }, 10740 { cutscene_non_painting_end, 0 } 10741 }; 10742 10743 /** 10744 * Cutscene that plays when Mario talks to a creature. 10745 */ 10746 struct Cutscene sCutsceneDialog[] = { 10747 { cutscene_dialog, CUTSCENE_LOOP }, 10748 { cutscene_dialog_set_flag, 12 }, 10749 { cutscene_dialog_end, 0 } 10750 }; 10751 10752 /** 10753 * Cutscene that plays when Mario reads a sign or message. 10754 */ 10755 struct Cutscene sCutsceneReadMessage[] = { 10756 { cutscene_read_message, CUTSCENE_LOOP }, 10757 { cutscene_read_message_set_flag, 15 }, 10758 { cutscene_read_message_end, 0 } 10759 }; 10760 10761 /* TODO: 10762 * The next two arrays are both related to levels, and they look generated. 10763 * These should be split into their own file. 10764 */ 10765 10766 /** 10767 * Converts the u32 given in DEFINE_COURSE to a u8 with the odd and even digits rotated into the right 10768 * order for sDanceCutsceneIndexTable 10769 */ 10770 #define DROT(value, index) ((value >> (32 - (index + 1) * 8)) & 0xF0) >> 4 | \ 10771 ((value >> (32 - (index + 1) * 8)) & 0x0F) << 4 10772 10773 #define DANCE_ENTRY(c) { DROT(c, 0), DROT(c, 1), DROT(c, 2), DROT(c, 3) }, 10774 10775 #define DEFINE_COURSE(_0, cutscenes) DANCE_ENTRY(cutscenes) 10776 #define DEFINE_COURSES_END() 10777 #define DEFINE_BONUS_COURSE(_0, cutscenes) DANCE_ENTRY(cutscenes) 10778 10779 /** 10780 * Each hex digit is an index into sDanceCutsceneTable. 10781 * 10782 * 0: Lakitu flies away after the dance 10783 * 1: Only rotates the camera, doesn't zoom out 10784 * 2: The camera goes to a close up of Mario 10785 * 3: Bowser keys and the grand star 10786 * 4: Default, used for 100 coin stars, 8 red coin stars in bowser levels, and secret stars 10787 */ 10788 u8 sDanceCutsceneIndexTable[][4] = { 10789 #include "levels/course_defines.h" 10790 { 0x44, 0x44, 0x44, 0x04 }, // (26) Why go to all this trouble to save bytes and do this?! 10791 }; 10792 #undef DEFINE_COURSE 10793 #undef DEFINE_COURSES_END 10794 #undef DEFINE_BONUS_COURSE 10795 10796 #undef DANCE_ENTRY 10797 #undef DROT 10798 10799 /** 10800 * These masks set whether or not the camera zooms out when game is paused. 10801 * 10802 * Each entry is used by two levels. Even levels use the low 4 bits, odd levels use the high 4 bits 10803 * Because areas are 1-indexed, a mask of 0x1 will make area 1 (not area 0) zoom out. 10804 * 10805 * In zoom_out_if_paused_and_outside(), the current area is converted to a shift. 10806 * Then the value of (1 << shift) is &'d with the level's mask, 10807 * and if the result is non-zero, the camera will zoom out. 10808 */ 10809 u8 sZoomOutAreaMasks[] = { 10810 ZOOMOUT_AREA_MASK(0,0,0,0, 0,0,0,0), // Unused | Unused 10811 ZOOMOUT_AREA_MASK(0,0,0,0, 0,0,0,0), // Unused | Unused 10812 ZOOMOUT_AREA_MASK(0,0,0,0, 1,0,0,0), // BBH | CCM 10813 ZOOMOUT_AREA_MASK(0,0,0,0, 0,0,0,0), // CASTLE_INSIDE | HMC 10814 ZOOMOUT_AREA_MASK(1,0,0,0, 1,0,0,0), // SSL | BOB 10815 ZOOMOUT_AREA_MASK(1,0,0,0, 1,0,0,0), // SL | WDW 10816 ZOOMOUT_AREA_MASK(0,0,0,0, 1,1,0,0), // JRB | THI 10817 ZOOMOUT_AREA_MASK(0,0,0,0, 1,0,0,0), // TTC | RR 10818 ZOOMOUT_AREA_MASK(1,0,0,0, 1,0,0,0), // CASTLE_GROUNDS | BITDW 10819 ZOOMOUT_AREA_MASK(0,0,0,0, 1,0,0,0), // VCUTM | BITFS 10820 ZOOMOUT_AREA_MASK(0,0,0,0, 1,0,0,0), // SA | BITS 10821 ZOOMOUT_AREA_MASK(1,0,0,0, 0,0,0,0), // LLL | DDD 10822 ZOOMOUT_AREA_MASK(1,0,0,0, 0,0,0,0), // WF | ENDING 10823 ZOOMOUT_AREA_MASK(0,0,0,0, 0,0,0,0), // COURTYARD | PSS 10824 ZOOMOUT_AREA_MASK(0,0,0,0, 1,0,0,0), // COTMC | TOTWC 10825 ZOOMOUT_AREA_MASK(1,0,0,0, 1,0,0,0), // BOWSER_1 | WMOTR 10826 ZOOMOUT_AREA_MASK(0,0,0,0, 1,0,0,0), // Unused | BOWSER_2 10827 ZOOMOUT_AREA_MASK(1,0,0,0, 0,0,0,0), // BOWSER_3 | Unused 10828 ZOOMOUT_AREA_MASK(1,0,0,0, 0,0,0,0), // TTM | Unused 10829 ZOOMOUT_AREA_MASK(0,0,0,0, 0,0,0,0), // Unused | Unused 10830 }; 10831 10832 STATIC_ASSERT(ARRAY_COUNT(sZoomOutAreaMasks) - 1 == LEVEL_MAX / 2, "Make sure you edit sZoomOutAreaMasks when adding / removing courses."); 10833 10834 /* 10835 * credits spline paths. 10836 * TODO: Separate these into their own file(s) 10837 */ 10838 10839 struct CutsceneSplinePoint sBoBCreditsSplinePositions[] = { 10840 { 1, 0, { 5984, 3255, 4975 } }, 10841 { 2, 0, { 4423, 3315, 1888 } }, 10842 { 3, 0, { 776, 2740, -1825 } }, 10843 { 4, 0, { -146, 3894, -3167 } }, 10844 { -1, 0, { 741, 4387, -5474 } } 10845 }; 10846 10847 struct CutsceneSplinePoint sBoBCreditsSplineFocus[] = { 10848 { 0, 30, { 5817, 3306, 4507 } }, 10849 { 0, 40, { 4025, 3378, 1593 } }, 10850 { 0, 50, { 1088, 2652, -2205 } }, 10851 { 0, 60, { 205, 3959, -3517 } }, 10852 { -1, 60, { 1231, 4400, -5649 } } 10853 }; 10854 10855 struct CutsceneSplinePoint sWFCreditsSplinePositions[] = { 10856 { 0, 0, { -301, 1399, 2643 } }, 10857 { 0, 0, { -182, 2374, 4572 } }, 10858 { 0, 0, { 4696, 3864, 413 } }, 10859 { 0, 0, { 1738, 4891, -1516 } }, 10860 { -1, 0, { 1783, 4891, -1516 } } 10861 }; 10862 10863 struct CutsceneSplinePoint sWFCreditsSplineFocus[] = { 10864 { 1, 30, { -249, 1484, 2153 } }, 10865 { 2, 40, { -200, 2470, 4082 } }, 10866 { 3, 40, { 4200, 3916, 370 } }, 10867 { 4, 40, { 1523, 4976, -1072 } }, 10868 { -1, 40, { 1523, 4976, -1072 } } 10869 }; 10870 10871 struct CutsceneSplinePoint sJRBCreditsSplinePositions[] = { 10872 { 0, 0, { 5538, -4272, 2376 } }, 10873 { 0, 0, { 5997, -3303, 2261 } }, 10874 { 0, 0, { 6345, -3255, 2179 } }, 10875 { 0, 0, { 6345, -3255, 2179 } }, 10876 { -1, 0, { 6694, -3203, 2116 } } 10877 }; 10878 10879 struct CutsceneSplinePoint sJRBCreditsSplineFocus[] = { 10880 { 0, 50, { 5261, -4683, 2443 } }, 10881 { 0, 50, { 5726, -3675, 2456 } }, 10882 { 0, 50, { 6268, -2817, 2409 } }, 10883 { 0, 50, { 6596, -2866, 2369 } }, 10884 { -1, 50, { 7186, -3153, 2041 } } 10885 }; 10886 10887 struct CutsceneSplinePoint sCCMSlideCreditsSplinePositions[] = { 10888 { 0, 0, { -6324, 6745, -5626 } }, 10889 { 1, 0, { -6324, 6745, -5626 } }, 10890 { 2, 0, { -6108, 6762, -5770 } }, 10891 { 3, 0, { -5771, 6787, -5962 } }, 10892 { -1, 0, { -5672, 6790, -5979 } } 10893 }; 10894 10895 struct CutsceneSplinePoint sCCMSlideCreditsSplineFocus[] = { 10896 { 0, 50, { -5911, 6758, -5908 } }, 10897 { 1, 50, { -5911, 6758, -5908 } }, 10898 { 2, 50, { -5652, 6814, -5968 } }, 10899 { 3, 50, { -5277, 6801, -6043 } }, 10900 { -1, 50, { -5179, 6804, -6060 } } 10901 }; 10902 10903 struct CutsceneSplinePoint sBBHCreditsSplinePositions[] = { 10904 { 1, 0, { 1088, 341, 2447 } }, 10905 { 2, 0, { 1338, 610, 2808 } }, 10906 { 3, 0, { 2267, 1612, 2966 } }, 10907 { -1, 0, { 2296, 1913, 2990 } } 10908 }; 10909 10910 struct CutsceneSplinePoint sBBHCreditsSplineFocus[] = { 10911 { 1, 50, { 1160, 263, 1958 } }, 10912 { 2, 50, { 1034, 472, 2436 } }, 10913 { 3, 50, { 1915, 1833, 2688 } }, 10914 { -1, 50, { 2134, 2316, 2742 } } 10915 }; 10916 10917 struct CutsceneSplinePoint sHMCCreditsSplinePositions[] = { 10918 { 1, 0, { -5952, 1807, -5882 } }, 10919 { 2, 0, { -5623, 1749, -4863 } }, 10920 { 3, 0, { -5472, 1955, -2520 } }, 10921 { 4, 0, { -5544, 1187, -1085 } }, 10922 { -1, 0, { -5547, 391, -721 } } 10923 }; 10924 10925 struct CutsceneSplinePoint sHMCCreditsSplineFocus[] = { 10926 { 1, 210, { -5952, 1884, -6376 } }, 10927 { 2, 58, { -5891, 1711, -5283 } }, 10928 { 3, 30, { -5595, 1699, -2108 } }, 10929 { 4, 31, { -5546, 794, -777 } }, 10930 { -1, 31, { -5548, -85, -572 } } 10931 }; 10932 10933 struct CutsceneSplinePoint sTHIWigglerCreditsSplinePositions[] = { 10934 { 1, 0, { -1411, 2474, -1276 } }, 10935 { 2, 0, { -1606, 2479, -434 } }, 10936 { -1, 0, { -1170, 2122, 1337 } } 10937 }; 10938 10939 struct CutsceneSplinePoint sTHIWigglerCreditsSplineFocus[] = { 10940 { 1, 50, { -1053, 2512, -928 } }, 10941 { 2, 50, { -1234, 2377, -114 } }, 10942 { -1, 50, { -758, 2147, 1054 } } 10943 }; 10944 10945 struct CutsceneSplinePoint sVolcanoCreditsSplinePositions[] = { 10946 { 0, 0, { -1445, 1094, 1617 } }, 10947 { 0, 0, { -1509, 649, 871 } }, 10948 { 0, 0, { -1133, 420, -248 } }, 10949 { 0, 0, { -778, 359, -1052 } }, 10950 { 0, 0, { -565, 260, -1730 } }, 10951 { -1, 0, { 1274, 473, -275 } } 10952 }; 10953 10954 struct CutsceneSplinePoint sVolcanoCreditsSplineFocus[] = { 10955 { 0, 50, { -1500, 757, 1251 } }, 10956 { 0, 50, { -1401, 439, 431 } }, 10957 { 0, 50, { -749, 270, -532 } }, 10958 { 0, 50, { -396, 270, -1363 } }, 10959 { 0, 50, { -321, 143, -2151 } }, 10960 { -1, 50, { 1002, 460, -694 } } 10961 }; 10962 10963 struct CutsceneSplinePoint sSSLCreditsSplinePositions[] = { 10964 { 0, 0, { -4262, 4658, -5015 } }, 10965 { 0, 0, { -3274, 2963, -4661 } }, 10966 { 0, 0, { -2568, 812, -6528 } }, 10967 { 0, 0, { -414, 660, -7232 } }, 10968 { 0, 0, { 1466, 660, -6898 } }, 10969 { -1, 0, { 2724, 660, -6298 } } 10970 }; 10971 10972 struct CutsceneSplinePoint sSSLCreditsSplineFocus[] = { 10973 { 0, 50, { -4083, 4277, -4745 } }, 10974 { 0, 50, { -2975, 2574, -4759 } }, 10975 { 0, 50, { -2343, 736, -6088 } }, 10976 { 0, 50, { -535, 572, -6755 } }, 10977 { 0, 50, { 1311, 597, -6427 } }, 10978 { -1, 50, { 2448, 612, -5884 } } 10979 }; 10980 10981 struct CutsceneSplinePoint sDDDCreditsSplinePositions[] = { 10982 { 0, 0, { -874, -4933, 366 } }, 10983 { 0, 0, { -1463, -4782, 963 } }, 10984 { 0, 0, { -1893, -4684, 1303 } }, 10985 { 0, 0, { -2818, -4503, 1583 } }, 10986 { 0, 0, { -4095, -2924, 730 } }, 10987 { 0, 0, { -4737, -1594, -63 } }, 10988 { -1, 0, { -4681, -1084, -623 } } 10989 }; 10990 10991 struct CutsceneSplinePoint sDDDCreditsSplineFocus[] = { 10992 { 0, 50, { -1276, -4683, 622 } }, 10993 { 0, 50, { -1858, -4407, 1097 } }, 10994 { 0, 50, { -2324, -4332, 1318 } }, 10995 { 0, 50, { -3138, -4048, 1434 } }, 10996 { 0, 50, { -4353, -2444, 533 } }, 10997 { 0, 50, { -4807, -1169, -436 } }, 10998 { -1, 50, { -4665, -664, -1007 } } 10999 }; 11000 11001 struct CutsceneSplinePoint sSLCreditsSplinePositions[] = { 11002 { 0, 0, { 939, 6654, 6196 } }, 11003 { 0, 0, { 1873, 5160, 3714 } }, 11004 { 0, 0, { 3120, 3564, 1314 } }, 11005 { -1, 0, { 2881, 4231, 573 } } 11006 }; 11007 11008 struct CutsceneSplinePoint sSLCreditsSplineFocus[] = { 11009 { 0, 50, { 875, 6411, 5763 } }, 11010 { 0, 50, { 1659, 4951, 3313 } }, 11011 { 0, 50, { 2630, 3565, 1215 } }, 11012 { -1, 50, { 2417, 4056, 639 } } 11013 }; 11014 11015 struct CutsceneSplinePoint sWDWCreditsSplinePositions[] = { 11016 { 0, 0, { 3927, 2573, 3685 } }, 11017 { 0, 0, { 2389, 2054, 1210 } }, 11018 { 0, 0, { 2309, 2069, 22 } }, 11019 { -1, 0, { 2122, 2271, -979 } } 11020 }; 11021 11022 struct CutsceneSplinePoint sWDWCreditsSplineFocus[] = { 11023 { 0, 50, { 3637, 2460, 3294 } }, 11024 { 0, 50, { 1984, 2067, 918 } }, 11025 { 0, 50, { 1941, 2255, -261 } }, 11026 { -1, 50, { 1779, 2587, -1158 } } 11027 }; 11028 11029 struct CutsceneSplinePoint sTTMCreditsSplinePositions[] = { 11030 { 0, 0, { 386, 2535, 644 } }, 11031 { 0, 0, { 1105, 2576, 918 } }, 11032 { 0, 0, { 3565, 2261, 2098 } }, 11033 { 0, 0, { 6715, -2791, 4554 } }, 11034 { 0, 0, { 3917, -3130, 3656 } }, 11035 { -1, 0, { 3917, -3130, 3656 } } 11036 }; 11037 11038 struct CutsceneSplinePoint sTTMCreditsSplineFocus[] = { 11039 { 1, 50, { 751, 2434, 318 } }, 11040 { 2, 50, { 768, 2382, 603 } }, 11041 { 3, 60, { 3115, 2086, 1969 } }, 11042 { 4, 30, { 6370, -3108, 4727 } }, 11043 { 5, 50, { 4172, -3385, 4001 } }, 11044 { -1, 50, { 4172, -3385, 4001 } } 11045 }; 11046 11047 struct CutsceneSplinePoint sTHIHugeCreditsSplinePositions[] = { 11048 { 0, 0, { 6990, -1000, -4858 } }, 11049 { 0, 0, { 7886, -1055, 2878 } }, 11050 { 0, 0, { 1952, -1481, 10920 } }, 11051 { 0, 0, { -1684, -219, 2819 } }, 11052 { 0, 0, { -2427, -131, 2755 } }, 11053 { 0, 0, { -3246, 416, 3286 } }, 11054 { -1, 0, { -3246, 416, 3286 } } 11055 }; 11056 11057 struct CutsceneSplinePoint sTHIHugeCreditsSplineFocus[] = { 11058 { 1, 70, { 7022, -965, -5356 } }, 11059 { 2, 40, { 7799, -915, 2405 } }, 11060 { 3, 60, { 1878, -1137, 10568 } }, 11061 { 4, 50, { -1931, -308, 2394 } }, 11062 { 5, 50, { -2066, -386, 2521 } }, 11063 { 6, 50, { -2875, 182, 3045 } }, 11064 { -1, 50, { -2875, 182, 3045 } } 11065 }; 11066 11067 struct CutsceneSplinePoint sTTCCreditsSplinePositions[] = { 11068 { 1, 0, { -1724, 277, -994 } }, 11069 { 2, 0, { -1720, 456, -995 } }, 11070 { 3, 0, { -1655, 810, -1014 } }, 11071 { -1, 0, { -1753, 883, -1009 } } 11072 }; 11073 11074 struct CutsceneSplinePoint sTTCCreditsSplineFocus[] = { 11075 { 1, 50, { -1554, 742, -1063 } }, 11076 { 2, 50, { -1245, 571, -1102 } }, 11077 { 3, 50, { -1220, 603, -1151 } }, 11078 { -1, 50, { -1412, 520, -1053 } } 11079 }; 11080 11081 struct CutsceneSplinePoint sRRCreditsSplinePositions[] = { 11082 { 0, 0, { -1818, 4036, 97 } }, 11083 { 0, 0, { -575, 3460, -505 } }, 11084 { 0, 0, { 1191, 3611, -1134 } }, 11085 { -1, 0, { 2701, 3777, -3686 } } 11086 }; 11087 11088 struct CutsceneSplinePoint sRRCreditsSplineFocus[] = { 11089 { 0, 50, { -1376, 3885, -81 } }, 11090 { 0, 50, { -146, 3343, -734 } }, 11091 { 0, 50, { 1570, 3446, -1415 } }, 11092 { -1, 50, { 2794, 3627, -3218 } } 11093 }; 11094 11095 struct CutsceneSplinePoint sSACreditsSplinePositions[] = { 11096 { 0, 0, { -295, -396, -585 } }, 11097 { 1, 0, { -295, -396, -585 } }, 11098 { 2, 0, { -292, -856, -573 } }, 11099 { 3, 0, { -312, -856, -541 } }, 11100 { -1, 0, { 175, -856, -654 } } 11101 }; 11102 11103 struct CutsceneSplinePoint sSACreditsSplineFocus[] = { 11104 { 0, 50, { -175, -594, -142 } }, 11105 { 1, 50, { -175, -594, -142 } }, 11106 { 2, 50, { -195, -956, -92 } }, 11107 { 3, 50, { -572, -956, -150 } }, 11108 { -1, 50, { -307, -956, -537 } } 11109 }; 11110 11111 struct CutsceneSplinePoint sCotMCCreditsSplinePositions[] = { 11112 { 0, 0, { -296, 495, 1607 } }, 11113 { 0, 0, { -430, 541, 654 } }, 11114 { 0, 0, { -466, 601, -359 } }, 11115 { 0, 0, { -217, 433, -1549 } }, 11116 { -1, 0, { -95, 366, -2922 } } 11117 }; 11118 11119 struct CutsceneSplinePoint sCotMCCreditsSplineFocus[] = { 11120 { 0, 50, { -176, 483, 2092 } }, 11121 { 0, 50, { -122, 392, 1019 } }, 11122 { 0, 50, { -268, 450, -792 } }, 11123 { 0, 50, { -172, 399, -2046 } }, 11124 { -1, 50, { -51, 355, -3420 } } 11125 }; 11126 11127 struct CutsceneSplinePoint sDDDSubCreditsSplinePositions[] = { 11128 { 0, 0, { 4656, 2171, 5028 } }, 11129 { 0, 0, { 4548, 1182, 4596 } }, 11130 { 0, 0, { 5007, 813, 3257 } }, 11131 { 0, 0, { 5681, 648, 1060 } }, 11132 { -1, 0, { 4644, 774, 113 } } 11133 }; 11134 11135 struct CutsceneSplinePoint sDDDSubCreditsSplineFocus[] = { 11136 { 0, 50, { 4512, 2183, 4549 } }, 11137 { 0, 50, { 4327, 838, 4308 } }, 11138 { 0, 50, { 4774, 749, 2819 } }, 11139 { 0, 50, { 5279, 660, 763 } }, 11140 { -1, 50, { 4194, 885, -75 } } 11141 }; 11142 11143 struct CutsceneSplinePoint sCCMOutsideCreditsSplinePositions[] = { 11144 { 1, 0, { 1427, -1387, 5409 } }, 11145 { 2, 0, { -1646, -1536, 4526 } }, 11146 { 3, 0, { -3852, -1448, 3913 } }, 11147 { -1, 0, { -5199, -1366, 1886 } } 11148 }; 11149 11150 struct CutsceneSplinePoint sCCMOutsideCreditsSplineFocus[] = { 11151 { 1, 50, { 958, -1481, 5262 } }, 11152 { 2, 50, { -2123, -1600, 4391 } }, 11153 { 3, 50, { -3957, -1401, 3426 } }, 11154 { -1, 50, { -4730, -1215, 1795 } } 11155 }; 11156 11157 /** 11158 * Play the current cutscene until either gCutsceneTimer reaches the max time, or c->cutscene is set to 0 11159 * 11160 * Note that CAM_FLAG_SMOOTH_MOVEMENT is cleared while a cutscene is playing, so cutscenes set it for 11161 * the duration they want the flag to be active. 11162 */ 11163 void play_cutscene(struct Camera *c) { 11164 UNUSED u8 filler[12]; 11165 UNUSED s16 unusedYawFocToMario; 11166 s16 cutsceneDuration; 11167 u8 oldCutscene; 11168 11169 unusedYawFocToMario = sAreaYaw; 11170 oldCutscene = c->cutscene; 11171 sStatusFlags &= ~CAM_FLAG_SMOOTH_MOVEMENT; 11172 gCameraMovementFlags &= ~CAM_MOVING_INTO_MODE; 11173 11174 #define CUTSCENE(id, cutscene) \ 11175 case id: \ 11176 cutsceneDuration = cutscene[sCutsceneShot].duration; \ 11177 cutscene[sCutsceneShot].shot(c); \ 11178 break; 11179 11180 switch (c->cutscene) { 11181 CUTSCENE(CUTSCENE_STAR_SPAWN, sCutsceneStarSpawn) 11182 CUTSCENE(CUTSCENE_RED_COIN_STAR_SPAWN, sCutsceneRedCoinStarSpawn) 11183 CUTSCENE(CUTSCENE_ENDING, sCutsceneEnding) 11184 CUTSCENE(CUTSCENE_GRAND_STAR, sCutsceneGrandStar) 11185 CUTSCENE(CUTSCENE_DOOR_WARP, sCutsceneDoorWarp) 11186 CUTSCENE(CUTSCENE_DOOR_PULL, sCutsceneDoorPull) 11187 CUTSCENE(CUTSCENE_DOOR_PUSH, sCutsceneDoorPush) 11188 CUTSCENE(CUTSCENE_DOOR_PULL_MODE, sCutsceneDoorPullMode) 11189 CUTSCENE(CUTSCENE_DOOR_PUSH_MODE, sCutsceneDoorPushMode) 11190 CUTSCENE(CUTSCENE_ENTER_CANNON, sCutsceneEnterCannon) 11191 CUTSCENE(CUTSCENE_ENTER_PAINTING, sCutsceneEnterPainting) 11192 CUTSCENE(CUTSCENE_DEATH_EXIT, sCutsceneDeathExit) 11193 CUTSCENE(CUTSCENE_EXIT_PAINTING_SUCC, sCutsceneExitPaintingSuccess) 11194 CUTSCENE(CUTSCENE_UNUSED_EXIT, sCutsceneUnusedExit) 11195 CUTSCENE(CUTSCENE_INTRO_PEACH, sCutsceneIntroPeach) 11196 CUTSCENE(CUTSCENE_ENTER_BOWSER_ARENA, sCutsceneEnterBowserArena) 11197 CUTSCENE(CUTSCENE_DANCE_ROTATE, sCutsceneDanceDefaultRotate) 11198 CUTSCENE(CUTSCENE_DANCE_DEFAULT, sCutsceneDanceDefaultRotate) 11199 CUTSCENE(CUTSCENE_DANCE_FLY_AWAY, sCutsceneDanceFlyAway) 11200 CUTSCENE(CUTSCENE_DANCE_CLOSEUP, sCutsceneDanceCloseup) 11201 CUTSCENE(CUTSCENE_KEY_DANCE, sCutsceneKeyDance) 11202 CUTSCENE(CUTSCENE_0F_UNUSED, sCutsceneUnused) 11203 CUTSCENE(CUTSCENE_END_WAVING, sCutsceneEndWaving) 11204 CUTSCENE(CUTSCENE_CREDITS, sCutsceneCredits) 11205 CUTSCENE(CUTSCENE_CAP_SWITCH_PRESS, sCutsceneCapSwitchPress) 11206 CUTSCENE(CUTSCENE_SLIDING_DOORS_OPEN, sCutsceneSlidingDoorsOpen) 11207 CUTSCENE(CUTSCENE_PREPARE_CANNON, sCutscenePrepareCannon) 11208 CUTSCENE(CUTSCENE_UNLOCK_KEY_DOOR, sCutsceneUnlockKeyDoor) 11209 CUTSCENE(CUTSCENE_STANDING_DEATH, sCutsceneStandingDeath) 11210 CUTSCENE(CUTSCENE_ENTER_POOL, sCutsceneEnterPool) 11211 CUTSCENE(CUTSCENE_DEATH_ON_STOMACH, sCutsceneDeathStomach) 11212 CUTSCENE(CUTSCENE_DEATH_ON_BACK, sCutsceneDeathOnBack) 11213 CUTSCENE(CUTSCENE_QUICKSAND_DEATH, sCutsceneQuicksandDeath) 11214 CUTSCENE(CUTSCENE_SUFFOCATION_DEATH, sCutsceneSuffocation) 11215 CUTSCENE(CUTSCENE_EXIT_BOWSER_SUCC, sCutsceneExitBowserSuccess) 11216 CUTSCENE(CUTSCENE_EXIT_BOWSER_DEATH, sCutsceneExitBowserDeath) 11217 CUTSCENE(CUTSCENE_EXIT_SPECIAL_SUCC, sCutsceneExitSpecialSuccess) 11218 CUTSCENE(CUTSCENE_EXIT_WATERFALL, sCutsceneExitWaterfall) 11219 CUTSCENE(CUTSCENE_EXIT_FALL_WMOTR, sCutsceneFallToCastleGrounds) 11220 CUTSCENE(CUTSCENE_NONPAINTING_DEATH, sCutsceneNonPaintingDeath) 11221 CUTSCENE(CUTSCENE_DIALOG, sCutsceneDialog) 11222 CUTSCENE(CUTSCENE_READ_MESSAGE, sCutsceneReadMessage) 11223 CUTSCENE(CUTSCENE_RACE_DIALOG, sCutsceneDialog) 11224 CUTSCENE(CUTSCENE_ENTER_PYRAMID_TOP, sCutsceneEnterPyramidTop) 11225 CUTSCENE(CUTSCENE_SSL_PYRAMID_EXPLODE, sCutscenePyramidTopExplode) 11226 } 11227 11228 #undef CUTSCENE 11229 11230 if ((cutsceneDuration != 0) && !(gCutsceneTimer & CUTSCENE_STOP)) { 11231 //! @bug This should check for 0x7FFF (CUTSCENE_LOOP) 11232 //! instead, cutscenes that last longer than 0x3FFF frames will never end on their own 11233 if (gCutsceneTimer < 0x3FFF) { 11234 gCutsceneTimer++; 11235 } 11236 //! Because gCutsceneTimer is often set to 0x7FFF (CUTSCENE_LOOP), this conditional can only 11237 //! check for == due to overflow 11238 if (gCutsceneTimer == cutsceneDuration) { 11239 sCutsceneShot++; 11240 gCutsceneTimer = 0; 11241 } 11242 } else { 11243 sMarioCamState->cameraEvent = 0; 11244 sCutsceneShot = 0; 11245 gCutsceneTimer = 0; 11246 } 11247 11248 sAreaYawChange = 0; 11249 11250 // The cutscene just ended 11251 if ((c->cutscene == 0) && (oldCutscene != 0)) { 11252 gRecentCutscene = oldCutscene; 11253 } 11254 } 11255 11256 /** 11257 * Call the event while `start` <= gCutsceneTimer <= `end` 11258 * If `end` is -1, call for the rest of the shot. 11259 */ 11260 s32 cutscene_event(CameraEvent event, struct Camera *c, s16 start, s16 end) { 11261 if (start <= gCutsceneTimer) { 11262 if (end == -1 || end >= gCutsceneTimer) { 11263 event(c); 11264 } 11265 } 11266 return 0; 11267 } 11268 11269 /** 11270 * Set gCutsceneObjSpawn when gCutsceneTimer == `frame`. 11271 * 11272 * @see intro_scene.inc.c for details on which objects are spawned. 11273 */ 11274 s32 cutscene_spawn_obj(u32 obj, s16 frame) { 11275 if (frame == gCutsceneTimer) { 11276 gCutsceneObjSpawn = obj; 11277 } 11278 return 0; 11279 } 11280 11281 /** 11282 * Start shaking the camera's field of view. 11283 * 11284 * @param shakeSpeed How fast the shake should progress through its period. The shake offset is 11285 * calculated from coss(), so this parameter can be thought of as an angular velocity. 11286 */ 11287 void set_fov_shake(s16 amplitude, s16 decay, s16 shakeSpeed) { 11288 if (amplitude > sFOVState.shakeAmplitude) { 11289 sFOVState.shakeAmplitude = amplitude; 11290 sFOVState.decay = decay; 11291 sFOVState.shakeSpeed = shakeSpeed; 11292 } 11293 } 11294 11295 /** 11296 * Start shaking the camera's field of view, but reduce `amplitude` by distance from camera 11297 */ 11298 void set_fov_shake_from_point(s16 amplitude, s16 decay, s16 shakeSpeed, f32 maxDist, f32 posX, f32 posY, f32 posZ) { 11299 amplitude = reduce_by_dist_from_camera(amplitude, maxDist, posX, posY, posZ); 11300 11301 if (amplitude != 0) { 11302 if (amplitude > sFOVState.shakeAmplitude) { // literally use the function above you silly nintendo, smh 11303 sFOVState.shakeAmplitude = amplitude; 11304 sFOVState.decay = decay; 11305 sFOVState.shakeSpeed = shakeSpeed; 11306 } 11307 } 11308 } 11309 11310 /** 11311 * Add a cyclic offset to the camera's field of view based on a cosine wave 11312 */ 11313 void shake_camera_fov(struct GraphNodePerspective *perspective) { 11314 if (sFOVState.shakeAmplitude != 0.f) { 11315 sFOVState.fovOffset = coss(sFOVState.shakePhase) * sFOVState.shakeAmplitude / 0x100; 11316 sFOVState.shakePhase += sFOVState.shakeSpeed; 11317 camera_approach_f32_symmetric_bool(&sFOVState.shakeAmplitude, 0.f, sFOVState.decay); 11318 perspective->fov += sFOVState.fovOffset; 11319 } else { 11320 sFOVState.shakePhase = 0; 11321 } 11322 } 11323 11324 static UNUSED void unused_deactivate_sleeping_camera(UNUSED struct MarioState *m) { 11325 sStatusFlags &= ~CAM_FLAG_SLEEPING; 11326 } 11327 11328 void set_fov_30(UNUSED struct MarioState *m) { 11329 sFOVState.fov = 30.f; 11330 } 11331 11332 void approach_fov_20(UNUSED struct MarioState *m) { 11333 camera_approach_f32_symmetric_bool(&sFOVState.fov, 20.f, 0.3f); 11334 } 11335 11336 void set_fov_45(UNUSED struct MarioState *m) { 11337 sFOVState.fov = 45.f; 11338 } 11339 11340 void set_fov_29(UNUSED struct MarioState *m) { 11341 sFOVState.fov = 29.f; 11342 } 11343 11344 void zoom_fov_30(UNUSED struct MarioState *m) { 11345 // Pretty sure approach_f32_asymptotic_bool would do a much nicer job here, but you do you, 11346 // Nintendo. 11347 camera_approach_f32_symmetric_bool(&sFOVState.fov, 30.f, (30.f - sFOVState.fov) / 60.f); 11348 } 11349 11350 /** 11351 * This is the default fov function. It makes fov approach 45 degrees, and it handles zooming in when 11352 * Mario falls a sleep. 11353 */ 11354 void fov_default(struct MarioState *m) { 11355 sStatusFlags &= ~CAM_FLAG_SLEEPING; 11356 11357 if ((m->action == ACT_SLEEPING) || (m->action == ACT_START_SLEEPING)) { 11358 camera_approach_f32_symmetric_bool(&sFOVState.fov, 30.f, (30.f - sFOVState.fov) / 30.f); 11359 sStatusFlags |= CAM_FLAG_SLEEPING; 11360 } else { 11361 camera_approach_f32_symmetric_bool(&sFOVState.fov, 45.f, (45.f - sFOVState.fov) / 30.f); 11362 sFOVState.unusedIsSleeping = 0; 11363 } 11364 if (m->area->camera->cutscene == CUTSCENE_0F_UNUSED) { 11365 sFOVState.fov = 45.f; 11366 } 11367 } 11368 11369 //??! Literally the exact same as below 11370 static UNUSED void unused_approach_fov_30(UNUSED struct MarioState *m) { 11371 camera_approach_f32_symmetric_bool(&sFOVState.fov, 30.f, 1.f); 11372 } 11373 11374 void approach_fov_30(UNUSED struct MarioState *m) { 11375 camera_approach_f32_symmetric_bool(&sFOVState.fov, 30.f, 1.f); 11376 } 11377 11378 void approach_fov_60(UNUSED struct MarioState *m) { 11379 camera_approach_f32_symmetric_bool(&sFOVState.fov, 60.f, 1.f); 11380 } 11381 11382 void approach_fov_45(struct MarioState *m) { 11383 f32 targetFoV = sFOVState.fov; 11384 11385 if (m->area->camera->mode == CAMERA_MODE_FIXED && m->area->camera->cutscene == 0) { 11386 targetFoV = 45.f; 11387 } else { 11388 targetFoV = 45.f; 11389 } 11390 11391 sFOVState.fov = approach_f32(sFOVState.fov, targetFoV, 2.f, 2.f); 11392 } 11393 11394 void approach_fov_80(UNUSED struct MarioState *m) { 11395 camera_approach_f32_symmetric_bool(&sFOVState.fov, 80.f, 3.5f); 11396 } 11397 11398 /** 11399 * Sets the fov in BBH. 11400 * If there's a cutscene, sets fov to 45. Otherwise sets fov to 60. 11401 */ 11402 void set_fov_bbh(struct MarioState *m) { 11403 f32 targetFoV = sFOVState.fov; 11404 11405 if (m->area->camera->mode == CAMERA_MODE_FIXED && m->area->camera->cutscene == 0) { 11406 targetFoV = 60.f; 11407 } else { 11408 targetFoV = 45.f; 11409 } 11410 11411 sFOVState.fov = approach_f32(sFOVState.fov, targetFoV, 2.f, 2.f); 11412 } 11413 11414 /** 11415 * Sets the field of view for the GraphNodeCamera 11416 */ 11417 Gfx *geo_camera_fov(s32 callContext, struct GraphNode *g, UNUSED void *context) { 11418 struct GraphNodePerspective *perspective = (struct GraphNodePerspective *) g; 11419 struct MarioState *marioState = &gMarioStates[0]; 11420 u8 fovFunc = sFOVState.fovFunc; 11421 11422 if (callContext == GEO_CONTEXT_RENDER) { 11423 switch (fovFunc) { 11424 case CAM_FOV_SET_45: 11425 set_fov_45(marioState); 11426 break; 11427 case CAM_FOV_SET_29: 11428 set_fov_29(marioState); 11429 break; 11430 case CAM_FOV_ZOOM_30: 11431 zoom_fov_30(marioState); 11432 break; 11433 case CAM_FOV_DEFAULT: 11434 fov_default(marioState); 11435 break; 11436 case CAM_FOV_BBH: 11437 set_fov_bbh(marioState); 11438 break; 11439 case CAM_FOV_APP_45: 11440 approach_fov_45(marioState); 11441 break; 11442 case CAM_FOV_SET_30: 11443 set_fov_30(marioState); 11444 break; 11445 case CAM_FOV_APP_20: 11446 approach_fov_20(marioState); 11447 break; 11448 case CAM_FOV_APP_80: 11449 approach_fov_80(marioState); 11450 break; 11451 case CAM_FOV_APP_30: 11452 approach_fov_30(marioState); 11453 break; 11454 case CAM_FOV_APP_60: 11455 approach_fov_60(marioState); 11456 break; 11457 //! No default case 11458 } 11459 } 11460 11461 perspective->fov = sFOVState.fov; 11462 shake_camera_fov(perspective); 11463 return NULL; 11464 } 11465 11466 /** 11467 * Change the camera's FOV mode. 11468 * 11469 * @see geo_camera_fov 11470 */ 11471 void set_fov_function(u8 func) { 11472 sFOVState.fovFunc = func; 11473 } 11474 11475 /** 11476 * Start a preset fov shake. Used in cutscenes 11477 */ 11478 void cutscene_set_fov_shake_preset(u8 preset) { 11479 switch (preset) { 11480 case 1: 11481 set_fov_shake(0x100, 0x30, 0x8000); 11482 break; 11483 case 2: 11484 set_fov_shake(0x400, 0x20, 0x4000); 11485 break; 11486 } 11487 } 11488 11489 /** 11490 * Start a preset fov shake that is reduced by the point's distance from the camera. 11491 * Used in set_camera_shake_from_point 11492 * 11493 * @see set_camera_shake_from_point 11494 */ 11495 void set_fov_shake_from_point_preset(u8 preset, f32 posX, f32 posY, f32 posZ) { 11496 switch (preset) { 11497 case SHAKE_FOV_SMALL: 11498 set_fov_shake_from_point(0x100, 0x30, 0x8000, 3000.f, posX, posY, posZ); 11499 break; 11500 case SHAKE_FOV_MEDIUM: 11501 set_fov_shake_from_point(0x200, 0x30, 0x8000, 4000.f, posX, posY, posZ); 11502 break; 11503 case SHAKE_FOV_LARGE: 11504 set_fov_shake_from_point(0x300, 0x30, 0x8000, 6000.f, posX, posY, posZ); 11505 break; 11506 case SHAKE_FOV_UNUSED: 11507 set_fov_shake_from_point(0x800, 0x20, 0x4000, 3000.f, posX, posY, posZ); 11508 break; 11509 } 11510 } 11511 11512 /** 11513 * Offset an object's position in a random direction within the given bounds. 11514 */ 11515 static UNUSED void unused_displace_obj_randomly(struct Object *o, f32 xRange, f32 yRange, f32 zRange) { 11516 f32 rnd = random_float(); 11517 11518 o->oPosX += (rnd * xRange - xRange / 2.f); 11519 o->oPosY += (rnd * yRange - yRange / 2.f); 11520 o->oPosZ += (rnd * zRange - zRange / 2.f); 11521 } 11522 11523 /** 11524 * Rotate an object in a random direction within the given bounds. 11525 */ 11526 static UNUSED void unused_rotate_obj_randomly(struct Object *o, f32 pitchRange, f32 yawRange) { 11527 f32 rnd = random_float(); 11528 11529 o->oMoveAnglePitch += (s16)(rnd * pitchRange - pitchRange / 2.f); 11530 o->oMoveAngleYaw += (s16)(rnd * yawRange - yawRange / 2.f); 11531 } 11532 11533 /** 11534 * Rotate the object towards the point `point`. 11535 */ 11536 void obj_rotate_towards_point(struct Object *o, Vec3f point, s16 pitchOff, s16 yawOff, s16 pitchDiv, s16 yawDiv) { 11537 f32 dist; 11538 s16 pitch, yaw; 11539 Vec3f oPos; 11540 11541 object_pos_to_vec3f(oPos, o); 11542 vec3f_get_dist_and_angle(oPos, point, &dist, &pitch, &yaw); 11543 o->oMoveAnglePitch = approach_s16_asymptotic(o->oMoveAnglePitch, pitchOff - pitch, pitchDiv); 11544 o->oMoveAngleYaw = approach_s16_asymptotic(o->oMoveAngleYaw, yaw + yawOff, yawDiv); 11545 } 11546 11547 #define o gCurrentObject 11548 11549 #include "behaviors/intro_peach.inc.c" 11550 #include "behaviors/intro_lakitu.inc.c" 11551 #include "behaviors/end_birds_1.inc.c" 11552 #include "behaviors/end_birds_2.inc.c" 11553 #include "behaviors/intro_scene.inc.c"