Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
MorsGames
GitHub Repository: MorsGames/sm64plus
Path: blob/master/src/game/camera.c
7858 views
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
#include "settings.h"
33
34
#define CBUTTON_MASK (U_CBUTTONS | D_CBUTTONS | L_CBUTTONS | R_CBUTTONS)
35
36
/**
37
* @file camera.c
38
* Implements the camera system, including C-button input, camera modes, camera triggers, and cutscenes.
39
*
40
* When working with the camera, you should be familiar with sm64's coordinate system.
41
* Relative to the camera, the coordinate system follows the right hand rule:
42
* +X points right.
43
* +Y points up.
44
* +Z points out of the screen.
45
*
46
* You should also be familiar with Euler angles: 'pitch', 'yaw', and 'roll'.
47
* pitch: rotation about the X-axis, measured from +Y.
48
* Unlike yaw and roll, pitch is bounded in +-0x4000 (90 degrees).
49
* Pitch is 0 when the camera points parallel to the xz-plane (+Y points straight up).
50
*
51
* yaw: rotation about the Y-axis, measured from (absolute) +Z.
52
* Positive yaw rotates clockwise, towards +X.
53
*
54
* roll: rotation about the Z-axis, measured from the camera's right direction.
55
* Unfortunately, it's weird: For some reason, roll is flipped. Positive roll makes the camera
56
* rotate counterclockwise, which means the WORLD rotates clockwise. Luckily roll is rarely
57
* used.
58
*
59
* Remember the right hand rule: make a thumbs-up with your right hand, stick your thumb in the
60
* +direction (except for roll), and the angle follows the rotation of your curled fingers.
61
*
62
* Illustrations:
63
* Following the right hand rule, each hidden axis's positive direction points out of the screen.
64
*
65
* YZ-Plane (pitch) XZ-Plane (yaw) XY-Plane (roll -- Note flipped)
66
* +Y -Z +Y
67
* ^ ^ (into the ^
68
* --|-- | screen) |<-
69
* +pitch / | \ -pitch | | \ -roll
70
* v | v | | |
71
* +Z <------O------> -Z -X <------O------> +X -X <------O------> +X
72
* | ^ | ^ | |
73
* | \ | / | / +roll
74
* | -yaw --|-- +yaw |<-
75
* v v v
76
* -Y +Z -Y
77
*
78
*/
79
80
// BSS
81
/**
82
* Stores Lakitu's position from the last frame, used for transitioning in next_lakitu_state()
83
*/
84
Vec3f sOldPosition;
85
/**
86
* Stores Lakitu's focus from the last frame, used for transitioning in next_lakitu_state()
87
*/
88
Vec3f sOldFocus;
89
/**
90
* Global array of PlayerCameraState.
91
* L is real.
92
*/
93
struct PlayerCameraState gPlayerCameraState[2];
94
/**
95
* Direction controlled by player 2, moves the focus during the credits.
96
*/
97
Vec3f sPlayer2FocusOffset;
98
/**
99
* The pitch used for the credits easter egg.
100
*/
101
s16 sCreditsPlayer2Pitch;
102
/**
103
* The yaw used for the credits easter egg.
104
*/
105
s16 sCreditsPlayer2Yaw;
106
/**
107
* Used to decide when to zoom out in the pause menu.
108
*/
109
u8 sFramesPaused;
110
111
extern struct CameraFOVStatus sFOVState;
112
extern struct TransitionInfo sModeTransition;
113
extern struct PlayerGeometry sMarioGeometry;
114
extern s16 unusedFreeRoamWallYaw;
115
extern s16 sAvoidYawVel;
116
extern s16 sCameraYawAfterDoorCutscene;
117
extern s16 unusedSplinePitch;
118
extern s16 unusedSplineYaw;
119
extern struct HandheldShakePoint sHandheldShakeSpline[4];
120
extern s16 sHandheldShakeMag;
121
extern f32 sHandheldShakeTimer;
122
extern f32 sHandheldShakeInc;
123
extern s16 sHandheldShakePitch;
124
extern s16 sHandheldShakeYaw;
125
extern s16 sHandheldShakeRoll;
126
extern u32 unused8033B30C;
127
extern u32 unused8033B310;
128
extern s16 sSelectionFlags;
129
extern s16 unused8033B316;
130
extern s16 s2ndRotateFlags;
131
extern s16 unused8033B31A;
132
extern s16 sCameraSoundFlags;
133
extern u16 sCButtonsPressed;
134
extern s16 sCutsceneDialogID;
135
extern struct LakituState gLakituState;
136
extern s16 unused8033B3E8;
137
extern s16 sAreaYaw;
138
extern s16 sAreaYawChange;
139
extern s16 sLakituDist;
140
extern s16 sLakituPitch;
141
extern f32 sZoomAmount;
142
extern s16 sCSideButtonYaw;
143
extern s16 sBehindMarioSoundTimer;
144
extern f32 sZeroZoomDist;
145
extern s16 sCUpCameraPitch;
146
extern s16 sModeOffsetYaw;
147
extern s16 sSpiralStairsYawOffset;
148
extern s16 s8DirModeBaseYaw;
149
extern s16 s8DirModeYawOffset;
150
extern f32 sPanDistance;
151
extern f32 sCannonYOffset;
152
extern struct ModeTransitionInfo sModeInfo;
153
extern Vec3f sCastleEntranceOffset;
154
extern u32 sParTrackIndex;
155
extern struct ParallelTrackingPoint *sParTrackPath;
156
extern struct CameraStoredInfo sParTrackTransOff;
157
extern struct CameraStoredInfo sCameraStoreCUp;
158
extern struct CameraStoredInfo sCameraStoreCutscene;
159
extern s16 gCameraMovementFlags;
160
extern s16 sStatusFlags;
161
extern struct CutsceneSplinePoint sCurCreditsSplinePos[32];
162
extern struct CutsceneSplinePoint sCurCreditsSplineFocus[32];
163
extern s16 sCutsceneSplineSegment;
164
extern f32 sCutsceneSplineSegmentProgress;
165
extern s16 unused8033B6E8;
166
extern s16 sCutsceneShot;
167
extern s16 gCutsceneTimer;
168
extern struct CutsceneVariable sCutsceneVars[10];
169
extern s32 gObjCutsceneDone;
170
extern u32 gCutsceneObjSpawn;
171
extern struct Camera *gCamera;
172
173
/**
174
* Lakitu's position and focus.
175
* @see LakituState
176
*/
177
struct LakituState gLakituState;
178
struct CameraFOVStatus sFOVState;
179
struct TransitionInfo sModeTransition;
180
struct PlayerGeometry sMarioGeometry;
181
struct Camera *gCamera;
182
s16 unusedFreeRoamWallYaw;
183
s16 sAvoidYawVel;
184
s16 sCameraYawAfterDoorCutscene;
185
/**
186
* The current spline that controls the camera's position during the credits.
187
*/
188
struct CutsceneSplinePoint sCurCreditsSplinePos[32];
189
190
/**
191
* The current spline that controls the camera's focus during the credits.
192
*/
193
struct CutsceneSplinePoint sCurCreditsSplineFocus[32];
194
195
s16 unusedSplinePitch;
196
s16 unusedSplineYaw;
197
198
/**
199
* The progress (from 0 to 1) through the current spline segment.
200
* When it becomes >= 1, 1.0 is subtracted from it and sCutsceneSplineSegment is increased.
201
*/
202
f32 sCutsceneSplineSegmentProgress;
203
204
/**
205
* The current segment of the CutsceneSplinePoint[] being used.
206
*/
207
s16 sCutsceneSplineSegment;
208
s16 unused8033B6E8;
209
210
// Shaky Hand-held Camera effect variables
211
struct HandheldShakePoint sHandheldShakeSpline[4];
212
s16 sHandheldShakeMag;
213
f32 sHandheldShakeTimer;
214
f32 sHandheldShakeInc;
215
s16 sHandheldShakePitch;
216
s16 sHandheldShakeYaw;
217
s16 sHandheldShakeRoll;
218
219
/**
220
* Controls which object to spawn in the intro and ending cutscenes.
221
*/
222
u32 gCutsceneObjSpawn;
223
/**
224
* Controls when an object-based cutscene should end. It's only used in the star spawn cutscenes, but
225
* Yoshi also toggles this.
226
*/
227
s32 gObjCutsceneDone;
228
229
u32 unused8033B30C;
230
u32 unused8033B310;
231
232
/**
233
* Determines which R-Trigger mode is selected in the pause menu.
234
*/
235
s16 sSelectionFlags;
236
237
/**
238
* Flags that determine what movements the camera should start / do this frame.
239
*/
240
s16 gCameraMovementFlags;
241
s16 unused8033B316;
242
243
/**
244
* Flags that change how modes operate and how Lakitu moves.
245
* The most commonly used flag is CAM_FLAG_SMOOTH_MOVEMENT, which makes Lakitu fly to the next position,
246
* instead of warping.
247
*/
248
s16 sStatusFlags;
249
/**
250
* Flags that determine whether the player has already rotated left or right. Used in radial mode to
251
* determine whether to rotate all the way, or just to 60 degrees.
252
*/
253
s16 s2ndRotateFlags;
254
s16 unused8033B31A;
255
/**
256
* Flags that control buzzes and sounds that play, mostly for C-button input.
257
*/
258
s16 sCameraSoundFlags;
259
/**
260
* Stores what C-Buttons are pressed this frame.
261
*/
262
u16 sCButtonsPressed;
263
/**
264
* A copy of gDialogID, the dialog displayed during the cutscene.
265
*/
266
s16 sCutsceneDialogID;
267
/**
268
* The currently playing shot in the cutscene.
269
*/
270
s16 sCutsceneShot;
271
/**
272
* The current frame of the cutscene shot.
273
*/
274
s16 gCutsceneTimer;
275
s16 unused8033B3E8;
276
#if defined(VERSION_EU) || defined(VERSION_SH)
277
s16 unused8033B3E82;
278
#endif
279
/**
280
* The angle of the direction vector from the area's center to Mario's position.
281
*/
282
s16 sAreaYaw;
283
284
/**
285
* How much sAreaYaw changed when Mario moved.
286
*/
287
s16 sAreaYawChange;
288
289
/**
290
* Lakitu's distance from Mario in C-Down mode
291
*/
292
s16 sLakituDist;
293
294
/**
295
* How much Lakitu looks down in C-Down mode
296
*/
297
s16 sLakituPitch;
298
299
/**
300
* The amount of distance left to zoom out
301
*/
302
f32 sZoomAmount;
303
304
s16 sCSideButtonYaw;
305
306
/**
307
* Sound timer used to space out sounds in behind Mario mode
308
*/
309
s16 sBehindMarioSoundTimer;
310
311
/**
312
* Virtually unused aside being set to 0 and compared with gCameraZoomDist (which is never < 0)
313
*/
314
f32 sZeroZoomDist;
315
316
/**
317
* The camera's pitch in C-Up mode. Mainly controls Mario's head rotation.
318
*/
319
s16 sCUpCameraPitch;
320
/**
321
* The current mode's yaw, which gets added to the camera's yaw.
322
*/
323
s16 sModeOffsetYaw;
324
325
/**
326
* Stores Mario's yaw around the stairs, relative to the camera's position.
327
*
328
* Used in update_spiral_stairs_camera()
329
*/
330
s16 sSpiralStairsYawOffset;
331
332
/**
333
* The constant offset to 8-direction mode's yaw.
334
*/
335
s16 s8DirModeBaseYaw;
336
/**
337
* Player-controlled yaw offset in 8-direction mode, a multiple of 45 degrees.
338
*/
339
s16 s8DirModeYawOffset;
340
341
/**
342
* The distance that the camera will look ahead of Mario in the direction Mario is facing.
343
*/
344
f32 sPanDistance;
345
346
/**
347
* When Mario gets in the cannon, it is pointing straight up and rotates down.
348
* This is used to make the camera start up and rotate down, like the cannon.
349
*/
350
f32 sCannonYOffset;
351
/**
352
* These structs are used by the cutscenes. Most of the fields are unused, and some (all?) of the used
353
* ones have multiple uses.
354
* Check the cutscene_start functions for documentation on the cvars used by a specific cutscene.
355
*/
356
struct CutsceneVariable sCutsceneVars[10];
357
struct ModeTransitionInfo sModeInfo;
358
/**
359
* Offset added to sFixedModeBasePosition when Mario is inside, near the castle lobby entrance
360
*/
361
Vec3f sCastleEntranceOffset;
362
363
/**
364
* The index into the current parallel tracking path
365
*/
366
u32 sParTrackIndex;
367
368
/**
369
* The current list of ParallelTrackingPoints used in update_parallel_tracking_camera()
370
*/
371
struct ParallelTrackingPoint *sParTrackPath;
372
373
/**
374
* On the first frame after the camera changes to a different parallel tracking path, this stores the
375
* displacement between the camera's calculated new position and its previous positions
376
*
377
* This transition offset is then used to smoothly interpolate the camera's position between the two
378
* paths
379
*/
380
struct CameraStoredInfo sParTrackTransOff;
381
382
/**
383
* The information stored when C-Up is active, used to update Lakitu's rotation when exiting C-Up
384
*/
385
struct CameraStoredInfo sCameraStoreCUp;
386
387
/**
388
* The information stored during cutscenes
389
*/
390
struct CameraStoredInfo sCameraStoreCutscene;
391
392
// first iteration of data
393
u32 unused8032CFC0 = 0;
394
struct Object *gCutsceneFocus = NULL;
395
396
u32 unused8032CFC8 = 0;
397
u32 unused8032CFCC = 0;
398
399
/**
400
* The information of a second focus camera used by some objects
401
*/
402
struct Object *gSecondCameraFocus = NULL;
403
404
/**
405
* How fast the camera's yaw should approach the next yaw.
406
*/
407
s16 sYawSpeed = 0x400;
408
s32 gCurrLevelArea = 0;
409
u32 gPrevLevel = 0;
410
411
f32 unused8032CFE0 = 1000.0f;
412
f32 unused8032CFE4 = 800.0f;
413
u32 unused8032CFE8 = 0;
414
f32 gCameraZoomDist = 800.0f;
415
416
/**
417
* A cutscene that plays when the player interacts with an object
418
*/
419
u8 sObjectCutscene = 0;
420
421
/**
422
* The ID of the cutscene that ended. It's set to 0 if no cutscene ended less than 8 frames ago.
423
*
424
* It is only used to prevent the same cutscene from playing twice before 8 frames have passed.
425
*/
426
u8 gRecentCutscene = 0;
427
428
/**
429
* A timer that increments for 8 frames when a cutscene ends.
430
* When it reaches 8, it sets gRecentCutscene to 0.
431
*/
432
u8 sFramesSinceCutsceneEnded = 0;
433
/**
434
* Mario's response to a dialog.
435
* 0 = No response yet
436
* 1 = Yes
437
* 2 = No
438
* 3 = Dialog doesn't have a response
439
*/
440
u8 sCutsceneDialogResponse = DIALOG_RESPONSE_NONE;
441
struct PlayerCameraState *sMarioCamState = &gPlayerCameraState[0];
442
struct PlayerCameraState *sLuigiCamState = &gPlayerCameraState[1];
443
u32 unused8032D008 = 0;
444
Vec3f sFixedModeBasePosition = { 646.0f, 143.0f, -1513.0f };
445
Vec3f sUnusedModeBasePosition_2 = { 646.0f, 143.0f, -1513.0f };
446
Vec3f sUnusedModeBasePosition_3 = { 646.0f, 143.0f, -1513.0f };
447
Vec3f sUnusedModeBasePosition_4 = { 646.0f, 143.0f, -1513.0f };
448
Vec3f sUnusedModeBasePosition_5 = { 646.0f, 143.0f, -1513.0f };
449
450
s32 update_radial_camera(struct Camera *c, Vec3f, Vec3f);
451
s32 update_outward_radial_camera(struct Camera *c, Vec3f, Vec3f);
452
s32 update_behind_mario_camera(struct Camera *c, Vec3f, Vec3f);
453
s32 update_mario_camera(struct Camera *c, Vec3f, Vec3f);
454
s32 unused_update_mode_5_camera(struct Camera *c, Vec3f, Vec3f);
455
s32 update_c_up(struct Camera *c, Vec3f, Vec3f);
456
s32 nop_update_water_camera(struct Camera *c, Vec3f, Vec3f);
457
s32 update_slide_or_0f_camera(struct Camera *c, Vec3f, Vec3f);
458
s32 update_in_cannon(struct Camera *c, Vec3f, Vec3f);
459
s32 update_boss_fight_camera(struct Camera *c, Vec3f, Vec3f);
460
s32 update_parallel_tracking_camera(struct Camera *c, Vec3f, Vec3f);
461
s32 update_fixed_camera(struct Camera *c, Vec3f, Vec3f);
462
s32 update_8_directions_camera(struct Camera *c, Vec3f, Vec3f);
463
s32 update_slide_or_0f_camera(struct Camera *c, Vec3f, Vec3f);
464
s32 update_spiral_stairs_camera(struct Camera *c, Vec3f, Vec3f);
465
466
typedef s32 (*CameraTransition)(struct Camera *c, Vec3f, Vec3f);
467
CameraTransition sModeTransitions[] = {
468
NULL,
469
update_radial_camera,
470
update_outward_radial_camera,
471
update_behind_mario_camera,
472
update_mario_camera,
473
unused_update_mode_5_camera,
474
update_c_up,
475
update_mario_camera,
476
nop_update_water_camera,
477
update_slide_or_0f_camera,
478
update_in_cannon,
479
update_boss_fight_camera,
480
update_parallel_tracking_camera,
481
update_fixed_camera,
482
update_8_directions_camera,
483
update_slide_or_0f_camera,
484
update_mario_camera,
485
update_spiral_stairs_camera
486
};
487
488
// Move these two tables to another include file?
489
extern u8 sDanceCutsceneIndexTable[][4];
490
extern u8 sZoomOutAreaMasks[];
491
492
// Define the analog camera speed
493
#define ANALOG_AMOUNT (12 * (1 - configInvertedCamera * 2))
494
#define ANALOG_AMOUNT_VERTICAL (12 * (1 - configInvertedVerticalCamera * 2))
495
#define LROTATE_SPEED 0x400
496
497
#define VERTICAL_MIN 6144.0f
498
#define VERTICAL_MAX 12288.0f
499
#define VERTICAL_MAX_LIMITED 8192.0f
500
#define VERTICAL_MAX_PITCH 9216.0f
501
502
static void skip_camera_interpolation(void) {
503
gLakituState.skipCameraInterpolationTimestamp = gGlobalTimer;
504
}
505
506
/**
507
* Starts a camera shake triggered by an interaction
508
*/
509
void set_camera_shake_from_hit(s16 shake) {
510
switch (shake) {
511
// Makes the camera stop for a bit
512
case SHAKE_ATTACK:
513
gLakituState.focHSpeed = 0;
514
gLakituState.posHSpeed = 0;
515
break;
516
517
case SHAKE_FALL_DAMAGE:
518
set_camera_pitch_shake(0x60, 0x3, 0x8000);
519
set_camera_roll_shake(0x60, 0x3, 0x8000);
520
break;
521
522
case SHAKE_GROUND_POUND:
523
set_camera_pitch_shake(0x60, 0xC, 0x8000);
524
break;
525
526
case SHAKE_SMALL_DAMAGE:
527
if (sMarioCamState->action & (ACT_FLAG_SWIMMING | ACT_FLAG_METAL_WATER)) {
528
set_camera_yaw_shake(0x200, 0x10, 0x1000);
529
set_camera_roll_shake(0x400, 0x20, 0x1000);
530
set_fov_shake(0x100, 0x30, 0x8000);
531
} else {
532
set_camera_yaw_shake(0x80, 0x8, 0x4000);
533
set_camera_roll_shake(0x80, 0x8, 0x4000);
534
set_fov_shake(0x100, 0x30, 0x8000);
535
}
536
537
gLakituState.focHSpeed = 0;
538
gLakituState.posHSpeed = 0;
539
break;
540
541
case SHAKE_MED_DAMAGE:
542
if (sMarioCamState->action & (ACT_FLAG_SWIMMING | ACT_FLAG_METAL_WATER)) {
543
set_camera_yaw_shake(0x400, 0x20, 0x1000);
544
set_camera_roll_shake(0x600, 0x30, 0x1000);
545
set_fov_shake(0x180, 0x40, 0x8000);
546
} else {
547
set_camera_yaw_shake(0x100, 0x10, 0x4000);
548
set_camera_roll_shake(0x100, 0x10, 0x4000);
549
set_fov_shake(0x180, 0x40, 0x8000);
550
}
551
552
gLakituState.focHSpeed = 0;
553
gLakituState.posHSpeed = 0;
554
break;
555
556
case SHAKE_LARGE_DAMAGE:
557
if (sMarioCamState->action & (ACT_FLAG_SWIMMING | ACT_FLAG_METAL_WATER)) {
558
set_camera_yaw_shake(0x600, 0x30, 0x1000);
559
set_camera_roll_shake(0x800, 0x40, 0x1000);
560
set_fov_shake(0x200, 0x50, 0x8000);
561
} else {
562
set_camera_yaw_shake(0x180, 0x20, 0x4000);
563
set_camera_roll_shake(0x200, 0x20, 0x4000);
564
set_fov_shake(0x200, 0x50, 0x8000);
565
}
566
567
gLakituState.focHSpeed = 0;
568
gLakituState.posHSpeed = 0;
569
break;
570
571
case SHAKE_HIT_FROM_BELOW:
572
gLakituState.focHSpeed = 0.07;
573
gLakituState.posHSpeed = 0.07;
574
break;
575
576
case SHAKE_SHOCK:
577
set_camera_pitch_shake(random_float() * 64.f, 0x8, 0x8000);
578
set_camera_yaw_shake(random_float() * 64.f, 0x8, 0x8000);
579
break;
580
}
581
}
582
583
/**
584
* Start a shake from the environment
585
*/
586
void set_environmental_camera_shake(s16 shake) {
587
switch (shake) {
588
case SHAKE_ENV_EXPLOSION:
589
set_camera_pitch_shake(0x60, 0x8, 0x4000);
590
break;
591
592
case SHAKE_ENV_BOWSER_THROW_BOUNCE:
593
set_camera_pitch_shake(0xC0, 0x8, 0x4000);
594
break;
595
596
case SHAKE_ENV_BOWSER_JUMP:
597
set_camera_pitch_shake(0x100, 0x8, 0x3000);
598
break;
599
600
case SHAKE_ENV_UNUSED_6:
601
set_camera_roll_shake(0x80, 0x10, 0x3000);
602
break;
603
604
case SHAKE_ENV_UNUSED_7:
605
set_camera_pitch_shake(0x20, 0x8, 0x8000);
606
break;
607
608
case SHAKE_ENV_PYRAMID_EXPLODE:
609
set_camera_pitch_shake(0x40, 0x8, 0x8000);
610
break;
611
612
case SHAKE_ENV_JRB_SHIP_DRAIN:
613
set_camera_pitch_shake(0x20, 0x8, 0x8000);
614
set_camera_roll_shake(0x400, 0x10, 0x100);
615
break;
616
617
case SHAKE_ENV_FALLING_BITS_PLAT:
618
set_camera_pitch_shake(0x40, 0x2, 0x8000);
619
break;
620
621
case SHAKE_ENV_UNUSED_5:
622
set_camera_yaw_shake(-0x200, 0x80, 0x200);
623
break;
624
}
625
}
626
627
/**
628
* Starts a camera shake, but scales the amplitude by the point's distance from the camera
629
*/
630
void set_camera_shake_from_point(s16 shake, f32 posX, f32 posY, f32 posZ) {
631
switch (shake) {
632
case SHAKE_POS_BOWLING_BALL:
633
set_pitch_shake_from_point(0x28, 0x8, 0x4000, 2000.f, posX, posY, posZ);
634
break;
635
636
case SHAKE_POS_SMALL:
637
set_pitch_shake_from_point(0x80, 0x8, 0x4000, 4000.f, posX, posY, posZ);
638
set_fov_shake_from_point_preset(SHAKE_FOV_SMALL, posX, posY, posZ);
639
break;
640
641
case SHAKE_POS_MEDIUM:
642
set_pitch_shake_from_point(0xC0, 0x8, 0x4000, 6000.f, posX, posY, posZ);
643
set_fov_shake_from_point_preset(SHAKE_FOV_MEDIUM, posX, posY, posZ);
644
break;
645
646
case SHAKE_POS_LARGE:
647
set_pitch_shake_from_point(0x100, 0x8, 0x3000, 8000.f, posX, posY, posZ);
648
set_fov_shake_from_point_preset(SHAKE_FOV_LARGE, posX, posY, posZ);
649
break;
650
}
651
}
652
653
/**
654
* Start a camera shake from an environmental source, but only shake the camera's pitch.
655
*/
656
void unused_set_camera_pitch_shake_env(s16 shake) {
657
switch (shake) {
658
case SHAKE_ENV_EXPLOSION:
659
set_camera_pitch_shake(0x60, 0x8, 0x4000);
660
break;
661
662
case SHAKE_ENV_BOWSER_THROW_BOUNCE:
663
set_camera_pitch_shake(0xC0, 0x8, 0x4000);
664
break;
665
666
case SHAKE_ENV_BOWSER_JUMP:
667
set_camera_pitch_shake(0x100, 0x8, 0x3000);
668
break;
669
}
670
}
671
672
/**
673
* Calculates Mario's distance to the floor, or the water level if it is above the floor. Then:
674
* `posOff` is set to the distance multiplied by posMul and bounded to [-posBound, posBound]
675
* `focOff` is set to the distance multiplied by focMul and bounded to [-focBound, focBound]
676
*
677
* Notes:
678
* posMul is always 1.0f, focMul is always 0.9f
679
* both ranges are always 200.f
680
* Since focMul is 0.9, `focOff` is closer to the floor than `posOff`
681
* posOff and focOff are sometimes the same address, which just ignores the pos calculation
682
*! Doesn't return anything, but required to match on -O2
683
*/
684
BAD_RETURN(f32) calc_y_to_curr_floor(f32 *posOff, f32 posMul, f32 posBound, f32 *focOff, f32 focMul, f32 focBound) {
685
f32 floorHeight = sMarioGeometry.currFloorHeight;
686
f32 waterHeight;
687
UNUSED s32 filler;
688
689
if (!(sMarioCamState->action & ACT_FLAG_METAL_WATER)) {
690
//! @bug this should use sMarioGeometry.waterHeight
691
if (floorHeight < (waterHeight = find_water_level(sMarioCamState->pos[0], sMarioCamState->pos[2]))) {
692
floorHeight = waterHeight;
693
}
694
}
695
696
if (sMarioCamState->action & ACT_FLAG_ON_POLE) {
697
if (sMarioGeometry.currFloorHeight >= gMarioStates[0].usedObj->oPosY && sMarioCamState->pos[1]
698
< 0.7f * gMarioStates[0].usedObj->hitboxHeight + gMarioStates[0].usedObj->oPosY) {
699
posBound = 1200;
700
}
701
}
702
703
*posOff = (floorHeight - sMarioCamState->pos[1]) * posMul;
704
705
if (*posOff > posBound) {
706
*posOff = posBound;
707
}
708
709
if (*posOff < -posBound) {
710
*posOff = -posBound;
711
}
712
713
*focOff = (floorHeight - sMarioCamState->pos[1]) * focMul;
714
715
if (*focOff > focBound) {
716
*focOff = focBound;
717
}
718
719
if (*focOff < -focBound) {
720
*focOff = -focBound;
721
}
722
}
723
724
void focus_on_mario(Vec3f focus, Vec3f pos, f32 posYOff, f32 focYOff, f32 dist, s16 pitch, s16 yaw) {
725
Vec3f marioPos;
726
727
marioPos[0] = sMarioCamState->pos[0];
728
marioPos[1] = sMarioCamState->pos[1] + posYOff;
729
marioPos[2] = sMarioCamState->pos[2];
730
731
vec3f_set_dist_and_angle(marioPos, pos, dist, pitch + sLakituPitch, yaw);
732
733
focus[0] = sMarioCamState->pos[0];
734
focus[1] = sMarioCamState->pos[1] + focYOff;
735
focus[2] = sMarioCamState->pos[2];
736
}
737
738
static UNUSED void set_pos_to_mario(Vec3f foc, Vec3f pos, f32 yOff, f32 focYOff, f32 dist, s16 pitch, s16 yaw) {
739
Vec3f marioPos;
740
f32 posDist;
741
f32 focDist;
742
743
s16 posPitch;
744
s16 posYaw;
745
s16 focPitch;
746
s16 focYaw;
747
748
vec3f_copy(marioPos, sMarioCamState->pos);
749
marioPos[1] += yOff;
750
751
vec3f_set_dist_and_angle(marioPos, pos, dist, pitch + sLakituPitch, yaw);
752
vec3f_get_dist_and_angle(pos, sMarioCamState->pos, &posDist, &posPitch, &posYaw);
753
754
//! Useless get and set
755
vec3f_get_dist_and_angle(pos, foc, &focDist, &focPitch, &focYaw);
756
vec3f_set_dist_and_angle(pos, foc, focDist, focPitch, focYaw);
757
758
foc[1] = sMarioCamState->pos[1] + focYOff;
759
}
760
761
/**
762
* Set the camera's y coordinate to goalHeight, respecting floors and ceilings in the way
763
*/
764
void set_camera_height(struct Camera *c, f32 goalHeight) {
765
struct Surface *surface;
766
f32 marioFloorHeight;
767
f32 marioCeilHeight;
768
f32 camFloorHeight;
769
UNUSED u8 filler[8];
770
UNUSED s16 action = sMarioCamState->action;
771
f32 baseOff = 125.f;
772
f32 camCeilHeight = find_ceil(c->pos[0], gLakituState.goalPos[1] - 50.f, c->pos[2], &surface);
773
774
if (sMarioCamState->action & ACT_FLAG_HANGING) {
775
marioCeilHeight = sMarioGeometry.currCeilHeight;
776
marioFloorHeight = sMarioGeometry.currFloorHeight;
777
778
if (marioFloorHeight < marioCeilHeight - 400.f) {
779
marioFloorHeight = marioCeilHeight - 400.f;
780
}
781
782
goalHeight = marioFloorHeight + (marioCeilHeight - marioFloorHeight) * 0.4f;
783
784
if (sMarioCamState->pos[1] - 400 > goalHeight) {
785
goalHeight = sMarioCamState->pos[1] - 400;
786
}
787
788
approach_camera_height(c, goalHeight, 5.f);
789
} else {
790
camFloorHeight = find_floor(c->pos[0], c->pos[1] + 100.f, c->pos[2], &surface) + baseOff;
791
marioFloorHeight = baseOff + sMarioGeometry.currFloorHeight;
792
793
if (camFloorHeight < marioFloorHeight) {
794
camFloorHeight = marioFloorHeight;
795
}
796
if (goalHeight < camFloorHeight) {
797
goalHeight = camFloorHeight;
798
c->pos[1] = goalHeight;
799
}
800
// Warp camera to goalHeight if further than 1000 and Mario is stuck in the ground
801
if (sMarioCamState->action == ACT_BUTT_STUCK_IN_GROUND ||
802
sMarioCamState->action == ACT_HEAD_STUCK_IN_GROUND ||
803
sMarioCamState->action == ACT_FEET_STUCK_IN_GROUND) {
804
if (ABS(c->pos[1] - goalHeight) > 1000.f) {
805
c->pos[1] = goalHeight;
806
}
807
}
808
approach_camera_height(c, goalHeight, 20.f);
809
if (camCeilHeight != CELL_HEIGHT_LIMIT) {
810
camCeilHeight -= baseOff;
811
if ((c->pos[1] > camCeilHeight && sMarioGeometry.currFloorHeight + baseOff < camCeilHeight)
812
|| (sMarioGeometry.currCeilHeight != CELL_HEIGHT_LIMIT
813
&& sMarioGeometry.currCeilHeight > camCeilHeight && c->pos[1] > camCeilHeight)) {
814
c->pos[1] = camCeilHeight;
815
}
816
}
817
}
818
}
819
820
/**
821
* Pitch the camera down when the camera is facing down a slope
822
*/
823
s16 look_down_slopes(s16 camYaw) {
824
struct Surface *floor;
825
f32 floorDY;
826
// Default pitch
827
s16 pitch = 0x05B0;
828
// x and z offsets towards the camera
829
f32 xOff = sMarioCamState->pos[0] + sins(camYaw) * 40.f;
830
f32 zOff = sMarioCamState->pos[2] + coss(camYaw) * 40.f;
831
832
floorDY = find_floor(xOff, sMarioCamState->pos[1], zOff, &floor) - sMarioCamState->pos[1];
833
834
if (floor != NULL) {
835
if (floor->type != SURFACE_WALL_MISC && floorDY > 0) {
836
if (floor->normal.z == 0.f && floorDY < 100.f) {
837
pitch = 0x05B0;
838
} else {
839
// Add the slope's angle of declination to the pitch
840
pitch += atan2s(40.f, floorDY);
841
}
842
}
843
}
844
845
return pitch;
846
}
847
848
/**
849
* Look ahead to the left or right in the direction the player is facing
850
* The calculation for pan[0] could be simplified to:
851
* yaw = -yaw;
852
* pan[0] = sins(sMarioCamState->faceAngle[1] + yaw) * sins(0xC00) * dist;
853
* Perhaps, early in development, the pan used to be calculated for both the x and z directions
854
*
855
* Since this function only affects the camera's focus, Mario's movement direction isn't affected.
856
*/
857
void pan_ahead_of_player(struct Camera *c, u32 panLess) {
858
f32 dist;
859
s16 pitch;
860
s16 yaw;
861
Vec3f pan = { 0, 0, 0 };
862
863
// The beta doesn't seem to do this?
864
if (configBetaLikeCamera)
865
return;
866
867
// Get distance and angle from camera to Mario.
868
vec3f_get_dist_and_angle(c->pos, sMarioCamState->pos, &dist, &pitch, &yaw);
869
870
// The camera will pan ahead up to about 30% of the camera's distance to Mario.
871
pan[2] = sins(panLess ? 0x600 : 0xC00) * dist;
872
873
rotate_in_xz(pan, pan, sMarioCamState->faceAngle[1]);
874
// rotate in the opposite direction
875
yaw = -yaw;
876
rotate_in_xz(pan, pan, yaw);
877
// Only pan left or right
878
pan[2] = 0.f;
879
880
// If Mario is long jumping, or on a flag pole (but not at the top), then pan in the opposite direction
881
if (sMarioCamState->action == ACT_LONG_JUMP ||
882
(sMarioCamState->action != ACT_TOP_OF_POLE && (sMarioCamState->action & ACT_FLAG_ON_POLE))) {
883
pan[0] = -pan[0];
884
}
885
886
// Slowly make the actual pan, sPanDistance, approach the calculated pan
887
// If Mario is sleeping, then don't pan
888
if (sStatusFlags & CAM_FLAG_SLEEPING) {
889
approach_f32_asymptotic_bool(&sPanDistance, 0.f, 0.025f);
890
} else {
891
approach_f32_asymptotic_bool(&sPanDistance, pan[0], 0.025f);
892
}
893
894
// Now apply the pan. It's a dir vector to the left or right, rotated by the camera's yaw to Mario
895
pan[0] = sPanDistance;
896
yaw = -yaw;
897
rotate_in_xz(pan, pan, yaw);
898
vec3f_add(c->focus, pan);
899
}
900
901
s16 find_in_bounds_yaw_wdw_bob_thi(Vec3f pos, Vec3f origin, s16 yaw) {
902
switch (gCurrLevelArea) {
903
case AREA_WDW_MAIN:
904
yaw = clamp_positions_and_find_yaw(pos, origin, 4508.f, -3739.f, 4508.f, -3739.f);
905
break;
906
case AREA_BOB:
907
yaw = clamp_positions_and_find_yaw(pos, origin, 8000.f, -8000.f, 7050.f, -8000.f);
908
break;
909
case AREA_THI_HUGE:
910
yaw = clamp_positions_and_find_yaw(pos, origin, 8192.f, -8192.f, 8192.f, -8192.f);
911
break;
912
case AREA_THI_TINY:
913
yaw = clamp_positions_and_find_yaw(pos, origin, 2458.f, -2458.f, 2458.f, -2458.f);
914
break;
915
}
916
return yaw;
917
}
918
919
/**
920
* Rotates the camera around the area's center point.
921
*/
922
s32 update_radial_camera(struct Camera *c, Vec3f focus, Vec3f pos) {
923
f32 cenDistX = sMarioCamState->pos[0] - c->areaCenX;
924
f32 cenDistZ = sMarioCamState->pos[2] - c->areaCenZ;
925
s16 camYaw = atan2s(cenDistZ, cenDistX) + sModeOffsetYaw;
926
s16 pitch = look_down_slopes(camYaw);
927
UNUSED f32 unused1;
928
f32 posY;
929
f32 focusY;
930
UNUSED f32 unused2;
931
UNUSED f32 unused3;
932
f32 yOff = 125.f;
933
f32 baseDist = 1000.f + configAdditionalCameraDistance * 10.0f;
934
935
sAreaYaw = camYaw - sModeOffsetYaw;
936
calc_y_to_curr_floor(&posY, 1.f, 200.f, &focusY, 0.9f, 200.f);
937
focus_on_mario(focus, pos, posY + yOff, focusY + yOff, sLakituDist + baseDist, pitch, camYaw);
938
camYaw = find_in_bounds_yaw_wdw_bob_thi(pos, focus, camYaw);
939
940
return camYaw;
941
}
942
943
/**
944
* Update the camera during 8 directional mode
945
*/
946
s32 update_8_directions_camera(struct Camera *c, Vec3f focus, Vec3f pos) {
947
UNUSED f32 cenDistX = sMarioCamState->pos[0] - c->areaCenX;
948
UNUSED f32 cenDistZ = sMarioCamState->pos[2] - c->areaCenZ;
949
s16 camYaw = s8DirModeBaseYaw + s8DirModeYawOffset;
950
s16 pitch = look_down_slopes(camYaw);
951
f32 posY;
952
f32 focusY;
953
UNUSED f32 unused1;
954
UNUSED f32 unused2;
955
UNUSED f32 unused3;
956
f32 yOff = 125.f;
957
f32 baseDist = 1000.f + configAdditionalCameraDistance * 10.0f;
958
959
sAreaYaw = camYaw;
960
calc_y_to_curr_floor(&posY, 1.f, 200.f, &focusY, 0.9f, 200.f);
961
focus_on_mario(focus, pos, posY + yOff, focusY + yOff, sLakituDist + baseDist, pitch, camYaw);
962
pan_ahead_of_player(c, FALSE);
963
if (gCurrLevelArea == AREA_DDD_SUB) {
964
camYaw = clamp_positions_and_find_yaw(pos, focus, 6839.f, 995.f, 5994.f, -3945.f);
965
}
966
967
return camYaw;
968
}
969
970
/**
971
* Update the camera during custom camera mode
972
*/
973
s32 update_custom_camera(struct Camera *c, Vec3f focus, Vec3f pos, f32 yOff, f32 additionalDistance, s8 dynamic) {
974
s16 camYaw = sModeOffsetYaw;
975
//s16 pitch = dynamic ? look_down_slopes(camYaw) : 0.0f;
976
s16 pitch = 0.0f;
977
f32 posY;
978
f32 focusY;
979
980
f32 dist = (sLakituDist + (((gCameraMovementFlags & CAM_MOVE_ZOOMED_OUT) ? configCustomCameraDistanceZoomedOut : configCustomCameraDistance) + configAdditionalCameraDistance) * 10.0f + additionalDistance)
981
* (((MIN(sLakituPitch, VERTICAL_MAX_PITCH) + VERTICAL_MIN) / (VERTICAL_MIN + VERTICAL_MAX_PITCH)) * 1.25f + 0.5f);
982
983
sAreaYaw = camYaw;
984
985
calc_y_to_curr_floor(&posY, 1.f, 200.f, &focusY, 0.9f, 200.f);
986
focus_on_mario(focus, pos, posY + yOff, focusY + yOff, dist, pitch, camYaw);
987
988
if (dynamic) {
989
pan_ahead_of_player(c, TRUE);
990
}
991
992
return camYaw;
993
}
994
995
/**
996
* Moves the camera for the radial and outward radial camera modes.
997
*
998
* If sModeOffsetYaw is 0, the camera points directly at the area center point.
999
*/
1000
void radial_camera_move(struct Camera *c) {
1001
s16 maxAreaYaw = DEGREES(60);
1002
s16 minAreaYaw = DEGREES(-60);
1003
s16 rotateSpeed = 0x1000;
1004
s16 avoidYaw;
1005
s32 avoidStatus;
1006
UNUSED s16 unused1 = 0;
1007
UNUSED s32 unused2 = 0;
1008
f32 areaDistX = sMarioCamState->pos[0] - c->areaCenX;
1009
f32 areaDistZ = sMarioCamState->pos[2] - c->areaCenZ;
1010
UNUSED s32 filler;
1011
s16 lCamRotation = DEGREES(180);
1012
1013
// How much the camera's yaw changed
1014
s16 yawOffset = calculate_yaw(sMarioCamState->pos, c->pos) - atan2s(areaDistZ, areaDistX);
1015
1016
if (yawOffset > maxAreaYaw) {
1017
yawOffset = maxAreaYaw;
1018
}
1019
if (yawOffset < minAreaYaw) {
1020
yawOffset = minAreaYaw;
1021
}
1022
1023
// Check if Mario stepped on a surface that rotates the camera. For example, when Mario enters the
1024
// gate in BoB, the camera turns right to face up the hill path
1025
if (!(gCameraMovementFlags & CAM_MOVE_ROTATE)) {
1026
if (sMarioGeometry.currFloorType == SURFACE_CAMERA_MIDDLE
1027
&& sMarioGeometry.prevFloorType != SURFACE_CAMERA_MIDDLE) {
1028
gCameraMovementFlags |= (CAM_MOVE_RETURN_TO_MIDDLE | CAM_MOVE_ENTERED_ROTATE_SURFACE);
1029
}
1030
if (sMarioGeometry.currFloorType == SURFACE_CAMERA_ROTATE_RIGHT
1031
&& sMarioGeometry.prevFloorType != SURFACE_CAMERA_ROTATE_RIGHT) {
1032
gCameraMovementFlags |= (CAM_MOVE_ROTATE_RIGHT | CAM_MOVE_ENTERED_ROTATE_SURFACE);
1033
}
1034
if (sMarioGeometry.currFloorType == SURFACE_CAMERA_ROTATE_LEFT
1035
&& sMarioGeometry.prevFloorType != SURFACE_CAMERA_ROTATE_LEFT) {
1036
gCameraMovementFlags |= (CAM_MOVE_ROTATE_LEFT | CAM_MOVE_ENTERED_ROTATE_SURFACE);
1037
}
1038
}
1039
1040
if (gCameraMovementFlags & CAM_MOVE_ENTERED_ROTATE_SURFACE) {
1041
rotateSpeed = 0x200;
1042
}
1043
1044
if (c->mode == CAMERA_MODE_OUTWARD_RADIAL) {
1045
areaDistX = -areaDistX;
1046
areaDistZ = -areaDistZ;
1047
}
1048
1049
// Avoid obstructing walls
1050
avoidStatus = rotate_camera_around_walls(c, c->pos, &avoidYaw, 0x400);
1051
if (avoidStatus == 3) {
1052
if (avoidYaw - atan2s(areaDistZ, areaDistX) + DEGREES(90) < 0) {
1053
avoidYaw += DEGREES(180);
1054
}
1055
1056
// We want to change sModeOffsetYaw so that the player is no longer obstructed by the wall.
1057
// So, we make avoidYaw relative to the yaw around the area center
1058
avoidYaw -= atan2s(areaDistZ, areaDistX);
1059
1060
// Bound avoid yaw to radial mode constraints
1061
if (avoidYaw > DEGREES(105)) {
1062
avoidYaw = DEGREES(105);
1063
}
1064
if (avoidYaw < DEGREES(-105)) {
1065
avoidYaw = DEGREES(-105);
1066
}
1067
}
1068
1069
if (gCameraMovementFlags & CAM_MOVE_RETURN_TO_MIDDLE) {
1070
if (camera_approach_s16_symmetric_bool(&sModeOffsetYaw, 0, rotateSpeed) == 0) {
1071
gCameraMovementFlags &= ~CAM_MOVE_RETURN_TO_MIDDLE;
1072
}
1073
} else {
1074
// Prevent the player from rotating into obstructing walls
1075
if ((gCameraMovementFlags & CAM_MOVE_ROTATE_RIGHT) && avoidStatus == 3
1076
&& avoidYaw + 0x10 < sModeOffsetYaw) {
1077
sModeOffsetYaw = avoidYaw;
1078
gCameraMovementFlags &= ~(CAM_MOVE_ROTATE_RIGHT | CAM_MOVE_ENTERED_ROTATE_SURFACE);
1079
}
1080
if ((gCameraMovementFlags & CAM_MOVE_ROTATE_LEFT) && avoidStatus == 3
1081
&& avoidYaw - 0x10 > sModeOffsetYaw) {
1082
sModeOffsetYaw = avoidYaw;
1083
gCameraMovementFlags &= ~(CAM_MOVE_ROTATE_LEFT | CAM_MOVE_ENTERED_ROTATE_SURFACE);
1084
}
1085
1086
// If it's the first time rotating, just rotate to +-60 degrees
1087
if (!(s2ndRotateFlags & CAM_MOVE_ROTATE_RIGHT) && (gCameraMovementFlags & CAM_MOVE_ROTATE_RIGHT)
1088
&& camera_approach_s16_symmetric_bool(&sModeOffsetYaw, maxAreaYaw, rotateSpeed) == 0) {
1089
gCameraMovementFlags &= ~(CAM_MOVE_ROTATE_RIGHT | CAM_MOVE_ENTERED_ROTATE_SURFACE);
1090
}
1091
if (!(s2ndRotateFlags & CAM_MOVE_ROTATE_LEFT) && (gCameraMovementFlags & CAM_MOVE_ROTATE_LEFT)
1092
&& camera_approach_s16_symmetric_bool(&sModeOffsetYaw, minAreaYaw, rotateSpeed) == 0) {
1093
gCameraMovementFlags &= ~(CAM_MOVE_ROTATE_LEFT | CAM_MOVE_ENTERED_ROTATE_SURFACE);
1094
}
1095
1096
// If it's the second time rotating, rotate all the way to +-105 degrees.
1097
if ((s2ndRotateFlags & CAM_MOVE_ROTATE_RIGHT) && (gCameraMovementFlags & CAM_MOVE_ROTATE_RIGHT)
1098
&& camera_approach_s16_symmetric_bool(&sModeOffsetYaw, DEGREES(105), rotateSpeed) == 0) {
1099
gCameraMovementFlags &= ~(CAM_MOVE_ROTATE_RIGHT | CAM_MOVE_ENTERED_ROTATE_SURFACE);
1100
s2ndRotateFlags &= ~CAM_MOVE_ROTATE_RIGHT;
1101
}
1102
if ((s2ndRotateFlags & CAM_MOVE_ROTATE_LEFT) && (gCameraMovementFlags & CAM_MOVE_ROTATE_LEFT)
1103
&& camera_approach_s16_symmetric_bool(&sModeOffsetYaw, DEGREES(-105), rotateSpeed) == 0) {
1104
gCameraMovementFlags &= ~(CAM_MOVE_ROTATE_LEFT | CAM_MOVE_ENTERED_ROTATE_SURFACE);
1105
s2ndRotateFlags &= ~CAM_MOVE_ROTATE_LEFT;
1106
}
1107
1108
if (configImprovedCButtonCamera)
1109
{
1110
if (gPlayer1Controller->buttonPressed & L_CBUTTONS || gPlayer1Controller->buttonPressed & R_CBUTTONS) {
1111
play_sound_cbutton_side();
1112
}
1113
if (gPlayer1Controller->buttonDown & L_CBUTTONS) {
1114
sModeOffsetYaw -= ANALOG_AMOUNT * configCameraSpeed * 2.0f;
1115
gCameraMovementFlags &= ~(CAM_MOVE_ROTATE_RIGHT | CAM_MOVE_ENTERED_ROTATE_SURFACE);
1116
}
1117
if (gPlayer1Controller->buttonDown & R_CBUTTONS) {
1118
sModeOffsetYaw += ANALOG_AMOUNT * configCameraSpeed * 2.0f;
1119
gCameraMovementFlags &= ~(CAM_MOVE_ROTATE_LEFT | CAM_MOVE_ENTERED_ROTATE_SURFACE);
1120
}
1121
}
1122
1123
// Analog camera code
1124
if (gPlayer1Controller->stick2X != 0 &&
1125
gCurrDemoInput == NULL)
1126
{
1127
if (gPlayer1Controller->stick2X > 0) {
1128
gCameraMovementFlags &= ~(CAM_MOVE_ROTATE_RIGHT | CAM_MOVE_ENTERED_ROTATE_SURFACE);
1129
}
1130
else {
1131
gCameraMovementFlags &= ~(CAM_MOVE_ROTATE_LEFT | CAM_MOVE_ENTERED_ROTATE_SURFACE);
1132
}
1133
sModeOffsetYaw -= ANALOG_AMOUNT * (gPlayer1Controller->stick2X / 32.0f) * configCameraSpeed;
1134
}
1135
1136
if (configCenterCameraButton) {
1137
if (c->mode == CAMERA_MODE_OUTWARD_RADIAL) {
1138
lCamRotation = 0;
1139
}
1140
if (gPlayer1Controller->buttonPressed & L_TRIG) {
1141
sModeOffsetYaw = sMarioCamState->faceAngle[1]+lCamRotation-sAreaYaw;
1142
play_sound_rbutton_changed();
1143
}
1144
if (gPlayer1Controller->buttonDown & L_TRIG) {
1145
camera_approach_s16_symmetric_bool(&sModeOffsetYaw, sMarioCamState->faceAngle[1]+lCamRotation-sAreaYaw, LROTATE_SPEED);
1146
}
1147
}
1148
}
1149
if (!(gCameraMovementFlags & CAM_MOVE_ROTATE)) {
1150
// If not rotating, rotate away from walls obscuring Mario from view
1151
if (avoidStatus == 3) {
1152
approach_s16_asymptotic_bool(&sModeOffsetYaw, avoidYaw, 10);
1153
} else {
1154
if (c->mode == CAMERA_MODE_RADIAL) {
1155
// sModeOffsetYaw only updates when Mario is moving
1156
rotateSpeed = gMarioStates[0].forwardVel / 32.f * 128.f;
1157
camera_approach_s16_symmetric_bool(&sModeOffsetYaw, yawOffset, rotateSpeed);
1158
}
1159
if (c->mode == CAMERA_MODE_OUTWARD_RADIAL) {
1160
sModeOffsetYaw = offset_yaw_outward_radial(c, atan2s(areaDistZ, areaDistX));
1161
}
1162
}
1163
}
1164
if (!configImprovedCamera) {
1165
// Bound sModeOffsetYaw within (-120, 120) degrees
1166
if (sModeOffsetYaw > 0x5554) {
1167
sModeOffsetYaw = 0x5554;
1168
}
1169
if (sModeOffsetYaw < -0x5554) {
1170
sModeOffsetYaw = -0x5554;
1171
}
1172
}
1173
}
1174
1175
/**
1176
* Moves Lakitu from zoomed in to zoomed out and vice versa.
1177
* When C-Down mode is not active, sLakituDist and sLakituPitch decrease to 0.
1178
*/
1179
void lakitu_zoom(f32 rangeDist, s16 rangePitch) {
1180
if (sLakituDist < 0) {
1181
if ((sLakituDist += 30) > 0) {
1182
sLakituDist = 0;
1183
}
1184
} else if (rangeDist < sLakituDist) {
1185
if ((sLakituDist -= 30) < rangeDist) {
1186
sLakituDist = rangeDist;
1187
}
1188
} else if (gCameraMovementFlags & CAM_MOVE_ZOOMED_OUT) {
1189
if ((sLakituDist += 30) > rangeDist) {
1190
sLakituDist = rangeDist;
1191
}
1192
} else {
1193
if ((sLakituDist -= 30) < 0) {
1194
sLakituDist = 0;
1195
}
1196
}
1197
1198
if (rangePitch == 0) {
1199
sLakituPitch = MIN(MAX(sLakituPitch + ANALOG_AMOUNT_VERTICAL * (gPlayer1Controller->stick2Y / 48.0f) * configCameraSpeed, -VERTICAL_MIN), VERTICAL_MAX);
1200
}
1201
else {
1202
if (gCurrLevelArea == AREA_SSL_PYRAMID && gCamera->mode == CAMERA_MODE_OUTWARD_RADIAL) {
1203
rangePitch /= 2;
1204
}
1205
1206
if (gCameraMovementFlags & CAM_MOVE_ZOOMED_OUT) {
1207
if ((sLakituPitch += rangePitch / 13) > rangePitch) {
1208
sLakituPitch = rangePitch;
1209
}
1210
} else {
1211
if ((sLakituPitch -= rangePitch / 13) < 0) {
1212
sLakituPitch = 0;
1213
}
1214
}
1215
}
1216
}
1217
1218
void radial_camera_input_default(struct Camera *c) {
1219
radial_camera_input(c, 0.f);
1220
}
1221
1222
/**
1223
* Makes Lakitu cam's yaw match the angle turned towards in C-Up mode, and makes Lakitu slowly fly back
1224
* to the distance he was at before C-Up
1225
*/
1226
void update_yaw_and_dist_from_c_up(UNUSED struct Camera *c) {
1227
f32 dist = 1000.f;
1228
1229
sModeOffsetYaw = sModeInfo.transitionStart.yaw - sAreaYaw;
1230
sLakituDist = sModeInfo.transitionStart.dist - dist;
1231
// No longer in C-Up
1232
gCameraMovementFlags &= ~CAM_MOVING_INTO_MODE;
1233
}
1234
1235
/**
1236
* Handles input and updates for the radial camera mode
1237
*/
1238
void mode_radial_camera(struct Camera *c) {
1239
Vec3f pos;
1240
UNUSED u8 unused1[8];
1241
s16 oldAreaYaw = sAreaYaw;
1242
UNUSED u8 unused2[4];
1243
1244
if (gCameraMovementFlags & CAM_MOVING_INTO_MODE) {
1245
update_yaw_and_dist_from_c_up(c);
1246
}
1247
1248
radial_camera_input_default(c);
1249
radial_camera_move(c);
1250
1251
if (c->mode == CAMERA_MODE_RADIAL) {
1252
lakitu_zoom(400.f, 0x900);
1253
}
1254
c->nextYaw = update_radial_camera(c, c->focus, pos);
1255
c->pos[0] = pos[0];
1256
c->pos[2] = pos[2];
1257
sAreaYawChange = sAreaYaw - oldAreaYaw;
1258
if (sMarioCamState->action == ACT_RIDING_HOOT) {
1259
pos[1] += 500.f;
1260
}
1261
set_camera_height(c, pos[1]);
1262
pan_ahead_of_player(c, FALSE);
1263
}
1264
1265
/**
1266
* A mode that only has 8 camera angles, 45 degrees apart
1267
*/
1268
void mode_8_directions_camera(struct Camera *c) {
1269
Vec3f pos;
1270
UNUSED u8 unused[8];
1271
s16 oldAreaYaw = sAreaYaw;
1272
1273
radial_camera_input(c, 0.f);
1274
1275
if (configImprovedCButtonCamera)
1276
{
1277
if (gPlayer1Controller->buttonPressed & L_CBUTTONS || gPlayer1Controller->buttonPressed & R_CBUTTONS) {
1278
play_sound_cbutton_side();
1279
}
1280
if (gPlayer1Controller->buttonDown & L_CBUTTONS) {
1281
s8DirModeYawOffset += ANALOG_AMOUNT * configCameraSpeed * 2.0f;
1282
}
1283
if (gPlayer1Controller->buttonDown & R_CBUTTONS) {
1284
s8DirModeYawOffset -= ANALOG_AMOUNT * configCameraSpeed * 2.0f;
1285
}
1286
}
1287
else
1288
{
1289
if (gPlayer1Controller->buttonPressed & R_CBUTTONS) {
1290
s8DirModeYawOffset += DEGREES(45);
1291
play_sound_cbutton_side();
1292
}
1293
if (gPlayer1Controller->buttonPressed & L_CBUTTONS) {
1294
s8DirModeYawOffset -= DEGREES(45);
1295
play_sound_cbutton_side();
1296
}
1297
}
1298
1299
// Analog camera code
1300
if (gPlayer1Controller->stick2X != 0 &&
1301
gCurrDemoInput == NULL)
1302
{
1303
s8DirModeYawOffset -= ANALOG_AMOUNT * (gPlayer1Controller->stick2X / 32.0f) * configCameraSpeed;
1304
}
1305
1306
if (configCenterCameraButton) {
1307
if (gPlayer1Controller->buttonPressed & L_TRIG) {
1308
s8DirModeYawOffset = sMarioCamState->faceAngle[1] + DEGREES(180);
1309
play_sound_rbutton_changed();
1310
}
1311
if (gPlayer1Controller->buttonDown & L_TRIG) {
1312
camera_approach_s16_symmetric_bool(&s8DirModeYawOffset, sMarioCamState->faceAngle[1] + DEGREES(180), LROTATE_SPEED);
1313
}
1314
}
1315
1316
lakitu_zoom(400.f, 0x900);
1317
c->nextYaw = update_8_directions_camera(c, c->focus, pos);
1318
c->pos[0] = pos[0];
1319
c->pos[2] = pos[2];
1320
sAreaYawChange = sAreaYaw - oldAreaYaw;
1321
set_camera_height(c, pos[1]);
1322
}
1323
1324
1325
/**
1326
* A custom mode that gives you more control with the camera
1327
*/
1328
void mode_custom_camera(struct Camera *c, f32 yOff, f32 additionalDistance, s8 limitedAngle, s8 autoRotate, s8 dynamic) {
1329
Vec3f pos;
1330
s16 oldAreaYaw = sAreaYaw;
1331
s16 avoidYaw;
1332
1333
radial_camera_input(c, 0.f);
1334
1335
if (configImprovedCButtonCamera)
1336
{
1337
if (gPlayer1Controller->buttonPressed & L_CBUTTONS || gPlayer1Controller->buttonPressed & R_CBUTTONS) {
1338
play_sound_cbutton_side();
1339
}
1340
if (gPlayer1Controller->buttonDown & L_CBUTTONS) {
1341
sModeOffsetYaw -= ANALOG_AMOUNT * configCameraSpeed * 2.0f;
1342
}
1343
if (gPlayer1Controller->buttonDown & R_CBUTTONS) {
1344
sModeOffsetYaw += ANALOG_AMOUNT * configCameraSpeed * 2.0f;
1345
}
1346
}
1347
else
1348
{
1349
if (gPlayer1Controller->buttonPressed & R_CBUTTONS) {
1350
sModeOffsetYaw += DEGREES(22.5);
1351
play_sound_cbutton_side();
1352
}
1353
if (gPlayer1Controller->buttonPressed & L_CBUTTONS) {
1354
sModeOffsetYaw -= DEGREES(22.5);
1355
play_sound_cbutton_side();
1356
}
1357
}
1358
1359
// Analog camera code
1360
if (gPlayer1Controller->stick2X != 0 &&
1361
gCurrDemoInput == NULL)
1362
{
1363
sModeOffsetYaw -= ANALOG_AMOUNT * (gPlayer1Controller->stick2X / 32.0f) * configCameraSpeed;
1364
}
1365
1366
if (configCenterCameraButton) {
1367
if (gPlayer1Controller->buttonPressed & L_TRIG) {
1368
sModeOffsetYaw = sMarioCamState->faceAngle[1] + DEGREES(180);
1369
play_sound_rbutton_changed();
1370
}
1371
if (gPlayer1Controller->buttonDown & L_TRIG) {
1372
camera_approach_s16_symmetric_bool(&sModeOffsetYaw, sMarioCamState->faceAngle[1] + DEGREES(180), LROTATE_SPEED);
1373
}
1374
}
1375
1376
if (autoRotate) {
1377
camera_approach_s16_symmetric_bool(&sModeOffsetYaw, sMarioCamState->faceAngle[1] + DEGREES(180),
1378
ABS(gMarioState->forwardVel
1379
* ((gCameraMovementFlags & CAM_MOVE_ZOOMED_OUT) ? 8.0f : 12.0f)
1380
* (1.0f - MIN(MAX(sqrt((sLakituPitch + VERTICAL_MIN) / (VERTICAL_MAX+VERTICAL_MIN)), 0.0f), 0.75f))
1381
* (MIN(MAX(sqr(abs_angle_diff(sModeOffsetYaw, sMarioCamState->faceAngle[1] + DEGREES(180)) / 180), 0.0f), 1.0f))
1382
));
1383
}
1384
1385
lakitu_zoom(0, configVerticalCamera ? 0 : 0x900);
1386
1387
if (limitedAngle) {
1388
sLakituPitch = MIN(MAX(sLakituPitch, -VERTICAL_MIN), VERTICAL_MAX_LIMITED);
1389
}
1390
1391
c->nextYaw = update_custom_camera(c, c->focus, pos, yOff, additionalDistance, dynamic);
1392
c->pos[0] = pos[0];
1393
c->pos[1] = pos[1];
1394
c->pos[2] = pos[2];
1395
sAreaYawChange = sAreaYaw - oldAreaYaw;
1396
set_camera_height(c, pos[1]);
1397
1398
if (dynamic && rotate_camera_around_walls(c, c->pos, &avoidYaw, 0x400) > 0) {
1399
1400
camera_approach_s16_symmetric_bool(&sModeOffsetYaw, avoidYaw, 0x400);
1401
}
1402
}
1403
1404
/**
1405
* Updates the camera in outward radial mode.
1406
* sModeOffsetYaw is calculated in radial_camera_move, which calls offset_yaw_outward_radial
1407
*/
1408
s32 update_outward_radial_camera(struct Camera *c, Vec3f focus, Vec3f pos) {
1409
f32 xDistFocToMario = sMarioCamState->pos[0] - c->areaCenX;
1410
f32 zDistFocToMario = sMarioCamState->pos[2] - c->areaCenZ;
1411
s16 camYaw = atan2s(zDistFocToMario, xDistFocToMario) + sModeOffsetYaw + DEGREES(180);
1412
s16 pitch = look_down_slopes(camYaw);
1413
f32 baseDist = 1000.f + configAdditionalCameraDistance * 10.0f;
1414
// A base offset of 125.f is ~= Mario's eye height
1415
f32 yOff = 125.f;
1416
f32 posY;
1417
f32 focusY;
1418
1419
sAreaYaw = camYaw - sModeOffsetYaw - DEGREES(180);
1420
calc_y_to_curr_floor(&posY, 1.f, 200.f, &focusY, 0.9f, 200.f);
1421
focus_on_mario(focus, pos, posY + yOff, focusY + yOff, sLakituDist + baseDist, pitch, camYaw);
1422
1423
return camYaw;
1424
}
1425
1426
/**
1427
* Input and updates for the outward radial mode.
1428
*/
1429
void mode_outward_radial_camera(struct Camera *c) {
1430
Vec3f pos;
1431
s16 oldAreaYaw = sAreaYaw;
1432
1433
if (gCameraMovementFlags & CAM_MOVING_INTO_MODE) {
1434
update_yaw_and_dist_from_c_up(c);
1435
}
1436
radial_camera_input_default(c);
1437
radial_camera_move(c);
1438
lakitu_zoom(400.f, 0x900);
1439
c->nextYaw = update_outward_radial_camera(c, c->focus, pos);
1440
c->pos[0] = pos[0];
1441
c->pos[2] = pos[2];
1442
sAreaYawChange = sAreaYaw - oldAreaYaw;
1443
if (sMarioCamState->action == ACT_RIDING_HOOT) {
1444
pos[1] += 500.f;
1445
}
1446
set_camera_height(c, pos[1]);
1447
pan_ahead_of_player(c, FALSE);
1448
}
1449
1450
/**
1451
* Move the camera in parallel tracking mode
1452
*
1453
* Uses the line between the next two points in sParTrackPath
1454
* The camera can move forward/back and side to side, but it will face perpendicular to that line
1455
*
1456
* Although, annoyingly, it's not truly parallel, the function returns the yaw from the camera to Mario,
1457
* so Mario will run slightly towards the camera.
1458
*/
1459
s32 update_parallel_tracking_camera(struct Camera *c, Vec3f focus, Vec3f pos) {
1460
Vec3f path[2];
1461
Vec3f parMidPoint;
1462
Vec3f marioOffset;
1463
Vec3f camOffset;
1464
/// Adjusts the focus to look where Mario is facing. Unused since marioOffset is copied to focus
1465
Vec3f focOffset;
1466
s16 pathPitch;
1467
s16 pathYaw;
1468
UNUSED u8 filler[4];
1469
f32 distThresh;
1470
f32 zoom;
1471
f32 camParDist;
1472
UNUSED u8 filler2[8];
1473
f32 pathLength;
1474
UNUSED u8 filler3[8];
1475
UNUSED f32 unusedScale = 0.5f;
1476
f32 parScale = 0.5f;
1477
f32 marioFloorDist;
1478
Vec3f marioPos;
1479
UNUSED u8 filler4[12];
1480
UNUSED Vec3f unused4;
1481
Vec3s pathAngle;
1482
// Variables for changing to the next/prev path in the list
1483
Vec3f oldPos;
1484
Vec3f prevPathPos;
1485
Vec3f nextPathPos;
1486
f32 distToNext;
1487
f32 distToPrev;
1488
s16 prevPitch;
1489
s16 nextPitch;
1490
s16 prevYaw;
1491
s16 nextYaw;
1492
1493
unused4[0] = 0.f;
1494
unused4[1] = 0.f;
1495
unused4[2] = 0.f;
1496
1497
// Store camera pos, for changing between paths
1498
vec3f_copy(oldPos, pos);
1499
1500
vec3f_copy(path[0], sParTrackPath[sParTrackIndex].pos);
1501
vec3f_copy(path[1], sParTrackPath[sParTrackIndex + 1].pos);
1502
1503
distThresh = sParTrackPath[sParTrackIndex].distThresh;
1504
zoom = sParTrackPath[sParTrackIndex].zoom;
1505
calc_y_to_curr_floor(&marioFloorDist, 1.f, 200.f, &marioFloorDist, 0.9f, 200.f);
1506
1507
marioPos[0] = sMarioCamState->pos[0];
1508
// Mario's y pos + ~Mario's height + Mario's height above the floor
1509
marioPos[1] = sMarioCamState->pos[1] + 150.f + marioFloorDist;
1510
marioPos[2] = sMarioCamState->pos[2];
1511
1512
// Calculate middle of the path (parScale is 0.5f)
1513
parMidPoint[0] = path[0][0] + (path[1][0] - path[0][0]) * parScale;
1514
parMidPoint[1] = path[0][1] + (path[1][1] - path[0][1]) * parScale;
1515
parMidPoint[2] = path[0][2] + (path[1][2] - path[0][2]) * parScale;
1516
1517
// Get direction of path
1518
vec3f_get_dist_and_angle(path[0], path[1], &pathLength, &pathPitch, &pathYaw);
1519
1520
marioOffset[0] = marioPos[0] - parMidPoint[0];
1521
marioOffset[1] = marioPos[1] - parMidPoint[1];
1522
marioOffset[2] = marioPos[2] - parMidPoint[2];
1523
1524
// Make marioOffset point from the midpoint -> the start of the path
1525
// Rotating by -yaw then -pitch moves the hor dist from the midpoint into marioOffset's z coordinate
1526
// marioOffset[0] = the (perpendicular) horizontal distance from the path
1527
// marioOffset[1] = the vertical distance from the path
1528
// marioOffset[2] = the (parallel) horizontal distance from the path's midpoint
1529
pathYaw = -pathYaw;
1530
rotate_in_xz(marioOffset, marioOffset, pathYaw);
1531
pathYaw = -pathYaw;
1532
pathPitch = -pathPitch;
1533
rotate_in_yz(marioOffset, marioOffset, pathPitch);
1534
pathPitch = -pathPitch;
1535
vec3f_copy(focOffset, marioOffset);
1536
1537
// OK
1538
focOffset[0] = -focOffset[0] * 0.f;
1539
focOffset[1] = focOffset[1] * 0.f;
1540
1541
// Repeat above calcs with camOffset
1542
camOffset[0] = pos[0] - parMidPoint[0];
1543
camOffset[1] = pos[1] - parMidPoint[1];
1544
camOffset[2] = pos[2] - parMidPoint[2];
1545
pathYaw = -pathYaw;
1546
rotate_in_xz(camOffset, camOffset, pathYaw);
1547
pathYaw = -pathYaw;
1548
pathPitch = -pathPitch;
1549
rotate_in_yz(camOffset, camOffset, pathPitch);
1550
pathPitch = -pathPitch;
1551
1552
// If Mario is distThresh units away from the camera along the path, move the camera
1553
//! When distThresh != 0, it causes Mario to move slightly towards the camera when running sideways
1554
//! Set each ParallelTrackingPoint's distThresh to 0 to make Mario truly run parallel to the path
1555
if (marioOffset[2] > camOffset[2]) {
1556
if (marioOffset[2] - camOffset[2] > distThresh) {
1557
camOffset[2] = marioOffset[2] - distThresh;
1558
}
1559
} else {
1560
if (marioOffset[2] - camOffset[2] < -distThresh) {
1561
camOffset[2] = marioOffset[2] + distThresh;
1562
}
1563
}
1564
1565
// If zoom != 0.0, the camera will move zoom% closer to Mario
1566
marioOffset[0] = -marioOffset[0] * zoom;
1567
marioOffset[1] = marioOffset[1] * zoom;
1568
marioOffset[2] = camOffset[2];
1569
1570
//! Does nothing because focOffset[0] is always 0
1571
focOffset[0] *= 0.3f;
1572
//! Does nothing because focOffset[1] is always 0
1573
focOffset[1] *= 0.3f;
1574
1575
pathAngle[0] = pathPitch;
1576
pathAngle[1] = pathYaw; //! No effect
1577
1578
// make marioOffset[2] == distance from the start of the path
1579
marioOffset[2] = pathLength / 2 - marioOffset[2];
1580
1581
pathAngle[1] = pathYaw + DEGREES(180);
1582
pathAngle[2] = 0;
1583
1584
// Rotate the offset in the direction of the path again
1585
offset_rotated(pos, path[0], marioOffset, pathAngle);
1586
vec3f_get_dist_and_angle(path[0], c->pos, &camParDist, &pathPitch, &pathYaw);
1587
1588
// Adjust the focus. Does nothing, focus is set to Mario at the end
1589
focOffset[2] = pathLength / 2 - focOffset[2];
1590
offset_rotated(c->focus, path[0], focOffset, pathAngle);
1591
1592
// Changing paths, update the stored position offset
1593
if (sStatusFlags & CAM_FLAG_CHANGED_PARTRACK_INDEX) {
1594
sStatusFlags &= ~CAM_FLAG_CHANGED_PARTRACK_INDEX;
1595
sParTrackTransOff.pos[0] = oldPos[0] - c->pos[0];
1596
sParTrackTransOff.pos[1] = oldPos[1] - c->pos[1];
1597
sParTrackTransOff.pos[2] = oldPos[2] - c->pos[2];
1598
}
1599
// Slowly transition to the next path
1600
approach_f32_asymptotic_bool(&sParTrackTransOff.pos[0], 0.f, 0.025f);
1601
approach_f32_asymptotic_bool(&sParTrackTransOff.pos[1], 0.f, 0.025f);
1602
approach_f32_asymptotic_bool(&sParTrackTransOff.pos[2], 0.f, 0.025f);
1603
vec3f_add(c->pos, sParTrackTransOff.pos);
1604
1605
// Check if the camera should go to the next path
1606
if (sParTrackPath[sParTrackIndex + 1].startOfPath != 0) {
1607
// get Mario's distance to the next path
1608
calculate_angles(sParTrackPath[sParTrackIndex + 1].pos, sParTrackPath[sParTrackIndex + 2].pos, &nextPitch, &nextYaw);
1609
vec3f_set_dist_and_angle(sParTrackPath[sParTrackIndex + 1].pos, nextPathPos, 400.f, nextPitch, nextYaw);
1610
distToPrev = calc_abs_dist(marioPos, nextPathPos);
1611
1612
// get Mario's distance to the previous path
1613
calculate_angles(sParTrackPath[sParTrackIndex + 1].pos, sParTrackPath[sParTrackIndex].pos, &prevPitch, &prevYaw);
1614
vec3f_set_dist_and_angle(sParTrackPath[sParTrackIndex + 1].pos, prevPathPos, 400.f, prevPitch, prevYaw);
1615
distToNext = calc_abs_dist(marioPos, prevPathPos);
1616
if (distToPrev < distToNext) {
1617
sParTrackIndex++;
1618
sStatusFlags |= CAM_FLAG_CHANGED_PARTRACK_INDEX;
1619
}
1620
}
1621
1622
// Check if the camera should go to the previous path
1623
if (sParTrackIndex != 0) {
1624
// get Mario's distance to the next path
1625
calculate_angles((*(sParTrackPath + sParTrackIndex)).pos, (*(sParTrackPath + sParTrackIndex + 1)).pos, &nextPitch, &nextYaw);
1626
vec3f_set_dist_and_angle(sParTrackPath[sParTrackIndex].pos, nextPathPos, 700.f, nextPitch, nextYaw);
1627
distToPrev = calc_abs_dist(marioPos, nextPathPos);
1628
1629
// get Mario's distance to the previous path
1630
calculate_angles((*(sParTrackPath + sParTrackIndex)).pos, (*(sParTrackPath + sParTrackIndex - 1)).pos, &prevPitch, &prevYaw);
1631
vec3f_set_dist_and_angle(sParTrackPath[sParTrackIndex].pos, prevPathPos, 700.f, prevPitch, prevYaw);
1632
distToNext = calc_abs_dist(marioPos, prevPathPos);
1633
if (distToPrev > distToNext) {
1634
sParTrackIndex--;
1635
sStatusFlags |= CAM_FLAG_CHANGED_PARTRACK_INDEX;
1636
}
1637
}
1638
1639
// Update the camera focus and return the camera's yaw
1640
vec3f_copy(focus, marioPos);
1641
vec3f_get_dist_and_angle(focus, pos, &camParDist, &pathPitch, &pathYaw);
1642
return pathYaw;
1643
}
1644
1645
/**
1646
* Updates the camera during fixed mode.
1647
*/
1648
s32 update_fixed_camera(struct Camera *c, Vec3f focus, UNUSED Vec3f pos) {
1649
f32 focusFloorOff;
1650
f32 goalHeight;
1651
f32 ceilHeight;
1652
f32 heightOffset;
1653
f32 distCamToFocus;
1654
UNUSED u8 filler2[8];
1655
f32 scaleToMario = 0.5f;
1656
s16 pitch;
1657
s16 yaw;
1658
Vec3s faceAngle;
1659
struct Surface *ceiling;
1660
Vec3f basePos;
1661
UNUSED u8 filler[12];
1662
1663
play_camera_buzz_if_c_sideways();
1664
1665
// Don't move closer to Mario in these areas
1666
switch (gCurrLevelArea) {
1667
case AREA_RR:
1668
scaleToMario = 0.f;
1669
heightOffset = 0.f;
1670
break;
1671
1672
case AREA_CASTLE_LOBBY:
1673
scaleToMario = 0.3f;
1674
heightOffset = 0.f;
1675
break;
1676
1677
case AREA_BBH:
1678
scaleToMario = 0.f;
1679
heightOffset = 0.f;
1680
break;
1681
}
1682
1683
handle_c_button_movement(c);
1684
play_camera_buzz_if_cdown();
1685
1686
calc_y_to_curr_floor(&focusFloorOff, 1.f, 200.f, &focusFloorOff, 0.9f, 200.f);
1687
vec3f_copy(focus, sMarioCamState->pos);
1688
focus[1] += focusFloorOff + 125.f;
1689
vec3f_get_dist_and_angle(focus, c->pos, &distCamToFocus, &faceAngle[0], &faceAngle[1]);
1690
faceAngle[2] = 0;
1691
1692
vec3f_copy(basePos, sFixedModeBasePosition);
1693
vec3f_add(basePos, sCastleEntranceOffset);
1694
1695
if (sMarioGeometry.currFloorType != SURFACE_DEATH_PLANE
1696
&& sMarioGeometry.currFloorHeight != FLOOR_LOWER_LIMIT) {
1697
goalHeight = sMarioGeometry.currFloorHeight + basePos[1] + heightOffset;
1698
} else {
1699
goalHeight = gLakituState.goalPos[1];
1700
}
1701
1702
if (300 > distCamToFocus) {
1703
goalHeight += 300 - distCamToFocus;
1704
}
1705
1706
ceilHeight = find_ceil(c->pos[0], goalHeight - 100.f, c->pos[2], &ceiling);
1707
if (ceilHeight != CELL_HEIGHT_LIMIT) {
1708
if (goalHeight > (ceilHeight -= 125.f)) {
1709
goalHeight = ceilHeight;
1710
}
1711
}
1712
1713
if (sStatusFlags & CAM_FLAG_SMOOTH_MOVEMENT) {
1714
camera_approach_f32_symmetric_bool(&c->pos[1], goalHeight, 15.f);
1715
} else {
1716
if (goalHeight < sMarioCamState->pos[1] - 500.f) {
1717
goalHeight = sMarioCamState->pos[1] - 500.f;
1718
}
1719
c->pos[1] = goalHeight;
1720
}
1721
1722
c->pos[0] = basePos[0] + (sMarioCamState->pos[0] - basePos[0]) * scaleToMario;
1723
c->pos[2] = basePos[2] + (sMarioCamState->pos[2] - basePos[2]) * scaleToMario;
1724
1725
if (scaleToMario != 0.f) {
1726
vec3f_get_dist_and_angle(c->focus, c->pos, &distCamToFocus, &pitch, &yaw);
1727
if (distCamToFocus > 1000.f) {
1728
distCamToFocus = 1000.f;
1729
vec3f_set_dist_and_angle(c->focus, c->pos, distCamToFocus, pitch, yaw);
1730
}
1731
}
1732
1733
return faceAngle[1];
1734
}
1735
1736
/**
1737
* Updates the camera during a boss fight
1738
*/
1739
s32 update_boss_fight_camera(struct Camera *c, Vec3f focus, Vec3f pos) {
1740
struct Object *o;
1741
UNUSED u8 filler2[12];
1742
f32 focusDistance;
1743
UNUSED u8 filler3[4];
1744
// Floor normal values
1745
f32 nx;
1746
f32 ny;
1747
f32 nz;
1748
/// Floor originOffset
1749
f32 oo;
1750
UNUSED u8 filler4[4];
1751
UNUSED s16 unused;
1752
s16 yaw;
1753
s16 heldState;
1754
struct Surface *floor;
1755
UNUSED u8 filler[20];
1756
Vec3f secondFocus;
1757
Vec3f holdFocOffset = { 0.f, -150.f, -125.f };
1758
1759
handle_c_button_movement(c);
1760
1761
// Start camera shakes if bowser jumps or gets thrown.
1762
if (sMarioCamState->cameraEvent == CAM_EVENT_BOWSER_JUMP) {
1763
set_environmental_camera_shake(SHAKE_ENV_BOWSER_JUMP);
1764
sMarioCamState->cameraEvent = 0;
1765
}
1766
if (sMarioCamState->cameraEvent == CAM_EVENT_BOWSER_THROW_BOUNCE) {
1767
set_environmental_camera_shake(SHAKE_ENV_BOWSER_THROW_BOUNCE);
1768
sMarioCamState->cameraEvent = 0;
1769
}
1770
1771
yaw = sModeOffsetYaw + DEGREES(45);
1772
// Get boss's position and whether Mario is holding it.
1773
if ((o = gSecondCameraFocus) != NULL) {
1774
object_pos_to_vec3f(secondFocus, o);
1775
heldState = o->oHeldState;
1776
} else {
1777
// If no boss is there, just rotate around the area's center point.
1778
secondFocus[0] = c->areaCenX;
1779
secondFocus[1] = sMarioCamState->pos[1];
1780
secondFocus[2] = c->areaCenZ;
1781
heldState = 0;
1782
}
1783
1784
focusDistance = calc_abs_dist(sMarioCamState->pos, secondFocus) * 1.6f;
1785
if (focusDistance < 800.f) {
1786
focusDistance = 800.f;
1787
}
1788
if (focusDistance > 5000.f) {
1789
focusDistance = 5000.f;
1790
}
1791
1792
// If holding the boss, add a slight offset to secondFocus so that the spinning is more pronounced.
1793
if (heldState == 1) {
1794
offset_rotated(secondFocus, sMarioCamState->pos, holdFocOffset, sMarioCamState->faceAngle);
1795
}
1796
1797
// Set the camera focus to the average of Mario and secondFocus
1798
focus[0] = (sMarioCamState->pos[0] + secondFocus[0]) / 2.f;
1799
focus[1] = (sMarioCamState->pos[1] + secondFocus[1]) / 2.f + 125.f;
1800
focus[2] = (sMarioCamState->pos[2] + secondFocus[2]) / 2.f;
1801
1802
// Calculate the camera's position as an offset from the focus
1803
// When C-Down is not active, this
1804
vec3f_set_dist_and_angle(focus, pos, focusDistance, 0x1000, yaw);
1805
// Find the floor of the arena
1806
pos[1] = find_floor(c->areaCenX, CELL_HEIGHT_LIMIT, c->areaCenZ, &floor);
1807
if (floor != NULL) {
1808
nx = floor->normal.x;
1809
ny = floor->normal.y;
1810
nz = floor->normal.z;
1811
oo = floor->originOffset;
1812
pos[1] = 300.f - (nx * pos[0] + nz * pos[2] + oo) / ny;
1813
switch (gCurrLevelArea) {
1814
case AREA_BOB:
1815
pos[1] += 125.f;
1816
//! fall through, makes the BoB boss fight camera move up twice as high as it should
1817
case AREA_WF:
1818
pos[1] += 125.f;
1819
}
1820
}
1821
1822
//! Must be same line to match on -O2
1823
// Prevent the camera from going to the ground in the outside boss fight
1824
if (gCurrLevelNum == LEVEL_BBH) { pos[1] = 2047.f; }
1825
1826
// Rotate from C-Button input
1827
if (sCSideButtonYaw < 0) {
1828
sModeOffsetYaw += 0x200;
1829
if ((sCSideButtonYaw += 0x100) > 0) {
1830
sCSideButtonYaw = 0;
1831
}
1832
}
1833
if (sCSideButtonYaw > 0) {
1834
sModeOffsetYaw -= 0x200;
1835
if ((sCSideButtonYaw -= 0x100) < 0) {
1836
sCSideButtonYaw = 0;
1837
}
1838
}
1839
1840
focus[1] = (sMarioCamState->pos[1] + secondFocus[1]) / 2.f + 100.f;
1841
if (heldState == 1) {
1842
focus[1] += 300.f * sins((gMarioStates[0].angleVel[1] > 0.f) ? gMarioStates[0].angleVel[1]
1843
: -gMarioStates[0].angleVel[1]);
1844
}
1845
1846
//! Unnecessary conditional, focusDistance is already bounded to 800
1847
if (focusDistance < 400.f) {
1848
focusDistance = 400.f;
1849
}
1850
1851
// Set C-Down distance and pitch.
1852
// C-Down will essentially double the distance from the center.
1853
// sLakituPitch approaches 33.75 degrees.
1854
lakitu_zoom(focusDistance, 0x1800);
1855
1856
// Move the camera position back as sLakituDist and sLakituPitch increase.
1857
// This doesn't zoom out of bounds because pos is set above each frame.
1858
// The constant 0x1000 doubles the pitch from the center when sLakituPitch is 0
1859
// When Lakitu is fully zoomed out, the pitch comes to 0x3800, or 78.75 degrees, up from the focus.
1860
vec3f_set_dist_and_angle(pos, pos, sLakituDist, sLakituPitch + 0x1000, yaw);
1861
1862
return yaw;
1863
}
1864
1865
// 2nd iteration of data
1866
s16 unused8032D0A8[] = { 14, 1, 2, 4 };
1867
s16 unused8032D0B0[] = { 16, 9, 17, 0 };
1868
1869
/**
1870
* Maps cutscene to numbers in [0,4]. Used in determine_dance_cutscene() with sDanceCutsceneIndexTable.
1871
*
1872
* Only the first 5 entries are used. Perhaps the last 5 were bools used to indicate whether the star
1873
* type exits the course or not.
1874
*/
1875
u8 sDanceCutsceneTable[] = {
1876
CUTSCENE_DANCE_FLY_AWAY, CUTSCENE_DANCE_ROTATE, CUTSCENE_DANCE_CLOSEUP, CUTSCENE_KEY_DANCE, CUTSCENE_DANCE_DEFAULT,
1877
FALSE, FALSE, FALSE, FALSE, TRUE,
1878
};
1879
1880
/**
1881
* Perhaps used by different dance cutscenes.
1882
*/
1883
struct UnusedDanceInfo {
1884
Vec3f point;
1885
f32 distTarget;
1886
f32 distMultiplier;
1887
};
1888
1889
struct UnusedDanceInfo unusedDanceInfo1 = {
1890
{-3026.0f, 912.0f, -2148.0f},
1891
600.0f,
1892
0.3f
1893
};
1894
1895
u32 unusedDanceType = 0;
1896
struct UnusedDanceInfo unusedDanceInfo2 = {
1897
{-4676.0f, 917.0f, -3802.0f},
1898
600.0f,
1899
0.3f
1900
};
1901
1902
1903
/**
1904
* Table that dictates camera movement in bookend room.
1905
* Due to only the X being varied in the table, this only moves along the X axis linearly.
1906
* Third entry is seemingly unused.
1907
*/
1908
struct ParallelTrackingPoint sBBHLibraryParTrackPath[] = {
1909
{ 1, { -929.0f, 1619.0f, -1490.0f }, 50.0f, 0.0f },
1910
{ 0, { -2118.0f, 1619.0f, -1490.0f }, 50.0f, 0.0f },
1911
{ 0, { 0.0f, 0.0f, 0.0f }, 0.0f, 0.0f },
1912
};
1913
1914
s32 unused_update_mode_5_camera(UNUSED struct Camera *c, UNUSED Vec3f focus, UNUSED Vec3f pos) {
1915
#ifdef AVOID_UB
1916
return 0;
1917
#endif
1918
}
1919
1920
UNUSED static void stub_camera_1(UNUSED s32 unused) {
1921
}
1922
1923
void mode_boss_fight_camera(struct Camera *c) {
1924
c->nextYaw = update_boss_fight_camera(c, c->focus, c->pos);
1925
}
1926
1927
/**
1928
* Parallel tracking mode, the camera faces perpendicular to a line defined by sParTrackPath
1929
*
1930
* @see update_parallel_tracking_camera
1931
*/
1932
void mode_parallel_tracking_camera(struct Camera *c) {
1933
s16 dummy;
1934
1935
radial_camera_input(c, 0.f);
1936
set_fov_function(CAM_FOV_DEFAULT);
1937
c->nextYaw = update_parallel_tracking_camera(c, c->focus, c->pos);
1938
camera_approach_s16_symmetric_bool(&dummy, 0, 0x0400);
1939
}
1940
1941
/**
1942
* Fixed camera mode, the camera rotates around a point and looks and zooms toward Mario.
1943
*/
1944
void mode_fixed_camera(struct Camera *c) {
1945
UNUSED u8 unused[8];
1946
1947
if (gCurrLevelNum == LEVEL_BBH) {
1948
set_fov_function(CAM_FOV_BBH);
1949
} else {
1950
set_fov_function(CAM_FOV_APP_45);
1951
}
1952
c->nextYaw = update_fixed_camera(c, c->focus, c->pos);
1953
c->yaw = c->nextYaw;
1954
pan_ahead_of_player(c, FALSE);
1955
vec3f_set(sCastleEntranceOffset, 0.f, 0.f, 0.f);
1956
}
1957
1958
/**
1959
* Updates the camera in BEHIND_MARIO mode.
1960
*
1961
* The C-Buttons rotate the camera 90 degrees left/right and 67.5 degrees up/down.
1962
*/
1963
s32 update_behind_mario_camera(struct Camera *c, Vec3f focus, Vec3f pos) {
1964
UNUSED u8 unused2[12];
1965
f32 dist;
1966
UNUSED u8 unused3[4];
1967
s16 absPitch;
1968
s16 pitch;
1969
s16 yaw;
1970
s16 goalPitch = -sMarioCamState->faceAngle[0];
1971
s16 marioYaw = sMarioCamState->faceAngle[1] + DEGREES(180);
1972
s16 goalYawOff = 0;
1973
s16 yawSpeed;
1974
s16 pitchInc = 32;
1975
UNUSED u8 unused[12];
1976
f32 maxDist = 800.f;
1977
f32 focYOff = 125.f;
1978
1979
// Zoom in when Mario R_TRIG mode is active
1980
if (sSelectionFlags & CAM_MODE_MARIO_ACTIVE) {
1981
maxDist = 350.f;
1982
focYOff = 120.f;
1983
}
1984
if (!(sMarioCamState->action & (ACT_FLAG_SWIMMING | ACT_FLAG_METAL_WATER))) {
1985
pitchInc = 128;
1986
}
1987
1988
// Focus on Mario
1989
vec3f_copy(focus, sMarioCamState->pos);
1990
c->focus[1] += focYOff;
1991
//! @bug unnecessary
1992
dist = calc_abs_dist(focus, pos);
1993
//! @bug unnecessary
1994
pitch = calculate_pitch(focus, pos);
1995
vec3f_get_dist_and_angle(focus, pos, &dist, &pitch, &yaw);
1996
if (dist > maxDist) {
1997
dist = maxDist;
1998
}
1999
if ((absPitch = pitch) < 0) {
2000
absPitch = -absPitch;
2001
}
2002
2003
// Determine the yaw speed based on absPitch. A higher absPitch (further away from looking straight)
2004
// translates to a slower speed
2005
// Note: Pitch is always within +- 90 degrees or +-0x4000, and 0x4000 / 0x200 = 32
2006
yawSpeed = 32 - absPitch / 0x200;
2007
if (yawSpeed < 1) {
2008
yawSpeed = 1;
2009
}
2010
if (yawSpeed > 32) {
2011
yawSpeed = 32;
2012
}
2013
2014
if (sCSideButtonYaw != 0) {
2015
camera_approach_s16_symmetric_bool(&sCSideButtonYaw, 0, 1);
2016
yawSpeed = 8;
2017
}
2018
if (sBehindMarioSoundTimer != 0) {
2019
goalPitch = 0;
2020
camera_approach_s16_symmetric_bool(&sBehindMarioSoundTimer, 0, 1);
2021
pitchInc = 0x800;
2022
}
2023
2024
if (sBehindMarioSoundTimer == 28) {
2025
if (sCSideButtonYaw < 5 || sCSideButtonYaw > 28) {
2026
play_sound_cbutton_up();
2027
}
2028
}
2029
if (sCSideButtonYaw == 28) {
2030
if (sBehindMarioSoundTimer < 5 || sBehindMarioSoundTimer > 28) {
2031
play_sound_cbutton_up();
2032
}
2033
}
2034
2035
// C-Button input. Note: Camera rotates in the opposite direction of the button (airplane controls)
2036
//! @bug C-Right and C-Up take precedence due to the way input is handled here
2037
2038
// Rotate right
2039
if (sCButtonsPressed & L_CBUTTONS) {
2040
if (gPlayer1Controller->buttonPressed & L_CBUTTONS) {
2041
play_sound_cbutton_side();
2042
}
2043
if (dist < maxDist) {
2044
camera_approach_f32_symmetric_bool(&dist, maxDist, 5.f);
2045
}
2046
goalYawOff = -0x3FF8;
2047
sCSideButtonYaw = 30;
2048
yawSpeed = 2;
2049
}
2050
// Rotate left
2051
if (sCButtonsPressed & R_CBUTTONS) {
2052
if (gPlayer1Controller->buttonPressed & R_CBUTTONS) {
2053
play_sound_cbutton_side();
2054
}
2055
if (dist < maxDist) {
2056
camera_approach_f32_symmetric_bool(&dist, maxDist, 5.f);
2057
}
2058
goalYawOff = 0x3FF8;
2059
sCSideButtonYaw = 30;
2060
yawSpeed = 2;
2061
}
2062
// Analog camera
2063
if (gPlayer1Controller->stick2X != 0 &&
2064
gCurrDemoInput == NULL)
2065
{
2066
if (dist < maxDist) {
2067
camera_approach_f32_symmetric_bool(&dist, maxDist, 5.f);
2068
}
2069
goalYawOff = -0x3FF8 * (gPlayer1Controller->stick2X / 64.0f);
2070
sCSideButtonYaw = 30;
2071
yawSpeed = 2;
2072
}
2073
// Rotate up
2074
if (sCButtonsPressed & D_CBUTTONS) {
2075
if (gPlayer1Controller->buttonPressed & (U_CBUTTONS | D_CBUTTONS)) {
2076
play_sound_cbutton_side();
2077
}
2078
if (dist < maxDist) {
2079
camera_approach_f32_symmetric_bool(&dist, maxDist, 5.f);
2080
}
2081
goalPitch = -0x3000;
2082
sBehindMarioSoundTimer = 30;
2083
pitchInc = 0x800;
2084
}
2085
// Rotate down
2086
if (sCButtonsPressed & U_CBUTTONS) {
2087
if (gPlayer1Controller->buttonPressed & (U_CBUTTONS | D_CBUTTONS)) {
2088
play_sound_cbutton_side();
2089
}
2090
if (dist < maxDist) {
2091
camera_approach_f32_symmetric_bool(&dist, maxDist, 5.f);
2092
}
2093
goalPitch = 0x3000;
2094
sBehindMarioSoundTimer = 30;
2095
pitchInc = 0x800;
2096
}
2097
2098
approach_s16_asymptotic_bool(&yaw, marioYaw + goalYawOff, yawSpeed);
2099
camera_approach_s16_symmetric_bool(&pitch, goalPitch, pitchInc);
2100
if (dist < 300.f) {
2101
dist = 300.f;
2102
}
2103
vec3f_set_dist_and_angle(focus, pos, dist, pitch, yaw);
2104
if (gCurrLevelArea == AREA_WDW_MAIN) {
2105
yaw = clamp_positions_and_find_yaw(pos, focus, 4508.f, -3739.f, 4508.f, -3739.f);
2106
}
2107
if (gCurrLevelArea == AREA_THI_HUGE) {
2108
yaw = clamp_positions_and_find_yaw(pos, focus, 8192.f, -8192.f, 8192.f, -8192.f);
2109
}
2110
if (gCurrLevelArea == AREA_THI_TINY) {
2111
yaw = clamp_positions_and_find_yaw(pos, focus, 2458.f, -2458.f, 2458.f, -2458.f);
2112
}
2113
2114
return yaw;
2115
}
2116
2117
/**
2118
* "Behind Mario" mode: used when Mario is flying, on the water's surface, or shot from a cannon
2119
*/
2120
s32 mode_behind_mario(struct Camera *c) {
2121
struct MarioState *marioState = &gMarioStates[0];
2122
struct Surface *floor;
2123
Vec3f newPos;
2124
//! @bug oldPos is unused, see resolve_geometry_collisions
2125
Vec3f oldPos;
2126
f32 waterHeight;
2127
f32 floorHeight;
2128
f32 distCamToFocus;
2129
s16 camPitch;
2130
s16 camYaw;
2131
s16 yaw;
2132
2133
vec3f_copy(oldPos, c->pos);
2134
gCameraMovementFlags &= ~CAM_MOVING_INTO_MODE;
2135
vec3f_copy(newPos, c->pos);
2136
yaw = update_behind_mario_camera(c, c->focus, newPos);
2137
c->pos[0] = newPos[0];
2138
c->pos[2] = newPos[2];
2139
2140
// Keep the camera above the water surface if swimming
2141
if (c->mode == CAMERA_MODE_WATER_SURFACE) {
2142
floorHeight = find_floor(c->pos[0], c->pos[1], c->pos[2], &floor);
2143
newPos[1] = marioState->waterLevel + 120;
2144
if (newPos[1] < (floorHeight += 120.f)) {
2145
newPos[1] = floorHeight;
2146
}
2147
}
2148
approach_camera_height(c, newPos[1], 50.f);
2149
waterHeight = find_water_level(c->pos[0], c->pos[2]) + 100.f;
2150
if (c->pos[1] <= waterHeight) {
2151
gCameraMovementFlags |= CAM_MOVE_SUBMERGED;
2152
} else {
2153
gCameraMovementFlags &= ~CAM_MOVE_SUBMERGED;
2154
}
2155
2156
resolve_geometry_collisions(c->pos, oldPos);
2157
// Prevent camera getting too far away
2158
vec3f_get_dist_and_angle(c->focus, c->pos, &distCamToFocus, &camPitch, &camYaw);
2159
if (distCamToFocus > 800.f) {
2160
distCamToFocus = 800.f;
2161
vec3f_set_dist_and_angle(c->focus, c->pos, distCamToFocus, camPitch, camYaw);
2162
}
2163
pan_ahead_of_player(c, FALSE);
2164
2165
return yaw;
2166
}
2167
2168
/**
2169
* Update the camera in slide and hoot mode.
2170
*
2171
* In slide mode, keep the camera 800 units from Mario
2172
*/
2173
s16 update_slide_camera(struct Camera *c) {
2174
struct Surface *floor;
2175
f32 floorHeight;
2176
Vec3f pos;
2177
f32 distCamToFocus;
2178
f32 maxCamDist;
2179
f32 pitchScale;
2180
s16 camPitch;
2181
s16 camYaw;
2182
UNUSED struct MarioState *marioState = &gMarioStates[0];
2183
s16 goalPitch = 0x1555;
2184
s16 goalYaw = sMarioCamState->faceAngle[1] + DEGREES(180);
2185
2186
// Zoom in when inside the CCM shortcut
2187
if (sStatusFlags & CAM_FLAG_CCM_SLIDE_SHORTCUT) {
2188
sLakituDist = approach_f32(sLakituDist, -600.f, 20.f, 20.f);
2189
} else {
2190
sLakituDist = approach_f32(sLakituDist, 0.f, 20.f, 20.f);
2191
}
2192
2193
// No C-Button input in this mode, notify the player with a buzzer
2194
play_camera_buzz_if_cbutton();
2195
2196
// Focus on Mario
2197
vec3f_copy(c->focus, sMarioCamState->pos);
2198
c->focus[1] += 50.f;
2199
2200
vec3f_get_dist_and_angle(c->focus, c->pos, &distCamToFocus, &camPitch, &camYaw);
2201
maxCamDist = 800.f;
2202
2203
// In hoot mode, zoom further out and rotate faster
2204
if (sMarioCamState->action == ACT_RIDING_HOOT) {
2205
maxCamDist = 1000.f;
2206
goalPitch = 0x2800;
2207
camera_approach_s16_symmetric_bool(&camYaw, goalYaw, 0x100);
2208
} else {
2209
camera_approach_s16_symmetric_bool(&camYaw, goalYaw, 0x80);
2210
}
2211
camera_approach_s16_symmetric_bool(&camPitch, goalPitch, 0x100);
2212
2213
// Hoot mode
2214
if (sMarioCamState->action != ACT_RIDING_HOOT && sMarioGeometry.currFloorType == SURFACE_DEATH_PLANE) {
2215
vec3f_set_dist_and_angle(c->focus, pos, maxCamDist + sLakituDist, camPitch, camYaw);
2216
c->pos[0] = pos[0];
2217
c->pos[2] = pos[2];
2218
camera_approach_f32_symmetric_bool(&c->pos[1], c->focus[1], 30.f);
2219
vec3f_get_dist_and_angle(c->pos, c->focus, &distCamToFocus, &camPitch, &camYaw);
2220
pitchScale = (distCamToFocus - maxCamDist + sLakituDist) / 10000.f;
2221
if (pitchScale > 1.f) {
2222
pitchScale = 1.f;
2223
}
2224
camPitch += 0x1000 * pitchScale;
2225
vec3f_set_dist_and_angle(c->pos, c->focus, distCamToFocus, camPitch, camYaw);
2226
2227
// Slide mode
2228
} else {
2229
vec3f_set_dist_and_angle(c->focus, c->pos, maxCamDist + sLakituDist, camPitch, camYaw);
2230
sStatusFlags |= CAM_FLAG_BLOCK_SMOOTH_MOVEMENT;
2231
2232
// Stay above the slide floor
2233
floorHeight = find_floor(c->pos[0], c->pos[1] + 200.f, c->pos[2], &floor) + 125.f;
2234
if (c->pos[1] < floorHeight) {
2235
c->pos[1] = floorHeight;
2236
}
2237
// Stay closer than maxCamDist
2238
vec3f_get_dist_and_angle(c->focus, c->pos, &distCamToFocus, &camPitch, &camYaw);
2239
if (distCamToFocus > maxCamDist + sLakituDist) {
2240
distCamToFocus = maxCamDist + sLakituDist;
2241
vec3f_set_dist_and_angle(c->focus, c->pos, distCamToFocus, camPitch, camYaw);
2242
}
2243
}
2244
2245
camYaw = calculate_yaw(c->focus, c->pos);
2246
return camYaw;
2247
}
2248
2249
void mode_behind_mario_camera(struct Camera *c) {
2250
c->nextYaw = mode_behind_mario(c);
2251
}
2252
2253
s32 nop_update_water_camera(UNUSED struct Camera *c, UNUSED Vec3f focus, UNUSED Vec3f pos) {
2254
#ifdef AVOID_UB
2255
return 0;
2256
#endif
2257
}
2258
2259
/**
2260
* Exactly the same as BEHIND_MARIO
2261
*/
2262
void mode_water_surface_camera(struct Camera *c) {
2263
c->nextYaw = mode_behind_mario(c);
2264
}
2265
2266
/**
2267
* Used in sModeTransitions for CLOSE and FREE_ROAM mode
2268
*/
2269
s32 update_mario_camera(UNUSED struct Camera *c, Vec3f focus, Vec3f pos) {
2270
s16 yaw = sMarioCamState->faceAngle[1] + sModeOffsetYaw + DEGREES(180);
2271
focus_on_mario(focus, pos, 125.f, 125.f, gCameraZoomDist, 0x05B0, yaw);
2272
2273
return sMarioCamState->faceAngle[1];
2274
}
2275
2276
/**
2277
* Update the camera in default, close, and free roam mode
2278
*
2279
* The camera moves behind Mario, and can rotate all the way around
2280
*/
2281
s16 update_default_camera(struct Camera *c) {
2282
Vec3f tempPos;
2283
Vec3f cPos;
2284
UNUSED u8 unused1[12];
2285
struct Surface *marioFloor;
2286
struct Surface *cFloor;
2287
struct Surface *tempFloor;
2288
struct Surface *ceil;
2289
f32 camFloorHeight;
2290
f32 tempFloorHeight;
2291
f32 marioFloorHeight;
2292
UNUSED u8 unused2[4];
2293
f32 dist;
2294
f32 zoomDist;
2295
f32 waterHeight;
2296
f32 gasHeight;
2297
s16 avoidYaw;
2298
s16 pitch;
2299
s16 yaw;
2300
s16 yawGoal = sMarioCamState->faceAngle[1] + DEGREES(180);
2301
f32 posHeight;
2302
f32 focHeight;
2303
f32 distFromWater;
2304
s16 tempPitch;
2305
s16 tempYaw;
2306
f32 xzDist;
2307
UNUSED u8 unused4[4];
2308
s16 nextYawVel;
2309
s16 yawVel = 0;
2310
f32 scale;
2311
s32 avoidStatus = 0;
2312
s32 closeToMario = 0;
2313
f32 ceilHeight = find_ceil(gLakituState.goalPos[0],
2314
gLakituState.goalPos[1],
2315
gLakituState.goalPos[2], &ceil);
2316
s16 yawDir;
2317
2318
handle_c_button_movement(c);
2319
vec3f_get_dist_and_angle(sMarioCamState->pos, c->pos, &dist, &pitch, &yaw);
2320
2321
gCameraZoomDist += configAdditionalCameraDistance * 10.0f;
2322
2323
// If C-Down is active, determine what distance the camera should be from Mario
2324
if (gCameraMovementFlags & CAM_MOVE_ZOOMED_OUT) {
2325
//! In Mario mode, the camera is zoomed out further than in Lakitu mode (1400 vs 1200)
2326
if (set_cam_angle(0) == CAM_ANGLE_MARIO) {
2327
zoomDist = gCameraZoomDist + 1050;
2328
} else {
2329
zoomDist = gCameraZoomDist + 400;
2330
}
2331
} else {
2332
zoomDist = gCameraZoomDist;
2333
}
2334
2335
if (sMarioCamState->action & ACT_FLAG_HANGING ||
2336
sMarioCamState->action == ACT_RIDING_HOOT) {
2337
zoomDist *= 0.8f;
2338
set_handheld_shake(HAND_CAM_SHAKE_HANG_OWL);
2339
}
2340
2341
// If not zooming out, only allow dist to decrease
2342
if (sZoomAmount == 0.f) {
2343
if (dist > zoomDist) {
2344
if ((dist -= 50.f) < zoomDist) {
2345
dist = zoomDist;
2346
}
2347
}
2348
} else {
2349
if ((sZoomAmount -= 30.f) < 0.f) {
2350
sZoomAmount = 0.f;
2351
}
2352
if (dist > zoomDist) {
2353
if ((dist -= 30.f) < zoomDist) {
2354
dist = zoomDist;
2355
}
2356
}
2357
if (dist < zoomDist) {
2358
if ((dist += 30.f) > zoomDist) {
2359
dist = zoomDist;
2360
}
2361
}
2362
}
2363
2364
// Determine how fast to rotate the camera
2365
if (sCSideButtonYaw == 0) {
2366
if (c->mode == CAMERA_MODE_FREE_ROAM) {
2367
nextYawVel = 0xC0;
2368
} else {
2369
nextYawVel = 0x100;
2370
}
2371
if ((gPlayer1Controller->stickX != 0.f || gPlayer1Controller->stickY != 0.f) != 0) {
2372
nextYawVel = 0x20;
2373
}
2374
} else {
2375
if (sCSideButtonYaw < 0) {
2376
yaw += 0x200;
2377
}
2378
if (sCSideButtonYaw > 0) {
2379
yaw -= 0x200;
2380
}
2381
camera_approach_s16_symmetric_bool(&sCSideButtonYaw, 0, 0x100);
2382
nextYawVel = 0;
2383
}
2384
sYawSpeed = 0x400;
2385
xzDist = calc_hor_dist(sMarioCamState->pos, c->pos);
2386
2387
if (sStatusFlags & CAM_FLAG_BEHIND_MARIO_POST_DOOR) {
2388
if (xzDist >= 250) {
2389
sStatusFlags &= ~CAM_FLAG_BEHIND_MARIO_POST_DOOR;
2390
}
2391
if (ABS((sMarioCamState->faceAngle[1] - yaw) / 2) < 0x1800) {
2392
sStatusFlags &= ~CAM_FLAG_BEHIND_MARIO_POST_DOOR;
2393
yaw = sCameraYawAfterDoorCutscene + DEGREES(180);
2394
dist = 800.f;
2395
sStatusFlags |= CAM_FLAG_BLOCK_SMOOTH_MOVEMENT;
2396
}
2397
} else if (xzDist < 250) {
2398
// Turn rapidly if very close to Mario
2399
c->pos[0] += (250 - xzDist) * sins(yaw);
2400
c->pos[2] += (250 - xzDist) * coss(yaw);
2401
if (sCSideButtonYaw == 0) {
2402
nextYawVel = 0x1000;
2403
sYawSpeed = 0;
2404
vec3f_get_dist_and_angle(sMarioCamState->pos, c->pos, &dist, &pitch, &yaw);
2405
}
2406
closeToMario |= 1;
2407
}
2408
2409
if (-16 < gPlayer1Controller->stickY) {
2410
c->yaw = yaw;
2411
}
2412
2413
calc_y_to_curr_floor(&posHeight, 1, 200, &focHeight, 0.9f, 200);
2414
vec3f_copy(cPos, c->pos);
2415
avoidStatus = rotate_camera_around_walls(c, cPos, &avoidYaw, 0x600);
2416
// If a wall is blocking the view of Mario, then rotate in the calculated direction
2417
if (avoidStatus == 3) {
2418
unusedFreeRoamWallYaw = avoidYaw;
2419
sAvoidYawVel = yaw;
2420
sStatusFlags |= CAM_FLAG_COLLIDED_WITH_WALL;
2421
//! Does nothing
2422
vec3f_get_dist_and_angle(sMarioCamState->pos, cPos, &xzDist, &tempPitch, &tempYaw);
2423
// Rotate to avoid the wall
2424
approach_s16_asymptotic_bool(&yaw, avoidYaw, 10);
2425
//! Does nothing
2426
vec3f_set_dist_and_angle(sMarioCamState->pos, cPos, xzDist, tempPitch, tempYaw);
2427
sAvoidYawVel = (sAvoidYawVel - yaw) / 0x100;
2428
} else {
2429
if (gMarioStates[0].forwardVel == 0.f) {
2430
if (sStatusFlags & CAM_FLAG_COLLIDED_WITH_WALL) {
2431
if ((yawGoal - yaw) / 0x100 >= 0) {
2432
yawDir = -1;
2433
} else {
2434
yawDir = 1;
2435
}
2436
if ((sAvoidYawVel > 0 && yawDir > 0) || (sAvoidYawVel < 0 && yawDir < 0)) {
2437
yawVel = nextYawVel;
2438
}
2439
} else {
2440
yawVel = nextYawVel;
2441
}
2442
} else {
2443
if (nextYawVel == 0x1000) {
2444
yawVel = nextYawVel;
2445
}
2446
sStatusFlags &= ~CAM_FLAG_COLLIDED_WITH_WALL;
2447
}
2448
2449
// If a wall is near the camera, turn twice as fast
2450
if (avoidStatus != 0) {
2451
yawVel += yawVel;
2452
}
2453
// ...Unless the camera already rotated from being close to Mario
2454
if ((closeToMario & 1) && avoidStatus != 0) {
2455
yawVel = 0;
2456
}
2457
if (yawVel != 0 && get_dialog_id() == DIALOG_NONE) {
2458
camera_approach_s16_symmetric_bool(&yaw, yawGoal, yawVel);
2459
}
2460
}
2461
2462
// Only zoom out if not obstructed by walls and Lakitu hasn't collided with any
2463
if (avoidStatus == 0 && !(sStatusFlags & CAM_FLAG_COLLIDED_WITH_WALL)) {
2464
approach_f32_asymptotic_bool(&dist, zoomDist - 100.f, 0.05f);
2465
}
2466
vec3f_set_dist_and_angle(sMarioCamState->pos, cPos, dist, pitch, yaw);
2467
cPos[1] += posHeight + 125.f;
2468
2469
// Move the camera away from walls and set the collision flag
2470
if (collide_with_walls(cPos, 10.f, 80.f) != 0) {
2471
sStatusFlags |= CAM_FLAG_COLLIDED_WITH_WALL;
2472
}
2473
2474
c->focus[0] = sMarioCamState->pos[0];
2475
c->focus[1] = sMarioCamState->pos[1] + 125.f + focHeight;
2476
c->focus[2] = sMarioCamState->pos[2];
2477
2478
marioFloorHeight = 125.f + sMarioGeometry.currFloorHeight;
2479
marioFloor = sMarioGeometry.currFloor;
2480
camFloorHeight = find_floor(cPos[0], cPos[1] + 50.f, cPos[2], &cFloor) + 125.f;
2481
for (scale = 0.1f; scale < 1.f; scale += 0.2f) {
2482
scale_along_line(tempPos, cPos, sMarioCamState->pos, scale);
2483
tempFloorHeight = find_floor(tempPos[0], tempPos[1], tempPos[2], &tempFloor) + 125.f;
2484
if (tempFloor != NULL && tempFloorHeight > marioFloorHeight) {
2485
marioFloorHeight = tempFloorHeight;
2486
marioFloor = tempFloor;
2487
}
2488
}
2489
2490
// Lower the camera in Mario mode
2491
if (sSelectionFlags & CAM_MODE_MARIO_ACTIVE) {
2492
marioFloorHeight -= 35.f;
2493
camFloorHeight -= 35.f;
2494
c->focus[1] -= 25.f;
2495
}
2496
2497
// If there's water below the camera, decide whether to keep the camera above the water surface
2498
waterHeight = find_water_level(cPos[0], cPos[2]);
2499
if (waterHeight != FLOOR_LOWER_LIMIT) {
2500
waterHeight += 125.f;
2501
distFromWater = waterHeight - marioFloorHeight;
2502
if (!(gCameraMovementFlags & CAM_MOVE_METAL_BELOW_WATER)) {
2503
if (distFromWater > 800.f && (sMarioCamState->action & ACT_FLAG_METAL_WATER)) {
2504
gCameraMovementFlags |= CAM_MOVE_METAL_BELOW_WATER;
2505
}
2506
} else {
2507
if (distFromWater < 400.f || !(sMarioCamState->action & ACT_FLAG_METAL_WATER)) {
2508
gCameraMovementFlags &= ~CAM_MOVE_METAL_BELOW_WATER;
2509
}
2510
}
2511
// If not wearing the metal cap, always stay above
2512
if (!(gCameraMovementFlags & CAM_MOVE_METAL_BELOW_WATER) && camFloorHeight < waterHeight) {
2513
camFloorHeight = waterHeight;
2514
}
2515
} else {
2516
gCameraMovementFlags &= ~CAM_MOVE_METAL_BELOW_WATER;
2517
}
2518
2519
cPos[1] = camFloorHeight;
2520
vec3f_copy(tempPos, cPos);
2521
tempPos[1] -= 125.f;
2522
if (marioFloor != NULL && camFloorHeight <= marioFloorHeight) {
2523
avoidStatus = is_range_behind_surface(c->focus, tempPos, marioFloor, 0, -1);
2524
if (avoidStatus != 1 && ceilHeight > marioFloorHeight) {
2525
camFloorHeight = marioFloorHeight;
2526
}
2527
}
2528
2529
posHeight = 0.f;
2530
if (c->mode == CAMERA_MODE_FREE_ROAM) {
2531
if (gCameraMovementFlags & CAM_MOVE_ZOOMED_OUT) {
2532
posHeight = 375.f;
2533
if (gCurrLevelArea == AREA_SSL_PYRAMID) {
2534
posHeight /= 2;
2535
}
2536
} else {
2537
posHeight = 100.f;
2538
}
2539
}
2540
if ((gCameraMovementFlags & CAM_MOVE_ZOOMED_OUT) && (sSelectionFlags & CAM_MODE_MARIO_ACTIVE)) {
2541
posHeight = 610.f;
2542
if (gCurrLevelArea == AREA_SSL_PYRAMID || gCurrLevelNum == LEVEL_CASTLE) {
2543
posHeight /= 2;
2544
}
2545
}
2546
2547
// Make Lakitu fly above the gas
2548
gasHeight = find_poison_gas_level(cPos[0], cPos[2]);
2549
if (gasHeight != FLOOR_LOWER_LIMIT) {
2550
if ((gasHeight += 130.f) > c->pos[1]) {
2551
c->pos[1] = gasHeight;
2552
}
2553
}
2554
2555
if (sMarioCamState->action & ACT_FLAG_HANGING || sMarioCamState->action == ACT_RIDING_HOOT) {
2556
camFloorHeight = sMarioCamState->pos[1] + 400.f;
2557
if (c->mode == CAMERA_MODE_FREE_ROAM) {
2558
camFloorHeight -= 100.f;
2559
}
2560
ceilHeight = CELL_HEIGHT_LIMIT;
2561
vec3f_copy(c->focus, sMarioCamState->pos);
2562
}
2563
2564
if (sMarioCamState->action & ACT_FLAG_ON_POLE) {
2565
camFloorHeight = gMarioStates[0].usedObj->oPosY + 125.f;
2566
if (sMarioCamState->pos[1] - 100.f > camFloorHeight) {
2567
camFloorHeight = sMarioCamState->pos[1] - 100.f;
2568
}
2569
ceilHeight = CELL_HEIGHT_LIMIT;
2570
vec3f_copy(c->focus, sMarioCamState->pos);
2571
}
2572
if (camFloorHeight != FLOOR_LOWER_LIMIT) {
2573
camFloorHeight += posHeight;
2574
approach_camera_height(c, camFloorHeight, 20.f);
2575
}
2576
c->pos[0] = cPos[0];
2577
c->pos[2] = cPos[2];
2578
cPos[0] = gLakituState.goalPos[0];
2579
cPos[1] = c->pos[1];
2580
cPos[2] = gLakituState.goalPos[2];
2581
vec3f_get_dist_and_angle(cPos, c->pos, &dist, &tempPitch, &tempYaw);
2582
// Prevent the camera from lagging behind too much
2583
if (dist > 50.f) {
2584
dist = 50.f;
2585
vec3f_set_dist_and_angle(cPos, c->pos, dist, tempPitch, tempYaw);
2586
}
2587
if (sMarioGeometry.currFloorType != SURFACE_DEATH_PLANE) {
2588
vec3f_get_dist_and_angle(c->focus, c->pos, &dist, &tempPitch, &tempYaw);
2589
if (dist > zoomDist) {
2590
dist = zoomDist;
2591
vec3f_set_dist_and_angle(c->focus, c->pos, dist, tempPitch, tempYaw);
2592
}
2593
}
2594
if (ceilHeight != CELL_HEIGHT_LIMIT) {
2595
if (c->pos[1] > (ceilHeight -= 150.f)
2596
&& (avoidStatus = is_range_behind_surface(c->pos, sMarioCamState->pos, ceil, 0, -1)) == 1) {
2597
c->pos[1] = ceilHeight;
2598
}
2599
}
2600
if (gCurrLevelArea == AREA_WDW_TOWN) {
2601
yaw = clamp_positions_and_find_yaw(c->pos, c->focus, 2254.f, -3789.f, 3790.f, -2253.f);
2602
}
2603
2604
if (configCenterCameraButton) {
2605
if (gPlayer1Controller->buttonPressed & L_TRIG) {
2606
if (yaw != sMarioCamState->faceAngle[1] + DEGREES(180)) {
2607
yaw = sMarioCamState->faceAngle[1] + DEGREES(180);
2608
focus_on_mario(c->focus, c->pos, 0.0f, 0.0f, dist, pitch, yaw);
2609
}
2610
play_sound_rbutton_changed();
2611
}
2612
}
2613
2614
return yaw;
2615
}
2616
2617
/**
2618
* The default camera mode
2619
* Used by close and free roam modes
2620
*/
2621
void mode_default_camera(struct Camera *c) {
2622
set_fov_function(CAM_FOV_DEFAULT);
2623
c->nextYaw = update_default_camera(c);
2624
pan_ahead_of_player(c, FALSE);
2625
}
2626
2627
/**
2628
* The mode used by close and free roam
2629
*/
2630
void mode_lakitu_camera(struct Camera *c) {
2631
gCameraZoomDist = 800.f;
2632
mode_default_camera(c);
2633
}
2634
2635
/**
2636
* When no other mode is active and the current R button mode is Mario
2637
*/
2638
void mode_mario_camera(struct Camera *c) {
2639
gCameraZoomDist = 350.f;
2640
mode_default_camera(c);
2641
}
2642
2643
/**
2644
* Rotates the camera around the spiral staircase.
2645
*/
2646
s32 update_spiral_stairs_camera(struct Camera *c, Vec3f focus, Vec3f pos) {
2647
UNUSED s16 unused1;
2648
/// The returned yaw
2649
s16 camYaw;
2650
// unused
2651
s16 focPitch;
2652
/// The focus (Mario)'s yaw around the stairs
2653
s16 focYaw;
2654
// unused
2655
s16 posPitch;
2656
/// The camera's yaw around the stairs
2657
s16 posYaw;
2658
UNUSED s32 unused2;
2659
Vec3f cPos;
2660
Vec3f checkPos;
2661
struct Surface *floor;
2662
// unused
2663
f32 dist;
2664
f32 focusHeight;
2665
f32 floorHeight;
2666
f32 focY;
2667
2668
handle_c_button_movement(c);
2669
// Set base pos to the center of the staircase
2670
vec3f_set(sFixedModeBasePosition, -1280.f, 614.f, 1740.f);
2671
2672
// Focus on Mario, and move the focus up the staircase with him
2673
calc_y_to_curr_floor(&focusHeight, 1.f, 200.f, &focusHeight, 0.9f, 200.f);
2674
focus[0] = sMarioCamState->pos[0];
2675
focY = sMarioCamState->pos[1] + 125.f + focusHeight;
2676
focus[2] = sMarioCamState->pos[2];
2677
2678
vec3f_copy(cPos, pos);
2679
vec3f_get_dist_and_angle(sFixedModeBasePosition, focus, &dist, &focPitch, &focYaw);
2680
vec3f_get_dist_and_angle(sFixedModeBasePosition, cPos, &dist, &posPitch, &posYaw);
2681
2682
sSpiralStairsYawOffset = posYaw - focYaw;
2683
// posYaw will change if Mario is more than 90 degrees around the stairs, relative to the camera
2684
if (sSpiralStairsYawOffset < DEGREES(-90)) {
2685
sSpiralStairsYawOffset = DEGREES(-90);
2686
}
2687
if (sSpiralStairsYawOffset > DEGREES(90)) {
2688
sSpiralStairsYawOffset = DEGREES(90);
2689
}
2690
focYaw += sSpiralStairsYawOffset;
2691
posYaw = focYaw;
2692
//! @bug unnecessary
2693
camera_approach_s16_symmetric_bool(&posYaw, focYaw, 0x1000);
2694
2695
vec3f_set_dist_and_angle(sFixedModeBasePosition, cPos, 300.f, 0, posYaw);
2696
2697
// Move the camera's y coord up/down the staircase
2698
checkPos[0] = focus[0] + (cPos[0] - focus[0]) * 0.7f;
2699
checkPos[1] = focus[1] + (cPos[1] - focus[1]) * 0.7f + 300.f;
2700
checkPos[2] = focus[2] + (cPos[2] - focus[2]) * 0.7f;
2701
floorHeight = find_floor(checkPos[0], checkPos[1] + 50.f, checkPos[2], &floor);
2702
2703
if (floorHeight != FLOOR_LOWER_LIMIT) {
2704
if (floorHeight < sMarioGeometry.currFloorHeight) {
2705
floorHeight = sMarioGeometry.currFloorHeight;
2706
}
2707
pos[1] = approach_f32(pos[1], (floorHeight += 125.f), 30.f, 30.f);
2708
}
2709
2710
camera_approach_f32_symmetric_bool(&focus[1], focY, 30.f);
2711
pos[0] = cPos[0];
2712
pos[2] = cPos[2];
2713
camYaw = calculate_yaw(focus, pos);
2714
2715
return camYaw;
2716
}
2717
2718
/**
2719
* The mode used in the spiral staircase in the castle
2720
*/
2721
void mode_spiral_stairs_camera(struct Camera *c) {
2722
c->nextYaw = update_spiral_stairs_camera(c, c->focus, c->pos);
2723
}
2724
2725
s32 update_slide_or_0f_camera(UNUSED struct Camera *c, Vec3f focus, Vec3f pos) {
2726
s16 yaw = sMarioCamState->faceAngle[1] + sModeOffsetYaw + DEGREES(180);
2727
2728
focus_on_mario(focus, pos, 125.f, 125.f, 800.f, 5461, yaw);
2729
return sMarioCamState->faceAngle[1];
2730
}
2731
2732
static UNUSED void unused_mode_0f_camera(struct Camera *c) {
2733
if (gPlayer1Controller->buttonPressed & U_CBUTTONS) {
2734
gCameraMovementFlags |= CAM_MOVE_C_UP_MODE;
2735
}
2736
c->nextYaw = update_slide_camera(c);
2737
}
2738
2739
/**
2740
* Slide/hoot mode.
2741
* In this mode, the camera is always at the back of Mario, because Mario generally only moves forward.
2742
*/
2743
void mode_slide_camera(struct Camera *c) {
2744
if (sMarioGeometry.currFloorType == SURFACE_CLOSE_CAMERA ||
2745
sMarioGeometry.currFloorType == SURFACE_NO_CAM_COL_SLIPPERY) {
2746
mode_lakitu_camera(c);
2747
} else {
2748
if (gPlayer1Controller->buttonPressed & U_CBUTTONS) {
2749
gCameraMovementFlags |= CAM_MOVE_C_UP_MODE;
2750
}
2751
c->nextYaw = update_slide_camera(c);
2752
}
2753
}
2754
2755
void store_lakitu_cam_info_for_c_up(struct Camera *c) {
2756
vec3f_copy(sCameraStoreCUp.pos, c->pos);
2757
vec3f_sub(sCameraStoreCUp.pos, sMarioCamState->pos);
2758
// Only store the y value, and as an offset from Mario, for some reason
2759
vec3f_set(sCameraStoreCUp.focus, 0.f, c->focus[1] - sMarioCamState->pos[1], 0.f);
2760
}
2761
2762
/**
2763
* Start C-Up mode. The actual mode change is handled in update_mario_inputs() in mario.c
2764
*
2765
* @see update_mario_inputs
2766
*/
2767
s32 set_mode_c_up(struct Camera *c) {
2768
if (!(gCameraMovementFlags & CAM_MOVE_C_UP_MODE)) {
2769
gCameraMovementFlags |= CAM_MOVE_C_UP_MODE;
2770
store_lakitu_cam_info_for_c_up(c);
2771
sCameraSoundFlags &= ~CAM_SOUND_C_UP_PLAYED;
2772
return 1;
2773
}
2774
return 0;
2775
}
2776
2777
/**
2778
* Zoom the camera out of C-Up mode, avoiding moving into a wall, if possible, by searching for an open
2779
* direction.
2780
*/
2781
s32 exit_c_up(struct Camera *c) {
2782
struct Surface *surface;
2783
Vec3f checkFoc;
2784
Vec3f curPos;
2785
// Variables for searching for an open direction
2786
s32 searching = 0;
2787
/// The current sector of the circle that we are checking
2788
s32 sector;
2789
f32 ceilHeight;
2790
f32 floorHeight;
2791
f32 curDist;
2792
f32 d;
2793
s16 curPitch;
2794
s16 curYaw;
2795
s16 checkYaw = 0;
2796
Vec3f storePos; // unused
2797
Vec3f storeFoc; // unused
2798
2799
if ((gCameraMovementFlags & CAM_MOVE_C_UP_MODE) && !(gCameraMovementFlags & CAM_MOVE_STARTED_EXITING_C_UP)) {
2800
// Copy the stored pos and focus. This is unused.
2801
vec3f_copy(storePos, sCameraStoreCUp.pos);
2802
vec3f_add(storePos, sMarioCamState->pos);
2803
vec3f_copy(storeFoc, sCameraStoreCUp.focus);
2804
vec3f_add(storeFoc, sMarioCamState->pos);
2805
2806
vec3f_copy(checkFoc, c->focus);
2807
checkFoc[0] = sMarioCamState->pos[0];
2808
checkFoc[2] = sMarioCamState->pos[2];
2809
vec3f_get_dist_and_angle(checkFoc, c->pos, &curDist, &curPitch, &curYaw);
2810
vec3f_copy(curPos, c->pos);
2811
curDist = 80.f;
2812
2813
// Search for an open direction to zoom out in, if the camera is changing to close, free roam,
2814
// or spiral-stairs mode
2815
if (sModeInfo.lastMode == CAMERA_MODE_SPIRAL_STAIRS || sModeInfo.lastMode == CAMERA_MODE_CLOSE
2816
|| sModeInfo.lastMode == CAMERA_MODE_FREE_ROAM) {
2817
searching = 1;
2818
// Check the whole circle around Mario for an open direction to zoom out to
2819
for (sector = 0; sector < 16 && searching == 1; sector++) {
2820
vec3f_set_dist_and_angle(checkFoc, curPos, curDist, 0, curYaw + checkYaw);
2821
2822
// If there are no walls this way,
2823
if (f32_find_wall_collision(&curPos[0], &curPos[1], &curPos[2], 20.f, 50.f) == 0) {
2824
2825
// Start close to Mario, check for walls, floors, and ceilings all the way to the
2826
// zoomed out distance
2827
for (d = curDist; d < gCameraZoomDist; d += 20.f) {
2828
vec3f_set_dist_and_angle(checkFoc, curPos, d, 0, curYaw + checkYaw);
2829
2830
// Check if we're zooming out into a floor or ceiling
2831
ceilHeight = find_ceil(curPos[0], curPos[1] - 150.f, curPos[2], &surface) + -10.f;
2832
if (surface != NULL && ceilHeight < curPos[1]) {
2833
break;
2834
}
2835
floorHeight = find_floor(curPos[0], curPos[1] + 150.f, curPos[2], &surface) + 10.f;
2836
if (surface != NULL && floorHeight > curPos[1]) {
2837
break;
2838
}
2839
2840
// Stop checking this direction if there is a wall blocking the way
2841
if (f32_find_wall_collision(&curPos[0], &curPos[1], &curPos[2], 20.f, 50.f) == 1) {
2842
break;
2843
}
2844
}
2845
2846
// If there was no collision found all the way to the max distance, it's an opening
2847
if (d >= gCameraZoomDist) {
2848
searching = 0;
2849
}
2850
}
2851
2852
// Alternate left and right, checking each 1/16th (22.5 degrees) of the circle
2853
if (searching == 1) {
2854
checkYaw = -checkYaw;
2855
if (checkYaw < 0) {
2856
checkYaw -= 0x1000;
2857
} else {
2858
checkYaw += 0x1000;
2859
}
2860
}
2861
}
2862
2863
// Update the stored focus and pos to the direction found in the search
2864
if (searching == 0) {
2865
vec3f_set_dist_and_angle(checkFoc, sCameraStoreCUp.pos, gCameraZoomDist, 0, curYaw + checkYaw);
2866
vec3f_copy(sCameraStoreCUp.focus, checkFoc);
2867
vec3f_sub(sCameraStoreCUp.pos, sMarioCamState->pos);
2868
vec3f_sub(sCameraStoreCUp.focus, sMarioCamState->pos);
2869
}
2870
2871
gCameraMovementFlags |= CAM_MOVE_STARTED_EXITING_C_UP;
2872
transition_next_state(c, 15);
2873
} else {
2874
// Let the next camera mode handle it
2875
gCameraMovementFlags &= ~(CAM_MOVE_STARTED_EXITING_C_UP | CAM_MOVE_C_UP_MODE);
2876
vec3f_set_dist_and_angle(checkFoc, c->pos, curDist, curPitch, curYaw + checkYaw);
2877
}
2878
play_sound_cbutton_down();
2879
}
2880
return 0;
2881
}
2882
2883
/**
2884
* The mode used when C-Up is pressed.
2885
*/
2886
s32 update_c_up(UNUSED struct Camera *c, Vec3f focus, Vec3f pos) {
2887
s16 pitch = sCUpCameraPitch;
2888
s16 yaw = sMarioCamState->faceAngle[1] + sModeOffsetYaw + DEGREES(180);
2889
2890
focus_on_mario(focus, pos, 125.f, 125.f, 250.f, pitch, yaw);
2891
return sMarioCamState->faceAngle[1];
2892
}
2893
2894
/**
2895
* Make Mario's head move in C-Up mode.
2896
*/
2897
void move_mario_head_c_up(UNUSED struct Camera *c) {
2898
UNUSED s16 pitch = sCUpCameraPitch;
2899
UNUSED s16 yaw = sModeOffsetYaw;
2900
2901
sCUpCameraPitch += (s16)((gPlayer1Controller->stickY + gPlayer1Controller->stick2Y) * 10.f);
2902
sModeOffsetYaw -= (s16)((gPlayer1Controller->stickX + gPlayer1Controller->stick2X) * 10.f);
2903
2904
// Bound looking up to nearly 80 degrees.
2905
if (sCUpCameraPitch > 0x38E3) {
2906
sCUpCameraPitch = 0x38E3;
2907
}
2908
// Bound looking down to -45 degrees
2909
if (sCUpCameraPitch < -0x2000) {
2910
sCUpCameraPitch = -0x2000;
2911
}
2912
2913
// Bound the camera yaw to +-120 degrees
2914
if (sModeOffsetYaw > 0x5555) {
2915
sModeOffsetYaw = 0x5555;
2916
}
2917
if (sModeOffsetYaw < -0x5555) {
2918
sModeOffsetYaw = -0x5555;
2919
}
2920
2921
// Give Mario's neck natural-looking constraints
2922
sMarioCamState->headRotation[0] = sCUpCameraPitch * 3 / 4;
2923
sMarioCamState->headRotation[1] = sModeOffsetYaw * 3 / 4;
2924
}
2925
2926
/**
2927
* Zooms the camera in for C-Up mode
2928
*/
2929
void move_into_c_up(struct Camera *c) {
2930
struct LinearTransitionPoint *start = &sModeInfo.transitionStart;
2931
struct LinearTransitionPoint *end = &sModeInfo.transitionEnd;
2932
2933
f32 dist = end->dist - start->dist;
2934
s16 pitch = end->pitch - start->pitch;
2935
s16 yaw = end->yaw - start->yaw;
2936
2937
// Linearly interpolate from start to end position's polar coordinates
2938
dist = start->dist + dist * sModeInfo.frame / sModeInfo.max;
2939
pitch = start->pitch + pitch * sModeInfo.frame / sModeInfo.max;
2940
yaw = start->yaw + yaw * sModeInfo.frame / sModeInfo.max;
2941
2942
// Linearly interpolate the focus from start to end
2943
c->focus[0] = start->focus[0] + (end->focus[0] - start->focus[0]) * sModeInfo.frame / sModeInfo.max;
2944
c->focus[1] = start->focus[1] + (end->focus[1] - start->focus[1]) * sModeInfo.frame / sModeInfo.max;
2945
c->focus[2] = start->focus[2] + (end->focus[2] - start->focus[2]) * sModeInfo.frame / sModeInfo.max;
2946
2947
vec3f_add(c->focus, sMarioCamState->pos);
2948
vec3f_set_dist_and_angle(c->focus, c->pos, dist, pitch, yaw);
2949
2950
sMarioCamState->headRotation[0] = 0;
2951
sMarioCamState->headRotation[1] = 0;
2952
2953
// Finished zooming in
2954
if (++sModeInfo.frame == sModeInfo.max) {
2955
gCameraMovementFlags &= ~CAM_MOVING_INTO_MODE;
2956
}
2957
}
2958
2959
/**
2960
* The main update function for C-Up mode
2961
*/
2962
s32 mode_c_up_camera(struct Camera *c) {
2963
UNUSED u8 unused[12];
2964
2965
// Play a sound when entering C-Up mode
2966
if (!(sCameraSoundFlags & CAM_SOUND_C_UP_PLAYED)) {
2967
play_sound_cbutton_up();
2968
sCameraSoundFlags |= CAM_SOUND_C_UP_PLAYED;
2969
}
2970
2971
// Zoom in first
2972
if (gCameraMovementFlags & CAM_MOVING_INTO_MODE) {
2973
gCameraMovementFlags |= CAM_MOVE_C_UP_MODE;
2974
move_into_c_up(c);
2975
return 1;
2976
}
2977
2978
if (!(gCameraMovementFlags & CAM_MOVE_STARTED_EXITING_C_UP)) {
2979
// Normal update
2980
move_mario_head_c_up(c);
2981
update_c_up(c, c->focus, c->pos);
2982
} else {
2983
// Exiting C-Up
2984
if (sStatusFlags & CAM_FLAG_TRANSITION_OUT_OF_C_UP) {
2985
// Retrieve the previous position and focus
2986
vec3f_copy(c->pos, sCameraStoreCUp.pos);
2987
vec3f_add(c->pos, sMarioCamState->pos);
2988
vec3f_copy(c->focus, sCameraStoreCUp.focus);
2989
vec3f_add(c->focus, sMarioCamState->pos);
2990
// Make Mario look forward
2991
camera_approach_s16_symmetric_bool(&sMarioCamState->headRotation[0], 0, 1024);
2992
camera_approach_s16_symmetric_bool(&sMarioCamState->headRotation[1], 0, 1024);
2993
} else {
2994
// Finished exiting C-Up
2995
gCameraMovementFlags &= ~(CAM_MOVE_STARTED_EXITING_C_UP | CAM_MOVE_C_UP_MODE);
2996
}
2997
}
2998
sPanDistance = 0.f;
2999
3000
// Exit C-Up mode
3001
if (gPlayer1Controller->buttonPressed & (A_BUTTON | B_BUTTON | D_CBUTTONS | L_CBUTTONS | R_CBUTTONS)) {
3002
exit_c_up(c);
3003
}
3004
return 0;
3005
}
3006
3007
/**
3008
* Used when Mario is in a cannon.
3009
*/
3010
s32 update_in_cannon(UNUSED struct Camera *c, Vec3f focus, Vec3f pos) {
3011
focus_on_mario(pos, focus, 125.f + sCannonYOffset, 125.f, 800.f,
3012
sMarioCamState->faceAngle[0], sMarioCamState->faceAngle[1]);
3013
return sMarioCamState->faceAngle[1];
3014
}
3015
3016
/**
3017
* Updates the camera when Mario is in a cannon.
3018
* sCannonYOffset is used to make the camera rotate down when Mario has just entered the cannon
3019
*/
3020
void mode_cannon_camera(struct Camera *c, s8 manual) {
3021
UNUSED u8 unused[24];
3022
3023
sLakituPitch = 0;
3024
gCameraMovementFlags &= ~CAM_MOVING_INTO_MODE;
3025
c->nextYaw = update_in_cannon(c, c->focus, c->pos);
3026
if (gPlayer1Controller->buttonPressed & A_BUTTON) {
3027
set_camera_mode(c, manual ? CAMERA_MODE_NONE : CAMERA_MODE_BEHIND_MARIO, 1);
3028
sPanDistance = 0.f;
3029
sCannonYOffset = 0.f;
3030
sStatusFlags &= ~CAM_FLAG_BLOCK_SMOOTH_MOVEMENT;
3031
} else {
3032
sCannonYOffset = approach_f32(sCannonYOffset, 0.f, 100.f, 100.f);
3033
}
3034
}
3035
3036
/**
3037
* Cause Lakitu to fly to the next Camera position and focus over a number of frames.
3038
*
3039
* At the end of each frame, Lakitu's position and focus ("state") are stored.
3040
* Calling this function makes next_lakitu_state() fly from the last frame's state to the
3041
* current frame's calculated state.
3042
*
3043
* @see next_lakitu_state()
3044
*/
3045
void transition_next_state(UNUSED struct Camera *c, s16 frames) {
3046
if (!(sStatusFlags & CAM_FLAG_FRAME_AFTER_CAM_INIT)) {
3047
sStatusFlags |= (CAM_FLAG_START_TRANSITION | CAM_FLAG_TRANSITION_OUT_OF_C_UP);
3048
sModeTransition.framesLeft = frames;
3049
}
3050
}
3051
3052
/**
3053
* Sets the camera mode to `newMode` and initializes sModeTransition with `numFrames` frames
3054
*
3055
* Used to change the camera mode to 'level-oriented' modes
3056
* namely: RADIAL/OUTWARD_RADIAL, 8_DIRECTIONS, FREE_ROAM, CLOSE, SPIRAL_STAIRS, and SLIDE_HOOT
3057
*/
3058
void transition_to_camera_mode(struct Camera *c, s16 newMode, s16 numFrames) {
3059
if (c->mode != newMode) {
3060
sModeInfo.newMode = (newMode != -1) ? newMode : sModeInfo.lastMode;
3061
sModeInfo.lastMode = c->mode;
3062
c->mode = sModeInfo.newMode;
3063
3064
// Clear movement flags that would affect the transition
3065
gCameraMovementFlags &= (u16)~(CAM_MOVE_RESTRICT | CAM_MOVE_ROTATE);
3066
if (!(sStatusFlags & CAM_FLAG_FRAME_AFTER_CAM_INIT)) {
3067
transition_next_state(c, numFrames);
3068
sCUpCameraPitch = 0;
3069
sModeOffsetYaw = 0;
3070
sLakituDist = 0;
3071
sLakituPitch = 0;//configVerticalCamera ? 1024 : 0;
3072
sAreaYawChange = 0;
3073
sPanDistance = 0.f;
3074
sCannonYOffset = 0.f;
3075
}
3076
}
3077
}
3078
3079
/**
3080
* Used to change the camera mode between its default/previous and certain Mario-oriented modes,
3081
* namely: C_UP, WATER_SURFACE, CLOSE, and BEHIND_MARIO
3082
*
3083
* Stores the current pos and focus in sModeInfo->transitionStart, and
3084
* stores the next pos and focus into sModeInfo->transitionEnd. These two fields are used in
3085
* move_into_c_up().
3086
*
3087
* @param mode the mode to change to, or -1 to switch to the previous mode
3088
* @param frames number of frames the transition should last, only used when entering C_UP
3089
*/
3090
void set_camera_mode(struct Camera *c, s16 mode, s16 frames) {
3091
struct LinearTransitionPoint *start = &sModeInfo.transitionStart;
3092
struct LinearTransitionPoint *end = &sModeInfo.transitionEnd;
3093
3094
if (mode == CAMERA_MODE_WATER_SURFACE && gCurrLevelArea == AREA_TTM_OUTSIDE) {
3095
} else {
3096
// Clear movement flags that would affect the transition
3097
gCameraMovementFlags &= (u16)~(CAM_MOVE_RESTRICT | CAM_MOVE_ROTATE);
3098
gCameraMovementFlags |= CAM_MOVING_INTO_MODE;
3099
if (mode == CAMERA_MODE_NONE) {
3100
mode = CAMERA_MODE_CLOSE;
3101
}
3102
sCUpCameraPitch = 0;
3103
sModeOffsetYaw = 0;
3104
sLakituDist = 0;
3105
sLakituPitch = 0;//configVerticalCamera ? 1024 : 0;
3106
sAreaYawChange = 0;
3107
3108
sModeInfo.newMode = (mode != -1) ? mode : sModeInfo.lastMode;
3109
sModeInfo.lastMode = c->mode;
3110
sModeInfo.max = frames;
3111
sModeInfo.frame = 1;
3112
3113
c->mode = sModeInfo.newMode;
3114
gLakituState.mode = c->mode;
3115
3116
vec3f_copy(end->focus, c->focus);
3117
vec3f_sub(end->focus, sMarioCamState->pos);
3118
3119
vec3f_copy(end->pos, c->pos);
3120
vec3f_sub(end->pos, sMarioCamState->pos);
3121
3122
sAreaYaw = sModeTransitions[sModeInfo.newMode](c, end->focus, end->pos);
3123
3124
// End was updated by sModeTransitions
3125
vec3f_sub(end->focus, sMarioCamState->pos);
3126
vec3f_sub(end->pos, sMarioCamState->pos);
3127
3128
vec3f_copy(start->focus, gLakituState.curFocus);
3129
vec3f_sub(start->focus, sMarioCamState->pos);
3130
3131
vec3f_copy(start->pos, gLakituState.curPos);
3132
vec3f_sub(start->pos, sMarioCamState->pos);
3133
3134
vec3f_get_dist_and_angle(start->focus, start->pos, &start->dist, &start->pitch, &start->yaw);
3135
vec3f_get_dist_and_angle(end->focus, end->pos, &end->dist, &end->pitch, &end->yaw);
3136
}
3137
}
3138
3139
/**
3140
* Updates Lakitu's position/focus and applies camera shakes.
3141
*/
3142
void update_lakitu(struct Camera *c) {
3143
struct Surface *floor = NULL;
3144
Vec3f newPos;
3145
Vec3f newFoc;
3146
UNUSED Vec3f unusedVec3f;
3147
f32 distToFloor;
3148
s16 newYaw;
3149
UNUSED u8 unused1[8];
3150
3151
if (gCameraMovementFlags & CAM_MOVE_PAUSE_SCREEN) {
3152
} else {
3153
if (c->cutscene) {
3154
}
3155
if (TRUE) {
3156
newYaw = next_lakitu_state(newPos, newFoc, c->pos, c->focus, sOldPosition, sOldFocus,
3157
c->nextYaw);
3158
set_or_approach_s16_symmetric(&c->yaw, newYaw, sYawSpeed);
3159
sStatusFlags &= ~CAM_FLAG_UNUSED_CUTSCENE_ACTIVE;
3160
} else {
3161
//! dead code, moved to next_lakitu_state()
3162
vec3f_copy(newPos, c->pos);
3163
vec3f_copy(newFoc, c->focus);
3164
}
3165
3166
// Update old state
3167
vec3f_copy(sOldPosition, newPos);
3168
vec3f_copy(sOldFocus, newFoc);
3169
3170
gLakituState.yaw = c->yaw;
3171
gLakituState.nextYaw = c->nextYaw;
3172
vec3f_copy(gLakituState.goalPos, c->pos);
3173
vec3f_copy(gLakituState.goalFocus, c->focus);
3174
3175
// Simulate Lakitu flying to the new position and turning towards the new focus
3176
set_or_approach_vec3f_asymptotic(gLakituState.curPos, newPos,
3177
gLakituState.posHSpeed, gLakituState.posVSpeed,
3178
gLakituState.posHSpeed);
3179
set_or_approach_vec3f_asymptotic(gLakituState.curFocus, newFoc,
3180
gLakituState.focHSpeed, gLakituState.focVSpeed,
3181
gLakituState.focHSpeed);
3182
// Adjust Lakitu's speed back to normal
3183
set_or_approach_f32_asymptotic(&gLakituState.focHSpeed, 0.8f, 0.05f);
3184
set_or_approach_f32_asymptotic(&gLakituState.focVSpeed, 0.3f, 0.05f);
3185
set_or_approach_f32_asymptotic(&gLakituState.posHSpeed, 0.3f, 0.05f);
3186
set_or_approach_f32_asymptotic(&gLakituState.posVSpeed, 0.3f, 0.05f);
3187
3188
// Turn on smooth movement when it hasn't been blocked for 2 frames
3189
if (sStatusFlags & CAM_FLAG_BLOCK_SMOOTH_MOVEMENT) {
3190
sStatusFlags &= ~CAM_FLAG_BLOCK_SMOOTH_MOVEMENT;
3191
} else {
3192
sStatusFlags |= CAM_FLAG_SMOOTH_MOVEMENT;
3193
}
3194
3195
vec3f_copy(gLakituState.pos, gLakituState.curPos);
3196
vec3f_copy(gLakituState.focus, gLakituState.curFocus);
3197
3198
if (c->cutscene) {
3199
vec3f_add(gLakituState.focus, sPlayer2FocusOffset);
3200
vec3f_set(sPlayer2FocusOffset, 0, 0, 0);
3201
}
3202
3203
vec3f_get_dist_and_angle(gLakituState.pos, gLakituState.focus, &gLakituState.focusDistance,
3204
&gLakituState.oldPitch, &gLakituState.oldYaw);
3205
3206
gLakituState.roll = 0;
3207
3208
// Apply camera shakes
3209
shake_camera_pitch(gLakituState.pos, gLakituState.focus);
3210
shake_camera_yaw(gLakituState.pos, gLakituState.focus);
3211
shake_camera_roll(&gLakituState.roll);
3212
shake_camera_handheld(gLakituState.pos, gLakituState.focus);
3213
3214
if (sMarioCamState->action == ACT_DIVE && gLakituState.lastFrameAction != ACT_DIVE) {
3215
set_camera_shake_from_hit(SHAKE_HIT_FROM_BELOW);
3216
}
3217
3218
gLakituState.roll += sHandheldShakeRoll;
3219
gLakituState.roll += gLakituState.keyDanceRoll;
3220
3221
if (c->mode != CAMERA_MODE_C_UP && c->cutscene == 0) {
3222
gCheckingSurfaceCollisionsForCamera = TRUE;
3223
distToFloor = find_floor(gLakituState.pos[0],
3224
gLakituState.pos[1] + 20.0f,
3225
gLakituState.pos[2], &floor);
3226
if (distToFloor != FLOOR_LOWER_LIMIT) {
3227
if (gLakituState.pos[1] < (distToFloor += 100.0f)) {
3228
gLakituState.pos[1] = distToFloor;
3229
} else {
3230
gCheckingSurfaceCollisionsForCamera = FALSE;
3231
}
3232
}
3233
}
3234
3235
vec3f_copy(sModeTransition.marioPos, sMarioCamState->pos);
3236
}
3237
clamp_pitch(gLakituState.pos, gLakituState.focus, 0x3E00, -0x3E00);
3238
gLakituState.mode = c->mode;
3239
gLakituState.defMode = c->defMode;
3240
}
3241
3242
void manual_cam_modes(struct Camera *c);
3243
void mario_cam_modes(struct Camera *c);
3244
void lakitu_cam_modes(struct Camera *c);
3245
3246
/**
3247
* The main camera update function.
3248
* Gets controller input, checks for cutscenes, handles mode changes, and moves the camera
3249
*/
3250
void update_camera(struct Camera *c) {
3251
UNUSED u8 unused[24];
3252
3253
gCamera = c;
3254
update_camera_hud_status(c);
3255
if (c->cutscene == 0) {
3256
// Only process R_TRIG if 'fixed' is not selected in the menu
3257
if (cam_select_alt_mode(0) == CAM_SELECTION_MARIO) {
3258
if (gPlayer1Controller->buttonPressed & R_TRIG) {
3259
if (set_cam_angle(0) == CAM_ANGLE_LAKITU) {
3260
set_cam_angle(CAM_ANGLE_MARIO);
3261
} else {
3262
set_cam_angle(CAM_ANGLE_LAKITU);
3263
}
3264
}
3265
}
3266
play_sound_if_cam_switched_to_lakitu_or_mario();
3267
}
3268
3269
// Initialize the camera
3270
sStatusFlags &= ~CAM_FLAG_FRAME_AFTER_CAM_INIT;
3271
if (gCameraMovementFlags & CAM_MOVE_INIT_CAMERA) {
3272
init_camera(c);
3273
gCameraMovementFlags &= ~CAM_MOVE_INIT_CAMERA;
3274
sStatusFlags |= CAM_FLAG_FRAME_AFTER_CAM_INIT;
3275
}
3276
3277
// Store previous geometry information
3278
sMarioGeometry.prevFloorHeight = sMarioGeometry.currFloorHeight;
3279
sMarioGeometry.prevCeilHeight = sMarioGeometry.currCeilHeight;
3280
sMarioGeometry.prevFloor = sMarioGeometry.currFloor;
3281
sMarioGeometry.prevCeil = sMarioGeometry.currCeil;
3282
sMarioGeometry.prevFloorType = sMarioGeometry.currFloorType;
3283
sMarioGeometry.prevCeilType = sMarioGeometry.currCeilType;
3284
3285
find_mario_floor_and_ceil(&sMarioGeometry);
3286
gCheckingSurfaceCollisionsForCamera = TRUE;
3287
vec3f_copy(c->pos, gLakituState.goalPos);
3288
vec3f_copy(c->focus, gLakituState.goalFocus);
3289
3290
c->yaw = gLakituState.yaw;
3291
c->nextYaw = gLakituState.nextYaw;
3292
c->mode = gLakituState.mode;
3293
c->defMode = gLakituState.defMode;
3294
3295
camera_course_processing(c);
3296
stub_camera_3(c);
3297
sCButtonsPressed = find_c_buttons_pressed(sCButtonsPressed, gPlayer1Controller->buttonPressed,
3298
gPlayer1Controller->buttonDown);
3299
3300
if (c->cutscene != 0) {
3301
sYawSpeed = 0;
3302
play_cutscene(c);
3303
sFramesSinceCutsceneEnded = 0;
3304
} else {
3305
// Clear the recent cutscene after 8 frames
3306
if (gRecentCutscene != 0 && sFramesSinceCutsceneEnded < 8) {
3307
sFramesSinceCutsceneEnded++;
3308
if (sFramesSinceCutsceneEnded >= 8) {
3309
gRecentCutscene = 0;
3310
sFramesSinceCutsceneEnded = 0;
3311
}
3312
}
3313
}
3314
// If not in a cutscene, do mode processing
3315
if (c->cutscene == 0) {
3316
sYawSpeed = 0x400;
3317
3318
if (sSelectionFlags & CAM_MODE_MARIO_ACTIVE) {
3319
switch (configAlternateCameraMode) {
3320
// Manual Cam
3321
case 2:
3322
manual_cam_modes(c);
3323
break;
3324
3325
// Mario Cam
3326
case 1:
3327
mario_cam_modes(c);
3328
break;
3329
3330
// Lakitu Cam
3331
default:
3332
lakitu_cam_modes(c);
3333
break;
3334
}
3335
} else {
3336
switch (configDefaultCameraMode) {
3337
// Manual Cam
3338
case 2:
3339
manual_cam_modes(c);
3340
break;
3341
3342
// Mario Cam
3343
case 1:
3344
mario_cam_modes(c);
3345
break;
3346
3347
// Lakitu Cam
3348
default:
3349
lakitu_cam_modes(c);
3350
break;
3351
}
3352
}
3353
}
3354
// Start any Mario-related cutscenes
3355
start_cutscene(c, get_cutscene_from_mario_status(c));
3356
stub_camera_2(c);
3357
gCheckingSurfaceCollisionsForCamera = FALSE;
3358
if (gCurrLevelNum != LEVEL_CASTLE) {
3359
// If fixed camera is selected as the alternate mode, then fix the camera as long as the right
3360
// trigger is held
3361
if ((c->cutscene == 0 &&
3362
(gPlayer1Controller->buttonDown & R_TRIG) && cam_select_alt_mode(0) == CAM_SELECTION_FIXED)
3363
|| (gCameraMovementFlags & CAM_MOVE_FIX_IN_PLACE)
3364
|| (sMarioCamState->action) == ACT_GETTING_BLOWN) {
3365
3366
// If this is the first frame that R_TRIG is held, play the "click" sound
3367
if (c->cutscene == 0 && (gPlayer1Controller->buttonPressed & R_TRIG)
3368
&& cam_select_alt_mode(0) == CAM_SELECTION_FIXED) {
3369
sCameraSoundFlags |= CAM_SOUND_FIXED_ACTIVE;
3370
play_sound_rbutton_changed();
3371
}
3372
3373
// Fixed mode only prevents Lakitu from moving. The camera pos still updates, so
3374
// Lakitu will fly to his next position as normal whenever R_TRIG is released.
3375
gLakituState.posHSpeed = 0.f;
3376
gLakituState.posVSpeed = 0.f;
3377
3378
c->nextYaw = calculate_yaw(gLakituState.focus, gLakituState.pos);
3379
c->yaw = c->nextYaw;
3380
gCameraMovementFlags &= ~CAM_MOVE_FIX_IN_PLACE;
3381
} else {
3382
// Play the "click" sound when fixed mode is released
3383
if (sCameraSoundFlags & CAM_SOUND_FIXED_ACTIVE) {
3384
play_sound_rbutton_changed();
3385
sCameraSoundFlags &= ~CAM_SOUND_FIXED_ACTIVE;
3386
}
3387
}
3388
} else {
3389
if ((gPlayer1Controller->buttonPressed & R_TRIG) && cam_select_alt_mode(0) == CAM_SELECTION_FIXED) {
3390
play_sound_button_change_blocked();
3391
}
3392
}
3393
3394
update_lakitu(c);
3395
3396
gLakituState.lastFrameAction = sMarioCamState->action;
3397
}
3398
3399
void lakitu_cam_modes(struct Camera *c) {
3400
3401
switch (c->mode) {
3402
case CAMERA_MODE_BEHIND_MARIO:
3403
mode_behind_mario_camera(c);
3404
break;
3405
3406
case CAMERA_MODE_C_UP:
3407
mode_c_up_camera(c);
3408
break;
3409
3410
case CAMERA_MODE_WATER_SURFACE:
3411
mode_water_surface_camera(c);
3412
break;
3413
3414
case CAMERA_MODE_INSIDE_CANNON:
3415
mode_cannon_camera(c, 0);
3416
break;
3417
3418
case CAMERA_MODE_8_DIRECTIONS:
3419
mode_8_directions_camera(c);
3420
break;
3421
3422
case CAMERA_MODE_RADIAL:
3423
mode_radial_camera(c);
3424
break;
3425
3426
case CAMERA_MODE_OUTWARD_RADIAL:
3427
mode_outward_radial_camera(c);
3428
break;
3429
3430
case CAMERA_MODE_CLOSE:
3431
mode_lakitu_camera(c);
3432
break;
3433
3434
case CAMERA_MODE_FREE_ROAM:
3435
mode_lakitu_camera(c);
3436
break;
3437
3438
case CAMERA_MODE_BOSS_FIGHT:
3439
mode_boss_fight_camera(c);
3440
break;
3441
3442
case CAMERA_MODE_PARALLEL_TRACKING:
3443
mode_parallel_tracking_camera(c);
3444
break;
3445
3446
case CAMERA_MODE_SLIDE_HOOT:
3447
mode_slide_camera(c);
3448
break;
3449
3450
case CAMERA_MODE_FIXED:
3451
mode_fixed_camera(c);
3452
break;
3453
3454
case CAMERA_MODE_SPIRAL_STAIRS:
3455
mode_spiral_stairs_camera(c);
3456
break;
3457
}
3458
}
3459
3460
void mario_cam_modes(struct Camera *c) {
3461
3462
switch (c->mode) {
3463
case CAMERA_MODE_BEHIND_MARIO:
3464
mode_behind_mario_camera(c);
3465
break;
3466
3467
case CAMERA_MODE_C_UP:
3468
mode_c_up_camera(c);
3469
break;
3470
3471
case CAMERA_MODE_WATER_SURFACE:
3472
mode_water_surface_camera(c);
3473
break;
3474
3475
case CAMERA_MODE_INSIDE_CANNON:
3476
mode_cannon_camera(c, 0);
3477
break;
3478
3479
default:
3480
mode_mario_camera(c);
3481
break;
3482
}
3483
}
3484
3485
void manual_cam_modes(struct Camera *c) {
3486
3487
switch (c->mode) {
3488
3489
case CAMERA_MODE_8_DIRECTIONS:
3490
mode_custom_camera(c, 150.0f, 256.0f, TRUE, FALSE, TRUE);
3491
break;
3492
3493
case CAMERA_MODE_BEHIND_MARIO:
3494
mode_custom_camera(c, -75.0f, 0.0f, FALSE, TRUE, TRUE);
3495
break;
3496
3497
case CAMERA_MODE_C_UP:
3498
mode_c_up_camera(c);
3499
break;
3500
3501
case CAMERA_MODE_WATER_SURFACE:
3502
mode_custom_camera(c, 75.0f, 0.0f, FALSE, TRUE, TRUE);
3503
break;
3504
3505
case CAMERA_MODE_INSIDE_CANNON:
3506
mode_cannon_camera(c, 1);
3507
break;
3508
3509
default:
3510
mode_custom_camera(c, 150.0f, 0.0f, FALSE, TRUE, TRUE);
3511
break;
3512
}
3513
}
3514
3515
/**
3516
* Reset all the camera variables to their arcane defaults
3517
*/
3518
void reset_camera(struct Camera *c) {
3519
UNUSED s32 unused = 0;
3520
UNUSED u8 unused1[16];
3521
UNUSED struct LinearTransitionPoint *start = &sModeInfo.transitionStart;
3522
UNUSED struct LinearTransitionPoint *end = &sModeInfo.transitionEnd;
3523
3524
gCamera = c;
3525
gCameraMovementFlags = 0;
3526
s2ndRotateFlags = 0;
3527
sStatusFlags = 0;
3528
gCutsceneTimer = 0;
3529
sCutsceneShot = 0;
3530
gCutsceneObjSpawn = 0;
3531
gObjCutsceneDone = FALSE;
3532
gCutsceneFocus = NULL;
3533
unused8032CFC8 = 0;
3534
unused8032CFCC = 0;
3535
gSecondCameraFocus = NULL;
3536
sCButtonsPressed = 0;
3537
vec3f_copy(sModeTransition.marioPos, sMarioCamState->pos);
3538
sModeTransition.framesLeft = 0;
3539
unused8032CFCC = -1;
3540
unused8032CFC8 = -1;
3541
gCameraMovementFlags = 0;
3542
gCameraMovementFlags |= CAM_MOVE_INIT_CAMERA;
3543
unused8033B316 = 0;
3544
sStatusFlags = 0;
3545
unused8033B31A = 0;
3546
sCameraSoundFlags = 0;
3547
sCUpCameraPitch = 0;
3548
sModeOffsetYaw = 0;
3549
sSpiralStairsYawOffset = 0;
3550
sLakituDist = 0;
3551
sLakituPitch = 0;//configVerticalCamera ? 1024 : 0;
3552
sAreaYaw = 0;
3553
sAreaYawChange = 0.f;
3554
sPanDistance = 0.f;
3555
sCannonYOffset = 0.f;
3556
sZoomAmount = 0.f;
3557
sZeroZoomDist = 0.f;
3558
sBehindMarioSoundTimer = 0;
3559
sCSideButtonYaw = 0;
3560
s8DirModeBaseYaw = 0;
3561
s8DirModeYawOffset = 0;
3562
c->doorStatus = DOOR_DEFAULT;
3563
sMarioCamState->headRotation[0] = 0;
3564
sMarioCamState->headRotation[1] = 0;
3565
sLuigiCamState->headRotation[0] = 0;
3566
sLuigiCamState->headRotation[1] = 0;
3567
sMarioCamState->cameraEvent = 0;
3568
sMarioCamState->usedObj = NULL;
3569
gLakituState.shakeMagnitude[0] = 0;
3570
gLakituState.shakeMagnitude[1] = 0;
3571
gLakituState.shakeMagnitude[2] = 0;
3572
gLakituState.unusedVec2[0] = 0;
3573
gLakituState.unusedVec2[1] = 0;
3574
gLakituState.unusedVec2[2] = 0;
3575
gLakituState.unusedVec1[0] = 0.f;
3576
gLakituState.unusedVec1[1] = 0.f;
3577
gLakituState.unusedVec1[2] = 0.f;
3578
gLakituState.lastFrameAction = 0;
3579
set_fov_function(CAM_FOV_DEFAULT);
3580
sFOVState.fov = 45.f;
3581
sFOVState.fovOffset = 0.f;
3582
sFOVState.unusedIsSleeping = 0;
3583
sFOVState.shakeAmplitude = 0.f;
3584
sFOVState.shakePhase = 0;
3585
sObjectCutscene = 0;
3586
gRecentCutscene = 0;
3587
unused8033B30C = 0;
3588
unused8033B310 = 0;
3589
}
3590
3591
void init_camera(struct Camera *c) {
3592
struct Surface *floor = 0;
3593
Vec3f marioOffset;
3594
s32 i;
3595
3596
sCreditsPlayer2Pitch = 0;
3597
sCreditsPlayer2Yaw = 0;
3598
gPrevLevel = gCurrLevelArea / 16;
3599
gCurrLevelArea = gCurrLevelNum * 16 + gCurrentArea->index;
3600
sSelectionFlags &= CAM_MODE_MARIO_SELECTED;
3601
sFramesPaused = 0;
3602
gLakituState.mode = c->mode;
3603
gLakituState.defMode = c->defMode;
3604
gLakituState.posHSpeed = 0.3f;
3605
gLakituState.posVSpeed = 0.3f;
3606
gLakituState.focHSpeed = 0.8f;
3607
gLakituState.focHSpeed = 0.3f; // @bug set focHSpeed back-to-back
3608
gLakituState.roll = 0;
3609
gLakituState.keyDanceRoll = 0;
3610
gLakituState.unused = 0;
3611
sStatusFlags &= ~CAM_FLAG_SMOOTH_MOVEMENT;
3612
vec3f_set(sCastleEntranceOffset, 0.f, 0.f, 0.f);
3613
vec3f_set(sPlayer2FocusOffset, 0.f, 0.f, 0.f);
3614
find_mario_floor_and_ceil(&sMarioGeometry);
3615
sMarioGeometry.prevFloorHeight = sMarioGeometry.currFloorHeight;
3616
sMarioGeometry.prevCeilHeight = sMarioGeometry.currCeilHeight;
3617
sMarioGeometry.prevFloor = sMarioGeometry.currFloor;
3618
sMarioGeometry.prevCeil = sMarioGeometry.currCeil;
3619
sMarioGeometry.prevFloorType = sMarioGeometry.currFloorType;
3620
sMarioGeometry.prevCeilType = sMarioGeometry.currCeilType;
3621
for (i = 0; i < 32; i++) {
3622
sCurCreditsSplinePos[i].index = -1;
3623
sCurCreditsSplineFocus[i].index = -1;
3624
}
3625
sCutsceneSplineSegment = 0;
3626
sCutsceneSplineSegmentProgress = 0.f;
3627
unused8033B6E8 = 0;
3628
sHandheldShakeInc = 0.f;
3629
sHandheldShakeTimer = 0.f;
3630
sHandheldShakeMag = 0;
3631
for (i = 0; i < 4; i++) {
3632
sHandheldShakeSpline[i].index = -1;
3633
}
3634
sHandheldShakePitch = 0;
3635
sHandheldShakeYaw = 0;
3636
sHandheldShakeRoll = 0;
3637
c->cutscene = 0;
3638
marioOffset[0] = 0.f;
3639
marioOffset[1] = 125.f;
3640
marioOffset[2] = 400.f;
3641
3642
// Set the camera's starting position or start a cutscene for certain levels
3643
switch (gCurrLevelNum) {
3644
// Calls the initial cutscene when you enter Bowser battle levels
3645
// Note: This replaced an "old" way to call these cutscenes using
3646
// a camEvent value: CAM_EVENT_BOWSER_INIT
3647
case LEVEL_BOWSER_1:
3648
#ifndef VERSION_JP
3649
// Since Bowser 1 has a demo entry, check for it
3650
// If it is, then set CamAct to the end to directly activate Bowser
3651
// If it isn't, then start cutscene
3652
if ((gCurrDemoInput == NULL)) {
3653
start_cutscene(c, CUTSCENE_ENTER_BOWSER_ARENA);
3654
} else if (gSecondCameraFocus != NULL) {
3655
gSecondCameraFocus->oBowserCamAct = BOWSER_CAM_ACT_END;
3656
}
3657
#else
3658
start_cutscene(c, CUTSCENE_ENTER_BOWSER_ARENA);
3659
#endif
3660
break;
3661
case LEVEL_BOWSER_2:
3662
start_cutscene(c, CUTSCENE_ENTER_BOWSER_ARENA);
3663
break;
3664
case LEVEL_BOWSER_3:
3665
start_cutscene(c, CUTSCENE_ENTER_BOWSER_ARENA);
3666
break;
3667
3668
//! Hardcoded position checks determine which cutscene to play when Mario enters castle grounds.
3669
case LEVEL_CASTLE_GROUNDS:
3670
if (is_within_100_units_of_mario(-1328.f, 260.f, 4664.f) != 1) {
3671
marioOffset[0] = -400.f;
3672
marioOffset[2] = -800.f;
3673
}
3674
if (is_within_100_units_of_mario(-6901.f, 2376.f, -6509.f) == 1) {
3675
start_cutscene(c, CUTSCENE_EXIT_WATERFALL);
3676
}
3677
if (is_within_100_units_of_mario(5408.f, 4500.f, 3637.f) == 1) {
3678
start_cutscene(c, CUTSCENE_EXIT_FALL_WMOTR);
3679
}
3680
gLakituState.mode = CAMERA_MODE_FREE_ROAM;
3681
break;
3682
case LEVEL_SA:
3683
marioOffset[2] = 200.f;
3684
break;
3685
case LEVEL_CASTLE_COURTYARD:
3686
marioOffset[2] = -300.f;
3687
break;
3688
case LEVEL_LLL:
3689
gCameraMovementFlags |= CAM_MOVE_ZOOMED_OUT;
3690
break;
3691
case LEVEL_CASTLE:
3692
marioOffset[2] = 150.f;
3693
break;
3694
case LEVEL_RR:
3695
vec3f_set(sFixedModeBasePosition, -2985.f, 478.f, -5568.f);
3696
break;
3697
}
3698
if (c->mode == CAMERA_MODE_8_DIRECTIONS) {
3699
gCameraMovementFlags |= CAM_MOVE_ZOOMED_OUT;
3700
}
3701
switch (gCurrLevelArea) {
3702
case AREA_SSL_EYEROK:
3703
vec3f_set(marioOffset, 0.f, 500.f, -100.f);
3704
break;
3705
case AREA_CCM_SLIDE:
3706
marioOffset[2] = -300.f;
3707
break;
3708
case AREA_THI_WIGGLER:
3709
marioOffset[2] = -300.f;
3710
break;
3711
case AREA_SL_IGLOO:
3712
marioOffset[2] = -300.f;
3713
break;
3714
case AREA_SL_OUTSIDE:
3715
if (is_within_100_units_of_mario(257.f, 2150.f, 1399.f) == 1) {
3716
marioOffset[2] = -300.f;
3717
}
3718
break;
3719
case AREA_CCM_OUTSIDE:
3720
gCameraMovementFlags |= CAM_MOVE_ZOOMED_OUT;
3721
break;
3722
case AREA_TTM_OUTSIDE:
3723
gLakituState.mode = CAMERA_MODE_RADIAL;
3724
break;
3725
}
3726
3727
// Set the camera pos to marioOffset (relative to Mario), added to Mario's position
3728
offset_rotated(c->pos, sMarioCamState->pos, marioOffset, sMarioCamState->faceAngle);
3729
if (c->mode != CAMERA_MODE_BEHIND_MARIO) {
3730
c->pos[1] = find_floor(sMarioCamState->pos[0], sMarioCamState->pos[1] + 100.f,
3731
sMarioCamState->pos[2], &floor) + 125.f;
3732
}
3733
vec3f_copy(c->focus, sMarioCamState->pos);
3734
vec3f_copy(gLakituState.curPos, c->pos);
3735
vec3f_copy(gLakituState.curFocus, c->focus);
3736
vec3f_copy(gLakituState.goalPos, c->pos);
3737
vec3f_copy(gLakituState.goalFocus, c->focus);
3738
vec3f_copy(gLakituState.pos, c->pos);
3739
vec3f_copy(gLakituState.focus, c->focus);
3740
if (c->mode == CAMERA_MODE_FIXED) {
3741
set_fixed_cam_axis_sa_lobby(c->mode);
3742
}
3743
store_lakitu_cam_info_for_c_up(c);
3744
gLakituState.yaw = calculate_yaw(c->focus, c->pos);
3745
gLakituState.nextYaw = gLakituState.yaw;
3746
c->yaw = gLakituState.yaw;
3747
c->nextYaw = gLakituState.yaw;
3748
}
3749
3750
/**
3751
* Zooms out the camera if paused and the level is 'outside', as determined by sZoomOutAreaMasks.
3752
*
3753
* Because gCurrLevelArea is assigned gCurrLevelNum * 16 + gCurrentArea->index,
3754
* dividing by 32 maps 2 levels to one index.
3755
*
3756
* areaBit definition:
3757
* (gCurrLevelArea & 0x10) / 4):
3758
* This adds 4 to the shift if the level is an odd multiple of 16
3759
*
3760
* ((gCurrLevelArea & 0xF) - 1) & 3):
3761
* This isolates the lower 16 'area' bits, subtracts 1 because areas are 1-indexed, and effectively
3762
* modulo-4's the result, because each 8-bit mask only has 4 area bits for each level
3763
*/
3764
void zoom_out_if_paused_and_outside(struct GraphNodeCamera *camera) {
3765
UNUSED u8 unused1[8];
3766
UNUSED f32 dist;
3767
UNUSED s16 pitch;
3768
s16 yaw;
3769
UNUSED u8 unused2[4];
3770
s32 areaMaskIndex = gCurrLevelArea / 32;
3771
s32 areaBit = 1 << (((gCurrLevelArea & 0x10) / 4) + (((gCurrLevelArea & 0xF) - 1) & 3));
3772
3773
if (areaMaskIndex >= LEVEL_MAX / 2) {
3774
areaMaskIndex = 0;
3775
areaBit = 0;
3776
}
3777
if (gCameraMovementFlags & CAM_MOVE_PAUSE_SCREEN) {
3778
if (sFramesPaused >= 2) {
3779
if (sZoomOutAreaMasks[areaMaskIndex] & areaBit) {
3780
3781
camera->focus[0] = gCamera->areaCenX;
3782
camera->focus[1] = (sMarioCamState->pos[1] + gCamera->areaCenY) / 2;
3783
camera->focus[2] = gCamera->areaCenZ;
3784
vec3f_get_dist_and_angle(camera->focus, sMarioCamState->pos, &dist, &pitch, &yaw);
3785
vec3f_set_dist_and_angle(sMarioCamState->pos, camera->pos, 6000.f, 0x1000, yaw);
3786
if (gCurrLevelNum != LEVEL_THI) {
3787
find_in_bounds_yaw_wdw_bob_thi(camera->pos, camera->focus, 0);
3788
}
3789
}
3790
} else {
3791
sFramesPaused++;
3792
}
3793
} else {
3794
sFramesPaused = 0;
3795
}
3796
}
3797
3798
void select_mario_cam_mode(void) {
3799
sSelectionFlags = CAM_MODE_MARIO_SELECTED;
3800
}
3801
3802
/**
3803
* Allocate the GraphNodeCamera's config.camera, and copy `c`'s focus to the Camera's area center point.
3804
*/
3805
void create_camera(struct GraphNodeCamera *gc, struct AllocOnlyPool *pool) {
3806
s16 mode = gc->config.mode;
3807
struct Camera *c = alloc_only_pool_alloc(pool, sizeof(struct Camera));
3808
3809
gc->config.camera = c;
3810
c->mode = mode;
3811
c->defMode = mode;
3812
c->cutscene = 0;
3813
c->doorStatus = DOOR_DEFAULT;
3814
c->areaCenX = gc->focus[0];
3815
c->areaCenY = gc->focus[1];
3816
c->areaCenZ = gc->focus[2];
3817
c->yaw = 0;
3818
vec3f_copy(c->pos, gc->pos);
3819
vec3f_copy(c->focus, gc->focus);
3820
}
3821
3822
/**
3823
* Copy Lakitu's pos and foc into `gc`
3824
*/
3825
void update_graph_node_camera(struct GraphNodeCamera *gc) {
3826
UNUSED u8 unused[8];
3827
UNUSED struct Camera *c = gc->config.camera;
3828
3829
gc->rollScreen = gLakituState.roll;
3830
vec3f_copy(gc->pos, gLakituState.pos);
3831
vec3f_copy(gc->focus, gLakituState.focus);
3832
zoom_out_if_paused_and_outside(gc);
3833
}
3834
3835
Gfx *geo_camera_main(s32 callContext, struct GraphNode *g, void *context) {
3836
struct GraphNodeCamera *gc = (struct GraphNodeCamera *) g;
3837
UNUSED Mat4 *unusedMat = context;
3838
3839
switch (callContext) {
3840
case GEO_CONTEXT_CREATE:
3841
create_camera(gc, context);
3842
break;
3843
case GEO_CONTEXT_RENDER:
3844
update_graph_node_camera(gc);
3845
break;
3846
}
3847
return NULL;
3848
}
3849
3850
void stub_camera_2(UNUSED struct Camera *c) {
3851
}
3852
3853
void stub_camera_3(UNUSED struct Camera *c) {
3854
}
3855
3856
void vec3f_sub(Vec3f dst, Vec3f src) {
3857
dst[0] -= src[0];
3858
dst[1] -= src[1];
3859
dst[2] -= src[2];
3860
}
3861
3862
void object_pos_to_vec3f(Vec3f dst, struct Object *o) {
3863
dst[0] = o->oPosX;
3864
dst[1] = o->oPosY;
3865
dst[2] = o->oPosZ;
3866
}
3867
3868
void vec3f_to_object_pos(struct Object *o, Vec3f src) {
3869
o->oPosX = src[0];
3870
o->oPosY = src[1];
3871
o->oPosZ = src[2];
3872
}
3873
3874
void unused_object_angle_to_vec3s(Vec3s dst, struct Object *o) {
3875
dst[0] = o->oMoveAnglePitch;
3876
dst[1] = o->oMoveAngleYaw;
3877
dst[2] = o->oMoveAngleRoll;
3878
}
3879
3880
/**
3881
* Produces values using a cubic b-spline curve. Basically Q is the used output,
3882
* u is a value between 0 and 1 that represents the position along the spline,
3883
* and a0-a3 are parameters that define the spline.
3884
*
3885
* The spline is described at www2.cs.uregina.ca/~anima/408/Notes/Interpolation/UniformBSpline.htm
3886
*/
3887
void evaluate_cubic_spline(f32 u, Vec3f Q, Vec3f a0, Vec3f a1, Vec3f a2, Vec3f a3) {
3888
f32 B[4];
3889
f32 x;
3890
f32 y;
3891
f32 z;
3892
UNUSED u8 unused[16];
3893
3894
if (u > 1.f) {
3895
u = 1.f;
3896
}
3897
3898
B[0] = (1.f - u) * (1.f - u) * (1.f - u) / 6.f;
3899
B[1] = u * u * u / 2.f - u * u + 0.6666667f;
3900
B[2] = -u * u * u / 2.f + u * u / 2.f + u / 2.f + 0.16666667f;
3901
B[3] = u * u * u / 6.f;
3902
3903
Q[0] = B[0] * a0[0] + B[1] * a1[0] + B[2] * a2[0] + B[3] * a3[0];
3904
Q[1] = B[0] * a0[1] + B[1] * a1[1] + B[2] * a2[1] + B[3] * a3[1];
3905
Q[2] = B[0] * a0[2] + B[1] * a1[2] + B[2] * a2[2] + B[3] * a3[2];
3906
3907
// Unused code
3908
B[0] = -0.5f * u * u + u - 0.33333333f;
3909
B[1] = 1.5f * u * u - 2.f * u - 0.5f;
3910
B[2] = -1.5f * u * u + u + 1.f;
3911
B[3] = 0.5f * u * u - 0.16666667f;
3912
3913
x = B[0] * a0[0] + B[1] * a1[0] + B[2] * a2[0] + B[3] * a3[0];
3914
y = B[0] * a0[1] + B[1] * a1[1] + B[2] * a2[1] + B[3] * a3[1];
3915
z = B[0] * a0[2] + B[1] * a1[2] + B[2] * a2[2] + B[3] * a3[2];
3916
3917
unusedSplinePitch = atan2s(sqrtf(x * x + z * z), y);
3918
unusedSplineYaw = atan2s(z, x);
3919
}
3920
3921
/**
3922
* Computes the point that is `progress` percent of the way through segment `splineSegment` of `spline`,
3923
* and stores the result in `p`. `progress` and `splineSegment` are updated if `progress` becomes >= 1.0.
3924
*
3925
* When neither of the next two points' speeds == 0, the number of frames is between 1 and 255. Otherwise
3926
* it's infinite.
3927
*
3928
* To calculate the number of frames it will take to progress through a spline segment:
3929
* If the next two speeds are the same and nonzero, it's 1.0 / firstSpeed.
3930
*
3931
* s1 and s2 are short hand for first/secondSpeed. The progress at any frame n is defined by a recurrency relation:
3932
* p(n+1) = (s2 - s1 + 1) * p(n) + s1
3933
* Which can be written as
3934
* p(n) = (s2 * ((s2 - s1 + 1)^(n) - 1)) / (s2 - s1)
3935
*
3936
* Solving for the number of frames:
3937
* n = log(((s2 - s1) / s1) + 1) / log(s2 - s1 + 1)
3938
*
3939
* @return 1 if the point has reached the end of the spline, when `progress` reaches 1.0 or greater, and
3940
* the 4th CutsceneSplinePoint in the current segment away from spline[splineSegment] has an index of -1.
3941
*/
3942
s32 move_point_along_spline(Vec3f p, struct CutsceneSplinePoint spline[], s16 *splineSegment, f32 *progress) {
3943
s32 finished = 0;
3944
Vec3f controlPoints[4];
3945
s32 i = 0;
3946
f32 u = *progress;
3947
f32 progressChange;
3948
f32 firstSpeed = 0;
3949
f32 secondSpeed = 0;
3950
s32 segment = *splineSegment;
3951
3952
if (*splineSegment < 0) {
3953
segment = 0;
3954
u = 0;
3955
}
3956
if (spline[segment].index == -1 || spline[segment + 1].index == -1 || spline[segment + 2].index == -1) {
3957
return 1;
3958
}
3959
3960
for (i = 0; i < 4; i++) {
3961
controlPoints[i][0] = spline[segment + i].point[0];
3962
controlPoints[i][1] = spline[segment + i].point[1];
3963
controlPoints[i][2] = spline[segment + i].point[2];
3964
}
3965
evaluate_cubic_spline(u, p, controlPoints[0], controlPoints[1], controlPoints[2], controlPoints[3]);
3966
3967
if (spline[*splineSegment + 1].speed != 0) {
3968
firstSpeed = 1.0f / spline[*splineSegment + 1].speed;
3969
}
3970
if (spline[*splineSegment + 2].speed != 0) {
3971
secondSpeed = 1.0f / spline[*splineSegment + 2].speed;
3972
}
3973
progressChange = (secondSpeed - firstSpeed) * *progress + firstSpeed;
3974
3975
#ifdef VERSION_EU
3976
if (gCamera->cutscene == CUTSCENE_INTRO_PEACH) {
3977
progressChange += progressChange * 0.19f;
3978
}
3979
if (gCamera->cutscene == CUTSCENE_CREDITS) {
3980
progressChange += progressChange * 0.15f;
3981
}
3982
if (gCamera->cutscene == CUTSCENE_ENDING) {
3983
progressChange += progressChange * 0.1f;
3984
}
3985
#endif
3986
3987
if (1 <= (*progress += progressChange)) {
3988
(*splineSegment)++;
3989
if (spline[*splineSegment + 3].index == -1) {
3990
*splineSegment = 0;
3991
finished = 1;
3992
}
3993
*progress -= 1;
3994
}
3995
return finished;
3996
}
3997
3998
/**
3999
* If `selection` is 0, just get the current selection
4000
* If `selection` is 1, select 'Mario' as the alt mode.
4001
* If `selection` is 2, select 'fixed' as the alt mode.
4002
*
4003
* @return the current selection
4004
*/
4005
s32 cam_select_alt_mode(s32 selection) {
4006
s32 mode = CAM_SELECTION_FIXED;
4007
4008
if (selection == CAM_SELECTION_MARIO) {
4009
if (!(sSelectionFlags & CAM_MODE_MARIO_SELECTED)) {
4010
sSelectionFlags |= CAM_MODE_MARIO_SELECTED;
4011
}
4012
sCameraSoundFlags |= CAM_SOUND_UNUSED_SELECT_MARIO;
4013
}
4014
4015
// The alternate mode is up-close, but the player just selected fixed in the pause menu
4016
if (selection == CAM_SELECTION_FIXED && (sSelectionFlags & CAM_MODE_MARIO_SELECTED)) {
4017
// So change to normal mode in case the user paused in up-close mode
4018
set_cam_angle(CAM_ANGLE_LAKITU);
4019
sSelectionFlags &= ~CAM_MODE_MARIO_SELECTED;
4020
sCameraSoundFlags |= CAM_SOUND_UNUSED_SELECT_FIXED;
4021
}
4022
4023
if (sSelectionFlags & CAM_MODE_MARIO_SELECTED) {
4024
mode = CAM_SELECTION_MARIO;
4025
}
4026
return mode;
4027
}
4028
4029
/**
4030
* Sets the camera angle to either Lakitu or Mario mode. Returns the current mode.
4031
*
4032
* If `mode` is 0, just returns the current mode.
4033
* If `mode` is 1, start Mario mode
4034
* If `mode` is 2, start Lakitu mode
4035
*/
4036
s32 set_cam_angle(s32 mode) {
4037
s32 curMode = CAM_ANGLE_LAKITU;
4038
4039
// Switch to Mario mode
4040
if (mode == CAM_ANGLE_MARIO && !(sSelectionFlags & CAM_MODE_MARIO_ACTIVE)) {
4041
sSelectionFlags |= CAM_MODE_MARIO_ACTIVE;
4042
if (gCameraMovementFlags & CAM_MOVE_ZOOMED_OUT) {
4043
sSelectionFlags |= CAM_MODE_LAKITU_WAS_ZOOMED_OUT;
4044
gCameraMovementFlags &= ~CAM_MOVE_ZOOMED_OUT;
4045
}
4046
sCameraSoundFlags |= CAM_SOUND_MARIO_ACTIVE;
4047
}
4048
4049
// Switch back to normal mode
4050
if (mode == CAM_ANGLE_LAKITU && (sSelectionFlags & CAM_MODE_MARIO_ACTIVE)) {
4051
sSelectionFlags &= ~CAM_MODE_MARIO_ACTIVE;
4052
if (sSelectionFlags & CAM_MODE_LAKITU_WAS_ZOOMED_OUT) {
4053
sSelectionFlags &= ~CAM_MODE_LAKITU_WAS_ZOOMED_OUT;
4054
gCameraMovementFlags |= CAM_MOVE_ZOOMED_OUT;
4055
} else {
4056
gCameraMovementFlags &= ~CAM_MOVE_ZOOMED_OUT;
4057
}
4058
sCameraSoundFlags |= CAM_SOUND_NORMAL_ACTIVE;
4059
}
4060
if (sSelectionFlags & CAM_MODE_MARIO_ACTIVE) {
4061
curMode = CAM_ANGLE_MARIO;
4062
}
4063
return curMode;
4064
}
4065
4066
/**
4067
* Enables the handheld shake effect for this frame.
4068
*
4069
* @see shake_camera_handheld()
4070
*/
4071
void set_handheld_shake(u8 mode) {
4072
switch (mode) {
4073
// They're not in numerical order because that would be too simple...
4074
case HAND_CAM_SHAKE_CUTSCENE: // Lowest increment
4075
sHandheldShakeMag = 0x600;
4076
sHandheldShakeInc = 0.04f;
4077
break;
4078
case HAND_CAM_SHAKE_LOW: // Lowest magnitude
4079
sHandheldShakeMag = 0x300;
4080
sHandheldShakeInc = 0.06f;
4081
break;
4082
case HAND_CAM_SHAKE_HIGH: // Highest mag and inc
4083
sHandheldShakeMag = 0x1000;
4084
sHandheldShakeInc = 0.1f;
4085
break;
4086
case HAND_CAM_SHAKE_UNUSED: // Never used
4087
sHandheldShakeMag = 0x600;
4088
sHandheldShakeInc = 0.07f;
4089
break;
4090
case HAND_CAM_SHAKE_HANG_OWL: // exactly the same as UNUSED...
4091
sHandheldShakeMag = 0x600;
4092
sHandheldShakeInc = 0.07f;
4093
break;
4094
case HAND_CAM_SHAKE_STAR_DANCE: // Slightly steadier than HANG_OWL and UNUSED
4095
sHandheldShakeMag = 0x400;
4096
sHandheldShakeInc = 0.07f;
4097
break;
4098
default:
4099
sHandheldShakeMag = 0x0;
4100
sHandheldShakeInc = 0.f;
4101
}
4102
}
4103
4104
/**
4105
* When sHandheldShakeMag is nonzero, this function adds small random offsets to `focus` every time
4106
* sHandheldShakeTimer increases above 1.0, simulating the camera shake caused by unsteady hands.
4107
*
4108
* This function must be called every frame in order to actually apply the effect, since the effect's
4109
* mag and inc are set to 0 every frame at the end of this function.
4110
*/
4111
void shake_camera_handheld(Vec3f pos, Vec3f focus) {
4112
s32 i;
4113
Vec3f shakeOffset;
4114
Vec3f shakeSpline[4];
4115
f32 dist;
4116
s16 pitch;
4117
s16 yaw;
4118
UNUSED u8 unused[8];
4119
4120
if (sHandheldShakeMag == 0) {
4121
vec3f_set(shakeOffset, 0.f, 0.f, 0.f);
4122
} else {
4123
for (i = 0; i < 4; i++) {
4124
shakeSpline[i][0] = sHandheldShakeSpline[i].point[0];
4125
shakeSpline[i][1] = sHandheldShakeSpline[i].point[1];
4126
shakeSpline[i][2] = sHandheldShakeSpline[i].point[2];
4127
}
4128
evaluate_cubic_spline(sHandheldShakeTimer, shakeOffset, shakeSpline[0],
4129
shakeSpline[1], shakeSpline[2], shakeSpline[3]);
4130
if (1.f <= (sHandheldShakeTimer += sHandheldShakeInc)) {
4131
// The first 3 control points are always (0,0,0), so the random spline is always just a
4132
// straight line
4133
for (i = 0; i < 3; i++) {
4134
vec3s_copy(sHandheldShakeSpline[i].point, sHandheldShakeSpline[i + 1].point);
4135
}
4136
random_vec3s(sHandheldShakeSpline[3].point, sHandheldShakeMag, sHandheldShakeMag, sHandheldShakeMag / 2);
4137
sHandheldShakeTimer -= 1.f;
4138
4139
// Code dead, this is set to be 0 before it is used.
4140
sHandheldShakeInc = random_float() * 0.5f;
4141
if (sHandheldShakeInc < 0.02f) {
4142
sHandheldShakeInc = 0.02f;
4143
}
4144
}
4145
}
4146
4147
approach_s16_asymptotic_bool(&sHandheldShakePitch, shakeOffset[0], 0x08);
4148
approach_s16_asymptotic_bool(&sHandheldShakeYaw, shakeOffset[1], 0x08);
4149
approach_s16_asymptotic_bool(&sHandheldShakeRoll, shakeOffset[2], 0x08);
4150
4151
if (sHandheldShakePitch | sHandheldShakeYaw) {
4152
vec3f_get_dist_and_angle(pos, focus, &dist, &pitch, &yaw);
4153
pitch += sHandheldShakePitch;
4154
yaw += sHandheldShakeYaw;
4155
vec3f_set_dist_and_angle(pos, focus, dist, pitch, yaw);
4156
}
4157
4158
// Unless called every frame, the effect will stop after the first time.
4159
sHandheldShakeMag = 0;
4160
sHandheldShakeInc = 0.f;
4161
}
4162
4163
/**
4164
* Updates C Button input state and stores it in `currentState`
4165
*/
4166
s32 find_c_buttons_pressed(u16 currentState, u16 buttonsPressed, u16 buttonsDown) {
4167
buttonsPressed &= CBUTTON_MASK;
4168
buttonsDown &= CBUTTON_MASK;
4169
4170
if (buttonsPressed & L_CBUTTONS) {
4171
currentState |= L_CBUTTONS;
4172
currentState &= ~R_CBUTTONS;
4173
}
4174
if (!(buttonsDown & L_CBUTTONS)) {
4175
currentState &= ~L_CBUTTONS;
4176
}
4177
4178
if (buttonsPressed & R_CBUTTONS) {
4179
currentState |= R_CBUTTONS;
4180
currentState &= ~L_CBUTTONS;
4181
}
4182
if (!(buttonsDown & R_CBUTTONS)) {
4183
currentState &= ~R_CBUTTONS;
4184
}
4185
4186
if (buttonsPressed & U_CBUTTONS) {
4187
currentState |= U_CBUTTONS;
4188
currentState &= ~D_CBUTTONS;
4189
}
4190
if (!(buttonsDown & U_CBUTTONS)) {
4191
currentState &= ~U_CBUTTONS;
4192
}
4193
4194
if (buttonsPressed & D_CBUTTONS) {
4195
currentState |= D_CBUTTONS;
4196
currentState &= ~U_CBUTTONS;
4197
}
4198
if (!(buttonsDown & D_CBUTTONS)) {
4199
currentState &= ~D_CBUTTONS;
4200
}
4201
4202
return currentState;
4203
}
4204
4205
/**
4206
* Determine which icon to show on the HUD
4207
*/
4208
s32 update_camera_hud_status(struct Camera *c) {
4209
s16 status = CAM_STATUS_NONE;
4210
4211
if (c->cutscene != 0
4212
|| ((gPlayer1Controller->buttonDown & R_TRIG) && cam_select_alt_mode(0) == CAM_SELECTION_FIXED)) {
4213
status |= CAM_STATUS_FIXED;
4214
} else if (set_cam_angle(0) == CAM_ANGLE_MARIO) {
4215
status |= CAM_STATUS_MARIO;
4216
} else {
4217
status |= CAM_STATUS_LAKITU;
4218
}
4219
if (gCameraMovementFlags & CAM_MOVE_ZOOMED_OUT) {
4220
status |= CAM_STATUS_C_DOWN;
4221
}
4222
if (gCameraMovementFlags & CAM_MOVE_C_UP_MODE) {
4223
status |= CAM_STATUS_C_UP;
4224
}
4225
set_hud_camera_status(status);
4226
return status;
4227
}
4228
4229
/**
4230
* Check `pos` for collisions within `radius`, and update `pos`
4231
*
4232
* @return the number of collisions found
4233
*/
4234
s32 collide_with_walls(Vec3f pos, f32 offsetY, f32 radius) {
4235
struct WallCollisionData collisionData;
4236
struct Surface *wall = NULL;
4237
f32 normX;
4238
f32 normY;
4239
f32 normZ;
4240
f32 originOffset;
4241
f32 offset;
4242
f32 offsetAbsolute;
4243
Vec3f newPos[4];
4244
s32 i;
4245
s32 numCollisions = 0;
4246
4247
collisionData.x = pos[0];
4248
collisionData.y = pos[1];
4249
collisionData.z = pos[2];
4250
collisionData.radius = radius;
4251
collisionData.offsetY = offsetY;
4252
numCollisions = find_wall_collisions(&collisionData);
4253
if (numCollisions != 0) {
4254
for (i = 0; i < collisionData.numWalls; i++) {
4255
wall = collisionData.walls[collisionData.numWalls - 1];
4256
vec3f_copy(newPos[i], pos);
4257
normX = wall->normal.x;
4258
normY = wall->normal.y;
4259
normZ = wall->normal.z;
4260
originOffset = wall->originOffset;
4261
offset = normX * newPos[i][0] + normY * newPos[i][1] + normZ * newPos[i][2] + originOffset;
4262
offsetAbsolute = ABS2(offset);
4263
if (offsetAbsolute < radius) {
4264
newPos[i][0] += normX * (radius - offset);
4265
newPos[i][2] += normZ * (radius - offset);
4266
vec3f_copy(pos, newPos[i]);
4267
}
4268
}
4269
}
4270
return numCollisions;
4271
}
4272
4273
/**
4274
* Compare a vector to a position, return TRUE if they match.
4275
*/
4276
s32 vec3f_compare(Vec3f pos, f32 posX, f32 posY, f32 posZ) {
4277
s32 equal = FALSE;
4278
4279
if (pos[0] == posX && pos[1] == posY && pos[2] == posZ) {
4280
equal = TRUE;
4281
}
4282
return equal;
4283
}
4284
4285
s32 clamp_pitch(Vec3f from, Vec3f to, s16 maxPitch, s16 minPitch) {
4286
s32 outOfRange = 0;
4287
s16 pitch;
4288
s16 yaw;
4289
f32 dist;
4290
4291
vec3f_get_dist_and_angle(from, to, &dist, &pitch, &yaw);
4292
if (pitch > maxPitch) {
4293
pitch = maxPitch;
4294
outOfRange++;
4295
}
4296
if (pitch < minPitch) {
4297
pitch = minPitch;
4298
outOfRange++;
4299
}
4300
vec3f_set_dist_and_angle(from, to, dist, pitch, yaw);
4301
return outOfRange;
4302
}
4303
4304
s32 is_within_100_units_of_mario(f32 posX, f32 posY, f32 posZ) {
4305
s32 isCloseToMario = 0;
4306
Vec3f pos;
4307
4308
vec3f_set(pos, posX, posY, posZ);
4309
if (calc_abs_dist(sMarioCamState->pos, pos) < 100.f) {
4310
isCloseToMario = 1;
4311
}
4312
return isCloseToMario;
4313
}
4314
4315
s32 set_or_approach_f32_asymptotic(f32 *dst, f32 goal, f32 scale) {
4316
if (sStatusFlags & CAM_FLAG_SMOOTH_MOVEMENT) {
4317
approach_f32_asymptotic_bool(dst, goal, scale);
4318
} else {
4319
*dst = goal;
4320
}
4321
if (*dst == goal) {
4322
return FALSE;
4323
} else {
4324
return TRUE;
4325
}
4326
}
4327
4328
/**
4329
* Approaches an f32 value by taking the difference between the target and current value
4330
* and adding a fraction of that to the current value.
4331
* Edits the current value directly, returns TRUE if the target has been reached, FALSE otherwise.
4332
*/
4333
s32 approach_f32_asymptotic_bool(f32 *current, f32 target, f32 multiplier) {
4334
if (multiplier > 1.f) {
4335
multiplier = 1.f;
4336
}
4337
*current = *current + (target - *current) * multiplier;
4338
if (*current == target) {
4339
return FALSE;
4340
} else {
4341
return TRUE;
4342
}
4343
}
4344
4345
/**
4346
* Nearly the same as the above function, returns new value instead.
4347
*/
4348
f32 approach_f32_asymptotic(f32 current, f32 target, f32 multiplier) {
4349
current = current + (target - current) * multiplier;
4350
return current;
4351
}
4352
4353
/**
4354
* Approaches an s16 value in the same fashion as approach_f32_asymptotic_bool, returns TRUE if target
4355
* is reached. Note: Since this function takes integers as parameters, the last argument is the
4356
* reciprocal of what it would be in the previous two functions.
4357
*/
4358
s32 approach_s16_asymptotic_bool(s16 *current, s16 target, s16 divisor) {
4359
s16 temp = *current;
4360
4361
if (divisor == 0) {
4362
*current = target;
4363
} else {
4364
temp -= target;
4365
temp -= temp / divisor;
4366
temp += target;
4367
*current = temp;
4368
}
4369
if (*current == target) {
4370
return FALSE;
4371
} else {
4372
return TRUE;
4373
}
4374
}
4375
4376
/**
4377
* Approaches an s16 value in the same fashion as approach_f32_asymptotic, returns the new value.
4378
* Note: last parameter is the reciprocal of what it would be in the f32 functions
4379
*/
4380
s32 approach_s16_asymptotic(s16 current, s16 target, s16 divisor) {
4381
s16 temp = current;
4382
4383
if (divisor == 0) {
4384
current = target;
4385
} else {
4386
temp -= target;
4387
temp -= temp / divisor;
4388
temp += target;
4389
current = temp;
4390
}
4391
return current;
4392
}
4393
4394
/**
4395
* Applies the approach_f32_asymptotic_bool function to each of the X, Y, & Z components of the given
4396
* vector.
4397
*/
4398
void approach_vec3f_asymptotic(Vec3f current, Vec3f target, f32 xMul, f32 yMul, f32 zMul) {
4399
approach_f32_asymptotic_bool(&current[0], target[0], xMul);
4400
approach_f32_asymptotic_bool(&current[1], target[1], yMul);
4401
approach_f32_asymptotic_bool(&current[2], target[2], zMul);
4402
}
4403
4404
/**
4405
* Applies the set_or_approach_f32_asymptotic_bool function to each of the X, Y, & Z components of the
4406
* given vector.
4407
*/
4408
void set_or_approach_vec3f_asymptotic(Vec3f dst, Vec3f goal, f32 xMul, f32 yMul, f32 zMul) {
4409
set_or_approach_f32_asymptotic(&dst[0], goal[0], xMul);
4410
set_or_approach_f32_asymptotic(&dst[1], goal[1], yMul);
4411
set_or_approach_f32_asymptotic(&dst[2], goal[2], zMul);
4412
}
4413
4414
/**
4415
* Applies the approach_s32_asymptotic function to each of the X, Y, & Z components of the given
4416
* vector.
4417
*/
4418
void approach_vec3s_asymptotic(Vec3s current, Vec3s target, s16 xMul, s16 yMul, s16 zMul) {
4419
approach_s16_asymptotic_bool(&current[0], target[0], xMul);
4420
approach_s16_asymptotic_bool(&current[1], target[1], yMul);
4421
approach_s16_asymptotic_bool(&current[2], target[2], zMul);
4422
}
4423
4424
s32 camera_approach_s16_symmetric_bool(s16 *current, s16 target, s16 increment) {
4425
s16 dist = target - *current;
4426
4427
if (increment < 0) {
4428
increment = -1 * increment;
4429
}
4430
if (dist > 0) {
4431
dist -= increment;
4432
if (dist >= 0) {
4433
*current = target - dist;
4434
} else {
4435
*current = target;
4436
}
4437
} else {
4438
dist += increment;
4439
if (dist <= 0) {
4440
*current = target - dist;
4441
} else {
4442
*current = target;
4443
}
4444
}
4445
if (*current == target) {
4446
return FALSE;
4447
} else {
4448
return TRUE;
4449
}
4450
}
4451
4452
s32 camera_approach_s16_symmetric(s16 current, s16 target, s16 increment) {
4453
s16 dist = target - current;
4454
4455
if (increment < 0) {
4456
increment = -1 * increment;
4457
}
4458
if (dist > 0) {
4459
dist -= increment;
4460
if (dist >= 0) {
4461
current = target - dist;
4462
} else {
4463
current = target;
4464
}
4465
} else {
4466
dist += increment;
4467
if (dist <= 0) {
4468
current = target - dist;
4469
} else {
4470
current = target;
4471
}
4472
}
4473
return current;
4474
}
4475
4476
s32 set_or_approach_s16_symmetric(s16 *current, s16 target, s16 increment) {
4477
if (sStatusFlags & CAM_FLAG_SMOOTH_MOVEMENT) {
4478
camera_approach_s16_symmetric_bool(current, target, increment);
4479
} else {
4480
*current = target;
4481
}
4482
if (*current == target) {
4483
return FALSE;
4484
} else {
4485
return TRUE;
4486
}
4487
}
4488
4489
/**
4490
* Approaches a value by a given increment, returns FALSE if the target is reached.
4491
* Appears to be a strange way of implementing approach_f32_symmetric from object_helpers.c.
4492
* It could possibly be an older version of the function
4493
*/
4494
s32 camera_approach_f32_symmetric_bool(f32 *current, f32 target, f32 increment) {
4495
f32 dist = target - *current;
4496
4497
if (increment < 0) {
4498
increment = -1 * increment;
4499
}
4500
if (dist > 0) {
4501
dist -= increment;
4502
if (dist > 0) {
4503
*current = target - dist;
4504
} else {
4505
*current = target;
4506
}
4507
} else {
4508
dist += increment;
4509
if (dist < 0) {
4510
*current = target - dist;
4511
} else {
4512
*current = target;
4513
}
4514
}
4515
if (*current == target) {
4516
return FALSE;
4517
} else {
4518
return TRUE;
4519
}
4520
}
4521
4522
/**
4523
* Nearly the same as the above function, this one returns the new value in place of a bool.
4524
*/
4525
f32 camera_approach_f32_symmetric(f32 current, f32 target, f32 increment) {
4526
f32 dist = target - current;
4527
4528
if (increment < 0) {
4529
increment = -1 * increment;
4530
}
4531
if (dist > 0) {
4532
dist -= increment;
4533
if (dist > 0) {
4534
current = target - dist;
4535
} else {
4536
current = target;
4537
}
4538
} else {
4539
dist += increment;
4540
if (dist < 0) {
4541
current = target - dist;
4542
} else {
4543
current = target;
4544
}
4545
}
4546
return current;
4547
}
4548
4549
/**
4550
* Generate a vector with all three values about zero. The
4551
* three ranges determine how wide the range about zero.
4552
*/
4553
void random_vec3s(Vec3s dst, s16 xRange, s16 yRange, s16 zRange) {
4554
f32 randomFloat;
4555
UNUSED u8 unused[4];
4556
f32 tempXRange;
4557
f32 tempYRange;
4558
f32 tempZRange;
4559
4560
randomFloat = random_float();
4561
tempXRange = xRange;
4562
dst[0] = randomFloat * tempXRange - tempXRange / 2;
4563
4564
randomFloat = random_float();
4565
tempYRange = yRange;
4566
dst[1] = randomFloat * tempYRange - tempYRange / 2;
4567
4568
randomFloat = random_float();
4569
tempZRange = zRange;
4570
dst[2] = randomFloat * tempZRange - tempZRange / 2;
4571
}
4572
4573
/**
4574
* Decrease value by multiplying it by the distance from (`posX`, `posY`, `posZ`) to
4575
* the camera divided by `maxDist`
4576
*
4577
* @return the reduced value
4578
*/
4579
s16 reduce_by_dist_from_camera(s16 value, f32 maxDist, f32 posX, f32 posY, f32 posZ) {
4580
Vec3f pos;
4581
f32 dist;
4582
s16 pitch;
4583
s16 yaw;
4584
s16 goalPitch;
4585
s16 goalYaw;
4586
s16 result = 0;
4587
// Direction from pos to (Lakitu's) goalPos
4588
f32 goalDX = gLakituState.goalPos[0] - posX;
4589
f32 goalDY = gLakituState.goalPos[1] - posY;
4590
f32 goalDZ = gLakituState.goalPos[2] - posZ;
4591
4592
dist = sqrtf(goalDX * goalDX + goalDY * goalDY + goalDZ * goalDZ);
4593
if (maxDist > dist) {
4594
pos[0] = posX;
4595
pos[1] = posY;
4596
pos[2] = posZ;
4597
vec3f_get_dist_and_angle(gLakituState.goalPos, pos, &dist, &pitch, &yaw);
4598
if (dist < maxDist) {
4599
calculate_angles(gLakituState.goalPos, gLakituState.goalFocus, &goalPitch, &goalYaw);
4600
//! Must be same line to match on -O2
4601
pitch -= goalPitch; yaw -= goalYaw;
4602
dist -= 2000.f;
4603
if (dist < 0.f) {
4604
dist = 0.f;
4605
}
4606
maxDist -= 2000.f;
4607
if (maxDist < 2000.f) {
4608
maxDist = 2000.f;
4609
}
4610
result = value * (1.f - dist / maxDist);
4611
if (pitch < -0x1800 || pitch > 0x400 ||
4612
yaw < -0x1800 || yaw > 0x1800) {
4613
result /= 2;
4614
}
4615
}
4616
}
4617
return result;
4618
}
4619
4620
s32 clamp_positions_and_find_yaw(Vec3f pos, Vec3f origin, f32 xMax, f32 xMin, f32 zMax, f32 zMin) {
4621
s16 yaw = gCamera->nextYaw;
4622
4623
if (pos[0] >= xMax) {
4624
pos[0] = xMax;
4625
}
4626
if (pos[0] <= xMin) {
4627
pos[0] = xMin;
4628
}
4629
if (pos[2] >= zMax) {
4630
pos[2] = zMax;
4631
}
4632
if (pos[2] <= zMin) {
4633
pos[2] = zMin;
4634
}
4635
yaw = calculate_yaw(origin, pos);
4636
return yaw;
4637
}
4638
4639
/**
4640
* The yaw passed here is the yaw of the direction FROM Mario TO Lakitu.
4641
*
4642
* wallYaw always has 90 degrees added to it before this is called -- it's parallel to the wall.
4643
*
4644
* @return the new yaw from Mario to rotate towards.
4645
*
4646
* @warning this is jank. It actually returns the yaw that will rotate further INTO the wall. So, the
4647
* developers just add 180 degrees to the result.
4648
*/
4649
s32 calc_avoid_yaw(s16 yawFromMario, s16 wallYaw) {
4650
s16 yawDiff;
4651
UNUSED u8 unused[34]; // Debug print buffer? ;)
4652
UNUSED s32 unused1 = 0;
4653
UNUSED s32 unused2 = 0;
4654
4655
yawDiff = wallYaw - yawFromMario + DEGREES(90);
4656
4657
if (yawDiff < 0) {
4658
// Deflect to the right
4659
yawFromMario = wallYaw;
4660
} else {
4661
// Note: this favors the left side if the wall is exactly perpendicular to the camera.
4662
// Deflect to the left
4663
yawFromMario = wallYaw + DEGREES(180);
4664
}
4665
return yawFromMario;
4666
}
4667
4668
/**
4669
* Checks if `surf` is within the rect prism defined by xMax, yMax, and zMax
4670
*
4671
* @param surf surface to check
4672
* @param xMax absolute-value max size in x, set to -1 to ignore
4673
* @param yMax absolute-value max size in y, set to -1 to ignore
4674
* @param zMax absolute-value max size in z, set to -1 to ignore
4675
*/
4676
s32 is_surf_within_bounding_box(struct Surface *surf, f32 xMax, f32 yMax, f32 zMax) {
4677
// Surface vertex coordinates
4678
Vec3s sx;
4679
Vec3s sy;
4680
Vec3s sz;
4681
// Max delta between x, y, and z
4682
s16 dxMax = 0;
4683
s16 dyMax = 0;
4684
s16 dzMax = 0;
4685
// Current deltas between x, y, and z
4686
f32 dx;
4687
f32 dy;
4688
f32 dz;
4689
UNUSED u8 unused[4];
4690
s32 i;
4691
s32 j;
4692
// result
4693
s32 smaller = FALSE;
4694
4695
sx[0] = surf->vertex1[0];
4696
sx[1] = surf->vertex2[0];
4697
sx[2] = surf->vertex3[0];
4698
sy[0] = surf->vertex1[1];
4699
sy[1] = surf->vertex2[1];
4700
sy[2] = surf->vertex3[1];
4701
sz[0] = surf->vertex1[2];
4702
sz[1] = surf->vertex2[2];
4703
sz[2] = surf->vertex3[2];
4704
4705
for (i = 0; i < 3; i++) {
4706
j = i + 1;
4707
if (j >= 3) {
4708
j = 0;
4709
}
4710
dx = ABS(sx[i] - sx[j]);
4711
if (dx > dxMax) {
4712
dxMax = dx;
4713
}
4714
dy = ABS(sy[i] - sy[j]);
4715
if (dy > dyMax) {
4716
dyMax = dy;
4717
}
4718
dz = ABS(sz[i] - sz[j]);
4719
if (dz > dzMax) {
4720
dzMax = dz;
4721
}
4722
}
4723
if (yMax != -1.f) {
4724
if (dyMax < yMax) {
4725
smaller = TRUE;
4726
}
4727
}
4728
if (xMax != -1.f && zMax != -1.f) {
4729
if (dxMax < xMax && dzMax < zMax) {
4730
smaller = TRUE;
4731
}
4732
}
4733
return smaller;
4734
}
4735
4736
/**
4737
* Checks if `pos` is behind the surface, using the dot product.
4738
*
4739
* Because the function only uses `surf`s first vertex, some surfaces can shadow others.
4740
*/
4741
s32 is_behind_surface(Vec3f pos, struct Surface *surf) {
4742
s32 behindSurface = 0;
4743
// Surface normal
4744
f32 normX = (surf->vertex2[1] - surf->vertex1[1]) * (surf->vertex3[2] - surf->vertex2[2]) -
4745
(surf->vertex3[1] - surf->vertex2[1]) * (surf->vertex2[2] - surf->vertex1[2]);
4746
f32 normY = (surf->vertex2[2] - surf->vertex1[2]) * (surf->vertex3[0] - surf->vertex2[0]) -
4747
(surf->vertex3[2] - surf->vertex2[2]) * (surf->vertex2[0] - surf->vertex1[0]);
4748
f32 normZ = (surf->vertex2[0] - surf->vertex1[0]) * (surf->vertex3[1] - surf->vertex2[1]) -
4749
(surf->vertex3[0] - surf->vertex2[0]) * (surf->vertex2[1] - surf->vertex1[1]);
4750
f32 dirX = surf->vertex1[0] - pos[0];
4751
f32 dirY = surf->vertex1[1] - pos[1];
4752
f32 dirZ = surf->vertex1[2] - pos[2];
4753
4754
if (dirX * normX + dirY * normY + dirZ * normZ < 0) {
4755
behindSurface = 1;
4756
}
4757
return behindSurface;
4758
}
4759
4760
/**
4761
* Checks if the whole circular sector is behind the surface.
4762
*/
4763
s32 is_range_behind_surface(Vec3f from, Vec3f to, struct Surface *surf, s16 range, s16 surfType) {
4764
s32 behindSurface = TRUE;
4765
s32 leftBehind = 0;
4766
s32 rightBehind = 0;
4767
UNUSED u8 unused[20];
4768
f32 checkDist;
4769
s16 checkPitch;
4770
s16 checkYaw;
4771
Vec3f checkPos;
4772
4773
if (surf != NULL) {
4774
if (surfType == -1 || surf->type != surfType) {
4775
if (range == 0) {
4776
behindSurface = is_behind_surface(to, surf);
4777
} else {
4778
vec3f_get_dist_and_angle(from, to, &checkDist, &checkPitch, &checkYaw);
4779
vec3f_set_dist_and_angle(from, checkPos, checkDist, checkPitch, checkYaw + range);
4780
leftBehind = is_behind_surface(checkPos, surf);
4781
vec3f_set_dist_and_angle(from, checkPos, checkDist, checkPitch, checkYaw - range);
4782
rightBehind = is_behind_surface(checkPos, surf);
4783
behindSurface = leftBehind * rightBehind;
4784
}
4785
}
4786
}
4787
return behindSurface;
4788
}
4789
4790
s32 is_mario_behind_surface(UNUSED struct Camera *c, struct Surface *surf) {
4791
s32 behindSurface = is_behind_surface(sMarioCamState->pos, surf);
4792
4793
return behindSurface;
4794
}
4795
4796
/**
4797
* Calculates the distance between two points and sets a vector to a point
4798
* scaled along a line between them. Typically, somewhere in the middle.
4799
*/
4800
void scale_along_line(Vec3f dst, Vec3f from, Vec3f to, f32 scale) {
4801
Vec3f tempVec;
4802
4803
tempVec[0] = (to[0] - from[0]) * scale + from[0];
4804
tempVec[1] = (to[1] - from[1]) * scale + from[1];
4805
tempVec[2] = (to[2] - from[2]) * scale + from[2];
4806
vec3f_copy(dst, tempVec);
4807
}
4808
/**
4809
* Effectively created a rectangular prism defined by a vector starting at the center
4810
* and extending to the corners. If the position is in this box, the function returns true.
4811
*/
4812
s32 is_pos_in_bounds(Vec3f pos, Vec3f center, Vec3f bounds, s16 boundsYaw) {
4813
s32 inBound = FALSE;
4814
Vec3f rel;
4815
4816
rel[0] = center[0] - pos[0];
4817
rel[1] = center[1] - pos[1];
4818
rel[2] = center[2] - pos[2];
4819
4820
rotate_in_xz(rel, rel, boundsYaw);
4821
4822
if (-bounds[0] < rel[0] && rel[0] < bounds[0] &&
4823
-bounds[1] < rel[1] && rel[1] < bounds[1] &&
4824
-bounds[2] < rel[2] && rel[2] < bounds[2]) {
4825
inBound = TRUE;
4826
}
4827
return inBound;
4828
}
4829
4830
s16 calculate_pitch(Vec3f from, Vec3f to) {
4831
f32 dx = to[0] - from[0];
4832
f32 dy = to[1] - from[1];
4833
f32 dz = to[2] - from[2];
4834
s16 pitch = atan2s(sqrtf(dx * dx + dz * dz), dy);
4835
4836
return pitch;
4837
}
4838
4839
s16 calculate_yaw(Vec3f from, Vec3f to) {
4840
f32 dx = to[0] - from[0];
4841
UNUSED f32 dy = to[1] - from[1];
4842
f32 dz = to[2] - from[2];
4843
s16 yaw = atan2s(dz, dx);
4844
4845
return yaw;
4846
}
4847
4848
/**
4849
* Calculates the pitch and yaw between two vectors.
4850
*/
4851
void calculate_angles(Vec3f from, Vec3f to, s16 *pitch, s16 *yaw) {
4852
f32 dx = to[0] - from[0];
4853
f32 dy = to[1] - from[1];
4854
f32 dz = to[2] - from[2];
4855
4856
*pitch = atan2s(sqrtf(dx * dx + dz * dz), dy);
4857
*yaw = atan2s(dz, dx);
4858
}
4859
4860
/**
4861
* Finds the distance between two vectors.
4862
*/
4863
f32 calc_abs_dist(Vec3f a, Vec3f b) {
4864
f32 distX = b[0] - a[0];
4865
f32 distY = b[1] - a[1];
4866
f32 distZ = b[2] - a[2];
4867
f32 distAbs = sqrtf(distX * distX + distY * distY + distZ * distZ);
4868
4869
return distAbs;
4870
}
4871
4872
/**
4873
* Finds the horizontal distance between two vectors.
4874
*/
4875
f32 calc_hor_dist(Vec3f a, Vec3f b) {
4876
f32 distX = b[0] - a[0];
4877
f32 distZ = b[2] - a[2];
4878
f32 distHor = sqrtf(distX * distX + distZ * distZ);
4879
4880
return distHor;
4881
}
4882
4883
/**
4884
* Rotates a vector in the horizontal plane and copies it to a new vector.
4885
*/
4886
void rotate_in_xz(Vec3f dst, Vec3f src, s16 yaw) {
4887
Vec3f tempVec;
4888
4889
vec3f_copy(tempVec, src);
4890
dst[0] = tempVec[2] * sins(yaw) + tempVec[0] * coss(yaw);
4891
dst[1] = tempVec[1];
4892
dst[2] = tempVec[2] * coss(yaw) - tempVec[0] * sins(yaw);
4893
}
4894
4895
/**
4896
* Rotates a vector in the YZ plane and copies it to a new vector.
4897
*
4898
* Note: This function also flips the Z axis, so +Z moves forward, not backward like it would in world
4899
* space. If possible, use vec3f_set_dist_and_angle()
4900
*/
4901
void rotate_in_yz(Vec3f dst, Vec3f src, s16 pitch) {
4902
Vec3f tempVec;
4903
4904
vec3f_copy(tempVec, src);
4905
dst[2] = -(tempVec[2] * coss(pitch) - tempVec[1] * sins(pitch));
4906
dst[1] = tempVec[2] * sins(pitch) + tempVec[1] * coss(pitch);
4907
dst[0] = tempVec[0];
4908
}
4909
4910
/**
4911
* Start shaking the camera's pitch (up and down)
4912
*/
4913
void set_camera_pitch_shake(s16 mag, s16 decay, s16 inc) {
4914
if (gLakituState.shakeMagnitude[0] < mag) {
4915
gLakituState.shakeMagnitude[0] = mag;
4916
gLakituState.shakePitchDecay = decay;
4917
gLakituState.shakePitchVel = inc;
4918
}
4919
}
4920
4921
/**
4922
* Start shaking the camera's yaw (side to side)
4923
*/
4924
void set_camera_yaw_shake(s16 mag, s16 decay, s16 inc) {
4925
if (ABS(mag) > ABS(gLakituState.shakeMagnitude[1])) {
4926
gLakituState.shakeMagnitude[1] = mag;
4927
gLakituState.shakeYawDecay = decay;
4928
gLakituState.shakeYawVel = inc;
4929
}
4930
}
4931
4932
/**
4933
* Start shaking the camera's roll (rotate screen clockwise and counterclockwise)
4934
*/
4935
void set_camera_roll_shake(s16 mag, s16 decay, s16 inc) {
4936
if (gLakituState.shakeMagnitude[2] < mag) {
4937
gLakituState.shakeMagnitude[2] = mag;
4938
gLakituState.shakeRollDecay = decay;
4939
gLakituState.shakeRollVel = inc;
4940
}
4941
}
4942
4943
/**
4944
* Start shaking the camera's pitch, but reduce `mag` by it's distance from the camera
4945
*/
4946
void set_pitch_shake_from_point(s16 mag, s16 decay, s16 inc, f32 maxDist, f32 posX, f32 posY, f32 posZ) {
4947
Vec3f pos;
4948
f32 dist;
4949
s16 dummyPitch;
4950
s16 dummyYaw;
4951
4952
pos[0] = posX;
4953
pos[1] = posY;
4954
pos[2] = posZ;
4955
vec3f_get_dist_and_angle(gLakituState.goalPos, pos, &dist, &dummyPitch, &dummyYaw);
4956
mag = reduce_by_dist_from_camera(mag, maxDist, posX, posY, posZ);
4957
if (mag != 0) {
4958
set_camera_pitch_shake(mag, decay, inc);
4959
}
4960
}
4961
4962
/**
4963
* Start shaking the camera's yaw, but reduce `mag` by it's distance from the camera
4964
*/
4965
void set_yaw_shake_from_point(s16 mag, s16 decay, s16 inc, f32 maxDist, f32 posX, f32 posY, f32 posZ) {
4966
Vec3f pos;
4967
f32 dist;
4968
s16 dummyPitch;
4969
s16 dummyYaw;
4970
4971
pos[0] = posX;
4972
pos[1] = posY;
4973
pos[2] = posZ;
4974
vec3f_get_dist_and_angle(gLakituState.goalPos, pos, &dist, &dummyPitch, &dummyYaw);
4975
mag = reduce_by_dist_from_camera(mag, maxDist, posX, posY, posZ);
4976
if (mag != 0) {
4977
set_camera_yaw_shake(mag, decay, inc);
4978
}
4979
}
4980
4981
/**
4982
* Update the shake offset by `increment`
4983
*/
4984
void increment_shake_offset(s16 *offset, s16 increment) {
4985
if (increment == -0x8000) {
4986
*offset = (*offset & 0x8000) + 0xC000;
4987
} else {
4988
*offset += increment;
4989
}
4990
}
4991
4992
/**
4993
* Apply a vertical shake to the camera by adjusting its pitch
4994
*/
4995
void shake_camera_pitch(Vec3f pos, Vec3f focus) {
4996
f32 dist;
4997
s16 pitch;
4998
s16 yaw;
4999
5000
if (gLakituState.shakeMagnitude[0] | gLakituState.shakeMagnitude[1]) {
5001
vec3f_get_dist_and_angle(pos, focus, &dist, &pitch, &yaw);
5002
pitch += gLakituState.shakeMagnitude[0] * sins(gLakituState.shakePitchPhase);
5003
vec3f_set_dist_and_angle(pos, focus, dist, pitch, yaw);
5004
increment_shake_offset(&gLakituState.shakePitchPhase, gLakituState.shakePitchVel);
5005
if (camera_approach_s16_symmetric_bool(&gLakituState.shakeMagnitude[0], 0,
5006
gLakituState.shakePitchDecay) == 0) {
5007
gLakituState.shakePitchPhase = 0;
5008
}
5009
}
5010
}
5011
5012
/**
5013
* Apply a horizontal shake to the camera by adjusting its yaw
5014
*/
5015
void shake_camera_yaw(Vec3f pos, Vec3f focus) {
5016
f32 dist;
5017
s16 pitch;
5018
s16 yaw;
5019
5020
if (gLakituState.shakeMagnitude[1] != 0) {
5021
vec3f_get_dist_and_angle(pos, focus, &dist, &pitch, &yaw);
5022
yaw += gLakituState.shakeMagnitude[1] * sins(gLakituState.shakeYawPhase);
5023
vec3f_set_dist_and_angle(pos, focus, dist, pitch, yaw);
5024
increment_shake_offset(&gLakituState.shakeYawPhase, gLakituState.shakeYawVel);
5025
if (camera_approach_s16_symmetric_bool(&gLakituState.shakeMagnitude[1], 0,
5026
gLakituState.shakeYawDecay) == 0) {
5027
gLakituState.shakeYawPhase = 0;
5028
}
5029
}
5030
}
5031
5032
/**
5033
* Apply a rotational shake to the camera by adjusting its roll
5034
*/
5035
void shake_camera_roll(s16 *roll) {
5036
UNUSED u8 unused[8];
5037
5038
if (gLakituState.shakeMagnitude[2] != 0) {
5039
increment_shake_offset(&gLakituState.shakeRollPhase, gLakituState.shakeRollVel);
5040
*roll += gLakituState.shakeMagnitude[2] * sins(gLakituState.shakeRollPhase);
5041
if (camera_approach_s16_symmetric_bool(&gLakituState.shakeMagnitude[2], 0,
5042
gLakituState.shakeRollDecay) == 0) {
5043
gLakituState.shakeRollPhase = 0;
5044
}
5045
}
5046
}
5047
5048
/**
5049
* Add an offset to the camera's yaw, used in levels that are inside a rectangular building, like the
5050
* pyramid or TTC.
5051
*/
5052
s32 offset_yaw_outward_radial(struct Camera *c, s16 areaYaw) {
5053
s16 yawGoal = DEGREES(60);
5054
s16 yaw = sModeOffsetYaw;
5055
f32 distFromAreaCenter;
5056
Vec3f areaCenter;
5057
s16 dYaw;
5058
switch (gCurrLevelArea) {
5059
case AREA_TTC:
5060
areaCenter[0] = c->areaCenX;
5061
areaCenter[1] = sMarioCamState->pos[1];
5062
areaCenter[2] = c->areaCenZ;
5063
distFromAreaCenter = calc_abs_dist(areaCenter, sMarioCamState->pos);
5064
if (800.f > distFromAreaCenter) {
5065
yawGoal = 0x3800;
5066
}
5067
break;
5068
case AREA_SSL_PYRAMID:
5069
// This mask splits the 360 degrees of yaw into 4 corners. It adds 45 degrees so that the yaw
5070
// offset at the corner will be 0, but the yaw offset near the center will face more towards
5071
// the direction Mario is running in.
5072
yawGoal = (areaYaw & 0xC000) - areaYaw + DEGREES(45);
5073
if (yawGoal < 0) {
5074
yawGoal = -yawGoal;
5075
}
5076
yawGoal = yawGoal / 32 * 48;
5077
break;
5078
case AREA_LLL_OUTSIDE:
5079
yawGoal = 0;
5080
break;
5081
}
5082
dYaw = gMarioStates[0].forwardVel / 32.f * 128.f;
5083
5084
if (sAreaYawChange < 0) {
5085
camera_approach_s16_symmetric_bool(&yaw, -yawGoal, dYaw);
5086
}
5087
if (sAreaYawChange > 0) {
5088
camera_approach_s16_symmetric_bool(&yaw, yawGoal, dYaw);
5089
}
5090
// When the final yaw is out of [-60,60] degrees, approach yawGoal faster than dYaw will ever be,
5091
// making the camera lock in one direction until yawGoal drops below 60 (or Mario presses a C button)
5092
if (yaw < -DEGREES(60)) {
5093
//! Maybe they meant to reverse yawGoal's sign?
5094
camera_approach_s16_symmetric_bool(&yaw, -yawGoal, 0x200);
5095
}
5096
if (yaw > DEGREES(60)) {
5097
//! Maybe they meant to reverse yawGoal's sign?
5098
camera_approach_s16_symmetric_bool(&yaw, yawGoal, 0x200);
5099
}
5100
return yaw;
5101
}
5102
5103
/**
5104
* Plays the background music that starts while peach reads the intro message.
5105
*/
5106
void cutscene_intro_peach_play_message_music(void) {
5107
play_music(SEQ_PLAYER_LEVEL, SEQUENCE_ARGS(4, SEQ_EVENT_PEACH_MESSAGE), 0);
5108
}
5109
5110
/**
5111
* Plays the music that starts after peach fades and Lakitu appears.
5112
*/
5113
void cutscene_intro_peach_play_lakitu_flying_music(void) {
5114
play_music(SEQ_PLAYER_LEVEL, SEQUENCE_ARGS(15, SEQ_EVENT_CUTSCENE_INTRO), 0);
5115
}
5116
5117
void play_camera_buzz_if_cdown(void) {
5118
if (gPlayer1Controller->buttonPressed & D_CBUTTONS) {
5119
play_sound_button_change_blocked();
5120
}
5121
}
5122
5123
void play_camera_buzz_if_cbutton(void) {
5124
if (gPlayer1Controller->buttonPressed & CBUTTON_MASK) {
5125
play_sound_button_change_blocked();
5126
}
5127
}
5128
5129
void play_camera_buzz_if_c_sideways(void) {
5130
if ((gPlayer1Controller->buttonPressed & L_CBUTTONS)
5131
|| (gPlayer1Controller->buttonPressed & R_CBUTTONS)) {
5132
play_sound_button_change_blocked();
5133
}
5134
}
5135
5136
void play_sound_cbutton_up(void) {
5137
play_sound(SOUND_MENU_CAMERA_ZOOM_IN, gGlobalSoundSource);
5138
}
5139
5140
void play_sound_cbutton_down(void) {
5141
play_sound(SOUND_MENU_CAMERA_ZOOM_OUT, gGlobalSoundSource);
5142
}
5143
5144
void play_sound_cbutton_side(void) {
5145
play_sound(SOUND_MENU_CAMERA_TURN, gGlobalSoundSource);
5146
}
5147
5148
void play_sound_button_change_blocked(void) {
5149
play_sound(SOUND_MENU_CAMERA_BUZZ, gGlobalSoundSource);
5150
}
5151
5152
void play_sound_rbutton_changed(void) {
5153
play_sound(SOUND_MENU_CLICK_CHANGE_VIEW, gGlobalSoundSource);
5154
}
5155
5156
void play_sound_if_cam_switched_to_lakitu_or_mario(void) {
5157
if (sCameraSoundFlags & CAM_SOUND_MARIO_ACTIVE) {
5158
play_sound_rbutton_changed();
5159
}
5160
if (sCameraSoundFlags & CAM_SOUND_NORMAL_ACTIVE) {
5161
play_sound_rbutton_changed();
5162
}
5163
sCameraSoundFlags &= ~(CAM_SOUND_MARIO_ACTIVE | CAM_SOUND_NORMAL_ACTIVE);
5164
}
5165
5166
/**
5167
* Handles input for radial, outwards radial, parallel tracking, and 8 direction mode.
5168
*/
5169
s32 radial_camera_input(struct Camera *c, UNUSED f32 unused) {
5170
s16 dummy;
5171
#ifdef AVOID_UB
5172
dummy = 0;
5173
#endif
5174
5175
if ((gCameraMovementFlags & CAM_MOVE_ENTERED_ROTATE_SURFACE) || !(gCameraMovementFlags & CAM_MOVE_ROTATE)) {
5176
5177
// If C-L or C-R are pressed, the camera is rotating
5178
if (gPlayer1Controller->buttonPressed & (L_CBUTTONS | R_CBUTTONS)) {
5179
gCameraMovementFlags &= ~CAM_MOVE_ENTERED_ROTATE_SURFACE;
5180
// @bug this does not clear the rotation flags set by the surface. It's possible to set
5181
// both ROTATE_LEFT and ROTATE_RIGHT, locking the camera.
5182
// Ex: If a surface set CAM_MOVE_ROTATE_RIGHT and the user presses C-R, it locks the
5183
// camera until a different mode is activated
5184
}
5185
5186
// Rotate Right and left
5187
if (!configImprovedCButtonCamera)
5188
{
5189
if (gPlayer1Controller->buttonPressed & R_CBUTTONS) {
5190
if (sModeOffsetYaw > -0x800) {
5191
// The camera is now rotating right
5192
if (!(gCameraMovementFlags & CAM_MOVE_ROTATE_RIGHT)) {
5193
gCameraMovementFlags |= CAM_MOVE_ROTATE_RIGHT;
5194
}
5195
5196
if (c->mode == CAMERA_MODE_RADIAL) {
5197
// if > ~48 degrees, we're rotating for the second time.
5198
if (sModeOffsetYaw > 0x22AA) {
5199
s2ndRotateFlags |= CAM_MOVE_ROTATE_RIGHT;
5200
}
5201
5202
if (sModeOffsetYaw == DEGREES(105)) {
5203
play_sound_button_change_blocked();
5204
} else {
5205
play_sound_cbutton_side();
5206
}
5207
} else {
5208
if (sModeOffsetYaw == DEGREES(60)) {
5209
play_sound_button_change_blocked();
5210
} else {
5211
play_sound_cbutton_side();
5212
}
5213
}
5214
} else {
5215
gCameraMovementFlags |= CAM_MOVE_RETURN_TO_MIDDLE;
5216
play_sound_cbutton_up();
5217
}
5218
}
5219
if (gPlayer1Controller->buttonPressed & L_CBUTTONS) {
5220
if (sModeOffsetYaw < 0x800) {
5221
if (!(gCameraMovementFlags & CAM_MOVE_ROTATE_LEFT)) {
5222
gCameraMovementFlags |= CAM_MOVE_ROTATE_LEFT;
5223
}
5224
5225
if (c->mode == CAMERA_MODE_RADIAL) {
5226
// if < ~48 degrees, we're rotating for the second time.
5227
if (sModeOffsetYaw < -0x22AA) {
5228
s2ndRotateFlags |= CAM_MOVE_ROTATE_LEFT;
5229
}
5230
5231
if (sModeOffsetYaw == DEGREES(-105)) {
5232
play_sound_button_change_blocked();
5233
} else {
5234
play_sound_cbutton_side();
5235
}
5236
} else {
5237
if (sModeOffsetYaw == DEGREES(-60)) {
5238
play_sound_button_change_blocked();
5239
} else {
5240
play_sound_cbutton_side();
5241
}
5242
}
5243
} else {
5244
gCameraMovementFlags |= CAM_MOVE_RETURN_TO_MIDDLE;
5245
play_sound_cbutton_up();
5246
}
5247
}
5248
}
5249
}
5250
5251
// Zoom in / enter C-Up
5252
if (gPlayer1Controller->buttonPressed & U_CBUTTONS) {
5253
if (gCameraMovementFlags & CAM_MOVE_ZOOMED_OUT) {
5254
gCameraMovementFlags &= ~CAM_MOVE_ZOOMED_OUT;
5255
play_sound_cbutton_up();
5256
} else {
5257
set_mode_c_up(c);
5258
}
5259
}
5260
5261
// Zoom out
5262
if (gPlayer1Controller->buttonPressed & D_CBUTTONS) {
5263
if (gCameraMovementFlags & CAM_MOVE_ZOOMED_OUT) {
5264
gCameraMovementFlags |= CAM_MOVE_ALREADY_ZOOMED_OUT;
5265
#ifndef VERSION_JP
5266
play_camera_buzz_if_cdown();
5267
#endif
5268
} else {
5269
gCameraMovementFlags |= CAM_MOVE_ZOOMED_OUT;
5270
play_sound_cbutton_down();
5271
}
5272
}
5273
5274
//! returning uninitialized variable
5275
return dummy;
5276
}
5277
5278
/**
5279
* Starts a cutscene dialog. Only has an effect when `trigger` is 1
5280
*/
5281
s32 trigger_cutscene_dialog(s32 trigger) {
5282
s32 result = 0;
5283
UNUSED struct Camera *c = gCamera;
5284
5285
if (trigger == 1) {
5286
start_object_cutscene_without_focus(CUTSCENE_READ_MESSAGE);
5287
}
5288
if (trigger == 2) {
5289
}
5290
return result;
5291
}
5292
5293
/**
5294
* Updates the camera based on which C buttons are pressed this frame
5295
*/
5296
void handle_c_button_movement(struct Camera *c) {
5297
s16 cSideYaw;
5298
5299
// Zoom in
5300
if (gPlayer1Controller->buttonPressed & U_CBUTTONS) {
5301
if (c->mode != CAMERA_MODE_FIXED && (gCameraMovementFlags & CAM_MOVE_ZOOMED_OUT)) {
5302
gCameraMovementFlags &= ~CAM_MOVE_ZOOMED_OUT;
5303
play_sound_cbutton_up();
5304
} else {
5305
set_mode_c_up(c);
5306
if (sZeroZoomDist > gCameraZoomDist) {
5307
sZoomAmount = -gCameraZoomDist;
5308
} else {
5309
sZoomAmount = gCameraZoomDist;
5310
}
5311
}
5312
}
5313
if (c->mode != CAMERA_MODE_FIXED) {
5314
// Zoom out
5315
if (gPlayer1Controller->buttonPressed & D_CBUTTONS) {
5316
if (gCameraMovementFlags & CAM_MOVE_ZOOMED_OUT) {
5317
gCameraMovementFlags |= CAM_MOVE_ALREADY_ZOOMED_OUT;
5318
sZoomAmount = gCameraZoomDist + 400.f;
5319
#ifndef VERSION_JP
5320
play_camera_buzz_if_cdown();
5321
#endif
5322
} else {
5323
gCameraMovementFlags |= CAM_MOVE_ZOOMED_OUT;
5324
sZoomAmount = gCameraZoomDist + 400.f;
5325
play_sound_cbutton_down();
5326
}
5327
}
5328
5329
// Rotate left or right
5330
if (configImprovedCButtonCamera)
5331
{
5332
if (gPlayer1Controller->buttonPressed & L_CBUTTONS || gPlayer1Controller->buttonPressed & R_CBUTTONS) {
5333
play_sound_cbutton_side();
5334
}
5335
if (gPlayer1Controller->buttonDown & L_CBUTTONS) {
5336
sCSideButtonYaw = ANALOG_AMOUNT * configCameraSpeed * 2.0f;
5337
gCameraMovementFlags &= ~(CAM_MOVE_ROTATE_RIGHT | CAM_MOVE_ENTERED_ROTATE_SURFACE);
5338
}
5339
if (gPlayer1Controller->buttonDown & R_CBUTTONS) {
5340
sCSideButtonYaw = -ANALOG_AMOUNT * configCameraSpeed * 2.0f;
5341
gCameraMovementFlags &= ~(CAM_MOVE_ROTATE_LEFT | CAM_MOVE_ENTERED_ROTATE_SURFACE);
5342
}
5343
}
5344
else
5345
{
5346
cSideYaw = 0x1000;
5347
if (gPlayer1Controller->buttonPressed & R_CBUTTONS) {
5348
if (gCameraMovementFlags & CAM_MOVE_ROTATE_LEFT) {
5349
gCameraMovementFlags &= ~CAM_MOVE_ROTATE_LEFT;
5350
} else {
5351
gCameraMovementFlags |= CAM_MOVE_ROTATE_RIGHT;
5352
if (sCSideButtonYaw == 0) {
5353
play_sound_cbutton_side();
5354
}
5355
sCSideButtonYaw = -cSideYaw;
5356
}
5357
}
5358
if (gPlayer1Controller->buttonPressed & L_CBUTTONS) {
5359
if (gCameraMovementFlags & CAM_MOVE_ROTATE_RIGHT) {
5360
gCameraMovementFlags &= ~CAM_MOVE_ROTATE_RIGHT;
5361
} else {
5362
gCameraMovementFlags |= CAM_MOVE_ROTATE_LEFT;
5363
if (sCSideButtonYaw == 0) {
5364
play_sound_cbutton_side();
5365
}
5366
sCSideButtonYaw = cSideYaw;
5367
}
5368
}
5369
}
5370
5371
// Analog camera code
5372
if (gPlayer1Controller->stick2X != 0 &&
5373
gCurrDemoInput == NULL)
5374
{
5375
if (gPlayer1Controller->stick2X > 0) {
5376
gCameraMovementFlags &= ~(CAM_MOVE_ROTATE_RIGHT | CAM_MOVE_ENTERED_ROTATE_SURFACE);
5377
}
5378
else {
5379
gCameraMovementFlags &= ~(CAM_MOVE_ROTATE_LEFT | CAM_MOVE_ENTERED_ROTATE_SURFACE);
5380
}
5381
sCSideButtonYaw = ANALOG_AMOUNT * (gPlayer1Controller->stick2X / 32.0f) * configCameraSpeed;
5382
}
5383
}
5384
}
5385
5386
/**
5387
* Zero the 10 cvars.
5388
*/
5389
void clear_cutscene_vars(UNUSED struct Camera *c) {
5390
s32 i;
5391
5392
for (i = 0; i < 10; i++) {
5393
sCutsceneVars[i].unused1 = 0;
5394
vec3f_set(sCutsceneVars[i].point, 0.f, 0.f, 0.f);
5395
vec3f_set(sCutsceneVars[i].unusedPoint, 0.f, 0.f, 0.f);
5396
vec3s_set(sCutsceneVars[i].angle, 0, 0, 0);
5397
sCutsceneVars[i].unused2 = 0;
5398
}
5399
}
5400
5401
/**
5402
* Start the cutscene, `cutscene`, if it is not already playing.
5403
*/
5404
void start_cutscene(struct Camera *c, u8 cutscene) {
5405
if (c->cutscene != cutscene) {
5406
c->cutscene = cutscene;
5407
clear_cutscene_vars(c);
5408
}
5409
}
5410
5411
/**
5412
* Look up the victory dance cutscene in sDanceCutsceneTable
5413
*
5414
* First the index entry is determined based on the course and the star that was just picked up
5415
* Like the entries in sZoomOutAreaMasks, each entry represents two stars
5416
* The current courses's 4 bits of the index entry are used as the actual index into sDanceCutsceneTable
5417
*
5418
* @return the victory cutscene to use
5419
*/
5420
s32 determine_dance_cutscene(UNUSED struct Camera *c) {
5421
u8 cutscene = 0;
5422
u8 cutsceneIndex = 0;
5423
u8 starIndex = (gLastCompletedStarNum - 1) / 2;
5424
u8 courseIndex = gCurrCourseNum;
5425
5426
if (starIndex > 3) {
5427
starIndex = 0;
5428
}
5429
if (courseIndex > COURSE_MAX) {
5430
courseIndex = COURSE_NONE;
5431
}
5432
cutsceneIndex = sDanceCutsceneIndexTable[courseIndex][starIndex];
5433
5434
if (gLastCompletedStarNum & 1) {
5435
// Odd stars take the lower four bytes
5436
cutsceneIndex &= 0xF;
5437
} else {
5438
// Even stars use the upper four bytes
5439
cutsceneIndex = cutsceneIndex >> 4;
5440
}
5441
cutscene = sDanceCutsceneTable[cutsceneIndex];
5442
return cutscene;
5443
}
5444
5445
/**
5446
* @return `pullResult` or `pushResult` depending on Mario's door action
5447
*/
5448
u8 open_door_cutscene(u8 pullResult, u8 pushResult) {
5449
s16 result;
5450
5451
if (sMarioCamState->action == ACT_PULLING_DOOR) {
5452
result = pullResult;
5453
}
5454
if (sMarioCamState->action == ACT_PUSHING_DOOR) {
5455
result = pushResult;
5456
}
5457
return result;
5458
}
5459
5460
/**
5461
* If no cutscenes are playing, determines if a cutscene should play based on Mario's action and
5462
* cameraEvent
5463
*
5464
* @return the cutscene that should start, 0 if none
5465
*/
5466
u8 get_cutscene_from_mario_status(struct Camera *c) {
5467
UNUSED u8 unused1[4];
5468
u8 cutscene = c->cutscene;
5469
UNUSED u8 unused2[12];
5470
5471
if (cutscene == 0) {
5472
// A cutscene started by an object, if any, will start if nothing else happened
5473
cutscene = sObjectCutscene;
5474
sObjectCutscene = 0;
5475
if (sMarioCamState->cameraEvent == CAM_EVENT_DOOR) {
5476
switch (gCurrLevelArea) {
5477
case AREA_CASTLE_LOBBY:
5478
//! doorStatus is never DOOR_ENTER_LOBBY when cameraEvent == 6, because
5479
//! doorStatus is only used for the star door in the lobby, which uses
5480
//! ACT_ENTERING_STAR_DOOR
5481
if (c->mode == CAMERA_MODE_SPIRAL_STAIRS || c->mode == CAMERA_MODE_CLOSE
5482
|| c->doorStatus == DOOR_ENTER_LOBBY) {
5483
cutscene = open_door_cutscene(CUTSCENE_DOOR_PULL_MODE, CUTSCENE_DOOR_PUSH_MODE);
5484
} else {
5485
cutscene = open_door_cutscene(CUTSCENE_DOOR_PULL, CUTSCENE_DOOR_PUSH);
5486
}
5487
break;
5488
case AREA_BBH:
5489
//! Castle Lobby uses 0 to mean 'no special modes', but BBH uses 1...
5490
if (c->doorStatus == DOOR_LEAVING_SPECIAL) {
5491
cutscene = open_door_cutscene(CUTSCENE_DOOR_PULL, CUTSCENE_DOOR_PUSH);
5492
} else {
5493
cutscene = open_door_cutscene(CUTSCENE_DOOR_PULL_MODE, CUTSCENE_DOOR_PUSH_MODE);
5494
}
5495
break;
5496
default:
5497
cutscene = open_door_cutscene(CUTSCENE_DOOR_PULL, CUTSCENE_DOOR_PUSH);
5498
break;
5499
}
5500
}
5501
if (sMarioCamState->cameraEvent == CAM_EVENT_DOOR_WARP) {
5502
cutscene = CUTSCENE_DOOR_WARP;
5503
}
5504
if (sMarioCamState->cameraEvent == CAM_EVENT_CANNON) {
5505
cutscene = CUTSCENE_ENTER_CANNON;
5506
}
5507
if (SURFACE_IS_PAINTING_WARP(sMarioGeometry.currFloorType)) {
5508
cutscene = CUTSCENE_ENTER_PAINTING;
5509
}
5510
switch (sMarioCamState->action) {
5511
case ACT_DEATH_EXIT:
5512
cutscene = configBetaLikeCamera ? CUTSCENE_UNUSED_EXIT : CUTSCENE_DEATH_EXIT;
5513
break;
5514
case ACT_EXIT_AIRBORNE:
5515
cutscene = CUTSCENE_EXIT_PAINTING_SUCC;
5516
break;
5517
case ACT_SPECIAL_EXIT_AIRBORNE:
5518
if (gPrevLevel == LEVEL_BOWSER_1 || gPrevLevel == LEVEL_BOWSER_2
5519
|| gPrevLevel == LEVEL_BOWSER_3) {
5520
cutscene = CUTSCENE_EXIT_BOWSER_SUCC;
5521
} else {
5522
cutscene = CUTSCENE_EXIT_SPECIAL_SUCC;
5523
}
5524
break;
5525
case ACT_SPECIAL_DEATH_EXIT:
5526
if (gPrevLevel == LEVEL_BOWSER_1 || gPrevLevel == LEVEL_BOWSER_2
5527
|| gPrevLevel == LEVEL_BOWSER_3) {
5528
cutscene = CUTSCENE_EXIT_BOWSER_DEATH;
5529
} else {
5530
cutscene = CUTSCENE_NONPAINTING_DEATH;
5531
}
5532
break;
5533
case ACT_ENTERING_STAR_DOOR:
5534
if (c->doorStatus == DOOR_DEFAULT) {
5535
cutscene = CUTSCENE_SLIDING_DOORS_OPEN;
5536
} else {
5537
cutscene = CUTSCENE_DOOR_PULL_MODE;
5538
}
5539
break;
5540
case ACT_UNLOCKING_KEY_DOOR:
5541
cutscene = CUTSCENE_UNLOCK_KEY_DOOR;
5542
break;
5543
case ACT_WATER_DEATH:
5544
cutscene = CUTSCENE_WATER_DEATH;
5545
break;
5546
case ACT_DEATH_ON_BACK:
5547
cutscene = CUTSCENE_DEATH_ON_BACK;
5548
break;
5549
case ACT_DEATH_ON_STOMACH:
5550
cutscene = CUTSCENE_DEATH_ON_STOMACH;
5551
break;
5552
case ACT_STANDING_DEATH:
5553
cutscene = CUTSCENE_STANDING_DEATH;
5554
break;
5555
case ACT_SUFFOCATION:
5556
cutscene = CUTSCENE_SUFFOCATION_DEATH;
5557
break;
5558
case ACT_QUICKSAND_DEATH:
5559
cutscene = CUTSCENE_QUICKSAND_DEATH;
5560
break;
5561
case ACT_ELECTROCUTION:
5562
cutscene = CUTSCENE_STANDING_DEATH;
5563
break;
5564
case ACT_STAR_DANCE_EXIT:
5565
if (stay_in_level())
5566
cutscene = CUTSCENE_DANCE_DEFAULT;
5567
else
5568
cutscene = determine_dance_cutscene(c);
5569
break;
5570
case ACT_STAR_DANCE_WATER:
5571
if (stay_in_level())
5572
cutscene = CUTSCENE_DANCE_DEFAULT;
5573
else
5574
cutscene = determine_dance_cutscene(c);
5575
break;
5576
case ACT_STAR_DANCE_NO_EXIT:
5577
cutscene = CUTSCENE_DANCE_DEFAULT;
5578
break;
5579
}
5580
switch (sMarioCamState->cameraEvent) {
5581
case CAM_EVENT_START_INTRO:
5582
cutscene = CUTSCENE_INTRO_PEACH;
5583
break;
5584
case CAM_EVENT_START_GRAND_STAR:
5585
cutscene = CUTSCENE_GRAND_STAR;
5586
break;
5587
case CAM_EVENT_START_ENDING:
5588
cutscene = CUTSCENE_ENDING;
5589
break;
5590
case CAM_EVENT_START_END_WAVING:
5591
cutscene = CUTSCENE_END_WAVING;
5592
break;
5593
case CAM_EVENT_START_CREDITS:
5594
cutscene = CUTSCENE_CREDITS;
5595
break;
5596
}
5597
}
5598
//! doorStatus is reset every frame. CameraTriggers need to constantly set doorStatus
5599
c->doorStatus = DOOR_DEFAULT;
5600
5601
return cutscene;
5602
}
5603
5604
/**
5605
* Moves the camera when Mario has triggered a warp
5606
*/
5607
void warp_camera(f32 displacementX, f32 displacementY, f32 displacementZ) {
5608
Vec3f displacement;
5609
struct MarioState *marioStates = &gMarioStates[0];
5610
struct LinearTransitionPoint *start = &sModeInfo.transitionStart;
5611
struct LinearTransitionPoint *end = &sModeInfo.transitionEnd;
5612
5613
gCurrLevelArea = gCurrLevelNum * 16 + gCurrentArea->index;
5614
displacement[0] = displacementX;
5615
displacement[1] = displacementY;
5616
displacement[2] = displacementZ;
5617
vec3f_add(gLakituState.curPos, displacement);
5618
vec3f_add(gLakituState.curFocus, displacement);
5619
vec3f_add(gLakituState.goalPos, displacement);
5620
vec3f_add(gLakituState.goalFocus, displacement);
5621
marioStates->waterLevel += displacementY;
5622
5623
vec3f_add(start->focus, displacement);
5624
vec3f_add(start->pos, displacement);
5625
vec3f_add(end->focus, displacement);
5626
vec3f_add(end->pos, displacement);
5627
}
5628
5629
/**
5630
* Make the camera's y coordinate approach `goal`,
5631
* unless smooth movement is off, in which case the y coordinate is simply set to `goal`
5632
*/
5633
void approach_camera_height(struct Camera *c, f32 goal, f32 inc) {
5634
if (sStatusFlags & CAM_FLAG_SMOOTH_MOVEMENT) {
5635
if (c->pos[1] < goal) {
5636
if ((c->pos[1] += inc) > goal) {
5637
c->pos[1] = goal;
5638
}
5639
} else {
5640
if ((c->pos[1] -= inc) < goal) {
5641
c->pos[1] = goal;
5642
}
5643
}
5644
} else {
5645
c->pos[1] = goal;
5646
}
5647
}
5648
5649
void stub_camera_4(UNUSED s32 a, UNUSED s32 b, UNUSED s32 c, UNUSED s32 d) {
5650
}
5651
5652
/**
5653
* Set the camera's focus to Mario's position, and add several relative offsets.
5654
*
5655
* @param leftRight offset to Mario's left/right, relative to his faceAngle
5656
* @param yOff y offset
5657
* @param forwBack offset to Mario's front/back, relative to his faceAngle
5658
* @param yawOff offset to Mario's faceAngle, changes the direction of `leftRight` and `forwBack`
5659
*/
5660
void set_focus_rel_mario(struct Camera *c, f32 leftRight, f32 yOff, f32 forwBack, s16 yawOff) {
5661
s16 yaw;
5662
UNUSED u16 unused;
5663
f32 focFloorYOff;
5664
5665
calc_y_to_curr_floor(&focFloorYOff, 1.f, 200.f, &focFloorYOff, 0.9f, 200.f);
5666
yaw = sMarioCamState->faceAngle[1] + yawOff;
5667
c->focus[2] = sMarioCamState->pos[2] + forwBack * coss(yaw) - leftRight * sins(yaw);
5668
c->focus[0] = sMarioCamState->pos[0] + forwBack * sins(yaw) + leftRight * coss(yaw);
5669
c->focus[1] = sMarioCamState->pos[1] + yOff + focFloorYOff;
5670
}
5671
5672
/**
5673
* Set the camera's position to Mario's position, and add several relative offsets. Unused.
5674
*
5675
* @param leftRight offset to Mario's left/right, relative to his faceAngle
5676
* @param yOff y offset
5677
* @param forwBack offset to Mario's front/back, relative to his faceAngle
5678
* @param yawOff offset to Mario's faceAngle, changes the direction of `leftRight` and `forwBack`
5679
*/
5680
UNUSED static void unused_set_pos_rel_mario(struct Camera *c, f32 leftRight, f32 yOff, f32 forwBack, s16 yawOff) {
5681
u16 yaw = sMarioCamState->faceAngle[1] + yawOff;
5682
5683
c->pos[0] = sMarioCamState->pos[0] + forwBack * sins(yaw) + leftRight * coss(yaw);
5684
c->pos[1] = sMarioCamState->pos[1] + yOff;
5685
c->pos[2] = sMarioCamState->pos[2] + forwBack * coss(yaw) - leftRight * sins(yaw);
5686
}
5687
5688
/**
5689
* Rotates the offset `to` according to the pitch and yaw values in `rotation`.
5690
* Adds `from` to the rotated offset, and stores the result in `dst`.
5691
*
5692
* @warning Flips the Z axis, so that relative to `rotation`, -Z moves forwards and +Z moves backwards.
5693
*/
5694
void offset_rotated(Vec3f dst, Vec3f from, Vec3f to, Vec3s rotation) {
5695
Vec3f unusedCopy;
5696
Vec3f pitchRotated;
5697
5698
vec3f_copy(unusedCopy, from);
5699
5700
// First rotate the direction by rotation's pitch
5701
//! The Z axis is flipped here.
5702
pitchRotated[2] = -(to[2] * coss(rotation[0]) - to[1] * sins(rotation[0]));
5703
pitchRotated[1] = to[2] * sins(rotation[0]) + to[1] * coss(rotation[0]);
5704
pitchRotated[0] = to[0];
5705
5706
// Rotate again by rotation's yaw
5707
dst[0] = from[0] + pitchRotated[2] * sins(rotation[1]) + pitchRotated[0] * coss(rotation[1]);
5708
dst[1] = from[1] + pitchRotated[1];
5709
dst[2] = from[2] + pitchRotated[2] * coss(rotation[1]) - pitchRotated[0] * sins(rotation[1]);
5710
}
5711
5712
/**
5713
* Rotates the offset defined by (`xTo`, `yTo`, `zTo`) according to the pitch and yaw values in `rotation`.
5714
* Adds `from` to the rotated offset, and stores the result in `dst`.
5715
*
5716
* @warning Flips the Z axis, so that relative to `rotation`, -Z moves forwards and +Z moves backwards.
5717
*/
5718
void offset_rotated_coords(Vec3f dst, Vec3f from, Vec3s rotation, f32 xTo, f32 yTo, f32 zTo) {
5719
Vec3f to;
5720
5721
vec3f_set(to, xTo, yTo, zTo);
5722
offset_rotated(dst, from, to, rotation);
5723
}
5724
5725
void determine_pushing_or_pulling_door(s16 *rotation) {
5726
if (sMarioCamState->action == ACT_PULLING_DOOR) {
5727
*rotation = 0;
5728
} else {
5729
*rotation = DEGREES(-180);
5730
}
5731
}
5732
5733
/**
5734
* Calculate Lakitu's next position and focus, according to gCamera's state,
5735
* and store them in `newPos` and `newFoc`.
5736
*
5737
* @param newPos where Lakitu should fly towards this frame
5738
* @param newFoc where Lakitu should look towards this frame
5739
*
5740
* @param curPos gCamera's pos this frame
5741
* @param curFoc gCamera's foc this frame
5742
*
5743
* @param oldPos gCamera's pos last frame
5744
* @param oldFoc gCamera's foc last frame
5745
*
5746
* @return Lakitu's next yaw, which is the same as the yaw passed in if no transition happened
5747
*/
5748
s16 next_lakitu_state(Vec3f newPos, Vec3f newFoc, Vec3f curPos, Vec3f curFoc,
5749
Vec3f oldPos, Vec3f oldFoc, s16 yaw) {
5750
s16 yawVelocity;
5751
s16 pitchVelocity;
5752
f32 distVelocity;
5753
f32 goalDist;
5754
UNUSED f32 unusedDist;
5755
s16 goalPitch;
5756
s16 goalYaw;
5757
UNUSED s16 unusedPitch;
5758
UNUSED s16 unusedYaw;
5759
f32 distTimer = sModeTransition.framesLeft;
5760
s16 angleTimer = sModeTransition.framesLeft;
5761
UNUSED s16 inTransition = 0;
5762
Vec3f nextPos;
5763
Vec3f nextFoc;
5764
Vec3f startPos;
5765
Vec3f startFoc;
5766
s32 i;
5767
f32 floorHeight;
5768
struct Surface *floor;
5769
5770
// If not transitioning, just use gCamera's current pos and foc
5771
vec3f_copy(newPos, curPos);
5772
vec3f_copy(newFoc, curFoc);
5773
5774
if (sStatusFlags & CAM_FLAG_START_TRANSITION) {
5775
for (i = 0; i < 3; i++) {
5776
// Add Mario's displacement from this frame to the last frame's pos and focus
5777
// Makes the transition start from where the camera would have moved
5778
startPos[i] = oldPos[i] + sMarioCamState->pos[i] - sModeTransition.marioPos[i];
5779
startFoc[i] = oldFoc[i] + sMarioCamState->pos[i] - sModeTransition.marioPos[i];
5780
}
5781
5782
5783
vec3f_get_dist_and_angle(curFoc, startFoc, &sModeTransition.focDist, &sModeTransition.focPitch,
5784
&sModeTransition.focYaw);
5785
vec3f_get_dist_and_angle(curFoc, startPos, &sModeTransition.posDist, &sModeTransition.posPitch,
5786
&sModeTransition.posYaw);
5787
sStatusFlags &= ~CAM_FLAG_START_TRANSITION;
5788
}
5789
5790
// Transition from the last mode to the current one
5791
if (sModeTransition.framesLeft > 0) {
5792
inTransition = 1;
5793
5794
vec3f_get_dist_and_angle(curFoc, curPos, &goalDist, &goalPitch, &goalYaw);
5795
distVelocity = ABS(goalDist - sModeTransition.posDist) / distTimer;
5796
pitchVelocity = ABS(goalPitch - sModeTransition.posPitch) / angleTimer;
5797
yawVelocity = ABS(goalYaw - sModeTransition.posYaw) / angleTimer;
5798
5799
camera_approach_f32_symmetric_bool(&sModeTransition.posDist, goalDist, distVelocity);
5800
camera_approach_s16_symmetric_bool(&sModeTransition.posYaw, goalYaw, yawVelocity);
5801
camera_approach_s16_symmetric_bool(&sModeTransition.posPitch, goalPitch, pitchVelocity);
5802
vec3f_set_dist_and_angle(curFoc, nextPos, sModeTransition.posDist, sModeTransition.posPitch,
5803
sModeTransition.posYaw);
5804
5805
vec3f_get_dist_and_angle(curPos, curFoc, &goalDist, &goalPitch, &goalYaw);
5806
pitchVelocity = sModeTransition.focPitch / (s16) sModeTransition.framesLeft;
5807
yawVelocity = sModeTransition.focYaw / (s16) sModeTransition.framesLeft;
5808
distVelocity = sModeTransition.focDist / sModeTransition.framesLeft;
5809
5810
camera_approach_s16_symmetric_bool(&sModeTransition.focPitch, goalPitch, pitchVelocity);
5811
camera_approach_s16_symmetric_bool(&sModeTransition.focYaw, goalYaw, yawVelocity);
5812
camera_approach_f32_symmetric_bool(&sModeTransition.focDist, 0, distVelocity);
5813
vec3f_set_dist_and_angle(curFoc, nextFoc, sModeTransition.focDist, sModeTransition.focPitch,
5814
sModeTransition.focYaw);
5815
5816
vec3f_copy(newFoc, nextFoc);
5817
vec3f_copy(newPos, nextPos);
5818
5819
if (gCamera->cutscene != 0 || !(gCameraMovementFlags & CAM_MOVE_C_UP_MODE)) {
5820
floorHeight = find_floor(newPos[0], newPos[1], newPos[2], &floor);
5821
if (floorHeight != FLOOR_LOWER_LIMIT) {
5822
if ((floorHeight += 125.f) > newPos[1]) {
5823
newPos[1] = floorHeight;
5824
}
5825
}
5826
f32_find_wall_collision(&newPos[0], &newPos[1], &newPos[2], 0.f, 100.f);
5827
}
5828
sModeTransition.framesLeft--;
5829
yaw = calculate_yaw(newFoc, newPos);
5830
} else {
5831
sModeTransition.posDist = 0.f;
5832
sModeTransition.posPitch = 0;
5833
sModeTransition.posYaw = 0;
5834
sStatusFlags &= ~CAM_FLAG_TRANSITION_OUT_OF_C_UP;
5835
}
5836
vec3f_copy(sModeTransition.marioPos, sMarioCamState->pos);
5837
return yaw;
5838
}
5839
5840
static UNUSED void stop_transitional_movement(void) {
5841
sStatusFlags &= ~(CAM_FLAG_START_TRANSITION | CAM_FLAG_TRANSITION_OUT_OF_C_UP);
5842
sModeTransition.framesLeft = 0;
5843
}
5844
5845
/**
5846
* Start fixed camera mode, setting the base position to (`x`, `y`, `z`)
5847
*
5848
* @return TRUE if the base pos was updated
5849
*/
5850
s32 set_camera_mode_fixed(struct Camera *c, s16 x, s16 y, s16 z) {
5851
s32 basePosSet = FALSE;
5852
f32 posX = x;
5853
f32 posY = y;
5854
f32 posZ = z;
5855
5856
if (sFixedModeBasePosition[0] != posX || sFixedModeBasePosition[1] != posY
5857
|| sFixedModeBasePosition[2] != posZ) {
5858
basePosSet = TRUE;
5859
sStatusFlags &= ~CAM_FLAG_SMOOTH_MOVEMENT;
5860
}
5861
vec3f_set(sFixedModeBasePosition, posX, posY, posZ);
5862
if (c->mode != CAMERA_MODE_FIXED) {
5863
sStatusFlags &= ~CAM_FLAG_SMOOTH_MOVEMENT;
5864
c->mode = CAMERA_MODE_FIXED;
5865
vec3f_set(c->pos, sFixedModeBasePosition[0], sMarioCamState->pos[1],
5866
sFixedModeBasePosition[2]);
5867
skip_camera_interpolation();
5868
}
5869
return basePosSet;
5870
}
5871
5872
void set_camera_mode_8_directions(struct Camera *c) {
5873
if (c->mode != CAMERA_MODE_8_DIRECTIONS) {
5874
c->mode = CAMERA_MODE_8_DIRECTIONS;
5875
sStatusFlags &= ~CAM_FLAG_SMOOTH_MOVEMENT;
5876
s8DirModeBaseYaw = 0;
5877
s8DirModeYawOffset = 0;
5878
}
5879
}
5880
5881
/**
5882
* If the camera mode is not already the boss fight camera (camera with two foci)
5883
* set it to be so.
5884
*/
5885
void set_camera_mode_boss_fight(struct Camera *c) {
5886
if (c->mode != CAMERA_MODE_BOSS_FIGHT) {
5887
transition_to_camera_mode(c, CAMERA_MODE_BOSS_FIGHT, 15);
5888
sModeOffsetYaw = c->nextYaw - DEGREES(45);
5889
}
5890
}
5891
5892
void set_camera_mode_close_cam(u8 *mode) {
5893
if (*mode != CAMERA_MODE_CLOSE) {
5894
sStatusFlags &= ~CAM_FLAG_SMOOTH_MOVEMENT;
5895
*mode = CAMERA_MODE_CLOSE;
5896
}
5897
}
5898
5899
/**
5900
* Change to radial mode.
5901
* If the difference in yaw between pos -> Mario and pos > focus is < 90 degrees, transition.
5902
* Otherwise jump to radial mode.
5903
*/
5904
void set_camera_mode_radial(struct Camera *c, s16 transitionTime) {
5905
Vec3f focus;
5906
s16 yaw;
5907
5908
focus[0] = c->areaCenX;
5909
focus[1] = sMarioCamState->pos[1];
5910
focus[2] = c->areaCenZ;
5911
if (c->mode != CAMERA_MODE_RADIAL) {
5912
yaw = calculate_yaw(focus, sMarioCamState->pos) - calculate_yaw(c->focus, c->pos) + DEGREES(90);
5913
if (yaw > 0) {
5914
transition_to_camera_mode(c, CAMERA_MODE_RADIAL, transitionTime);
5915
} else {
5916
c->mode = CAMERA_MODE_RADIAL;
5917
sStatusFlags &= ~CAM_FLAG_SMOOTH_MOVEMENT;
5918
}
5919
sModeOffsetYaw = 0;
5920
}
5921
}
5922
5923
/**
5924
* Start parallel tracking mode using the path `path`
5925
*/
5926
void parallel_tracking_init(struct Camera *c, struct ParallelTrackingPoint *path) {
5927
if (c->mode != CAMERA_MODE_PARALLEL_TRACKING) {
5928
sParTrackPath = path;
5929
sParTrackIndex = 0;
5930
sParTrackTransOff.pos[0] = 0.f;
5931
sParTrackTransOff.pos[1] = 0.f;
5932
sParTrackTransOff.pos[2] = 0.f;
5933
// Place the camera in the middle of the path
5934
c->pos[0] = (sParTrackPath[0].pos[0] + sParTrackPath[1].pos[0]) / 2;
5935
c->pos[1] = (sParTrackPath[0].pos[1] + sParTrackPath[1].pos[1]) / 2;
5936
c->pos[2] = (sParTrackPath[0].pos[2] + sParTrackPath[1].pos[2]) / 2;
5937
sStatusFlags &= ~CAM_FLAG_SMOOTH_MOVEMENT;
5938
c->mode = CAMERA_MODE_PARALLEL_TRACKING;
5939
}
5940
}
5941
5942
/**
5943
* Set the fixed camera base pos depending on the current level area
5944
*/
5945
void set_fixed_cam_axis_sa_lobby(UNUSED s16 preset) {
5946
switch (gCurrLevelArea) {
5947
case AREA_SA:
5948
vec3f_set(sFixedModeBasePosition, 646.f, 143.f, -1513.f);
5949
break;
5950
5951
case AREA_CASTLE_LOBBY:
5952
vec3f_set(sFixedModeBasePosition, -577.f, 143.f, 1443.f);
5953
break;
5954
}
5955
}
5956
5957
/**
5958
* Block area-specific CameraTrigger and special surface modes.
5959
* Generally, block area mode changes if:
5960
* Mario is wearing the metal cap, or at the water's surface, or the camera is in Mario mode
5961
*
5962
* However, if the level is WDW, DDD, or COTMC (levels that have metal cap and water):
5963
* Only block area mode changes if Mario is in a cannon,
5964
* or if the camera is in Mario mode and Mario is not swimming or in water with the metal cap
5965
*/
5966
void check_blocking_area_processing(const u8 *mode) {
5967
if (sMarioCamState->action & ACT_FLAG_METAL_WATER ||
5968
*mode == CAMERA_MODE_BEHIND_MARIO || *mode == CAMERA_MODE_WATER_SURFACE) {
5969
sStatusFlags |= CAM_FLAG_BLOCK_AREA_PROCESSING;
5970
}
5971
5972
if (gCurrLevelNum == LEVEL_DDD || gCurrLevelNum == LEVEL_WDW || gCurrLevelNum == LEVEL_COTMC) {
5973
sStatusFlags &= ~CAM_FLAG_BLOCK_AREA_PROCESSING;
5974
}
5975
5976
if ((*mode == CAMERA_MODE_BEHIND_MARIO &&
5977
!(sMarioCamState->action & (ACT_FLAG_SWIMMING | ACT_FLAG_METAL_WATER))) ||
5978
*mode == CAMERA_MODE_INSIDE_CANNON) {
5979
sStatusFlags |= CAM_FLAG_BLOCK_AREA_PROCESSING;
5980
}
5981
}
5982
5983
BAD_RETURN(s32) cam_rr_exit_building_side(struct Camera *c) {
5984
set_camera_mode_8_directions(c);
5985
s8DirModeBaseYaw = DEGREES(90);
5986
}
5987
5988
BAD_RETURN(s32) cam_rr_exit_building_top(struct Camera *c) {
5989
set_camera_mode_8_directions(c);
5990
if (c->pos[1] < 6343.f) {
5991
c->pos[1] = 7543.f;
5992
gLakituState.goalPos[1] = c->pos[1];
5993
gLakituState.curPos[1] = c->pos[1];
5994
sStatusFlags &= ~CAM_FLAG_SMOOTH_MOVEMENT;
5995
}
5996
}
5997
5998
BAD_RETURN(s32) cam_rr_enter_building_window(struct Camera *c) {
5999
if (c->mode != CAMERA_MODE_FIXED) {
6000
set_camera_mode_fixed(c, -2974, 478, -3975);
6001
}
6002
}
6003
6004
BAD_RETURN(s32) cam_rr_enter_building(struct Camera *c) {
6005
if (c->mode != CAMERA_MODE_FIXED) {
6006
set_camera_mode_fixed(c, -2953, 798, -3943);
6007
}
6008
// Prevent the camera from being above the roof
6009
if (c->pos[1] > 6043.f) {
6010
c->pos[1] = 6043.f;
6011
}
6012
}
6013
6014
BAD_RETURN(s32) cam_rr_enter_building_side(struct Camera *c) {
6015
if (c->mode != CAMERA_MODE_FIXED) {
6016
sStatusFlags &= ~CAM_FLAG_SMOOTH_MOVEMENT;
6017
c->mode = CAMERA_MODE_FIXED;
6018
skip_camera_interpolation();
6019
}
6020
}
6021
6022
/**
6023
* Fix the camera in place as Mario gets exits out the MC cave into the waterfall.
6024
*/
6025
BAD_RETURN(s32) cam_cotmc_exit_waterfall(UNUSED struct Camera *c) {
6026
gCameraMovementFlags |= CAM_MOVE_FIX_IN_PLACE;
6027
}
6028
6029
/**
6030
* Sets 8 directional mode and blocks the next trigger from processing.
6031
* Activated when Mario is walking in front of the snowman's head.
6032
*/
6033
BAD_RETURN(s32) cam_sl_snowman_head_8dir(struct Camera *c) {
6034
sStatusFlags |= CAM_FLAG_BLOCK_AREA_PROCESSING;
6035
transition_to_camera_mode(c, CAMERA_MODE_8_DIRECTIONS, 60);
6036
s8DirModeBaseYaw = 0x1D27;
6037
}
6038
6039
/**
6040
* Sets free roam mode in SL, called by a trigger that covers a large area and surrounds the 8 direction
6041
* trigger.
6042
*/
6043
BAD_RETURN(s32) cam_sl_free_roam(struct Camera *c) {
6044
transition_to_camera_mode(c, CAMERA_MODE_FREE_ROAM, 60);
6045
}
6046
6047
/**
6048
* Warps the camera underneath the floor, used in HMC to move under the elevator platforms
6049
*/
6050
void move_camera_through_floor_while_descending(struct Camera *c, f32 height) {
6051
UNUSED f32 pad;
6052
6053
if ((sMarioGeometry.currFloorHeight < height - 100.f)
6054
&& (sMarioGeometry.prevFloorHeight > sMarioGeometry.currFloorHeight)) {
6055
c->pos[1] = height - 400.f;
6056
gLakituState.curPos[1] = height - 400.f;
6057
gLakituState.goalPos[1] = height - 400.f;
6058
}
6059
}
6060
6061
BAD_RETURN(s32) cam_hmc_enter_maze(struct Camera *c) {
6062
s16 pitch, yaw;
6063
f32 dist;
6064
6065
if (c->pos[1] > -102.f) {
6066
vec3f_get_dist_and_angle(c->focus, gLakituState.goalPos, &dist, &pitch, &yaw);
6067
vec3f_set_dist_and_angle(c->focus, gLakituState.goalPos, 300.f, pitch, yaw);
6068
gLakituState.goalPos[1] = -800.f;
6069
#ifndef VERSION_JP
6070
c->pos[1] = gLakituState.goalPos[1];
6071
gLakituState.curPos[1] = gLakituState.goalPos[1];
6072
#endif
6073
sStatusFlags &= ~CAM_FLAG_SMOOTH_MOVEMENT;
6074
}
6075
}
6076
6077
BAD_RETURN(s32) cam_hmc_elevator_black_hole(struct Camera *c) {
6078
move_camera_through_floor_while_descending(c, 1536.f);
6079
}
6080
6081
BAD_RETURN(s32) cam_hmc_elevator_maze_emergency_exit(struct Camera *c) {
6082
move_camera_through_floor_while_descending(c, 2355.f);
6083
}
6084
6085
BAD_RETURN(s32) cam_hmc_elevator_lake(struct Camera *c) {
6086
move_camera_through_floor_while_descending(c, 1843.f);
6087
}
6088
6089
BAD_RETURN(s32) cam_hmc_elevator_maze(struct Camera *c) {
6090
move_camera_through_floor_while_descending(c, 1843.f);
6091
}
6092
6093
/**
6094
* Starts the "Enter Pyramid Top" cutscene.
6095
*/
6096
BAD_RETURN(s32) cam_ssl_enter_pyramid_top(UNUSED struct Camera *c) {
6097
start_object_cutscene_without_focus(CUTSCENE_ENTER_PYRAMID_TOP);
6098
}
6099
6100
/**
6101
* Change to close mode in the center of the pyramid. Outside this trigger, the default mode is outwards
6102
* radial.
6103
*/
6104
BAD_RETURN(s32) cam_ssl_pyramid_center(struct Camera *c) {
6105
sStatusFlags |= CAM_FLAG_BLOCK_AREA_PROCESSING;
6106
transition_to_camera_mode(c, CAMERA_MODE_CLOSE, 90);
6107
}
6108
6109
/**
6110
* Changes the mode back to outward radial in the boss room inside the pyramid.
6111
*/
6112
BAD_RETURN(s32) cam_ssl_boss_room(struct Camera *c) {
6113
sStatusFlags |= CAM_FLAG_BLOCK_AREA_PROCESSING;
6114
transition_to_camera_mode(c, CAMERA_MODE_OUTWARD_RADIAL, 90);
6115
}
6116
6117
/**
6118
* Moves the camera to through the tunnel by forcing sModeOffsetYaw
6119
*/
6120
BAD_RETURN(s32) cam_thi_move_cam_through_tunnel(UNUSED struct Camera *c) {
6121
if (sModeOffsetYaw < DEGREES(60)) {
6122
sModeOffsetYaw = DEGREES(60);
6123
}
6124
}
6125
6126
/**
6127
* Aligns the camera to look through the tunnel
6128
*/
6129
BAD_RETURN(s32) cam_thi_look_through_tunnel(UNUSED struct Camera *c) {
6130
// ~82.5 degrees
6131
if (sModeOffsetYaw > 0x3AAA) {
6132
sModeOffsetYaw = 0x3AAA;
6133
}
6134
}
6135
6136
/**
6137
* Unused. Changes the camera to radial mode when Mario is on the tower.
6138
*
6139
* @see sCamBOB for bounds.
6140
*/
6141
BAD_RETURN(s32) cam_bob_tower(struct Camera *c) {
6142
sStatusFlags |= CAM_FLAG_BLOCK_AREA_PROCESSING;
6143
transition_to_camera_mode(c, CAMERA_MODE_RADIAL, 90);
6144
}
6145
6146
/**
6147
* Unused. Changes the camera to free roam mode when Mario is not climbing the tower.
6148
*
6149
* This is the only CameraTrigger event that uses the area == -1 feature:
6150
* If this was used, it would be called by default in BoB.
6151
*
6152
* @see sCamBOB
6153
*/
6154
BAD_RETURN(s32) cam_bob_default_free_roam(struct Camera *c) {
6155
transition_to_camera_mode(c, CAMERA_MODE_FREE_ROAM, 90);
6156
}
6157
6158
/**
6159
* Starts the pool entrance cutscene if Mario is not exiting the pool.
6160
* Used in both the castle and HMC.
6161
*/
6162
BAD_RETURN(s32) cam_castle_hmc_start_pool_cutscene(struct Camera *c) {
6163
if ((sMarioCamState->action != ACT_SPECIAL_DEATH_EXIT)
6164
&& (sMarioCamState->action != ACT_SPECIAL_EXIT_AIRBORNE)) {
6165
start_cutscene(c, CUTSCENE_ENTER_POOL);
6166
}
6167
}
6168
6169
/**
6170
* Sets the fixed mode pos offset so that the camera faces the doorway when Mario is near the entrance
6171
* to the castle lobby
6172
*/
6173
BAD_RETURN(s32) cam_castle_lobby_entrance(UNUSED struct Camera *c) {
6174
vec3f_set(sCastleEntranceOffset, -813.f - sFixedModeBasePosition[0],
6175
378.f - sFixedModeBasePosition[1], 1103.f - sFixedModeBasePosition[2]);
6176
}
6177
6178
/**
6179
* Make the camera look up the stairs from the 2nd to 3rd floor of the castle
6180
*/
6181
BAD_RETURN(s32) cam_castle_look_upstairs(struct Camera *c) {
6182
struct Surface *floor;
6183
f32 floorHeight = find_floor(c->pos[0], c->pos[1], c->pos[2], &floor);
6184
6185
// If Mario is on the first few steps, fix the camera pos, making it look up
6186
if ((sMarioGeometry.currFloorHeight > 1229.f) && (floorHeight < 1229.f)
6187
&& (sCSideButtonYaw == 0)) {
6188
vec3f_set(c->pos, -227.f, 1425.f, 1533.f);
6189
}
6190
}
6191
6192
/**
6193
* Make the camera look down the stairs towards the basement star door
6194
*/
6195
BAD_RETURN(s32) cam_castle_basement_look_downstairs(struct Camera *c) {
6196
struct Surface *floor;
6197
f32 floorHeight = find_floor(c->pos[0], c->pos[1], c->pos[2], &floor);
6198
6199
// Fix the camera pos, making it look downwards. Only active on the top few steps
6200
if ((floorHeight > -110.f) && (sCSideButtonYaw == 0)) {
6201
vec3f_set(c->pos, -980.f, 249.f, -1398.f);
6202
}
6203
}
6204
6205
/**
6206
* Enter the fixed-mode castle lobby. A trigger for this is placed in every entrance so that the camera
6207
* changes to fixed mode.
6208
*/
6209
BAD_RETURN(s32) cam_castle_enter_lobby(struct Camera *c) {
6210
if (c->mode != CAMERA_MODE_FIXED) {
6211
sStatusFlags &= ~CAM_FLAG_SMOOTH_MOVEMENT;
6212
set_fixed_cam_axis_sa_lobby(c->mode);
6213
c->mode = CAMERA_MODE_FIXED;
6214
skip_camera_interpolation();
6215
}
6216
}
6217
6218
/**
6219
* Starts spiral stairs mode.
6220
*/
6221
BAD_RETURN(s32) cam_castle_enter_spiral_stairs(struct Camera *c) {
6222
transition_to_camera_mode(c, CAMERA_MODE_SPIRAL_STAIRS, 20);
6223
}
6224
6225
/**
6226
* unused, starts close mode if the camera is in spiral stairs mode.
6227
* This was replaced with cam_castle_close_mode
6228
*/
6229
static UNUSED BAD_RETURN(s32) cam_castle_leave_spiral_stairs(struct Camera *c) {
6230
if (c->mode == CAMERA_MODE_SPIRAL_STAIRS) {
6231
transition_to_camera_mode(c, CAMERA_MODE_CLOSE, 30);
6232
} else {
6233
set_camera_mode_close_cam(&c->mode);
6234
}
6235
}
6236
6237
/**
6238
* The default mode when outside of the lobby and spiral staircase. A trigger for this is placed at
6239
* every door leaving the lobby and spiral staircase.
6240
*/
6241
BAD_RETURN(s32) cam_castle_close_mode(struct Camera *c) {
6242
set_camera_mode_close_cam(&c->mode);
6243
}
6244
6245
/**
6246
* Functions the same as cam_castle_close_mode, but sets doorStatus so that the camera will enter
6247
* fixed-mode when Mario leaves the room.
6248
*/
6249
BAD_RETURN(s32) cam_castle_leave_lobby_sliding_door(struct Camera *c) {
6250
cam_castle_close_mode(c);
6251
c->doorStatus = DOOR_ENTER_LOBBY;
6252
}
6253
6254
/**
6255
* Just calls cam_castle_enter_lobby
6256
*/
6257
BAD_RETURN(s32) cam_castle_enter_lobby_sliding_door(struct Camera *c) {
6258
cam_castle_enter_lobby(c);
6259
}
6260
6261
BAD_RETURN(s32) cam_bbh_room_6(struct Camera *c) {
6262
parallel_tracking_init(c, sBBHLibraryParTrackPath);
6263
}
6264
6265
BAD_RETURN(s32) cam_bbh_fall_off_roof(struct Camera *c) {
6266
set_camera_mode_close_cam(&c->mode);
6267
}
6268
6269
BAD_RETURN(s32) cam_bbh_fall_into_pool(struct Camera *c) {
6270
Vec3f dir;
6271
set_camera_mode_close_cam(&c->mode);
6272
vec3f_set(dir, 0.f, 0.f, 300.f);
6273
offset_rotated(gLakituState.goalPos, sMarioCamState->pos, dir, sMarioCamState->faceAngle);
6274
gLakituState.goalPos[1] = -2300.f;
6275
vec3f_copy(c->pos, gLakituState.goalPos);
6276
sStatusFlags &= ~CAM_FLAG_SMOOTH_MOVEMENT;
6277
}
6278
6279
BAD_RETURN(s32) cam_bbh_room_1(struct Camera *c) {
6280
set_camera_mode_fixed(c, 956, 440, 1994);
6281
}
6282
6283
BAD_RETURN(s32) cam_bbh_leave_front_door(struct Camera *c) {
6284
c->doorStatus = DOOR_LEAVING_SPECIAL;
6285
cam_bbh_room_1(c);
6286
}
6287
6288
BAD_RETURN(s32) cam_bbh_room_2_lower(struct Camera *c) {
6289
set_camera_mode_fixed(c, 2591, 400, 1284);
6290
}
6291
6292
BAD_RETURN(s32) cam_bbh_room_4(struct Camera *c) {
6293
set_camera_mode_fixed(c, 3529, 340, -1384);
6294
}
6295
6296
BAD_RETURN(s32) cam_bbh_room_8(struct Camera *c) {
6297
set_camera_mode_fixed(c, -500, 740, -1306);
6298
}
6299
6300
/**
6301
* In BBH's room 5's library (the first floor room with the vanish cap/boo painting)
6302
* set the camera mode to fixed and position to (-2172, 200, 675)
6303
*/
6304
BAD_RETURN(s32) cam_bbh_room_5_library(struct Camera *c) {
6305
set_camera_mode_fixed(c, -2172, 200, 675);
6306
}
6307
6308
/**
6309
* In BBH's room 5 (the first floor room with the vanish cap/boo painting)
6310
* set the camera mode to to the hidden room's position
6311
* if coming from the library.
6312
*/
6313
BAD_RETURN(s32) cam_bbh_room_5_library_to_hidden_transition(struct Camera *c) {
6314
if (set_camera_mode_fixed(c, -2172, 200, 675) == 1) {
6315
transition_next_state(c, 20);
6316
}
6317
}
6318
6319
BAD_RETURN(s32) cam_bbh_room_5_hidden_to_library_transition(struct Camera *c) {
6320
if (set_camera_mode_fixed(c, -1542, 320, -307) == 1) {
6321
transition_next_state(c, 20);
6322
}
6323
}
6324
6325
BAD_RETURN(s32) cam_bbh_room_5_hidden(struct Camera *c) {
6326
c->doorStatus = DOOR_LEAVING_SPECIAL;
6327
set_camera_mode_fixed(c, -1542, 320, -307);
6328
}
6329
6330
BAD_RETURN(s32) cam_bbh_room_3(struct Camera *c) {
6331
set_camera_mode_fixed(c, -1893, 320, 2327);
6332
}
6333
6334
BAD_RETURN(s32) cam_bbh_room_7_mr_i(struct Camera *c) {
6335
set_camera_mode_fixed(c, 1371, 360, -1302);
6336
}
6337
6338
BAD_RETURN(s32) cam_bbh_room_7_mr_i_to_coffins_transition(struct Camera *c) {
6339
if (set_camera_mode_fixed(c, 1371, 360, -1302) == 1) {
6340
transition_next_state(c, 20);
6341
}
6342
}
6343
6344
BAD_RETURN(s32) cam_bbh_room_7_coffins_to_mr_i_transition(struct Camera *c) {
6345
if (set_camera_mode_fixed(c, 2115, 260, -772) == 1) {
6346
transition_next_state(c, 20);
6347
}
6348
}
6349
6350
BAD_RETURN(s32) cam_bbh_elevator_room_lower(struct Camera *c) {
6351
c->doorStatus = DOOR_LEAVING_SPECIAL;
6352
set_camera_mode_close_cam(&c->mode);
6353
}
6354
6355
BAD_RETURN(s32) cam_bbh_room_0_back_entrance(struct Camera *c) {
6356
set_camera_mode_close_cam(&c->mode);
6357
}
6358
6359
BAD_RETURN(s32) cam_bbh_elevator(struct Camera *c) {
6360
if (c->mode == CAMERA_MODE_FIXED) {
6361
set_camera_mode_close_cam(&c->mode);
6362
c->pos[1] = -405.f;
6363
gLakituState.goalPos[1] = -405.f;
6364
}
6365
}
6366
6367
BAD_RETURN(s32) cam_bbh_room_12_upper(struct Camera *c) {
6368
c->doorStatus = DOOR_LEAVING_SPECIAL;
6369
set_camera_mode_fixed(c, -2932, 296, 4429);
6370
}
6371
6372
BAD_RETURN(s32) cam_bbh_enter_front_door(struct Camera *c) {
6373
set_camera_mode_close_cam(&c->mode);
6374
}
6375
6376
BAD_RETURN(s32) cam_bbh_room_2_library(struct Camera *c) {
6377
set_camera_mode_fixed(c, 3493, 440, 617);
6378
}
6379
6380
BAD_RETURN(s32) cam_bbh_room_2_library_to_trapdoor_transition(struct Camera *c) {
6381
if (set_camera_mode_fixed(c, 3493, 440, 617) == 1) {
6382
transition_next_state(c, 20);
6383
}
6384
}
6385
6386
BAD_RETURN(s32) cam_bbh_room_2_trapdoor(struct Camera *c) {
6387
set_camera_mode_fixed(c, 3502, 440, 1217);
6388
}
6389
6390
BAD_RETURN(s32) cam_bbh_room_2_trapdoor_transition(struct Camera *c) {
6391
if (set_camera_mode_fixed(c, 3502, 440, 1217) == 1) {
6392
transition_next_state(c, 20);
6393
}
6394
}
6395
6396
BAD_RETURN(s32) cam_bbh_room_9_attic(struct Camera *c) {
6397
set_camera_mode_fixed(c, -670, 460, 372);
6398
}
6399
6400
BAD_RETURN(s32) cam_bbh_room_9_attic_transition(struct Camera *c) {
6401
if (set_camera_mode_fixed(c, -670, 460, 372) == 1) {
6402
transition_next_state(c, 20);
6403
}
6404
}
6405
6406
BAD_RETURN(s32) cam_bbh_room_9_mr_i_transition(struct Camera *c) {
6407
if (set_camera_mode_fixed(c, 131, 380, -263) == 1) {
6408
transition_next_state(c, 20);
6409
}
6410
}
6411
6412
BAD_RETURN(s32) cam_bbh_room_13_balcony(struct Camera *c) {
6413
set_camera_mode_fixed(c, 210, 420, 3109);
6414
}
6415
6416
BAD_RETURN(s32) cam_bbh_room_0(struct Camera *c) {
6417
c->doorStatus = DOOR_LEAVING_SPECIAL;
6418
set_camera_mode_fixed(c, -204, 807, 204);
6419
}
6420
6421
BAD_RETURN(s32) cam_ccm_enter_slide_shortcut(UNUSED struct Camera *c) {
6422
sStatusFlags |= CAM_FLAG_CCM_SLIDE_SHORTCUT;
6423
}
6424
6425
BAD_RETURN(s32) cam_ccm_leave_slide_shortcut(UNUSED struct Camera *c) {
6426
sStatusFlags &= ~CAM_FLAG_CCM_SLIDE_SHORTCUT;
6427
}
6428
6429
/**
6430
* Apply any modes that are triggered by special floor surface types
6431
*/
6432
u32 surface_type_modes(struct Camera *c) {
6433
u32 modeChanged = 0;
6434
6435
switch (sMarioGeometry.currFloorType) {
6436
case SURFACE_CLOSE_CAMERA:
6437
transition_to_camera_mode(c, CAMERA_MODE_CLOSE, 90);
6438
modeChanged += 1;
6439
break;
6440
6441
case SURFACE_CAMERA_FREE_ROAM:
6442
transition_to_camera_mode(c, CAMERA_MODE_FREE_ROAM, 90);
6443
modeChanged += 1;
6444
break;
6445
6446
case SURFACE_NO_CAM_COL_SLIPPERY:
6447
transition_to_camera_mode(c, CAMERA_MODE_CLOSE, 90);
6448
modeChanged += 1;
6449
break;
6450
}
6451
return modeChanged;
6452
}
6453
6454
/**
6455
* Set the camera mode to `mode` if Mario is not standing on a special surface
6456
*/
6457
u32 set_mode_if_not_set_by_surface(struct Camera *c, u8 mode) {
6458
u32 modeChanged = 0;
6459
modeChanged = surface_type_modes(c);
6460
6461
if ((modeChanged == 0) && (mode != 0)) {
6462
transition_to_camera_mode(c, mode, 90);
6463
}
6464
6465
return modeChanged;
6466
}
6467
6468
/**
6469
* Used in THI, check if Mario is standing on any of the special surfaces in that area
6470
*/
6471
void surface_type_modes_thi(struct Camera *c) {
6472
switch (sMarioGeometry.currFloorType) {
6473
case SURFACE_CLOSE_CAMERA:
6474
if (c->mode != CAMERA_MODE_CLOSE) {
6475
transition_to_camera_mode(c, CAMERA_MODE_FREE_ROAM, 90);
6476
}
6477
break;
6478
6479
case SURFACE_CAMERA_FREE_ROAM:
6480
if (c->mode != CAMERA_MODE_CLOSE) {
6481
transition_to_camera_mode(c, CAMERA_MODE_FREE_ROAM, 90);
6482
}
6483
break;
6484
6485
case SURFACE_NO_CAM_COL_SLIPPERY:
6486
if (c->mode != CAMERA_MODE_CLOSE) {
6487
transition_to_camera_mode(c, CAMERA_MODE_FREE_ROAM, 90);
6488
}
6489
break;
6490
6491
case SURFACE_CAMERA_8_DIR:
6492
transition_to_camera_mode(c, CAMERA_MODE_8_DIRECTIONS, 90);
6493
break;
6494
6495
default:
6496
transition_to_camera_mode(c, CAMERA_MODE_RADIAL, 90);
6497
}
6498
}
6499
6500
/**
6501
* Terminates a list of CameraTriggers.
6502
*/
6503
#define NULL_TRIGGER \
6504
{ 0, NULL, 0, 0, 0, 0, 0, 0, 0 }
6505
6506
/**
6507
* The SL triggers operate camera behavior in front of the snowman who blows air.
6508
* The first sets a 8 direction mode, while the latter (which encompasses the former)
6509
* sets free roam mode.
6510
*
6511
* This behavior is exploitable, since the ranges assume that Mario must pass through the latter on
6512
* exit. Using hyperspeed, the earlier area can be directly exited from, keeping the changes it applies.
6513
*/
6514
struct CameraTrigger sCamSL[] = {
6515
{ 1, cam_sl_snowman_head_8dir, 1119, 3584, 1125, 1177, 358, 358, -0x1D27 },
6516
// This trigger surrounds the previous one
6517
{ 1, cam_sl_free_roam, 1119, 3584, 1125, 4096, 4096, 4096, -0x1D27 },
6518
NULL_TRIGGER
6519
};
6520
6521
/**
6522
* The THI triggers are specifically for the tunnel near the start of the Huge Island.
6523
* The first helps the camera from getting stuck on the starting side, the latter aligns with the
6524
* tunnel. Both sides achieve their effect by editing the camera yaw.
6525
*/
6526
struct CameraTrigger sCamTHI[] = {
6527
{ 1, cam_thi_move_cam_through_tunnel, -4609, -2969, 6448, 100, 300, 300, 0 },
6528
{ 1, cam_thi_look_through_tunnel, -4809, -2969, 6448, 100, 300, 300, 0 },
6529
NULL_TRIGGER
6530
};
6531
6532
/**
6533
* The HMC triggers are mostly for warping the camera below platforms, but the second trigger is used to
6534
* start the cutscene for entering the CotMC pool.
6535
*/
6536
struct CameraTrigger sCamHMC[] = {
6537
{ 1, cam_hmc_enter_maze, 1996, 102, 0, 205, 100, 205, 0 },
6538
{ 1, cam_castle_hmc_start_pool_cutscene, 3350, -4689, 4800, 600, 50, 600, 0 },
6539
{ 1, cam_hmc_elevator_black_hole, -3278, 1236, 1379, 358, 200, 358, 0 },
6540
{ 1, cam_hmc_elevator_maze_emergency_exit, -2816, 2055, -2560, 358, 200, 358, 0 },
6541
{ 1, cam_hmc_elevator_lake, -3532, 1543, -7040, 358, 200, 358, 0 },
6542
{ 1, cam_hmc_elevator_maze, -972, 1543, -7347, 358, 200, 358, 0 },
6543
NULL_TRIGGER
6544
};
6545
6546
/**
6547
* The SSL triggers are for starting the enter pyramid top cutscene,
6548
* setting close mode in the middle of the pyramid, and setting the boss fight camera mode to outward
6549
* radial.
6550
*/
6551
struct CameraTrigger sCamSSL[] = {
6552
{ 1, cam_ssl_enter_pyramid_top, -2048, 1080, -1024, 150, 150, 150, 0 },
6553
{ 2, cam_ssl_pyramid_center, 0, -104, -104, 1248, 1536, 2950, 0 },
6554
{ 2, cam_ssl_pyramid_center, 0, 2500, 256, 515, 5000, 515, 0 },
6555
{ 3, cam_ssl_boss_room, 0, -1534, -2040, 1000, 800, 1000, 0 },
6556
NULL_TRIGGER
6557
};
6558
6559
/**
6560
* The RR triggers are for changing between fixed and 8 direction mode when entering / leaving the building at
6561
* the end of the ride.
6562
*/
6563
struct CameraTrigger sCamRR[] = {
6564
{ 1, cam_rr_exit_building_side, -4197, 3819, -3087, 1769, 1490, 342, 0 },
6565
{ 1, cam_rr_enter_building_side, -4197, 3819, -3771, 769, 490, 342, 0 },
6566
{ 1, cam_rr_enter_building_window, -5603, 4834, -5209, 300, 600, 591, 0 },
6567
{ 1, cam_rr_enter_building, -2609, 3730, -5463, 300, 650, 577, 0 },
6568
{ 1, cam_rr_exit_building_top, -4196, 7343, -5155, 4500, 1000, 4500, 0 },
6569
{ 1, cam_rr_enter_building, -4196, 6043, -5155, 500, 300, 500, 0 },
6570
NULL_TRIGGER,
6571
};
6572
6573
/**
6574
* These triggers are unused, but because the first trigger surrounds the BoB tower and activates radial
6575
* mode (which is called "tower mode" in the patent), it's speculated they belonged to BoB.
6576
*
6577
* This table contains the only instance of a CameraTrigger with an area set to -1, and it sets the mode
6578
* to free_roam when Mario is not walking up the tower.
6579
*/
6580
struct CameraTrigger sCamBOB[] = {
6581
{ 1, cam_bob_tower, 2468, 2720, -4608, 3263, 1696, 3072, 0 },
6582
{ -1, cam_bob_default_free_roam, 0, 0, 0, 0, 0, 0, 0 },
6583
NULL_TRIGGER
6584
};
6585
6586
/**
6587
* The CotMC trigger is only used to prevent fix Lakitu in place when Mario exits through the waterfall.
6588
*/
6589
struct CameraTrigger sCamCotMC[] = {
6590
{ 1, cam_cotmc_exit_waterfall, 0, 1500, 3500, 550, 10000, 1500, 0 },
6591
NULL_TRIGGER
6592
};
6593
6594
/**
6595
* The CCM triggers are used to set the flag that says when Mario is in the slide shortcut.
6596
*/
6597
struct CameraTrigger sCamCCM[] = {
6598
{ 2, cam_ccm_enter_slide_shortcut, -4846, 2061, 27, 1229, 1342, 396, 0 },
6599
{ 2, cam_ccm_leave_slide_shortcut, -6412, -3917, -6246, 307, 185, 132, 0 },
6600
NULL_TRIGGER
6601
};
6602
6603
/**
6604
* The Castle triggers are used to set the camera to fixed mode when entering the lobby, and to set it
6605
* to close mode when leaving it. They also set the mode to spiral staircase.
6606
*
6607
* There are two triggers for looking up and down straight staircases when Mario is at the start,
6608
* and one trigger that starts the enter pool cutscene when Mario enters HMC.
6609
*/
6610
struct CameraTrigger sCamCastle[] = {
6611
{ 1, cam_castle_close_mode, -1100, 657, -1346, 300, 150, 300, 0 },
6612
{ 1, cam_castle_enter_lobby, -1099, 657, -803, 300, 150, 300, 0 },
6613
{ 1, cam_castle_close_mode, -2304, -264, -4072, 140, 150, 140, 0 },
6614
{ 1, cam_castle_close_mode, -2304, 145, -1344, 140, 150, 140, 0 },
6615
{ 1, cam_castle_enter_lobby, -2304, 145, -802, 140, 150, 140, 0 },
6616
//! Sets the camera mode when leaving secret aquarium
6617
{ 1, cam_castle_close_mode, 2816, 1200, -256, 100, 100, 100, 0 },
6618
{ 1, cam_castle_close_mode, 256, -161, -4226, 140, 150, 140, 0 },
6619
{ 1, cam_castle_close_mode, 256, 145, -1344, 140, 150, 140, 0 },
6620
{ 1, cam_castle_enter_lobby, 256, 145, -802, 140, 150, 140, 0 },
6621
{ 1, cam_castle_close_mode, -1023, 44, -4870, 140, 150, 140, 0 },
6622
{ 1, cam_castle_close_mode, -459, 145, -1020, 140, 150, 140, 0x6000 },
6623
{ 1, cam_castle_enter_lobby, -85, 145, -627, 140, 150, 140, 0 },
6624
{ 1, cam_castle_close_mode, -1589, 145, -1020, 140, 150, 140, -0x6000 },
6625
{ 1, cam_castle_enter_lobby, -1963, 145, -627, 140, 150, 140, 0 },
6626
{ 1, cam_castle_leave_lobby_sliding_door, -2838, 657, -1659, 200, 150, 150, 0x2000 },
6627
{ 1, cam_castle_enter_lobby_sliding_door, -2319, 512, -1266, 300, 150, 300, 0x2000 },
6628
{ 1, cam_castle_close_mode, 844, 759, -1657, 40, 150, 40, -0x2000 },
6629
{ 1, cam_castle_enter_lobby, 442, 759, -1292, 140, 150, 140, -0x2000 },
6630
{ 2, cam_castle_enter_spiral_stairs, -1000, 657, 1740, 200, 300, 200, 0 },
6631
{ 2, cam_castle_enter_spiral_stairs, -996, 1348, 1814, 200, 300, 200, 0 },
6632
{ 2, cam_castle_close_mode, -946, 657, 2721, 50, 150, 50, 0 },
6633
{ 2, cam_castle_close_mode, -996, 1348, 907, 50, 150, 50, 0 },
6634
{ 2, cam_castle_close_mode, -997, 1348, 1450, 140, 150, 140, 0 },
6635
{ 1, cam_castle_close_mode, -4942, 452, -461, 140, 150, 140, 0x4000 },
6636
{ 1, cam_castle_close_mode, -3393, 350, -793, 140, 150, 140, 0x4000 },
6637
{ 1, cam_castle_enter_lobby, -2851, 350, -792, 140, 150, 140, 0x4000 },
6638
{ 1, cam_castle_enter_lobby, 803, 350, -228, 140, 150, 140, -0x4000 },
6639
//! Duplicate camera trigger outside JRB door
6640
{ 1, cam_castle_enter_lobby, 803, 350, -228, 140, 150, 140, -0x4000 },
6641
{ 1, cam_castle_close_mode, 1345, 350, -229, 140, 150, 140, 0x4000 },
6642
{ 1, cam_castle_close_mode, -946, -929, 622, 300, 150, 300, 0 },
6643
{ 2, cam_castle_look_upstairs, -205, 1456, 2508, 210, 928, 718, 0 },
6644
{ 1, cam_castle_basement_look_downstairs, -1027, -587, -718, 318, 486, 577, 0 },
6645
{ 1, cam_castle_lobby_entrance, -1023, 376, 1830, 300, 400, 300, 0 },
6646
{ 3, cam_castle_hmc_start_pool_cutscene, 2485, -1689, -2659, 600, 50, 600, 0 },
6647
NULL_TRIGGER
6648
};
6649
6650
/**
6651
* The BBH triggers are the most complex, they cause the camera to enter fixed mode for each room,
6652
* transition between rooms, and enter free roam when outside.
6653
*
6654
* The triggers are also responsible for warping the camera below platforms.
6655
*/
6656
struct CameraTrigger sCamBBH[] = {
6657
{ 1, cam_bbh_enter_front_door, 742, 0, 2369, 200, 200, 200, 0 },
6658
{ 1, cam_bbh_leave_front_door, 741, 0, 1827, 200, 200, 200, 0 },
6659
{ 1, cam_bbh_room_1, 222, 0, 1458, 200, 200, 200, 0 },
6660
{ 1, cam_bbh_room_1, 222, 0, 639, 200, 200, 200, 0 },
6661
{ 1, cam_bbh_room_1, 435, 0, 222, 200, 200, 200, 0 },
6662
{ 1, cam_bbh_room_1, 1613, 0, 222, 200, 200, 200, 0 },
6663
{ 1, cam_bbh_room_1, 1827, 0, 1459, 200, 200, 200, 0 },
6664
{ 1, cam_bbh_room_1, -495, 819, 1407, 200, 200, 200, 0 },
6665
{ 1, cam_bbh_room_1, -495, 819, 640, 250, 200, 200, 0 },
6666
{ 1, cam_bbh_room_1, 179, 819, 222, 200, 200, 200, 0 },
6667
{ 1, cam_bbh_room_1, 1613, 819, 222, 200, 200, 200, 0 },
6668
{ 1, cam_bbh_room_1, 1827, 819, 486, 200, 200, 200, 0 },
6669
{ 1, cam_bbh_room_1, 1827, 819, 1818, 200, 200, 200, 0 },
6670
{ 1, cam_bbh_room_2_lower, 2369, 0, 1459, 200, 200, 200, 0 },
6671
{ 1, cam_bbh_room_2_lower, 3354, 0, 1347, 200, 200, 200, 0 },
6672
{ 1, cam_bbh_room_2_lower, 2867, 514, 1843, 512, 102, 409, 0 },
6673
{ 1, cam_bbh_room_4, 3354, 0, 804, 200, 200, 200, 0 },
6674
{ 1, cam_bbh_room_4, 1613, 0, -320, 200, 200, 200, 0 },
6675
{ 1, cam_bbh_room_8, 435, 0, -320, 200, 200, 200, 0 },
6676
{ 1, cam_bbh_room_5_library, -2021, 0, 803, 200, 200, 200, 0 },
6677
{ 1, cam_bbh_room_5_library, -320, 0, 640, 200, 200, 200, 0 },
6678
{ 1, cam_bbh_room_5_library_to_hidden_transition, -1536, 358, -254, 716, 363, 102, 0 },
6679
{ 1, cam_bbh_room_5_hidden_to_library_transition, -1536, 358, -459, 716, 363, 102, 0 },
6680
{ 1, cam_bbh_room_5_hidden, -1560, 0, -1314, 200, 200, 200, 0 },
6681
{ 1, cam_bbh_room_3, -320, 0, 1459, 200, 200, 200, 0 },
6682
{ 1, cam_bbh_room_3, -2021, 0, 1345, 200, 200, 200, 0 },
6683
{ 1, cam_bbh_room_2_library, 2369, 819, 486, 200, 200, 200, 0 },
6684
{ 1, cam_bbh_room_2_library, 2369, 1741, 486, 200, 200, 200, 0 },
6685
{ 1, cam_bbh_room_2_library_to_trapdoor_transition, 2867, 1228, 1174, 716, 414, 102, 0 },
6686
{ 1, cam_bbh_room_2_trapdoor_transition, 2867, 1228, 1378, 716, 414, 102, 0 },
6687
{ 1, cam_bbh_room_2_trapdoor, 2369, 819, 1818, 200, 200, 200, 0 },
6688
{ 1, cam_bbh_room_9_attic, 1829, 1741, 486, 200, 200, 200, 0 },
6689
{ 1, cam_bbh_room_9_attic, 741, 1741, 1587, 200, 200, 200, 0 },
6690
{ 1, cam_bbh_room_9_attic_transition, 102, 2048, -191, 100, 310, 307, 0 },
6691
{ 1, cam_bbh_room_9_mr_i_transition, 409, 2048, -191, 100, 310, 307, 0 },
6692
{ 1, cam_bbh_room_13_balcony, 742, 1922, 2164, 200, 200, 200, 0 },
6693
{ 1, cam_bbh_fall_off_roof, 587, 1322, 2677, 1000, 400, 600, 0 },
6694
{ 1, cam_bbh_room_3, -1037, 819, 1408, 200, 200, 200, 0 },
6695
{ 1, cam_bbh_room_3, -1970, 1024, 1345, 200, 200, 200, 0 },
6696
{ 1, cam_bbh_room_8, 179, 819, -320, 200, 200, 200, 0 },
6697
{ 1, cam_bbh_room_7_mr_i, 1613, 819, -320, 200, 200, 200, 0 },
6698
{ 1, cam_bbh_room_7_mr_i_to_coffins_transition, 2099, 1228, -819, 102, 414, 716, 0 },
6699
{ 1, cam_bbh_room_7_coffins_to_mr_i_transition, 2304, 1228, -819, 102, 414, 716, 0 },
6700
{ 1, cam_bbh_room_6, -1037, 819, 640, 200, 200, 200, 0 },
6701
{ 1, cam_bbh_room_6, -1970, 1024, 803, 200, 200, 200, 0 },
6702
{ 1, cam_bbh_room_1, 1827, 819, 1818, 200, 200, 200, 0 },
6703
{ 1, cam_bbh_fall_into_pool, 2355, -1112, -193, 1228, 500, 1343, 0 },
6704
{ 1, cam_bbh_fall_into_pool, 2355, -1727, 1410, 1228, 500, 705, 0 },
6705
{ 1, cam_bbh_elevator_room_lower, 0, -2457, 1827, 250, 200, 250, 0 },
6706
{ 1, cam_bbh_elevator_room_lower, 0, -2457, 2369, 250, 200, 250, 0 },
6707
{ 1, cam_bbh_elevator_room_lower, 0, -2457, 4929, 250, 200, 250, 0 },
6708
{ 1, cam_bbh_elevator_room_lower, 0, -2457, 4387, 250, 200, 250, 0 },
6709
{ 1, cam_bbh_room_0_back_entrance, 1887, -2457, 204, 250, 200, 250, 0 },
6710
{ 1, cam_bbh_room_0, 1272, -2457, 204, 250, 200, 250, 0 },
6711
{ 1, cam_bbh_room_0, -1681, -2457, 204, 250, 200, 250, 0 },
6712
{ 1, cam_bbh_room_0_back_entrance, -2296, -2457, 204, 250, 200, 250, 0 },
6713
{ 1, cam_bbh_elevator, -2939, -605, 5367, 800, 100, 800, 0 },
6714
{ 1, cam_bbh_room_12_upper, -2939, -205, 5367, 300, 100, 300, 0 },
6715
{ 1, cam_bbh_room_12_upper, -2332, -204, 4714, 250, 200, 250, 0x6000 },
6716
{ 1, cam_bbh_room_0_back_entrance, -1939, -204, 4340, 250, 200, 250, 0x6000 },
6717
NULL_TRIGGER
6718
};
6719
6720
#define _ NULL
6721
#define STUB_LEVEL(_0, _1, _2, _3, _4, _5, _6, _7, cameratable) cameratable,
6722
#define DEFINE_LEVEL(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, cameratable) cameratable,
6723
6724
/*
6725
* This table has an extra 2 levels after the last unknown_38 stub level. What I think
6726
* the programmer was thinking was that the table is null terminated and so used the
6727
* level count as a correspondence to the ID of the final level, but the enum represents
6728
* an ID *after* the last stub level, not before or during it.
6729
*
6730
* Each table is terminated with NULL_TRIGGER
6731
*/
6732
struct CameraTrigger *sCameraTriggers[LEVEL_COUNT + 1] = {
6733
NULL,
6734
#include "levels/level_defines.h"
6735
};
6736
#undef _
6737
#undef STUB_LEVEL
6738
#undef DEFINE_LEVEL
6739
6740
struct CutsceneSplinePoint sIntroStartToPipePosition[] = {
6741
{ 0, 0, { 2122, 8762, 9114 } }, { 0, 0, { 2122, 8762, 9114 } }, { 1, 0, { 2122, 7916, 9114 } },
6742
{ 1, 0, { 2122, 7916, 9114 } }, { 2, 0, { 957, 5166, 8613 } }, { 3, 0, { 589, 4338, 7727 } },
6743
{ 4, 0, { 690, 3366, 6267 } }, { 5, 0, { -1600, 2151, 4955 } }, { 6, 0, { -1557, 232, 1283 } },
6744
{ 7, 0, { -6962, -295, 2729 } }, { 8, 0, { -6979, 131, 3246 } }, { 9, 0, { -6360, -283, 4044 } },
6745
{ 0, 0, { -5695, -334, 5264 } }, { 1, 0, { -5568, -319, 7933 } }, { 2, 0, { -3848, -200, 6278 } },
6746
{ 3, 0, { -965, -263, 6092 } }, { 4, 0, { 1607, 2465, 6329 } }, { 5, 0, { 2824, 180, 3548 } },
6747
{ 6, 0, { 1236, 136, 945 } }, { 0, 0, { 448, 136, 564 } }, { 0, 0, { 448, 136, 564 } },
6748
{ 0, 0, { 448, 136, 564 } }, { -1, 0, { 448, 136, 564 } }
6749
};
6750
6751
struct CutsceneSplinePoint sIntroStartToPipeFocus[] = {
6752
{ 0, 50, { 1753, 29800, 8999 } }, { 0, 50, { 1753, 29800, 8999 } },
6753
{ 1, 50, { 1753, 8580, 8999 } }, { 1, 100, { 1753, 8580, 8999 } },
6754
{ 2, 50, { 520, 5400, 8674 } }, { 3, 50, { 122, 4437, 7875 } },
6755
{ 4, 50, { 316, 3333, 6538 } }, { 5, 36, { -1526, 2189, 5448 } },
6756
{ 6, 50, { -1517, 452, 1731 } }, { 7, 50, { -6659, -181, 3109 } },
6757
{ 8, 17, { -6649, 183, 3618 } }, { 9, 20, { -6009, -214, 4395 } },
6758
{ 0, 50, { -5258, -175, 5449 } }, { 1, 36, { -5158, -266, 7651 } },
6759
{ 2, 26, { -3351, -192, 6222 } }, { 3, 25, { -483, -137, 6060 } },
6760
{ 4, 100, { 1833, 2211, 5962 } }, { 5, 26, { 3022, 207, 3090 } },
6761
{ 6, 20, { 1250, 197, 449 } }, { 7, 50, { 248, 191, 227 } },
6762
{ 7, 0, { 48, 191, 227 } }, { 7, 0, { 48, 191, 227 } },
6763
{ -1, 0, { 48, 191, 227 } }
6764
};
6765
6766
/**
6767
* Describes the spline the camera follows, starting when the camera jumps to Lakitu and ending after
6768
* Mario jumps out of the pipe when the first dialog opens. This table specifically updates the
6769
* camera's position.
6770
*/
6771
struct CutsceneSplinePoint sIntroPipeToDialogPosition[] = {
6772
{ 0, 0, { -785, 625, 4527 } }, { 1, 0, { -785, 625, 4527 } }, { 2, 0, { -1286, 644, 4376 } },
6773
{ 3, 0, { -1286, 623, 4387 } }, { 4, 0, { -1286, 388, 3963 } }, { 5, 0, { -1286, 358, 4093 } },
6774
{ 6, 0, { -1386, 354, 4159 } }, { 7, 0, { -1477, 306, 4223 } }, { 8, 0, { -1540, 299, 4378 } },
6775
{ 9, 0, { -1473, 316, 4574 } }, { 0, 0, { -1328, 485, 5017 } }, { 0, 0, { -1328, 485, 5017 } },
6776
{ 0, 0, { -1328, 485, 5017 } }, { -1, 0, { -1328, 485, 5017 } }
6777
};
6778
6779
/**
6780
* Describes the spline that the camera's focus follows, during the same part of the intro as the above.
6781
*/
6782
#ifdef VERSION_EU
6783
struct CutsceneSplinePoint sIntroPipeToDialogFocus[] = {
6784
{ 0, 25, { -1248, 450, 4596 } }, { 1, 71, { -1258, 485, 4606 } }, { 2, 71, { -1379, 344, 4769 } },
6785
{ 3, 22, { -1335, 366, 4815 } }, { 4, 23, { -1315, 370, 4450 } }, { 5, 40, { -1322, 333, 4591 } },
6786
{ 6, 25, { -1185, 329, 4616 } }, { 7, 21, { -1059, 380, 4487 } }, { 8, 14, { -1086, 421, 4206 } },
6787
{ 9, 21, { -1321, 346, 4098 } }, { 0, 0, { -1328, 385, 4354 } }, { 0, 0, { -1328, 385, 4354 } },
6788
{ 0, 0, { -1328, 385, 4354 } }, { -1, 0, { -1328, 385, 4354 } }
6789
};
6790
#else
6791
struct CutsceneSplinePoint sIntroPipeToDialogFocus[] = {
6792
{ 0, 20, { -1248, 450, 4596 } }, { 1, 59, { -1258, 485, 4606 } }, { 2, 59, { -1379, 344, 4769 } },
6793
{ 3, 20, { -1335, 366, 4815 } }, { 4, 23, { -1315, 370, 4450 } }, { 5, 40, { -1322, 333, 4591 } },
6794
{ 6, 25, { -1185, 329, 4616 } }, { 7, 21, { -1059, 380, 4487 } }, { 8, 14, { -1086, 421, 4206 } },
6795
{ 9, 21, { -1321, 346, 4098 } }, { 0, 0, { -1328, 385, 4354 } }, { 0, 0, { -1328, 385, 4354 } },
6796
{ 0, 0, { -1328, 385, 4354 } }, { -1, 0, { -1328, 385, 4354 } }
6797
};
6798
#endif
6799
6800
struct CutsceneSplinePoint sEndingFlyToWindowPos[] = {
6801
{ 0, 0, { -86, 876, 640 } }, { 1, 0, { -86, 876, 610 } }, { 2, 0, { -66, 945, 393 } },
6802
{ 3, 0, { -80, 976, 272 } }, { 4, 0, { -66, 1306, -36 } }, { 5, 0, { -70, 1869, -149 } },
6803
{ 6, 0, { -10, 2093, -146 } }, { 7, 0, { -10, 2530, -248 } }, { 8, 0, { -10, 2530, -263 } },
6804
{ 9, 0, { -10, 2530, -273 } }
6805
};
6806
6807
struct CutsceneSplinePoint sEndingFlyToWindowFocus[] = {
6808
{ 0, 50, { -33, 889, -7 } }, { 1, 35, { -33, 889, -7 } }, { 2, 31, { -17, 1070, -193 } },
6809
{ 3, 25, { -65, 1182, -272 } }, { 4, 20, { -64, 1559, -542 } }, { 5, 25, { -68, 2029, -677 } },
6810
{ 6, 25, { -9, 2204, -673 } }, { 7, 25, { -8, 2529, -772 } }, { 8, 0, { -8, 2529, -772 } },
6811
{ 9, 0, { -8, 2529, -772 } }, { -1, 0, { -8, 2529, -772 } }
6812
};
6813
6814
struct CutsceneSplinePoint sEndingPeachDescentCamPos[] = {
6815
{ 0, 50, { 1, 120, -1150 } }, { 1, 50, { 1, 120, -1150 } }, { 2, 40, { 118, 121, -1199 } },
6816
{ 3, 40, { 147, 74, -1306 } }, { 4, 40, { 162, 95, -1416 } }, { 5, 40, { 25, 111, -1555 } },
6817
{ 6, 40, { -188, 154, -1439 } }, { 7, 40, { -203, 181, -1242 } }, { 8, 40, { 7, 191, -1057 } },
6818
{ 9, 40, { 262, 273, -1326 } }, { 0, 40, { -4, 272, -1627 } }, { 1, 35, { -331, 206, -1287 } },
6819
{ 2, 30, { -65, 219, -877 } }, { 3, 25, { 6, 216, -569 } }, { 4, 25, { -8, 157, 40 } },
6820
{ 5, 25, { -4, 106, 200 } }, { 6, 25, { -6, 72, 574 } }, { 7, 0, { -6, 72, 574 } },
6821
{ 8, 0, { -6, 72, 574 } }, { -1, 0, { -6, 72, 574 } }
6822
};
6823
6824
struct CutsceneSplinePoint sEndingMarioToPeachPos[] = {
6825
{ 0, 0, { -130, 1111, -1815 } }, { 1, 0, { -131, 1052, -1820 } }, { 2, 0, { -271, 1008, -1651 } },
6826
{ 3, 0, { -439, 1043, -1398 } }, { 4, 0, { -433, 1040, -1120 } }, { 5, 0, { -417, 1040, -1076 } },
6827
{ 6, 0, { -417, 1040, -1076 } }, { 7, 0, { -417, 1040, -1076 } }, { -1, 0, { -417, 1040, -1076 } }
6828
};
6829
6830
struct CutsceneSplinePoint sEndingMarioToPeachFocus[] = {
6831
{ 0, 50, { -37, 1020, -1332 } }, { 1, 20, { -36, 1012, -1330 } }, { 2, 20, { -24, 1006, -1215 } },
6832
{ 3, 20, { 28, 1002, -1224 } }, { 4, 24, { 45, 1013, -1262 } }, { 5, 35, { 34, 1000, -1287 } },
6833
{ 6, 0, { 34, 1000, -1287 } }, { 7, 0, { 34, 1000, -1287 } }, { -1, 0, { 34, 1000, -1287 } }
6834
};
6835
6836
struct CutsceneSplinePoint sEndingLookUpAtCastle[] = {
6837
{ 0, 50, { 200, 1066, -1414 } }, { 0, 50, { 200, 1066, -1414 } }, { 0, 30, { 198, 1078, -1412 } },
6838
{ 0, 33, { 15, 1231, -1474 } }, { 0, 39, { -94, 1381, -1368 } }, { 0, 0, { -92, 1374, -1379 } },
6839
{ 0, 0, { -92, 1374, -1379 } }, { -1, 0, { -92, 1374, -1379 } }
6840
};
6841
6842
struct CutsceneSplinePoint sEndingLookAtSkyFocus[] = {
6843
#ifdef VERSION_EU
6844
{ 0, 50, { 484, 1368, -868 } }, { 0, 72, { 479, 1372, -872 } }, { 0, 50, { 351, 1817, -918 } },
6845
#else
6846
{ 0, 50, { 484, 1368, -888 } }, { 0, 72, { 479, 1372, -892 } }, { 0, 50, { 351, 1817, -918 } },
6847
#endif
6848
{ 0, 50, { 351, 1922, -598 } }, { 0, 0, { 636, 2027, -415 } }, { 0, 0, { 636, 2027, -415 } },
6849
{ -1, 0, { 636, 2027, -415 } }
6850
};
6851
6852
/**
6853
* Activates any CameraTriggers that Mario is inside.
6854
* Then, applies area-specific processing to the camera, such as setting the default mode, or changing
6855
* the mode based on the terrain type Mario is standing on.
6856
*
6857
* @return the camera's mode after processing, although this is unused in the code
6858
*/
6859
s16 camera_course_processing(struct Camera *c) {
6860
s16 level = gCurrLevelNum;
6861
s16 mode;
6862
s8 area = gCurrentArea->index;
6863
// Bounds iterator
6864
u32 b;
6865
// Camera trigger's bounding box
6866
Vec3f center, bounds;
6867
u32 insideBounds = FALSE;
6868
UNUSED struct CameraTrigger unused;
6869
u8 oldMode = c->mode;
6870
6871
if (c->mode == CAMERA_MODE_C_UP) {
6872
c->mode = sModeInfo.lastMode;
6873
}
6874
check_blocking_area_processing(&c->mode);
6875
if (level > LEVEL_COUNT + 1) {
6876
level = LEVEL_COUNT + 1;
6877
}
6878
6879
if (sCameraTriggers[level] != NULL) {
6880
b = 0;
6881
6882
// Process positional triggers.
6883
// All triggered events are called, not just the first one.
6884
while (sCameraTriggers[level][b].event != NULL) {
6885
6886
// Check only the current area's triggers
6887
if (sCameraTriggers[level][b].area == area) {
6888
// Copy the bounding box into center and bounds
6889
vec3f_set(center, sCameraTriggers[level][b].centerX,
6890
sCameraTriggers[level][b].centerY,
6891
sCameraTriggers[level][b].centerZ);
6892
vec3f_set(bounds, sCameraTriggers[level][b].boundsX,
6893
sCameraTriggers[level][b].boundsY,
6894
sCameraTriggers[level][b].boundsZ);
6895
6896
// Check if Mario is inside the bounds
6897
if (is_pos_in_bounds(sMarioCamState->pos, center, bounds,
6898
sCameraTriggers[level][b].boundsYaw) == TRUE) {
6899
//! This should be checked before calling is_pos_in_bounds. (It doesn't belong
6900
//! outside the while loop because some events disable area processing)
6901
if (!(sStatusFlags & CAM_FLAG_BLOCK_AREA_PROCESSING)) {
6902
sCameraTriggers[level][b].event(c);
6903
insideBounds = TRUE;
6904
}
6905
}
6906
}
6907
6908
if ((sCameraTriggers[level])[b].area == -1) {
6909
// Default triggers are only active if Mario is not already inside another trigger
6910
if (!insideBounds) {
6911
if (!(sStatusFlags & CAM_FLAG_BLOCK_AREA_PROCESSING)) {
6912
sCameraTriggers[level][b].event(c);
6913
}
6914
}
6915
}
6916
6917
b += 1;
6918
}
6919
}
6920
6921
// Area-specific camera processing
6922
if (!(sStatusFlags & CAM_FLAG_BLOCK_AREA_PROCESSING)) {
6923
switch (gCurrLevelArea) {
6924
case AREA_WF:
6925
if (sMarioCamState->action == ACT_RIDING_HOOT) {
6926
transition_to_camera_mode(c, CAMERA_MODE_SLIDE_HOOT, 60);
6927
} else {
6928
switch (sMarioGeometry.currFloorType) {
6929
case SURFACE_CAMERA_8_DIR:
6930
transition_to_camera_mode(c, CAMERA_MODE_8_DIRECTIONS, 90);
6931
s8DirModeBaseYaw = DEGREES(90);
6932
break;
6933
6934
case SURFACE_BOSS_FIGHT_CAMERA:
6935
if (gCurrActNum == 1) {
6936
set_camera_mode_boss_fight(c);
6937
} else {
6938
set_camera_mode_radial(c, 60);
6939
}
6940
break;
6941
default:
6942
set_camera_mode_radial(c, 60);
6943
}
6944
}
6945
break;
6946
6947
case AREA_BBH:
6948
// if camera is fixed at bbh_room_13_balcony_camera (but as floats)
6949
if (vec3f_compare(sFixedModeBasePosition, 210.f, 420.f, 3109.f) == 1)
6950
{
6951
if (sMarioCamState->pos[1] < 1800.f) {
6952
transition_to_camera_mode(c, CAMERA_MODE_CLOSE, 30);
6953
}
6954
}
6955
break;
6956
6957
case AREA_SSL_PYRAMID:
6958
set_mode_if_not_set_by_surface(c, CAMERA_MODE_OUTWARD_RADIAL);
6959
break;
6960
6961
case AREA_SSL_OUTSIDE:
6962
set_mode_if_not_set_by_surface(c, CAMERA_MODE_RADIAL);
6963
break;
6964
6965
case AREA_THI_HUGE:
6966
break;
6967
6968
case AREA_THI_TINY:
6969
surface_type_modes_thi(c);
6970
break;
6971
6972
case AREA_TTC:
6973
set_mode_if_not_set_by_surface(c, CAMERA_MODE_OUTWARD_RADIAL);
6974
break;
6975
6976
case AREA_BOB:
6977
if (set_mode_if_not_set_by_surface(c, CAMERA_MODE_NONE) == 0) {
6978
if (sMarioGeometry.currFloorType == SURFACE_BOSS_FIGHT_CAMERA) {
6979
set_camera_mode_boss_fight(c);
6980
} else {
6981
if (c->mode == CAMERA_MODE_CLOSE) {
6982
transition_to_camera_mode(c, CAMERA_MODE_RADIAL, 60);
6983
} else {
6984
set_camera_mode_radial(c, 60);
6985
}
6986
}
6987
}
6988
break;
6989
6990
case AREA_WDW_MAIN:
6991
switch (sMarioGeometry.currFloorType) {
6992
case SURFACE_INSTANT_WARP_1B:
6993
c->defMode = CAMERA_MODE_RADIAL;
6994
break;
6995
}
6996
break;
6997
6998
case AREA_WDW_TOWN:
6999
switch (sMarioGeometry.currFloorType) {
7000
case SURFACE_INSTANT_WARP_1C:
7001
c->defMode = CAMERA_MODE_CLOSE;
7002
break;
7003
}
7004
break;
7005
7006
case AREA_DDD_WHIRLPOOL:
7007
//! @bug this does nothing
7008
gLakituState.defMode = CAMERA_MODE_OUTWARD_RADIAL;
7009
break;
7010
7011
case AREA_DDD_SUB:
7012
if ((c->mode != CAMERA_MODE_BEHIND_MARIO)
7013
&& (c->mode != CAMERA_MODE_WATER_SURFACE)) {
7014
if (((sMarioCamState->action & ACT_FLAG_ON_POLE) != 0)
7015
|| (sMarioGeometry.currFloorHeight > 800.f)) {
7016
transition_to_camera_mode(c, CAMERA_MODE_8_DIRECTIONS, 60);
7017
7018
} else {
7019
if (sMarioCamState->pos[1] < 800.f) {
7020
transition_to_camera_mode(c, CAMERA_MODE_FREE_ROAM, 60);
7021
}
7022
}
7023
}
7024
//! @bug this does nothing
7025
gLakituState.defMode = CAMERA_MODE_FREE_ROAM;
7026
break;
7027
}
7028
}
7029
7030
sStatusFlags &= ~CAM_FLAG_BLOCK_AREA_PROCESSING;
7031
if (oldMode == CAMERA_MODE_C_UP) {
7032
sModeInfo.lastMode = c->mode;
7033
c->mode = oldMode;
7034
}
7035
mode = c->mode;
7036
return mode;
7037
}
7038
7039
/**
7040
* Move `pos` between the nearest floor and ceiling
7041
* @param lastGood unused, passed as the last position the camera was in
7042
*/
7043
void resolve_geometry_collisions(Vec3f pos, UNUSED Vec3f lastGood) {
7044
f32 ceilY, floorY;
7045
struct Surface *surf;
7046
7047
f32_find_wall_collision(&pos[0], &pos[1], &pos[2], 0.f, 100.f);
7048
floorY = find_floor(pos[0], pos[1] + 50.f, pos[2], &surf);
7049
ceilY = find_ceil(pos[0], pos[1] - 50.f, pos[2], &surf);
7050
7051
if ((FLOOR_LOWER_LIMIT != floorY) && (CELL_HEIGHT_LIMIT == ceilY)) {
7052
if (pos[1] < (floorY += 125.f)) {
7053
pos[1] = floorY;
7054
}
7055
}
7056
7057
if ((FLOOR_LOWER_LIMIT == floorY) && (CELL_HEIGHT_LIMIT != ceilY)) {
7058
if (pos[1] > (ceilY -= 125.f)) {
7059
pos[1] = ceilY;
7060
}
7061
}
7062
7063
if ((FLOOR_LOWER_LIMIT != floorY) && (CELL_HEIGHT_LIMIT != ceilY)) {
7064
floorY += 125.f;
7065
ceilY -= 125.f;
7066
7067
if ((pos[1] <= floorY) && (pos[1] < ceilY)) {
7068
pos[1] = floorY;
7069
}
7070
if ((pos[1] > floorY) && (pos[1] >= ceilY)) {
7071
pos[1] = ceilY;
7072
}
7073
if ((pos[1] <= floorY) && (pos[1] >= ceilY)) {
7074
pos[1] = (floorY + ceilY) * 0.5f;
7075
}
7076
}
7077
}
7078
7079
/**
7080
* Checks for any walls obstructing Mario from view, and calculates a new yaw that the camera should
7081
* rotate towards.
7082
*
7083
* @param[out] avoidYaw the angle (from Mario) that the camera should rotate towards to avoid the wall.
7084
* The camera then approaches avoidYaw until Mario is no longer obstructed.
7085
* avoidYaw is always parallel to the wall.
7086
* @param yawRange how wide of an arc to check for walls obscuring Mario.
7087
*
7088
* @return 3 if a wall is covering Mario, 1 if a wall is only near the camera.
7089
*/
7090
s32 rotate_camera_around_walls(struct Camera *c, Vec3f cPos, s16 *avoidYaw, s16 yawRange) {
7091
UNUSED f32 unused1;
7092
struct WallCollisionData colData;
7093
struct Surface *wall;
7094
UNUSED Vec3f unused2;
7095
f32 dummyDist, checkDist;
7096
UNUSED f32 unused3;
7097
f32 coarseRadius;
7098
f32 fineRadius;
7099
s16 wallYaw, horWallNorm;
7100
UNUSED s16 unused4;
7101
s16 dummyPitch;
7102
// The yaw of the vector from Mario to the camera.
7103
s16 yawFromMario;
7104
UNUSED s16 unused5;
7105
s32 status = 0;
7106
/// The current iteration. The algorithm takes 8 equal steps from Mario back to the camera.
7107
s32 step = 0;
7108
UNUSED s32 unused6;
7109
7110
vec3f_get_dist_and_angle(sMarioCamState->pos, cPos, &dummyDist, &dummyPitch, &yawFromMario);
7111
sStatusFlags &= ~CAM_FLAG_CAM_NEAR_WALL;
7112
colData.offsetY = 100.0f;
7113
// The distance from Mario to Lakitu
7114
checkDist = 0.0f;
7115
/// The radius used to find potential walls to avoid.
7116
/// @bug Increases to 250.f, but the max collision radius is 200.f
7117
coarseRadius = 150.0f;
7118
/// This only increases when there is a wall collision found in the coarse pass
7119
fineRadius = 100.0f;
7120
7121
for (step = 0; step < 8; step++) {
7122
// Start at Mario, move backwards to Lakitu's position
7123
colData.x = sMarioCamState->pos[0] + ((cPos[0] - sMarioCamState->pos[0]) * checkDist);
7124
colData.y = sMarioCamState->pos[1] + ((cPos[1] - sMarioCamState->pos[1]) * checkDist);
7125
colData.z = sMarioCamState->pos[2] + ((cPos[2] - sMarioCamState->pos[2]) * checkDist);
7126
colData.radius = coarseRadius;
7127
// Increase the coarse check radius
7128
camera_approach_f32_symmetric_bool(&coarseRadius, 250.f, 30.f);
7129
7130
if (find_wall_collisions(&colData) != 0) {
7131
wall = colData.walls[colData.numWalls - 1];
7132
7133
// If we're over halfway from Mario to Lakitu, then there's a wall near the camera, but
7134
// not necessarily obstructing Mario
7135
if (step >= 5) {
7136
sStatusFlags |= CAM_FLAG_CAM_NEAR_WALL;
7137
if (status <= 0) {
7138
status = 1;
7139
wall = colData.walls[colData.numWalls - 1];
7140
// wallYaw is parallel to the wall, not perpendicular
7141
wallYaw = atan2s(wall->normal.z, wall->normal.x) + DEGREES(90);
7142
// Calculate the avoid direction. The function returns the opposite direction so add 180
7143
// degrees.
7144
*avoidYaw = calc_avoid_yaw(yawFromMario, wallYaw) + DEGREES(180);
7145
}
7146
}
7147
7148
colData.x = sMarioCamState->pos[0] + ((cPos[0] - sMarioCamState->pos[0]) * checkDist);
7149
colData.y = sMarioCamState->pos[1] + ((cPos[1] - sMarioCamState->pos[1]) * checkDist);
7150
colData.z = sMarioCamState->pos[2] + ((cPos[2] - sMarioCamState->pos[2]) * checkDist);
7151
colData.radius = fineRadius;
7152
// Increase the fine check radius
7153
camera_approach_f32_symmetric_bool(&fineRadius, 200.f, 20.f);
7154
7155
if (find_wall_collisions(&colData) != 0) {
7156
wall = colData.walls[colData.numWalls - 1];
7157
horWallNorm = atan2s(wall->normal.z, wall->normal.x);
7158
wallYaw = horWallNorm + DEGREES(90);
7159
// If Mario would be blocked by the surface, then avoid it
7160
if ((is_range_behind_surface(sMarioCamState->pos, cPos, wall, yawRange, SURFACE_WALL_MISC) == 0)
7161
&& (is_mario_behind_surface(c, wall) == TRUE)
7162
// Also check if the wall is tall enough to cover Mario
7163
&& (is_surf_within_bounding_box(wall, -1.f, 150.f, -1.f) == FALSE)) {
7164
// Calculate the avoid direction. The function returns the opposite direction so add 180
7165
// degrees.
7166
*avoidYaw = calc_avoid_yaw(yawFromMario, wallYaw) + DEGREES(180);
7167
camera_approach_s16_symmetric_bool(avoidYaw, horWallNorm, yawRange);
7168
status = 3;
7169
step = 8;
7170
}
7171
}
7172
}
7173
checkDist += 0.125f;
7174
}
7175
7176
return status;
7177
}
7178
7179
/**
7180
* Stores type and height of the nearest floor and ceiling to Mario in `pg`
7181
*
7182
* Note: Also finds the water level, but waterHeight is unused
7183
*/
7184
void find_mario_floor_and_ceil(struct PlayerGeometry *pg) {
7185
struct Surface *surf;
7186
s16 tempCheckingSurfaceCollisionsForCamera = gCheckingSurfaceCollisionsForCamera;
7187
gCheckingSurfaceCollisionsForCamera = TRUE;
7188
7189
if (find_floor(sMarioCamState->pos[0], sMarioCamState->pos[1] + 10.f,
7190
sMarioCamState->pos[2], &surf) != FLOOR_LOWER_LIMIT) {
7191
pg->currFloorType = surf->type;
7192
} else {
7193
pg->currFloorType = 0;
7194
}
7195
7196
if (find_ceil(sMarioCamState->pos[0], sMarioCamState->pos[1] - 10.f,
7197
sMarioCamState->pos[2], &surf) != CELL_HEIGHT_LIMIT) {
7198
pg->currCeilType = surf->type;
7199
} else {
7200
pg->currCeilType = 0;
7201
}
7202
7203
gCheckingSurfaceCollisionsForCamera = FALSE;
7204
pg->currFloorHeight = find_floor(sMarioCamState->pos[0],
7205
sMarioCamState->pos[1] + 10.f,
7206
sMarioCamState->pos[2], &pg->currFloor);
7207
pg->currCeilHeight = find_ceil(sMarioCamState->pos[0],
7208
sMarioCamState->pos[1] - 10.f,
7209
sMarioCamState->pos[2], &pg->currCeil);
7210
pg->waterHeight = find_water_level(sMarioCamState->pos[0], sMarioCamState->pos[2]);
7211
gCheckingSurfaceCollisionsForCamera = tempCheckingSurfaceCollisionsForCamera;
7212
}
7213
7214
/**
7215
* Start a cutscene focusing on an object
7216
* This will play if nothing else happened in the same frame, like exiting or warping.
7217
*/
7218
void start_object_cutscene(u8 cutscene, struct Object *o) {
7219
sObjectCutscene = cutscene;
7220
gRecentCutscene = 0;
7221
gCutsceneFocus = o;
7222
gObjCutsceneDone = FALSE;
7223
}
7224
7225
/**
7226
* Start a low-priority cutscene without focusing on an object
7227
* This will play if nothing else happened in the same frame, like exiting or warping.
7228
*/
7229
u8 start_object_cutscene_without_focus(u8 cutscene) {
7230
sObjectCutscene = cutscene;
7231
sCutsceneDialogResponse = DIALOG_RESPONSE_NONE;
7232
return 0;
7233
}
7234
7235
s16 unused_dialog_cutscene_response(u8 cutscene) {
7236
// if not in a cutscene, start this one
7237
if ((gCamera->cutscene == 0) && (sObjectCutscene == 0)) {
7238
sObjectCutscene = cutscene;
7239
}
7240
7241
// if playing this cutscene and Mario responded, return the response
7242
if ((gCamera->cutscene == cutscene) && (sCutsceneDialogResponse)) {
7243
return sCutsceneDialogResponse;
7244
} else {
7245
return 0;
7246
}
7247
}
7248
7249
s16 cutscene_object_with_dialog(u8 cutscene, struct Object *o, s16 dialogID) {
7250
s16 response = DIALOG_RESPONSE_NONE;
7251
7252
if ((gCamera->cutscene == 0) && (sObjectCutscene == 0)) {
7253
if (gRecentCutscene != cutscene) {
7254
start_object_cutscene(cutscene, o);
7255
if (dialogID != DIALOG_NONE) {
7256
sCutsceneDialogID = dialogID;
7257
} else {
7258
sCutsceneDialogID = DIALOG_001;
7259
}
7260
} else {
7261
response = sCutsceneDialogResponse;
7262
}
7263
7264
gRecentCutscene = 0;
7265
}
7266
return response;
7267
}
7268
7269
s16 cutscene_object_without_dialog(u8 cutscene, struct Object *o) {
7270
s16 response = cutscene_object_with_dialog(cutscene, o, DIALOG_NONE);
7271
return response;
7272
}
7273
7274
/**
7275
* @return 0 if not started, 1 if started, and -1 if finished
7276
*/
7277
s16 cutscene_object(u8 cutscene, struct Object *o) {
7278
s16 status = 0;
7279
7280
if ((gCamera->cutscene == 0) && (sObjectCutscene == 0)) {
7281
if (gRecentCutscene != cutscene) {
7282
start_object_cutscene(cutscene, o);
7283
status = 1;
7284
} else {
7285
status = -1;
7286
}
7287
}
7288
return status;
7289
}
7290
7291
/**
7292
* Update the camera's yaw and nextYaw. This is called from cutscenes to ignore the camera mode's yaw.
7293
*/
7294
void update_camera_yaw(struct Camera *c) {
7295
c->nextYaw = calculate_yaw(c->focus, c->pos);
7296
c->yaw = c->nextYaw;
7297
}
7298
7299
void cutscene_reset_spline(void) {
7300
sCutsceneSplineSegment = 0;
7301
sCutsceneSplineSegmentProgress = 0;
7302
}
7303
7304
void stop_cutscene_and_retrieve_stored_info(struct Camera *c) {
7305
gCutsceneTimer = CUTSCENE_STOP;
7306
c->cutscene = 0;
7307
vec3f_copy(c->focus, sCameraStoreCutscene.focus);
7308
vec3f_copy(c->pos, sCameraStoreCutscene.pos);
7309
}
7310
7311
void cap_switch_save(s16 dummy) {
7312
UNUSED s16 unused = dummy;
7313
save_file_do_save(gCurrSaveFileNum - 1);
7314
}
7315
7316
void init_spline_point(struct CutsceneSplinePoint *splinePoint, s8 index, u8 speed, Vec3s point) {
7317
splinePoint->index = index;
7318
splinePoint->speed = speed;
7319
vec3s_copy(splinePoint->point, point);
7320
}
7321
7322
// TODO: (Scrub C)
7323
void copy_spline_segment(struct CutsceneSplinePoint dst[], struct CutsceneSplinePoint src[]) {
7324
s32 j = 0;
7325
s32 i = 0;
7326
UNUSED s32 pad[2];
7327
7328
init_spline_point(&dst[i], src[j].index, src[j].speed, src[j].point);
7329
i += 1;
7330
do {
7331
do {
7332
init_spline_point(&dst[i], src[j].index, src[j].speed, src[j].point);
7333
i += 1;
7334
j += 1;
7335
} while ((src[j].index != -1) && (src[j].index != -1)); //! same comparison performed twice
7336
} while (j > 16);
7337
7338
// Create the end of the spline by duplicating the last point
7339
do { init_spline_point(&dst[i], 0, src[j].speed, src[j].point); } while (0);
7340
do { init_spline_point(&dst[i + 1], 0, 0, src[j].point); } while (0);
7341
do { init_spline_point(&dst[i + 2], 0, 0, src[j].point); } while (0);
7342
do { init_spline_point(&dst[i + 3], -1, 0, src[j].point); } while (0);
7343
}
7344
7345
/**
7346
* Triggers Mario to enter a dialog state. This is used to make Mario look at the focus of a cutscene,
7347
* for example, bowser.
7348
* @param state 0 = stop, 1 = start, 2 = start and look up, and 3 = start and look down
7349
*
7350
* @return if Mario left the dialog state, return CUTSCENE_LOOP, else return gCutsceneTimer
7351
*/
7352
s16 cutscene_common_set_dialog_state(s32 state) {
7353
s16 timer = gCutsceneTimer;
7354
// If the dialog ended, return CUTSCENE_LOOP, which would end the cutscene shot
7355
if (set_mario_npc_dialog(state) == MARIO_DIALOG_STATUS_SPEAK) {
7356
timer = CUTSCENE_LOOP;
7357
}
7358
return timer;
7359
}
7360
7361
/// Unused SSL cutscene?
7362
static UNUSED void unused_cutscene_mario_dialog_looking_down(UNUSED struct Camera *c) {
7363
gCutsceneTimer = cutscene_common_set_dialog_state(MARIO_DIALOG_LOOK_DOWN);
7364
}
7365
7366
/**
7367
* Cause Mario to enter the normal dialog state.
7368
*/
7369
static BAD_RETURN(s32) cutscene_mario_dialog(UNUSED struct Camera *c) {
7370
gCutsceneTimer = cutscene_common_set_dialog_state(MARIO_DIALOG_LOOK_FRONT);
7371
}
7372
7373
/// Unused SSL cutscene?
7374
static UNUSED void unused_cutscene_mario_dialog_looking_up(UNUSED struct Camera *c) {
7375
gCutsceneTimer = cutscene_common_set_dialog_state(MARIO_DIALOG_LOOK_UP);
7376
}
7377
7378
/**
7379
* Lower the volume (US only) and start the peach letter background music
7380
*/
7381
BAD_RETURN(s32) cutscene_intro_peach_start_letter_music(UNUSED struct Camera *c) {
7382
#if defined(VERSION_US) || defined(VERSION_SH)
7383
seq_player_lower_volume(SEQ_PLAYER_LEVEL, 60, 40);
7384
#endif
7385
cutscene_intro_peach_play_message_music();
7386
}
7387
7388
/**
7389
* Raise the volume (not in JP) and start the flying music.
7390
*/
7391
BAD_RETURN(s32) cutscene_intro_peach_start_flying_music(UNUSED struct Camera *c) {
7392
#ifndef VERSION_JP
7393
seq_player_unlower_volume(SEQ_PLAYER_LEVEL, 60);
7394
#endif
7395
cutscene_intro_peach_play_lakitu_flying_music();
7396
}
7397
7398
#ifdef VERSION_EU
7399
/**
7400
* Lower the volume for the letter background music. In US, this happens on the same frame as the music
7401
* starts.
7402
*/
7403
BAD_RETURN(s32) cutscene_intro_peach_eu_lower_volume(UNUSED struct Camera *c) {
7404
seq_player_lower_volume(SEQ_PLAYER_LEVEL, 60, 40);
7405
}
7406
#endif
7407
7408
void reset_pan_distance(UNUSED struct Camera *c) {
7409
sPanDistance = 0;
7410
}
7411
7412
/**
7413
* Easter egg: the player 2 controller can move the camera's focus in the ending and credits.
7414
*/
7415
void player2_rotate_cam(struct Camera *c, s16 minPitch, s16 maxPitch, s16 minYaw, s16 maxYaw) {
7416
f32 distCamToFocus;
7417
s16 pitch, yaw, pitchCap;
7418
7419
// Change the camera rotation to match the 2nd player's stick
7420
approach_s16_asymptotic_bool(&sCreditsPlayer2Yaw, -(s16)(gPlayer1Controller->stick2X * 250.f), 4);
7421
approach_s16_asymptotic_bool(&sCreditsPlayer2Pitch, -(s16)(gPlayer1Controller->stick2Y * 265.f), 4);
7422
vec3f_get_dist_and_angle(c->pos, c->focus, &distCamToFocus, &pitch, &yaw);
7423
7424
pitchCap = 0x3800 - pitch; if (pitchCap < 0) {
7425
pitchCap = 0;
7426
}
7427
if (maxPitch > pitchCap) {
7428
maxPitch = pitchCap;
7429
}
7430
7431
pitchCap = -0x3800 - pitch;
7432
if (pitchCap > 0) {
7433
pitchCap = 0;
7434
}
7435
if (minPitch < pitchCap) {
7436
minPitch = pitchCap;
7437
}
7438
7439
if (sCreditsPlayer2Pitch > maxPitch) {
7440
sCreditsPlayer2Pitch = maxPitch;
7441
}
7442
if (sCreditsPlayer2Pitch < minPitch) {
7443
sCreditsPlayer2Pitch = minPitch;
7444
}
7445
7446
if (sCreditsPlayer2Yaw > maxYaw) {
7447
sCreditsPlayer2Yaw = maxYaw;
7448
}
7449
if (sCreditsPlayer2Yaw < minYaw) {
7450
sCreditsPlayer2Yaw = minYaw;
7451
}
7452
7453
pitch += sCreditsPlayer2Pitch;
7454
yaw += sCreditsPlayer2Yaw;
7455
vec3f_set_dist_and_angle(c->pos, sPlayer2FocusOffset, distCamToFocus, pitch, yaw);
7456
vec3f_sub(sPlayer2FocusOffset, c->focus);
7457
}
7458
7459
/**
7460
* Store camera info for the cannon opening cutscene
7461
*/
7462
void store_info_cannon(struct Camera *c) {
7463
vec3f_copy(sCameraStoreCutscene.pos, c->pos);
7464
vec3f_copy(sCameraStoreCutscene.focus, c->focus);
7465
sCameraStoreCutscene.panDist = sPanDistance;
7466
sCameraStoreCutscene.cannonYOffset = sCannonYOffset;
7467
}
7468
7469
/**
7470
* Retrieve camera info for the cannon opening cutscene
7471
*/
7472
void retrieve_info_cannon(struct Camera *c) {
7473
vec3f_copy(c->pos, sCameraStoreCutscene.pos);
7474
vec3f_copy(c->focus, sCameraStoreCutscene.focus);
7475
sPanDistance = sCameraStoreCutscene.panDist;
7476
sCannonYOffset = sCameraStoreCutscene.cannonYOffset;
7477
}
7478
7479
/**
7480
* Store camera info for the star spawn cutscene
7481
*/
7482
void store_info_star(struct Camera *c) {
7483
reset_pan_distance(c);
7484
vec3f_copy(sCameraStoreCutscene.pos, c->pos);
7485
sCameraStoreCutscene.focus[0] = sMarioCamState->pos[0];
7486
sCameraStoreCutscene.focus[1] = c->focus[1];
7487
sCameraStoreCutscene.focus[2] = sMarioCamState->pos[2];
7488
}
7489
7490
/**
7491
* Retrieve camera info for the star spawn cutscene
7492
*/
7493
void retrieve_info_star(struct Camera *c) {
7494
vec3f_copy(c->pos, sCameraStoreCutscene.pos);
7495
vec3f_copy(c->focus, sCameraStoreCutscene.focus);
7496
}
7497
7498
static UNUSED void unused_vec3s_to_vec3f(Vec3f dst, Vec3s src) {
7499
dst[0] = src[0];
7500
dst[1] = src[1];
7501
dst[2] = src[2];
7502
}
7503
7504
static UNUSED void unused_vec3f_to_vec3s(Vec3s dst, Vec3f src) {
7505
// note: unlike vec3f_to_vec3s(), this function doesn't round the numbers and instead simply
7506
// truncates them
7507
dst[0] = src[0];
7508
dst[1] = src[1];
7509
dst[2] = src[2];
7510
}
7511
7512
/**
7513
* Rotate the camera's focus around the camera's position by incYaw and incPitch
7514
*/
7515
void pan_camera(struct Camera *c, s16 incPitch, s16 incYaw) {
7516
UNUSED Vec3f unused1;
7517
f32 distCamToFocus;
7518
s16 pitch, yaw;
7519
7520
vec3f_get_dist_and_angle(c->pos, c->focus, &distCamToFocus, &pitch, &yaw);
7521
pitch += incPitch; yaw += incYaw;
7522
vec3f_set_dist_and_angle(c->pos, c->focus, distCamToFocus, pitch, yaw);
7523
}
7524
7525
BAD_RETURN(s32) cutscene_shake_explosion(UNUSED struct Camera *c) {
7526
set_environmental_camera_shake(SHAKE_ENV_EXPLOSION);
7527
cutscene_set_fov_shake_preset(1);
7528
}
7529
7530
static UNUSED void unused_start_bowser_bounce_shake(UNUSED struct Camera *c) {
7531
set_environmental_camera_shake(SHAKE_ENV_BOWSER_THROW_BOUNCE);
7532
}
7533
7534
/**
7535
* Change the spherical coordinates of `to` relative to `from` by `incDist`, `incPitch`, and `incYaw`
7536
*
7537
* @param from the base position
7538
* @param[out] to the destination position
7539
*/
7540
void rotate_and_move_vec3f(Vec3f to, Vec3f from, f32 incDist, s16 incPitch, s16 incYaw) {
7541
f32 dist;
7542
s16 pitch, yaw;
7543
7544
vec3f_get_dist_and_angle(from, to, &dist, &pitch, &yaw);
7545
pitch += incPitch;
7546
yaw += incYaw;
7547
dist += incDist;
7548
vec3f_set_dist_and_angle(from, to, dist, pitch, yaw);
7549
}
7550
7551
void set_flag_post_door(struct Camera *c) {
7552
sStatusFlags |= CAM_FLAG_BEHIND_MARIO_POST_DOOR;
7553
sCameraYawAfterDoorCutscene = calculate_yaw(c->focus, c->pos);
7554
}
7555
7556
void cutscene_soften_music(UNUSED struct Camera *c) {
7557
seq_player_lower_volume(SEQ_PLAYER_LEVEL, 60, 40);
7558
}
7559
7560
void cutscene_unsoften_music(UNUSED struct Camera *c) {
7561
seq_player_unlower_volume(SEQ_PLAYER_LEVEL, 60);
7562
}
7563
7564
UNUSED static void stub_camera_5(UNUSED struct Camera *c) {
7565
}
7566
7567
BAD_RETURN(s32) cutscene_unused_start(UNUSED struct Camera *c) {
7568
}
7569
7570
BAD_RETURN(s32) cutscene_unused_loop(UNUSED struct Camera *c) {
7571
}
7572
7573
/**
7574
* Set the camera position and focus for when Mario falls from the sky.
7575
*/
7576
BAD_RETURN(s32) cutscene_ending_mario_fall_start(struct Camera *c) {
7577
vec3f_set(c->focus, -26.f, 0.f, -137.f);
7578
vec3f_set(c->pos, 165.f, 4725.f, 324.f);
7579
skip_camera_interpolation();
7580
}
7581
7582
/**
7583
* Focus on Mario when he's falling from the sky.
7584
*/
7585
BAD_RETURN(s32) cutscene_ending_mario_fall_focus_mario(struct Camera *c) {
7586
Vec3f offset;
7587
vec3f_set(offset, 0.f, 80.f, 0.f);
7588
7589
offset[2] = ABS(sMarioCamState->pos[1] - c->pos[1]) * -0.1f;
7590
if (offset[2] > -100.f) {
7591
offset[2] = -100.f;
7592
}
7593
7594
offset_rotated(c->focus, sMarioCamState->pos, offset, sMarioCamState->faceAngle);
7595
}
7596
7597
/**
7598
* Mario falls from the sky after the grand star cutscene.
7599
*/
7600
BAD_RETURN(s32) cutscene_ending_mario_fall(struct Camera *c) {
7601
cutscene_event(cutscene_ending_mario_fall_start, c, 0, 0);
7602
cutscene_event(cutscene_ending_mario_fall_focus_mario, c, 0, -1);
7603
player2_rotate_cam(c, -0x2000, 0x2000, -0x2000, 0x2000);
7604
}
7605
7606
/**
7607
* Closeup of Mario as the wing cap fades and Mario looks up.
7608
*/
7609
BAD_RETURN(s32) cutscene_ending_mario_land_closeup(struct Camera *c) {
7610
vec3f_set(c->focus, 85.f, 826.f, 250.f);
7611
vec3f_set(c->pos, -51.f, 988.f, -202.f);
7612
skip_camera_interpolation();
7613
player2_rotate_cam(c, -0x2000, 0x2000, -0x2000, 0x2000);
7614
}
7615
7616
/**
7617
* Reset the spline progress and cvar9.
7618
*/
7619
BAD_RETURN(s32) cutscene_ending_reset_spline(UNUSED struct Camera *c) {
7620
sCutsceneVars[9].point[0] = 0.f;
7621
cutscene_reset_spline();
7622
skip_camera_interpolation();
7623
}
7624
7625
/**
7626
* Follow sEndingFlyToWindowPos/Focus up to the window.
7627
*/
7628
BAD_RETURN(s32) cutscene_ending_fly_up_to_window(struct Camera *c) {
7629
move_point_along_spline(c->pos, sEndingFlyToWindowPos, &sCutsceneSplineSegment, &sCutsceneSplineSegmentProgress);
7630
move_point_along_spline(c->focus, sEndingFlyToWindowFocus, &sCutsceneSplineSegment, &sCutsceneSplineSegmentProgress);
7631
}
7632
7633
/**
7634
* Move the camera up to the window as the star power frees peach.
7635
*/
7636
BAD_RETURN(s32) cutscene_ending_stars_free_peach(struct Camera *c) {
7637
cutscene_event(cutscene_ending_reset_spline, c, 0, 0);
7638
cutscene_event(cutscene_ending_fly_up_to_window, c, 0, -1);
7639
player2_rotate_cam(c, -0x2000, 0x2000, -0x2000, 0x2000);
7640
}
7641
7642
/**
7643
* Move the camera to the ground as Mario lands.
7644
*/
7645
BAD_RETURN(s32) cutscene_ending_mario_land(struct Camera *c) {
7646
vec3f_set(c->focus, sEndingFlyToWindowFocus[0].point[0], sEndingFlyToWindowFocus[0].point[1] + 80.f, sEndingFlyToWindowFocus[0].point[2]);
7647
vec3f_set(c->pos, sEndingFlyToWindowPos[0].point[0], sEndingFlyToWindowPos[0].point[1], sEndingFlyToWindowPos[0].point[2] + 150.f);
7648
player2_rotate_cam(c, -0x800, 0x2000, -0x2000, 0x2000);
7649
}
7650
7651
/**
7652
* Move the camera closer to peach appearing.
7653
*/
7654
BAD_RETURN(s32) cutscene_ending_peach_appear_closeup(struct Camera *c) {
7655
vec3f_set(c->pos, 179.f, 2463.f, -1216.f);
7656
c->pos[1] = gCutsceneFocus->oPosY + 35.f;
7657
vec3f_set(c->focus, gCutsceneFocus->oPosX, gCutsceneFocus->oPosY + 125.f, gCutsceneFocus->oPosZ);
7658
skip_camera_interpolation();
7659
}
7660
7661
/**
7662
* Peach fades in, the camera focuses on her.
7663
*/
7664
BAD_RETURN(s32) cutscene_ending_peach_appears(struct Camera *c) {
7665
cutscene_event(cutscene_ending_peach_appear_closeup, c, 0, 0);
7666
approach_f32_asymptotic_bool(&c->pos[1], gCutsceneFocus->oPosY + 35.f, 0.02f);
7667
approach_f32_asymptotic_bool(&c->focus[1], gCutsceneFocus->oPosY + 125.f, 0.15f);
7668
player2_rotate_cam(c, -0x2000, 0x2000, -0x2000, 0x2000);
7669
}
7670
7671
/**
7672
* Reset spline progress, set cvar2 y offset.
7673
*/
7674
BAD_RETURN(s32) cutscene_ending_peach_descends_start(UNUSED struct Camera *c) {
7675
cutscene_reset_spline();
7676
sCutsceneVars[2].point[1] = 150.f;
7677
skip_camera_interpolation();
7678
}
7679
7680
/**
7681
* Follow the sEndingPeachDescentCamPos spline, which rotates around peach.
7682
*/
7683
BAD_RETURN(s32) cutscene_ending_follow_peach_descent(struct Camera *c) {
7684
move_point_along_spline(c->pos, sEndingPeachDescentCamPos, &sCutsceneSplineSegment, &sCutsceneSplineSegmentProgress);
7685
c->pos[1] += gCutsceneFocus->oPosY + sCutsceneVars[3].point[1];
7686
}
7687
7688
/**
7689
* Decrease cvar2's y offset while the camera flies backwards to Mario.
7690
*/
7691
BAD_RETURN(s32) cutscene_ending_peach_descent_lower_focus(UNUSED struct Camera *c) {
7692
camera_approach_f32_symmetric_bool(&(sCutsceneVars[2].point[1]), 90.f, 0.5f);
7693
}
7694
7695
/**
7696
* Keep following the sEndingPeachDescentCamPos spline, which leads back to Mario.
7697
*/
7698
BAD_RETURN(s32) cutscene_ending_peach_descent_back_to_mario(struct Camera *c) {
7699
Vec3f pos;
7700
7701
move_point_along_spline(pos, sEndingPeachDescentCamPos, &sCutsceneSplineSegment, &sCutsceneSplineSegmentProgress);
7702
c->pos[0] = pos[0];
7703
c->pos[2] = pos[2];
7704
approach_f32_asymptotic_bool(&c->pos[1], (pos[1] += gCutsceneFocus->oPosY), 0.07f);
7705
}
7706
7707
/**
7708
* Peach starts floating to the ground. Rotate the camera around her, then fly backwards to Mario when
7709
* she lands.
7710
*/
7711
BAD_RETURN(s32) cutscene_ending_peach_descends(struct Camera *c) {
7712
cutscene_event(cutscene_ending_peach_descends_start, c, 0, 0);
7713
cutscene_event(cutscene_ending_follow_peach_descent, c, 0, 299);
7714
cutscene_event(cutscene_ending_peach_descent_back_to_mario, c, 300, -1);
7715
cutscene_event(cutscene_ending_peach_descent_lower_focus, c, 300, -1);
7716
vec3f_set(c->focus, gCutsceneFocus->oPosX, sCutsceneVars[2].point[1] + gCutsceneFocus->oPosY,
7717
gCutsceneFocus->oPosZ);
7718
player2_rotate_cam(c, -0x2000, 0x2000, -0x2000, 0x2000);
7719
}
7720
7721
/**
7722
* Mario runs across the bridge to peach, and takes off his cap.
7723
* Follow the sEndingMarioToPeach* splines while Mario runs across.
7724
*/
7725
BAD_RETURN(s32) cutscene_ending_mario_to_peach(struct Camera *c) {
7726
cutscene_event(cutscene_ending_reset_spline, c, 0, 0);
7727
move_point_along_spline(c->pos, sEndingMarioToPeachPos, &sCutsceneSplineSegment, &sCutsceneSplineSegmentProgress);
7728
move_point_along_spline(c->focus, sEndingMarioToPeachFocus, &sCutsceneSplineSegment, &sCutsceneSplineSegmentProgress);
7729
player2_rotate_cam(c, -0x2000, 0x2000, -0x2000, 0x2000);
7730
}
7731
7732
/**
7733
* Make the focus follow the sEndingLookUpAtCastle spline.
7734
*/
7735
BAD_RETURN(s32) cutscene_ending_look_up_at_castle(UNUSED struct Camera *c) {
7736
move_point_along_spline(c->focus, sEndingLookUpAtCastle, &sCutsceneSplineSegment, &sCutsceneSplineSegmentProgress);
7737
}
7738
7739
/**
7740
* Peach opens her eyes and the camera looks at the castle window again.
7741
*/
7742
BAD_RETURN(s32) cutscene_ending_peach_wakeup(struct Camera *c) {
7743
cutscene_event(cutscene_ending_reset_spline, c, 0, 0);
7744
cutscene_event(cutscene_ending_look_up_at_castle, c, 0, 0);
7745
#ifdef VERSION_EU
7746
cutscene_event(cutscene_ending_look_up_at_castle, c, 265, -1);
7747
cutscene_spawn_obj(7, 315);
7748
cutscene_spawn_obj(9, 355);
7749
#else
7750
cutscene_event(cutscene_ending_look_up_at_castle, c, 250, -1);
7751
cutscene_spawn_obj(7, 300);
7752
cutscene_spawn_obj(9, 340);
7753
#endif
7754
vec3f_set(c->pos, -163.f, 978.f, -1082.f);
7755
player2_rotate_cam(c, -0x800, 0x2000, -0x2000, 0x2000);
7756
}
7757
7758
/**
7759
* Side view of peach and Mario. Peach thanks Mario for saving her.
7760
*/
7761
BAD_RETURN(s32) cutscene_ending_dialog(struct Camera *c) {
7762
vec3f_set(c->focus, 11.f, 983.f, -1273.f);
7763
vec3f_set(c->pos, -473.f, 970.f, -1152.f);
7764
skip_camera_interpolation();
7765
player2_rotate_cam(c, -0x800, 0x2000, -0x2000, 0x2000);
7766
}
7767
7768
/**
7769
* Zoom in and move the camera close to Mario and peach.
7770
*/
7771
BAD_RETURN(s32) cutscene_ending_kiss_closeup(struct Camera *c) {
7772
set_fov_function(CAM_FOV_SET_29);
7773
vec3f_set(c->focus, 350.f, 1034.f, -1216.f);
7774
vec3f_set(c->pos, -149.f, 1021.f, -1216.f);
7775
skip_camera_interpolation();
7776
}
7777
7778
/**
7779
* Fly back and zoom out for Mario's spin after the kiss.
7780
*/
7781
BAD_RETURN(s32) cutscene_ending_kiss_here_we_go(struct Camera *c) {
7782
Vec3f pos, foc;
7783
7784
set_fov_function(CAM_FOV_DEFAULT);
7785
vec3f_set(foc, 233.f, 1068.f, -1298.f);
7786
vec3f_set(pos, -250.f, 966.f, -1111.f);
7787
//! another double typo
7788
approach_vec3f_asymptotic(c->pos, pos, 0.2, 0.1f, 0.2f);
7789
approach_vec3f_asymptotic(c->focus, foc, 0.2, 0.1f, 0.2f);
7790
}
7791
7792
/**
7793
* Peach kisses Mario on the nose.
7794
*/
7795
BAD_RETURN(s32) cutscene_ending_kiss(struct Camera *c) {
7796
cutscene_event(cutscene_ending_kiss_closeup, c, 0, 0);
7797
#ifdef VERSION_EU
7798
cutscene_event(cutscene_ending_kiss_here_we_go, c, 185, -1);
7799
#else
7800
cutscene_event(cutscene_ending_kiss_here_we_go, c, 155, -1);
7801
#endif
7802
player2_rotate_cam(c, -0x800, 0x2000, -0x2000, 0x2000);
7803
}
7804
7805
/**
7806
* Make the focus follow sEndingLookAtSkyFocus.
7807
*/
7808
BAD_RETURN(s32) cutscene_ending_look_at_sky(struct Camera *c) {
7809
move_point_along_spline(c->focus, sEndingLookAtSkyFocus, &sCutsceneSplineSegment, &sCutsceneSplineSegmentProgress);
7810
vec3f_set(c->pos, 699.f, 1680.f, -703.f);
7811
skip_camera_interpolation();
7812
}
7813
7814
/**
7815
* Zoom in the fov. The fovFunc was just set to default, so it wants to approach 45. But while this is
7816
* called, it will stay at about 37.26f
7817
*/
7818
BAD_RETURN(s32) cutscene_ending_zoom_fov(UNUSED struct Camera *c) {
7819
sFOVState.fov = 37.f;
7820
}
7821
7822
/**
7823
* Peach suggests baking a cake for Mario. Mario looks back at the camera before going inside the castle.
7824
*/
7825
BAD_RETURN(s32) cutscene_ending_cake_for_mario(struct Camera *c) {
7826
cutscene_event(cutscene_ending_reset_spline, c, 0, 0);
7827
cutscene_event(cutscene_ending_look_at_sky, c, 0, 0);
7828
cutscene_event(cutscene_ending_zoom_fov, c, 0, 499);
7829
cutscene_event(cutscene_ending_look_at_sky, c, 500, -1);
7830
cutscene_spawn_obj(8, 600);
7831
cutscene_spawn_obj(8, 608);
7832
cutscene_spawn_obj(8, 624);
7833
cutscene_spawn_obj(8, 710);
7834
}
7835
7836
/**
7837
* Stop the ending cutscene, reset the fov.
7838
*/
7839
BAD_RETURN(s32) cutscene_ending_stop(struct Camera *c) {
7840
set_fov_function(CAM_FOV_SET_45);
7841
c->cutscene = 0;
7842
gCutsceneTimer = CUTSCENE_STOP;
7843
}
7844
7845
/**
7846
* Start the grand star cutscene.
7847
* cvar0 is a relative offset from Mario.
7848
* cvar1 is the is the camera's goal position.
7849
*/
7850
BAD_RETURN(s32) cutscene_grand_star_start(UNUSED struct Camera *c) {
7851
vec3f_set(sCutsceneVars[0].point, 0.f, 150.f, -600.f);
7852
offset_rotated(sCutsceneVars[1].point, sMarioCamState->pos, sCutsceneVars[0].point, sMarioCamState->faceAngle);
7853
sCutsceneVars[1].point[1] = 457.f;
7854
}
7855
7856
/**
7857
* Make the camera fly to the front of Mario.
7858
*/
7859
BAD_RETURN(s32) cutscene_grand_star_front_of_mario(struct Camera *c) {
7860
f32 goalDist;
7861
s16 goalPitch, goalYaw;
7862
f32 dist;
7863
s16 pitch, yaw;
7864
7865
vec3f_get_dist_and_angle(sMarioCamState->pos, sCutsceneVars[1].point, &goalDist, &goalPitch, &goalYaw);
7866
vec3f_get_dist_and_angle(sMarioCamState->pos, c->pos, &dist, &pitch, &yaw);
7867
approach_f32_asymptotic_bool(&dist, goalDist, 0.1f);
7868
approach_s16_asymptotic_bool(&pitch, goalPitch, 32);
7869
approach_s16_asymptotic_bool(&yaw, goalYaw + 0x1200, 20);
7870
vec3f_set_dist_and_angle(sMarioCamState->pos, c->pos, dist, pitch, yaw);
7871
}
7872
7873
/**
7874
* Started shortly after Mario starts the triple jump. Stores Mario's face angle and zeros cvar2.
7875
*/
7876
BAD_RETURN(s32) cutscene_grand_star_mario_jump(UNUSED struct Camera *c) {
7877
vec3s_set(sCutsceneVars[0].angle, 0, sMarioCamState->faceAngle[1], 0);
7878
vec3f_set(sCutsceneVars[2].point, 0.f, 0.f, 0.f);
7879
}
7880
7881
/**
7882
* Accelerate cvar2 to point back and to the left (relative to the camera).
7883
*/
7884
BAD_RETURN(s32) cutscene_grand_star_accel_cvar2(UNUSED struct Camera *c) {
7885
camera_approach_f32_symmetric_bool(&sCutsceneVars[2].point[2], -40.f, 2.0f);
7886
sCutsceneVars[2].point[0] = 5.0f;
7887
}
7888
7889
/**
7890
* Decrease cvar2 offset, follow Mario by directly updating the camera's pos.
7891
*/
7892
BAD_RETURN(s32) cutscene_grand_star_approach_mario(struct Camera *c) {
7893
camera_approach_f32_symmetric_bool(&sCutsceneVars[2].point[2], 0.f, 2.f);
7894
sCutsceneVars[2].point[0] = 0.f;
7895
approach_f32_asymptotic_bool(&c->pos[0], sMarioCamState->pos[0], 0.01f);
7896
approach_f32_asymptotic_bool(&c->pos[2], sMarioCamState->pos[2], 0.01f);
7897
}
7898
7899
/**
7900
* Offset the camera's position by cvar2. Before Mario triple jumps, this moves back and to the left.
7901
* After the triple jump, cvar2 decelerates to 0.
7902
*/
7903
BAD_RETURN(s32) cutscene_grand_star_move_cvar2(struct Camera *c) {
7904
offset_rotated(c->pos, c->pos, sCutsceneVars[2].point, sCutsceneVars[0].angle);
7905
}
7906
7907
BAD_RETURN(s32) cutscene_grand_star_focus_mario(struct Camera *c) {
7908
Vec3f foc;
7909
7910
vec3f_set(foc, sMarioCamState->pos[0], (sMarioCamState->pos[1] - 307.f) * 0.5f + 407.f, sMarioCamState->pos[2]);
7911
approach_vec3f_asymptotic(c->focus, foc, 0.5f, 0.8f, 0.5f);
7912
}
7913
7914
/**
7915
* The first part of the grand star cutscene, after Mario has collected the grand star.
7916
*/
7917
BAD_RETURN(s32) cutscene_grand_star(struct Camera *c) {
7918
sStatusFlags |= CAM_FLAG_SMOOTH_MOVEMENT;
7919
cutscene_event(cutscene_grand_star_start, c, 0, 0);
7920
cutscene_event(cutscene_grand_star_front_of_mario, c, 0, 109);
7921
cutscene_event(cutscene_grand_star_focus_mario, c, 0, -1);
7922
cutscene_event(cutscene_grand_star_mario_jump, c, 110, 110);
7923
cutscene_event(cutscene_grand_star_accel_cvar2, c, 110, 159);
7924
cutscene_event(cutscene_grand_star_approach_mario, c, 160, -1);
7925
cutscene_event(cutscene_grand_star_move_cvar2, c, 110, -1);
7926
}
7927
7928
/**
7929
* Zero the cvars that are used when Mario is flying.
7930
*/
7931
BAD_RETURN(s32) cutscene_grand_star_fly_start(struct Camera *c) {
7932
//! cvar7 is unused in grand star
7933
vec3f_set(sCutsceneVars[7].point, 0.5f, 0.5f, 0.5f);
7934
//! cvar6 is unused in grand star
7935
vec3f_set(sCutsceneVars[6].point, 0.01f, 0.01f, 0.01f);
7936
vec3f_set(sCutsceneVars[4].point, 0.f, 0.f, 0.f);
7937
vec3f_set(sCutsceneVars[5].point, 0.f, c->focus[1] - sMarioCamState->pos[1], 0.f);
7938
sCutsceneVars[8].point[2] = 0.f;
7939
sCutsceneVars[8].point[0] = 0.f;
7940
}
7941
7942
/**
7943
* Decrease the cvar offsets so that Lakitu flies closer to Mario.
7944
*/
7945
BAD_RETURN(s32) cutscene_grand_star_fly_move_to_mario(UNUSED struct Camera *c) {
7946
Vec3f posOff;
7947
7948
vec3f_set(posOff, -600.f, 0.f, -400.f);
7949
approach_vec3f_asymptotic(sCutsceneVars[4].point, posOff, 0.05f, 0.05f, 0.05f);
7950
camera_approach_f32_symmetric_bool(&sCutsceneVars[5].point[1], 0.f, 2.f);
7951
camera_approach_f32_symmetric_bool(&sCutsceneVars[5].point[2], -200.f, 6.f);
7952
}
7953
7954
/**
7955
* Gradually increase the cvar offsets so Lakitu flies away. Mario flies offscreen to the right.
7956
*
7957
* cvar4 is the position offset from Mario.
7958
* cvar5 is the focus offset from Mario.
7959
* cvar8.point[0] is the approach velocity.
7960
*/
7961
BAD_RETURN(s32) cutscene_grand_star_fly_mario_offscreen(UNUSED struct Camera *c) {
7962
camera_approach_f32_symmetric_bool(&sCutsceneVars[8].point[0], 15.f, 0.1f);
7963
7964
camera_approach_f32_symmetric_bool(&sCutsceneVars[4].point[0], -2000.f, sCutsceneVars[8].point[0]);
7965
camera_approach_f32_symmetric_bool(&sCutsceneVars[4].point[1], 1200.f, sCutsceneVars[8].point[0] / 10.f);
7966
camera_approach_f32_symmetric_bool(&sCutsceneVars[4].point[2], 1000.f, sCutsceneVars[8].point[0] / 10.f);
7967
7968
camera_approach_f32_symmetric_bool(&sCutsceneVars[5].point[0], 0.f, sCutsceneVars[8].point[0]);
7969
camera_approach_f32_symmetric_bool(&sCutsceneVars[5].point[1], 1200.f, sCutsceneVars[8].point[0] / 2);
7970
camera_approach_f32_symmetric_bool(&sCutsceneVars[5].point[2], 1000.f, sCutsceneVars[8].point[0] / 1.5f);
7971
}
7972
7973
/**
7974
* Make Lakitu approach the cvars.
7975
* cvar4 is the position offset.
7976
* cvar5 is the focus offset.
7977
*/
7978
BAD_RETURN(s32) cutscene_grand_star_fly_app_cvars(struct Camera *c) {
7979
Vec3f goalPos, goalFoc;
7980
f32 dist;
7981
s16 pitch, yaw;
7982
7983
camera_approach_f32_symmetric_bool(&sCutsceneVars[8].point[2], 90.f, 2.5f);
7984
offset_rotated(goalPos, sMarioCamState->pos, sCutsceneVars[4].point, sMarioCamState->faceAngle);
7985
offset_rotated(goalFoc, sMarioCamState->pos, sCutsceneVars[5].point, sMarioCamState->faceAngle);
7986
7987
// Move towards goalPos by cvar8's Z speed
7988
vec3f_get_dist_and_angle(goalPos, c->pos, &dist, &pitch, &yaw);
7989
camera_approach_f32_symmetric_bool(&dist, 0, sCutsceneVars[8].point[2]);
7990
vec3f_set_dist_and_angle(goalPos, c->pos, dist, pitch, yaw);
7991
7992
approach_vec3f_asymptotic(c->pos, goalPos, 0.01f, 0.01f, 0.01f);
7993
approach_vec3f_asymptotic(c->focus, goalFoc, 0.5f, 0.8f, 0.5f);
7994
}
7995
7996
/**
7997
* Part of the grand star cutscene, starts after Mario is flying.
7998
*
7999
* cvar4 and cvar5 are directions, relative to Mario:
8000
* cvar4 is used as the camera position's offset from Mario.
8001
* cvar5 is used as the camera focus's offset from Mario.
8002
*
8003
* cvar8.point[2] is Lakitu's speed.
8004
*/
8005
BAD_RETURN(s32) cutscene_grand_star_fly(struct Camera *c) {
8006
sStatusFlags |= CAM_FLAG_SMOOTH_MOVEMENT;
8007
cutscene_event(cutscene_grand_star_fly_start, c, 0, 0);
8008
cutscene_event(cutscene_grand_star_fly_move_to_mario, c, 0, 140);
8009
cutscene_event(cutscene_grand_star_fly_mario_offscreen, c, 141, -1);
8010
cutscene_event(cutscene_grand_star_fly_app_cvars, c, 0, -1);
8011
}
8012
8013
/**
8014
* Adjust the camera focus towards a point `dist` units in front of Mario.
8015
* @param dist distance in Mario's forward direction. Note that this is relative to Mario, so a negative
8016
* distance will focus in front of Mario, and a positive distance will focus behind him.
8017
*/
8018
void focus_in_front_of_mario(struct Camera *c, f32 dist, f32 speed) {
8019
Vec3f goalFocus, offset;
8020
8021
offset[0] = 0.f;
8022
offset[2] = dist;
8023
offset[1] = 100.f;
8024
8025
offset_rotated(goalFocus, sMarioCamState->pos, offset, sMarioCamState->faceAngle);
8026
approach_vec3f_asymptotic(c->focus, goalFocus, speed, speed, speed);
8027
}
8028
8029
/**
8030
* Approach Mario and look up. Since Mario faces the camera when he collects the star, there's no need
8031
* to worry about the camera's yaw.
8032
*/
8033
BAD_RETURN(s32) cutscene_dance_move_to_mario(struct Camera *c) {
8034
s16 pitch, yaw;
8035
f32 dist;
8036
8037
vec3f_get_dist_and_angle(sMarioCamState->pos, c->pos, &dist, &pitch, &yaw);
8038
approach_f32_asymptotic_bool(&dist, 600.f, 0.3f);
8039
approach_s16_asymptotic_bool(&pitch, 0x1000, 0x10);
8040
vec3f_set_dist_and_angle(sMarioCamState->pos, c->pos, dist, pitch, yaw);
8041
}
8042
8043
BAD_RETURN(s32) cutscene_dance_rotate(struct Camera *c) {
8044
rotate_and_move_vec3f(c->pos, sMarioCamState->pos, 0, 0, 0x200);
8045
}
8046
8047
BAD_RETURN(s32) cutscene_dance_rotate_move_back(struct Camera *c) {
8048
rotate_and_move_vec3f(c->pos, sMarioCamState->pos, -15.f, 0, 0);
8049
}
8050
8051
BAD_RETURN(s32) cutscene_dance_rotate_move_towards_mario(struct Camera *c) {
8052
rotate_and_move_vec3f(c->pos, sMarioCamState->pos, 20.f, 0, 0);
8053
}
8054
8055
/**
8056
* Speculated to be dance-related due to its proximity to the other dance functions
8057
*/
8058
UNUSED static BAD_RETURN(s32) cutscene_dance_unused(UNUSED struct Camera *c) {
8059
}
8060
8061
/**
8062
* Slowly turn to the point 100 units in front of Mario
8063
*/
8064
BAD_RETURN(s32) cutscene_dance_default_focus_mario(struct Camera *c) {
8065
focus_in_front_of_mario(c, -100.f, 0.2f);
8066
}
8067
8068
/**
8069
* Focus twice as far away as default dance, and move faster.
8070
*/
8071
BAD_RETURN(s32) cutscene_dance_rotate_focus_mario(struct Camera *c) {
8072
focus_in_front_of_mario(c, -200.f, 0.03f);
8073
}
8074
8075
BAD_RETURN(s32) cutscene_dance_shake_fov(UNUSED struct Camera *c) {
8076
set_fov_shake(0x200, 0x28, 0x8000);
8077
}
8078
8079
/**
8080
* Handles both the default and rotate dance cutscenes.
8081
* In the default dance: the camera moves closer to Mario, then stays in place.
8082
* In the rotate dance: the camera moves closer and rotates clockwise around Mario.
8083
*/
8084
BAD_RETURN(s32) cutscene_dance_default_rotate(struct Camera *c) {
8085
sStatusFlags |= CAM_FLAG_SMOOTH_MOVEMENT;
8086
sYawSpeed = 0;
8087
set_fov_function(CAM_FOV_DEFAULT);
8088
cutscene_event(cutscene_dance_default_focus_mario, c, 0, 20);
8089
cutscene_event(cutscene_dance_move_to_mario, c, 0, 39);
8090
// Shake the camera on the 4th beat of the music, when Mario gives the peace sign.
8091
cutscene_event(cutscene_dance_shake_fov, c, 40, 40);
8092
8093
if (c->cutscene != CUTSCENE_DANCE_DEFAULT) { // CUTSCENE_DANCE_ROTATE
8094
cutscene_event(cutscene_dance_rotate_focus_mario, c, 75, 102);
8095
cutscene_event(cutscene_dance_rotate, c, 50, -1);
8096
// These two functions move the camera away and then towards Mario.
8097
cutscene_event(cutscene_dance_rotate_move_back, c, 50, 80);
8098
cutscene_event(cutscene_dance_rotate_move_towards_mario, c, 70, 90);
8099
} else {
8100
// secret star, 100 coin star, or bowser red coin star.
8101
if ((sMarioCamState->action != ACT_STAR_DANCE_NO_EXIT)
8102
&& (sMarioCamState->action != ACT_STAR_DANCE_WATER)
8103
&& (sMarioCamState->action != ACT_STAR_DANCE_EXIT)) {
8104
gCutsceneTimer = CUTSCENE_STOP;
8105
c->cutscene = 0;
8106
transition_next_state(c, 20);
8107
sStatusFlags |= CAM_FLAG_UNUSED_CUTSCENE_ACTIVE;
8108
}
8109
}
8110
}
8111
8112
/**
8113
* If the camera's yaw is out of the range of `absYaw` +- `yawMax`, then set the yaw to `absYaw`
8114
*/
8115
BAD_RETURN(s32) star_dance_bound_yaw(struct Camera *c, s16 absYaw, s16 yawMax) {
8116
s16 dummyPitch, yaw;
8117
f32 distCamToMario;
8118
s16 yawFromAbs;
8119
8120
vec3f_get_dist_and_angle(sMarioCamState->pos, c->pos, &distCamToMario, &dummyPitch, &yaw);
8121
yawFromAbs = yaw - absYaw;
8122
8123
// Because angles are s16, this checks if yaw is negative
8124
if ((yawFromAbs & 0x8000) != 0) {
8125
yawFromAbs = -yawFromAbs;
8126
}
8127
if (yawFromAbs > yawMax) {
8128
yaw = absYaw;
8129
c->nextYaw = yaw;
8130
c->yaw = yaw;
8131
}
8132
}
8133
8134
/**
8135
* Start the closeup dance cutscene by restricting the camera's yaw in certain areas.
8136
* Store the camera's focus in cvar9.
8137
*/
8138
BAD_RETURN(s32) cutscene_dance_closeup_start(struct Camera *c) {
8139
UNUSED s32 pad[2];
8140
8141
if ((gLastCompletedStarNum == 4) && (gCurrCourseNum == COURSE_JRB)) {
8142
star_dance_bound_yaw(c, 0x0, 0x4000);
8143
}
8144
if ((gLastCompletedStarNum == 1) && (gCurrCourseNum == COURSE_DDD)) {
8145
star_dance_bound_yaw(c, 0x8000, 0x5000);
8146
}
8147
if ((gLastCompletedStarNum == 5) && (gCurrCourseNum == COURSE_WDW)) {
8148
star_dance_bound_yaw(c, 0x8000, 0x800);
8149
}
8150
8151
vec3f_copy(sCutsceneVars[9].point, c->focus);
8152
//! cvar8 is unused in the closeup cutscene
8153
sCutsceneVars[8].angle[0] = 0x2000;
8154
}
8155
8156
/**
8157
* Focus the camera on Mario eye height.
8158
*/
8159
BAD_RETURN(s32) cutscene_dance_closeup_focus_mario(struct Camera *c) {
8160
Vec3f marioPos;
8161
8162
vec3f_set(marioPos, sMarioCamState->pos[0], sMarioCamState->pos[1] + 125.f, sMarioCamState->pos[2]);
8163
approach_vec3f_asymptotic(sCutsceneVars[9].point, marioPos, 0.2f, 0.2f, 0.2f);
8164
vec3f_copy(c->focus, sCutsceneVars[9].point);
8165
}
8166
8167
/**
8168
* Fly above Mario, looking down.
8169
*/
8170
BAD_RETURN(s32) cutscene_dance_closeup_fly_above(struct Camera *c) {
8171
s16 pitch, yaw;
8172
f32 dist;
8173
s16 goalPitch = 0x1800;
8174
8175
if ((gLastCompletedStarNum == 6 && gCurrCourseNum == COURSE_SL) ||
8176
(gLastCompletedStarNum == 4 && gCurrCourseNum == COURSE_TTC)) {
8177
goalPitch = 0x800;
8178
}
8179
8180
vec3f_get_dist_and_angle(sMarioCamState->pos, c->pos, &dist, &pitch, &yaw);
8181
approach_f32_asymptotic_bool(&dist, 800.f, 0.05f);
8182
approach_s16_asymptotic_bool(&pitch, goalPitch, 16);
8183
approach_s16_asymptotic_bool(&yaw, c->yaw, 8);
8184
vec3f_set_dist_and_angle(sMarioCamState->pos, c->pos, dist, pitch, yaw);
8185
}
8186
8187
/**
8188
* Fly closer right when Mario gives the peace sign.
8189
*/
8190
BAD_RETURN(s32) cutscene_dance_closeup_fly_closer(struct Camera *c) {
8191
s16 pitch, yaw;
8192
f32 dist;
8193
8194
vec3f_get_dist_and_angle(sMarioCamState->pos, c->pos, &dist, &pitch, &yaw);
8195
approach_f32_asymptotic_bool(&dist, 240.f, 0.4f);
8196
approach_s16_asymptotic_bool(&yaw, c->yaw, 8);
8197
approach_s16_asymptotic_bool(&pitch, 0x1000, 5);
8198
vec3f_set_dist_and_angle(sMarioCamState->pos, c->pos, dist, pitch, yaw);
8199
}
8200
8201
/**
8202
* Zoom in by increasing fov to 80 degrees. Most dramatic zoom in the game.
8203
*/
8204
BAD_RETURN(s32) cutscene_dance_closeup_zoom(UNUSED struct Camera *c) {
8205
set_fov_function(CAM_FOV_APP_80);
8206
}
8207
8208
/**
8209
* Shake fov, starts on the first frame Mario has the peace sign up.
8210
*/
8211
BAD_RETURN(s32) cutscene_dance_closeup_shake_fov(UNUSED struct Camera *c) {
8212
set_fov_shake(0x300, 0x30, 0x8000);
8213
}
8214
8215
/**
8216
* The camera moves in for a closeup on Mario. Used for stars that are underwater or in tight places.
8217
*/
8218
BAD_RETURN(s32) cutscene_dance_closeup(struct Camera *c) {
8219
sStatusFlags |= CAM_FLAG_SMOOTH_MOVEMENT;
8220
8221
if (sMarioCamState->action == ACT_STAR_DANCE_WATER) {
8222
cutscene_event(cutscene_dance_closeup_start, c, 0, 0);
8223
cutscene_event(cutscene_dance_closeup_focus_mario, c, 0, -1);
8224
cutscene_event(cutscene_dance_closeup_fly_above, c, 0, 62);
8225
cutscene_event(cutscene_dance_closeup_fly_closer, c, 63, -1);
8226
cutscene_event(cutscene_dance_closeup_zoom, c, 63, 63);
8227
cutscene_event(cutscene_dance_closeup_shake_fov, c, 70, 70);
8228
} else {
8229
cutscene_event(cutscene_dance_closeup_start, c, 0, 0);
8230
cutscene_event(cutscene_dance_closeup_focus_mario, c, 0, -1);
8231
// Almost twice as fast as under water
8232
cutscene_event(cutscene_dance_closeup_fly_above, c, 0, 32);
8233
cutscene_event(cutscene_dance_closeup_fly_closer, c, 33, -1);
8234
cutscene_event(cutscene_dance_closeup_zoom, c, 33, 33);
8235
cutscene_event(cutscene_dance_closeup_shake_fov, c, 40, 40);
8236
}
8237
set_handheld_shake(HAND_CAM_SHAKE_CUTSCENE);
8238
}
8239
8240
/**
8241
* cvar8.point[2] is the amount to increase distance from Mario
8242
*/
8243
BAD_RETURN(s32) cutscene_dance_fly_away_start(struct Camera *c) {
8244
Vec3f areaCenter;
8245
8246
vec3f_copy(sCutsceneVars[9].point, c->focus);
8247
sCutsceneVars[8].point[2] = 65.f;
8248
8249
if (c->mode == CAMERA_MODE_RADIAL) {
8250
vec3f_set(areaCenter, c->areaCenX, c->areaCenY, c->areaCenZ);
8251
c->yaw = calculate_yaw(areaCenter, c->pos);
8252
c->nextYaw = c->yaw;
8253
}
8254
8255
// Restrict the camera yaw in tight spaces
8256
if ((gLastCompletedStarNum == 6) && (gCurrCourseNum == COURSE_CCM)) {
8257
star_dance_bound_yaw(c, 0x5600, 0x800);
8258
}
8259
if ((gLastCompletedStarNum == 2) && (gCurrCourseNum == COURSE_TTM)) {
8260
star_dance_bound_yaw(c, 0x0, 0x800);
8261
}
8262
if ((gLastCompletedStarNum == 1) && (gCurrCourseNum == COURSE_SL)) {
8263
star_dance_bound_yaw(c, 0x2000, 0x800);
8264
}
8265
if ((gLastCompletedStarNum == 3) && (gCurrCourseNum == COURSE_RR)) {
8266
star_dance_bound_yaw(c, 0x0, 0x800);
8267
}
8268
}
8269
8270
BAD_RETURN(s32) cutscene_dance_fly_away_approach_mario(struct Camera *c) {
8271
s16 pitch, yaw;
8272
f32 dist;
8273
8274
vec3f_get_dist_and_angle(sMarioCamState->pos, c->pos, &dist, &pitch, &yaw);
8275
approach_f32_asymptotic_bool(&dist, 600.f, 0.3f);
8276
approach_s16_asymptotic_bool(&pitch, 0x1000, 16);
8277
approach_s16_asymptotic_bool(&yaw, c->yaw, 8);
8278
vec3f_set_dist_and_angle(sMarioCamState->pos, c->pos, dist, pitch, yaw);
8279
}
8280
8281
BAD_RETURN(s32) cutscene_dance_fly_away_focus_mario(struct Camera *c) {
8282
Vec3f marioPos;
8283
8284
vec3f_set(marioPos, sMarioCamState->pos[0], sMarioCamState->pos[1] + 125.f, sMarioCamState->pos[2]);
8285
approach_vec3f_asymptotic(sCutsceneVars[9].point, marioPos, 0.2f, 0.2f, 0.2f);
8286
vec3f_copy(c->focus, sCutsceneVars[9].point);
8287
}
8288
8289
/**
8290
* Slowly pan the camera downwards and to the camera's right, using cvar9's angle.
8291
*/
8292
void cutscene_pan_cvar9(struct Camera *c) {
8293
vec3f_copy(c->focus, sCutsceneVars[9].point);
8294
sCutsceneVars[9].angle[0] -= 29;
8295
sCutsceneVars[9].angle[1] += 29;
8296
pan_camera(c, sCutsceneVars[9].angle[0], sCutsceneVars[9].angle[1]);
8297
}
8298
8299
/**
8300
* Move backwards and rotate slowly around Mario.
8301
*/
8302
BAD_RETURN(s32) cutscene_dance_fly_rotate_around_mario(struct Camera *c) {
8303
cutscene_pan_cvar9(c);
8304
rotate_and_move_vec3f(c->pos, sMarioCamState->pos, sCutsceneVars[8].point[2], 0, 0);
8305
}
8306
8307
/**
8308
* Rotate quickly while Lakitu flies up.
8309
*/
8310
BAD_RETURN(s32) cutscene_dance_fly_away_rotate_while_flying(struct Camera *c) {
8311
rotate_and_move_vec3f(c->pos, sMarioCamState->pos, 0, 0, 0x80);
8312
}
8313
8314
BAD_RETURN(s32) cutscene_dance_fly_away_shake_fov(UNUSED struct Camera *c) {
8315
set_fov_shake(0x400, 0x30, 0x8000);
8316
}
8317
8318
/**
8319
* After collecting the star, Lakitu flies upwards out of the course.
8320
*/
8321
BAD_RETURN(s32) cutscene_dance_fly_away(struct Camera *c) {
8322
sStatusFlags |= CAM_FLAG_SMOOTH_MOVEMENT;
8323
cutscene_event(cutscene_dance_fly_away_start, c, 0, 0);
8324
cutscene_event(cutscene_dance_fly_away_focus_mario, c, 0, 30);
8325
cutscene_event(cutscene_dance_fly_away_approach_mario, c, 0, 30);
8326
cutscene_event(cutscene_dance_fly_rotate_around_mario, c, 55, 124);
8327
cutscene_event(cutscene_dance_fly_away_rotate_while_flying, c, 55, 124);
8328
cutscene_event(cutscene_dance_fly_away_shake_fov, c, 40, 40);
8329
set_fov_function(CAM_FOV_DEFAULT);
8330
set_handheld_shake(HAND_CAM_SHAKE_STAR_DANCE);
8331
}
8332
8333
/**
8334
* Jump the camera pos and focus to cvar 8 and 7.
8335
* Called every frame, starting after 10, so when these cvars are updated, the camera will jump.
8336
*/
8337
BAD_RETURN(s32) cutscene_key_dance_jump_cvar(struct Camera *c) {
8338
offset_rotated(c->pos, sMarioCamState->pos, sCutsceneVars[8].point, sMarioCamState->faceAngle);
8339
offset_rotated(c->focus, sMarioCamState->pos, sCutsceneVars[7].point, sMarioCamState->faceAngle);
8340
}
8341
8342
/**
8343
* Jump to a closeup view of Mario and the key.
8344
*/
8345
BAD_RETURN(s32) cutscene_key_dance_jump_closeup(UNUSED struct Camera *c) {
8346
vec3f_set(sCutsceneVars[8].point, 38.f, 171.f, -248.f);
8347
vec3f_set(sCutsceneVars[7].point, -57.f, 51.f, 187.f);
8348
}
8349
8350
/**
8351
* Jump to a view from the lower left (Mario's right).
8352
*/
8353
BAD_RETURN(s32) cutscene_key_dance_jump_lower_left(UNUSED struct Camera *c) {
8354
vec3f_set(sCutsceneVars[8].point, -178.f, 62.f, -132.f);
8355
vec3f_set(sCutsceneVars[7].point, 299.f, 91.f, 58.f);
8356
}
8357
8358
/**
8359
* Jump to a rotated view from above.
8360
*/
8361
BAD_RETURN(s32) cutscene_key_dance_jump_above(UNUSED struct Camera *c) {
8362
gLakituState.keyDanceRoll = 0x2800;
8363
vec3f_set(sCutsceneVars[8].point, 89.f, 373.f, -304.f);
8364
vec3f_set(sCutsceneVars[7].point, 0.f, 127.f, 0.f);
8365
}
8366
8367
/**
8368
* Finally, jump to a further view, slightly to Mario's left.
8369
*/
8370
BAD_RETURN(s32) cutscene_key_dance_jump_last(UNUSED struct Camera *c) {
8371
gLakituState.keyDanceRoll = 0;
8372
vec3f_set(sCutsceneVars[8].point, 135.f, 158.f, -673.f);
8373
vec3f_set(sCutsceneVars[7].point, -20.f, 135.f, -198.f);
8374
}
8375
8376
BAD_RETURN(s32) cutscene_key_dance_shake_fov(UNUSED struct Camera *c) {
8377
set_fov_shake(0x180, 0x30, 0x8000);
8378
}
8379
8380
BAD_RETURN(s32) cutscene_key_dance_handheld_shake(UNUSED struct Camera *c) {
8381
set_handheld_shake(HAND_CAM_SHAKE_CUTSCENE);
8382
}
8383
8384
BAD_RETURN(s32) cutscene_key_dance_focus_mario(struct Camera *c) {
8385
focus_in_front_of_mario(c, 0, 0.2f);
8386
}
8387
8388
/**
8389
* Cutscene that plays when Mario collects a key from bowser. It's basically a sequence of four jump
8390
* cuts.
8391
*/
8392
BAD_RETURN(s32) cutscene_key_dance(struct Camera *c) {
8393
cutscene_event(cutscene_dance_move_to_mario, c, 0, 10);
8394
cutscene_event(cutscene_key_dance_focus_mario, c, 0, 10);
8395
cutscene_event(cutscene_key_dance_jump_closeup, c, 0, 0);
8396
cutscene_event(cutscene_key_dance_jump_lower_left, c, 20, 20);
8397
cutscene_event(cutscene_key_dance_jump_above, c, 35, 35);
8398
cutscene_event(cutscene_key_dance_jump_last, c, 52, 52);
8399
cutscene_event(cutscene_key_dance_jump_cvar, c, 11, -1);
8400
cutscene_event(cutscene_key_dance_shake_fov, c, 54, 54);
8401
cutscene_event(cutscene_key_dance_handheld_shake, c, 52, -1);
8402
}
8403
8404
BAD_RETURN(s32) cutscene_bowser_area_shake_fov(UNUSED struct Camera *c) {
8405
cutscene_set_fov_shake_preset(2);
8406
}
8407
8408
/**
8409
* Set oBowserCamAct to 1, which causes bowser to start walking.
8410
*/
8411
BAD_RETURN(s32) cutscene_bowser_area_start_bowser_walking(UNUSED struct Camera *c) {
8412
gSecondCameraFocus->oBowserCamAct = BOWSER_CAM_ACT_WALK;
8413
}
8414
8415
/**
8416
* Offset the camera from bowser using cvar2 and cvar3
8417
* @bug cvar2.point is (0,0,0) on the first frame, but because of the warp transition, this behavior
8418
* isn't seen. After the first frame, cvar2.point is bowser's position.
8419
*/
8420
BAD_RETURN(s32) cutscene_bowser_arena_set_pos(struct Camera *c) {
8421
vec3f_set_dist_and_angle(sCutsceneVars[2].point, c->pos, sCutsceneVars[3].point[2],
8422
sCutsceneVars[3].angle[0], sCutsceneVars[3].angle[1]);
8423
vec3f_set(sCutsceneVars[2].point, gSecondCameraFocus->oPosX, gSecondCameraFocus->oPosY,
8424
gSecondCameraFocus->oPosZ);
8425
}
8426
8427
/**
8428
* Apply a sine wave to the focus's y coordinate.
8429
* The y offset starts at 120, then decreases to 0 before reaching ~240 on the last frame.
8430
*/
8431
BAD_RETURN(s32) cutscene_bowser_arena_focus_sine(UNUSED struct Camera *c) {
8432
//! unused initialization
8433
f32 yOff = 150.0f;
8434
8435
// cvar4 was zeroed when the cutscene started.
8436
yOff = sins(sCutsceneVars[4].angle[1]) * 120.0f + 120.0f;
8437
sCutsceneVars[4].angle[1] -= 0x200;
8438
approach_f32_asymptotic_bool(&sCutsceneVars[0].point[1], yOff, 0.5f);
8439
}
8440
8441
/**
8442
* Set the camera focus according to cvar0 and cvar2.
8443
*/
8444
BAD_RETURN(s32) cutscene_bowser_arena_set_focus(struct Camera *c) {
8445
offset_rotated(c->focus, sCutsceneVars[2].point, sCutsceneVars[0].point, sCutsceneVars[2].angle);
8446
}
8447
8448
/**
8449
* Adjust the cvar offsets, making the camera look up, move slightly further back, and focus a little
8450
* further in front of bowser.
8451
*/
8452
BAD_RETURN(s32) cutscene_bowser_arena_adjust_offsets(UNUSED struct Camera *c) {
8453
approach_s16_asymptotic_bool(&sCutsceneVars[3].angle[0], 0x6C8, 30);
8454
approach_f32_asymptotic_bool(&sCutsceneVars[0].point[2], -200.f, 0.02f);
8455
approach_f32_asymptotic_bool(&sCutsceneVars[3].point[2], 550.f, 0.02f);
8456
}
8457
8458
/**
8459
* Decrease cvar0's z offset, making the camera focus pan left towards bowser.
8460
*/
8461
BAD_RETURN(s32) cutscene_bowser_arena_pan_left(UNUSED struct Camera *c) {
8462
approach_f32_asymptotic_bool(&sCutsceneVars[0].point[2], 0.f, 0.05f);
8463
}
8464
8465
/**
8466
* Duplicate of cutscene_mario_dialog().
8467
*/
8468
BAD_RETURN(s32) cutscene_bowser_arena_mario_dialog(UNUSED struct Camera *c) {
8469
cutscene_common_set_dialog_state(MARIO_DIALOG_LOOK_FRONT);
8470
}
8471
8472
void cutscene_stop_dialog(UNUSED struct Camera *c) {
8473
cutscene_common_set_dialog_state(MARIO_DIALOG_STOP);
8474
}
8475
8476
/**
8477
* Active for the first 5 frames of the cutscene.
8478
* cvar3 is the camera's polar offset from bowser
8479
* cvar2.angle is bowser's move angle
8480
*
8481
* cvar0 is the focus offset from bowser
8482
*/
8483
BAD_RETURN(s32) cutscene_bowser_arena_start(struct Camera *c) {
8484
sCutsceneVars[3].point[2] = 430.f;
8485
sCutsceneVars[3].angle[1] = gSecondCameraFocus->oMoveAngleYaw - DEGREES(45);
8486
sCutsceneVars[3].angle[0] = 0xD90;
8487
8488
//! Tricky math: Bowser starts at (0, 307, -1000), with a moveAngle of (0,0,0). A sane person would
8489
//! expect this offset to move the focus to (0, 427, -1800).
8490
//! BUT because offset_rotated() flips the Z direction (to match sm64's coordinate system), this
8491
//! offset actually moves the focus to (0, 427, -200)
8492
vec3f_set(sCutsceneVars[0].point, 0.f, 120.f, -800.f);
8493
vec3s_set(sCutsceneVars[2].angle, gSecondCameraFocus->oMoveAnglePitch,
8494
gSecondCameraFocus->oMoveAngleYaw, gSecondCameraFocus->oMoveAngleRoll);
8495
8496
// Set the camera's position and focus.
8497
cutscene_bowser_arena_set_pos(c);
8498
cutscene_bowser_arena_set_focus(c);
8499
}
8500
8501
/**
8502
* Create the dialog box depending on which bowser fight Mario is in.
8503
*/
8504
BAD_RETURN(s32) bowser_fight_intro_dialog(UNUSED struct Camera *c) {
8505
s16 dialog;
8506
8507
switch (gCurrLevelNum) {
8508
case LEVEL_BOWSER_1:
8509
dialog = DIALOG_067;
8510
break;
8511
case LEVEL_BOWSER_2:
8512
dialog = DIALOG_092;
8513
break;
8514
default: // LEVEL_BOWSER_3
8515
dialog = DIALOG_093;
8516
}
8517
8518
create_dialog_box(dialog);
8519
}
8520
8521
/**
8522
* Create the dialog box and wait until it's gone.
8523
*/
8524
BAD_RETURN(s32) cutscene_bowser_arena_dialog(struct Camera *c) {
8525
cutscene_event(bowser_fight_intro_dialog, c, 0, 0);
8526
8527
if (get_dialog_id() == DIALOG_NONE) {
8528
gCutsceneTimer = CUTSCENE_LOOP;
8529
}
8530
}
8531
8532
/**
8533
* End the bowser arena cutscene.
8534
*/
8535
BAD_RETURN(s32) cutscene_bowser_arena_end(struct Camera *c) {
8536
cutscene_stop_dialog(c);
8537
c->cutscene = 0;
8538
transition_next_state(c, 20);
8539
sStatusFlags |= CAM_FLAG_UNUSED_CUTSCENE_ACTIVE;
8540
sModeOffsetYaw = sMarioCamState->faceAngle[1] + DEGREES(90);
8541
gSecondCameraFocus->oBowserCamAct = BOWSER_CAM_ACT_END;
8542
}
8543
8544
/**
8545
* Cutscene that plays when Mario enters a bowser fight.
8546
*/
8547
BAD_RETURN(s32) cutscene_bowser_arena(struct Camera *c) {
8548
//! This does nothing, but may have been used in development
8549
cutscene_spawn_obj(2, 0);
8550
8551
if (gSecondCameraFocus != NULL) {
8552
cutscene_event(cutscene_bowser_arena_mario_dialog, c, 0, -1);
8553
cutscene_event(cutscene_bowser_arena_start, c, 0, 5);
8554
cutscene_event(cutscene_bowser_area_start_bowser_walking, c, 40, 40);
8555
cutscene_event(cutscene_bowser_area_shake_fov, c, 145, 145);
8556
cutscene_event(cutscene_bowser_arena_set_pos, c, 40, -1);
8557
cutscene_event(cutscene_bowser_arena_pan_left, c, 40, 99);
8558
cutscene_event(cutscene_bowser_arena_adjust_offsets, c, 100, -1);
8559
cutscene_event(cutscene_bowser_arena_focus_sine, c, 40, 140);
8560
cutscene_event(cutscene_bowser_arena_set_focus, c, 40, -1);
8561
cutscene_event(cutscene_shake_explosion, c, 60, 60);
8562
cutscene_event(cutscene_shake_explosion, c, 82, 82);
8563
cutscene_event(cutscene_shake_explosion, c, 109, 109);
8564
cutscene_event(cutscene_shake_explosion, c, 127, 127);
8565
}
8566
}
8567
8568
BAD_RETURN(s32) cutscene_star_spawn_store_info(struct Camera *c) {
8569
store_info_star(c);
8570
}
8571
8572
/**
8573
* Focus on the top of the star.
8574
*/
8575
BAD_RETURN(s32) cutscene_star_spawn_focus_star(struct Camera *c) {
8576
UNUSED f32 hMul;
8577
Vec3f starPos;
8578
UNUSED f32 vMul;
8579
8580
if (gCutsceneFocus != NULL) {
8581
object_pos_to_vec3f(starPos, gCutsceneFocus);
8582
starPos[1] += gCutsceneFocus->hitboxHeight;
8583
approach_vec3f_asymptotic(c->focus, starPos, 0.1f, 0.1f, 0.1f);
8584
}
8585
}
8586
8587
/**
8588
* Use boss fight mode's update function to move the focus back.
8589
*/
8590
BAD_RETURN(s32) cutscene_star_spawn_update_boss_fight(struct Camera *c) {
8591
Vec3f pos, focus;
8592
8593
update_boss_fight_camera(c, focus, pos);
8594
approach_vec3f_asymptotic(c->focus, focus, 0.2f, 0.2f, 0.2f);
8595
approach_vec3f_asymptotic(c->pos, pos, 0.2f, 0.2f, 0.2f);
8596
}
8597
8598
/**
8599
* Fly back to the camera's previous pos and focus.
8600
*/
8601
BAD_RETURN(s32) cutscene_star_spawn_fly_back(struct Camera *c) {
8602
retrieve_info_star(c);
8603
transition_next_state(c, 15);
8604
}
8605
8606
/**
8607
* Plays when a star spawns (ie from a box).
8608
*/
8609
BAD_RETURN(s32) cutscene_star_spawn(struct Camera *c) {
8610
cutscene_event(cutscene_star_spawn_store_info, c, 0, 0);
8611
cutscene_event(cutscene_star_spawn_focus_star, c, 0, -1);
8612
sStatusFlags |= CAM_FLAG_SMOOTH_MOVEMENT;
8613
8614
if (gObjCutsceneDone) {
8615
// Set the timer to CUTSCENE_LOOP, which start the next shot.
8616
gCutsceneTimer = CUTSCENE_LOOP;
8617
}
8618
}
8619
8620
/**
8621
* Move the camera back to Mario.
8622
*/
8623
BAD_RETURN(s32) cutscene_star_spawn_back(struct Camera *c) {
8624
if ((c->mode == CAMERA_MODE_BOSS_FIGHT) && (set_cam_angle(0) == CAM_ANGLE_LAKITU)) {
8625
cutscene_event(cutscene_star_spawn_update_boss_fight, c, 0, -1);
8626
} else {
8627
cutscene_event(cutscene_star_spawn_fly_back, c, 0, 0);
8628
}
8629
8630
sStatusFlags |= CAM_FLAG_SMOOTH_MOVEMENT;
8631
sStatusFlags |= CAM_FLAG_UNUSED_CUTSCENE_ACTIVE;
8632
}
8633
8634
BAD_RETURN(s32) cutscene_star_spawn_end(struct Camera *c) {
8635
sStatusFlags |= CAM_FLAG_SMOOTH_MOVEMENT;
8636
gCutsceneTimer = CUTSCENE_STOP;
8637
c->cutscene = 0;
8638
}
8639
8640
BAD_RETURN(s32) cutscene_exit_waterfall_warp(struct Camera *c) {
8641
//! hardcoded position
8642
vec3f_set(c->pos, -3899.f, 39.f, -5671.f);
8643
}
8644
8645
/**
8646
* Look at Mario, used by cutscenes that play when Mario exits a course to castle grounds.
8647
*/
8648
BAD_RETURN(s32) cutscene_exit_to_castle_grounds_focus_mario(struct Camera *c) {
8649
vec3f_copy(c->focus, sMarioCamState->pos);
8650
c->focus[1] = c->pos[1] + (sMarioCamState->pos[1] + 125.f - c->pos[1]) * 0.5f;
8651
approach_vec3f_asymptotic(c->focus, sMarioCamState->pos, 0.05f, 0.4f, 0.05f);
8652
}
8653
8654
/**
8655
* Cutscene that plays when Mario leaves CotMC through the waterfall.
8656
*/
8657
BAD_RETURN(s32) cutscene_exit_waterfall(struct Camera *c) {
8658
cutscene_event(cutscene_exit_waterfall_warp, c, 0, 0);
8659
cutscene_event(cutscene_exit_to_castle_grounds_focus_mario, c, 0, -1);
8660
update_camera_yaw(c);
8661
}
8662
8663
/**
8664
* End the cutscene, used by cutscenes that play when Mario exits a course to castle grounds.
8665
*/
8666
BAD_RETURN(s32) cutscene_exit_to_castle_grounds_end(struct Camera *c) {
8667
sStatusFlags |= CAM_FLAG_SMOOTH_MOVEMENT;
8668
gCutsceneTimer = CUTSCENE_STOP;
8669
c->cutscene = 0;
8670
update_camera_yaw(c);
8671
}
8672
8673
BAD_RETURN(s32) cutscene_exit_fall_to_castle_grounds_warp(struct Camera *c) {
8674
//! hardcoded position
8675
vec3f_set(c->pos, 5830.f, 32.f, 3985.f);
8676
}
8677
8678
/**
8679
* Cutscene that plays when Mario falls from WMOTR.
8680
*/
8681
BAD_RETURN(s32) cutscene_exit_fall_to_castle_grounds(struct Camera *c) {
8682
cutscene_event(cutscene_exit_fall_to_castle_grounds_warp, c, 0, 0);
8683
cutscene_event(cutscene_exit_to_castle_grounds_focus_mario, c, 0, -1);
8684
update_camera_yaw(c);
8685
}
8686
8687
/**
8688
* Start the red coin star spawning cutscene.
8689
*/
8690
BAD_RETURN(s32) cutscene_red_coin_star_start(struct Camera *c) {
8691
object_pos_to_vec3f(sCutsceneVars[1].point, gCutsceneFocus);
8692
store_info_star(c);
8693
// Store the default fov for after the cutscene
8694
sCutsceneVars[2].point[2] = sFOVState.fov;
8695
}
8696
8697
/**
8698
* Look towards the star's x and z position
8699
*/
8700
BAD_RETURN(s32) cutscene_red_coin_star_focus_xz(struct Camera *c) {
8701
approach_f32_asymptotic_bool(&c->focus[0], gCutsceneFocus->oPosX, 0.15f);
8702
approach_f32_asymptotic_bool(&c->focus[2], gCutsceneFocus->oPosZ, 0.15f);
8703
}
8704
8705
/**
8706
* Look towards the star's y position. Only active before the camera warp.
8707
*/
8708
BAD_RETURN(s32) cutscene_red_coin_star_focus_y(struct Camera *c) {
8709
approach_f32_asymptotic_bool(&c->focus[1], gCutsceneFocus->oPosY, 0.1f);
8710
}
8711
8712
/**
8713
* Look 80% up towards the star. Only active after the camera warp.
8714
*/
8715
BAD_RETURN(s32) cutscene_red_coin_star_look_up_at_star(struct Camera *c) {
8716
c->focus[1] = sCutsceneVars[1].point[1] + (gCutsceneFocus->oPosY - sCutsceneVars[1].point[1]) * 0.8f;
8717
}
8718
8719
/**
8720
* Warp the camera near the star's spawn point
8721
*/
8722
BAD_RETURN(s32) cutscene_red_coin_star_warp(struct Camera *c) {
8723
f32 dist;
8724
s16 pitch, yaw, posYaw;
8725
struct Object *o = gCutsceneFocus;
8726
8727
vec3f_set(sCutsceneVars[1].point, o->oHomeX, o->oHomeY, o->oHomeZ);
8728
vec3f_get_dist_and_angle(sCutsceneVars[1].point, c->pos, &dist, &pitch, &yaw);
8729
posYaw = calculate_yaw(sCutsceneVars[1].point, c->pos);
8730
yaw = calculate_yaw(sCutsceneVars[1].point, sMarioCamState->pos);
8731
8732
if (ABS(yaw - posYaw + DEGREES(90)) < ABS(yaw - posYaw - DEGREES(90))) {
8733
yaw += DEGREES(90);
8734
} else {
8735
yaw -= DEGREES(90);
8736
}
8737
8738
vec3f_set_dist_and_angle(sCutsceneVars[1].point, c->pos, 400.f, 0x1000, yaw);
8739
sStatusFlags &= ~CAM_FLAG_SMOOTH_MOVEMENT;
8740
}
8741
8742
/**
8743
* Zoom out while looking at the star.
8744
*/
8745
BAD_RETURN(s32) cutscene_red_coin_star_set_fov(UNUSED struct Camera *c) {
8746
sFOVState.fov = 60.f;
8747
}
8748
8749
BAD_RETURN(s32) cutscene_red_coin_star(struct Camera *c) {
8750
sStatusFlags |= CAM_FLAG_SMOOTH_MOVEMENT;
8751
cutscene_event(cutscene_red_coin_star_start, c, 0, 0);
8752
cutscene_event(cutscene_red_coin_star_warp, c, 30, 30);
8753
cutscene_event(cutscene_red_coin_star_focus_xz, c, 0, -1);
8754
cutscene_event(cutscene_red_coin_star_focus_y, c, 0, 29);
8755
cutscene_event(cutscene_red_coin_star_look_up_at_star, c, 30, -1);
8756
cutscene_event(cutscene_red_coin_star_set_fov, c, 30, -1);
8757
8758
if (gObjCutsceneDone) {
8759
// Set the timer to CUTSCENE_LOOP, which start the next shot.
8760
gCutsceneTimer = CUTSCENE_LOOP;
8761
}
8762
}
8763
8764
/**
8765
* End the red coin star spawning cutscene
8766
*/
8767
BAD_RETURN(s32) cutscene_red_coin_star_end(struct Camera *c) {
8768
retrieve_info_star(c);
8769
gCutsceneTimer = CUTSCENE_STOP;
8770
c->cutscene = 0;
8771
// Restore the default fov
8772
sFOVState.fov = sCutsceneVars[2].point[2];
8773
}
8774
8775
/**
8776
* Moves the camera towards the cutscene's focus, stored in sCutsceneVars[3].point
8777
*
8778
* sCutsceneVars[3].point is used as the target point
8779
* sCutsceneVars[0].point is used as the current camera focus during the transition
8780
*
8781
* @param rotPitch constant pitch offset to add to the camera's focus
8782
* @param rotYaw constant yaw offset to add to the camera's focus
8783
*/
8784
void cutscene_goto_cvar_pos(struct Camera *c, f32 goalDist, s16 goalPitch, s16 rotPitch, s16 rotYaw) {
8785
UNUSED f32 unused1;
8786
f32 nextDist;
8787
s16 nextPitch, nextYaw;
8788
// The next 2 polar coord points are only used in CUTSCENE_PREPARE_CANNON
8789
f32 cannonDist;
8790
s16 cannonPitch, cannonYaw;
8791
f32 curDist;
8792
s16 curPitch, curYaw;
8793
UNUSED f64 unused2;
8794
vec3f_get_dist_and_angle(sCutsceneVars[3].point, c->pos, &nextDist, &nextPitch, &nextYaw);
8795
// If over 8000 units away from the cannon, just teleport there
8796
if ((nextDist > 8000.f) && (c->cutscene == CUTSCENE_PREPARE_CANNON)) {
8797
nextDist = goalDist * 4.f;
8798
nextPitch = goalPitch;
8799
vec3f_copy(sCutsceneVars[0].point, sCutsceneVars[3].point);
8800
sStatusFlags &= ~CAM_FLAG_SMOOTH_MOVEMENT;
8801
8802
if (gCurrLevelNum == LEVEL_TTM) {
8803
nextYaw = atan2s(sCutsceneVars[3].point[2] - c->areaCenZ,
8804
sCutsceneVars[3].point[0] - c->areaCenX);
8805
}
8806
} else {
8807
if (c->cutscene == CUTSCENE_PREPARE_CANNON) {
8808
vec3f_get_dist_and_angle(c->pos, sCutsceneVars[0].point, &curDist, &curPitch, &curYaw);
8809
vec3f_get_dist_and_angle(c->pos, sCutsceneVars[3].point, &cannonDist, &cannonPitch, &cannonYaw);
8810
approach_f32_asymptotic_bool(&curDist, cannonDist, 0.1f);
8811
approach_s16_asymptotic_bool(&curPitch, cannonPitch, 15);
8812
approach_s16_asymptotic_bool(&curYaw, cannonYaw, 15);
8813
// Move the current focus, sCutsceneVars[0].point, in the direction towards the cannon
8814
vec3f_set_dist_and_angle(c->pos, sCutsceneVars[0].point, curDist, curPitch, curYaw);
8815
} else {
8816
approach_vec3f_asymptotic(sCutsceneVars[0].point, sCutsceneVars[3].point, 0.1f, 0.1f, 0.1f);
8817
}
8818
}
8819
8820
approach_f32_asymptotic_bool(&nextDist, goalDist, 0.05f);
8821
approach_s16_asymptotic_bool(&nextPitch, goalPitch, 0x20);
8822
8823
vec3f_set_dist_and_angle(sCutsceneVars[3].point, c->pos, nextDist, nextPitch, nextYaw);
8824
vec3f_copy(c->focus, sCutsceneVars[0].point);
8825
8826
// Apply the constant rotation given
8827
pan_camera(c, rotPitch, rotYaw);
8828
vec3f_get_dist_and_angle(c->pos, c->focus, &nextDist, &nextPitch, &nextYaw);
8829
8830
if (nextPitch < -0x3000) {
8831
nextPitch = -0x3000;
8832
}
8833
if (nextPitch > 0x3000) {
8834
nextPitch = 0x3000;
8835
}
8836
8837
vec3f_set_dist_and_angle(c->pos, c->focus, nextDist, nextPitch, nextYaw);
8838
}
8839
8840
/**
8841
* Store the camera's pos and focus, and copy the cannon's position to cvars.
8842
*/
8843
BAD_RETURN(s32) cutscene_prepare_cannon_start(struct Camera *c) {
8844
store_info_cannon(c);
8845
vec3f_copy(sCutsceneVars[0].point, c->focus);
8846
sCutsceneVars[2].point[0] = 30.f;
8847
// Store the cannon door's position in sCutsceneVars[3]'s point
8848
object_pos_to_vec3f(sCutsceneVars[3].point, gCutsceneFocus);
8849
vec3s_set(sCutsceneVars[5].angle, 0, 0, 0);
8850
}
8851
8852
/**
8853
* Fly towards the cannon door.
8854
*/
8855
BAD_RETURN(s32) cutscene_prepare_cannon_fly_to_cannon(struct Camera *c) {
8856
cutscene_goto_cvar_pos(c, 300.f, 0x2000, 0, sCutsceneVars[5].angle[1]);
8857
camera_approach_s16_symmetric_bool(&sCutsceneVars[5].angle[1], 0x400, 17);
8858
set_handheld_shake(HAND_CAM_SHAKE_CUTSCENE);
8859
}
8860
8861
/**
8862
* Used in the cannon opening cutscene to fly back to the camera's last position and focus
8863
*/
8864
void cannon_approach_prev(f32 *value, f32 target) {
8865
f32 inc = ABS(target - *value) / sCutsceneVars[2].point[0];
8866
camera_approach_f32_symmetric_bool(value, target, inc);
8867
}
8868
8869
/**
8870
* Fly or warp back to the previous pos and focus, stored in sCameraStoreCutscene.
8871
*/
8872
BAD_RETURN(s32) cutscene_prepare_cannon_fly_back(struct Camera *c) {
8873
f32 distToPrevPos = calc_abs_dist(c->pos, sCameraStoreCutscene.pos);
8874
8875
if (distToPrevPos < 8000.f) {
8876
cannon_approach_prev(&c->pos[0], sCameraStoreCutscene.pos[0]);
8877
cannon_approach_prev(&c->pos[1], sCameraStoreCutscene.pos[1]);
8878
cannon_approach_prev(&c->pos[2], sCameraStoreCutscene.pos[2]);
8879
cannon_approach_prev(&c->focus[0], sCameraStoreCutscene.focus[0]);
8880
cannon_approach_prev(&c->focus[1], sCameraStoreCutscene.focus[1]);
8881
cannon_approach_prev(&c->focus[2], sCameraStoreCutscene.focus[2]);
8882
} else {
8883
// If too far away, just warp back
8884
vec3f_copy(c->focus, sCameraStoreCutscene.focus);
8885
vec3f_copy(c->pos, sCameraStoreCutscene.pos);
8886
sStatusFlags &= ~CAM_FLAG_SMOOTH_MOVEMENT;
8887
}
8888
if (sCutsceneVars[2].point[0] > 1.f) {
8889
sCutsceneVars[2].point[0] -= 1.f;
8890
}
8891
}
8892
8893
/**
8894
* Cutscene that plays when the cannon is opened.
8895
*/
8896
BAD_RETURN(s32) cutscene_prepare_cannon(struct Camera *c) {
8897
sStatusFlags |= CAM_FLAG_SMOOTH_MOVEMENT;
8898
cutscene_event(cutscene_prepare_cannon_start, c, 0, 0);
8899
cutscene_event(cutscene_prepare_cannon_fly_to_cannon, c, 0, 140);
8900
cutscene_event(cutscene_prepare_cannon_fly_back, c, 141, -1);
8901
}
8902
8903
/**
8904
* Stop the cannon opening cutscene.
8905
*/
8906
BAD_RETURN(s32) cutscene_prepare_cannon_end(struct Camera *c) {
8907
gCutsceneTimer = CUTSCENE_STOP;
8908
c->cutscene = 0;
8909
retrieve_info_cannon(c);
8910
sStatusFlags |= CAM_FLAG_SMOOTH_MOVEMENT;
8911
}
8912
8913
/**
8914
* Moves the camera to Mario's side when Mario starts ACT_WATER_DEATH
8915
* Note that ACT_WATER_DEATH only starts when Mario gets hit by an enemy under water. It does not start
8916
* when Mario drowns.
8917
*/
8918
void water_death_move_to_mario_side(struct Camera *c) {
8919
f32 dist;
8920
s16 pitch, yaw;
8921
8922
vec3f_get_dist_and_angle(sMarioCamState->pos, c->pos, &dist, &pitch, &yaw);
8923
approach_s16_asymptotic_bool(&yaw, (sMarioCamState->faceAngle[1] - 0x3000), 8);
8924
vec3f_set_dist_and_angle(sMarioCamState->pos, c->pos, dist, pitch, yaw);
8925
}
8926
8927
/**
8928
* Unnecessary, only used in cutscene_death_standing_goto_mario()
8929
*/
8930
void death_goto_mario(struct Camera *c) {
8931
cutscene_goto_cvar_pos(c, 400.f, 0x1000, 0x300, 0);
8932
}
8933
8934
BAD_RETURN(s32) cutscene_death_standing_start(struct Camera *c) {
8935
vec3f_copy(sCutsceneVars[0].point, c->focus);
8936
vec3f_copy(sCutsceneVars[3].point, sMarioCamState->pos);
8937
sCutsceneVars[3].point[1] += 70.f;
8938
}
8939
8940
/**
8941
* Fly to Mario and turn on handheld shake.
8942
*/
8943
BAD_RETURN(s32) cutscene_death_standing_goto_mario(struct Camera *c) {
8944
death_goto_mario(c);
8945
set_handheld_shake(HAND_CAM_SHAKE_HIGH);
8946
}
8947
8948
/**
8949
* Cutscene that plays when Mario dies while standing.
8950
*/
8951
BAD_RETURN(s32) cutscene_death_standing(struct Camera *c) {
8952
cutscene_event(cutscene_death_standing_start, c, 0, 0);
8953
cutscene_event(cutscene_death_standing_goto_mario, c, 0, -1);
8954
sStatusFlags |= CAM_FLAG_SMOOTH_MOVEMENT;
8955
}
8956
8957
BAD_RETURN(s32) cutscene_death_stomach_start(struct Camera *c) {
8958
Vec3f offset = { 0, 40.f, -60.f };
8959
8960
offset_rotated(sCutsceneVars[3].point, sMarioCamState->pos, offset, sMarioCamState->faceAngle);
8961
vec3f_copy(sCutsceneVars[0].point, c->focus);
8962
}
8963
8964
BAD_RETURN(s32) cutscene_death_stomach_goto_mario(struct Camera *c) {
8965
cutscene_goto_cvar_pos(c, 400.f, 0x1800, 0, -0x400);
8966
}
8967
8968
/**
8969
* Ah, yes
8970
*/
8971
UNUSED static void unused_water_death_move_to_side_of_mario(struct Camera *c) {
8972
water_death_move_to_mario_side(c);
8973
}
8974
8975
/**
8976
* Cutscene that plays when Mario dies on his stomach.
8977
*/
8978
BAD_RETURN(s32) cutscene_death_stomach(struct Camera *c) {
8979
cutscene_event(cutscene_death_stomach_start, c, 0, 0);
8980
cutscene_event(cutscene_death_stomach_goto_mario, c, 0, -1);
8981
sStatusFlags |= CAM_FLAG_SMOOTH_MOVEMENT;
8982
set_handheld_shake(HAND_CAM_SHAKE_CUTSCENE);
8983
}
8984
8985
BAD_RETURN(s32) cutscene_bbh_death_start(struct Camera *c) {
8986
Vec3f dir = { 0, 40.f, 60.f };
8987
8988
offset_rotated(sCutsceneVars[3].point, sMarioCamState->pos, dir, sMarioCamState->faceAngle);
8989
vec3f_copy(sCutsceneVars[0].point, c->focus);
8990
}
8991
8992
BAD_RETURN(s32) cutscene_bbh_death_goto_mario(struct Camera *c) {
8993
cutscene_goto_cvar_pos(c, 400.f, 0x1800, 0, 0x400);
8994
}
8995
8996
/**
8997
* Cutscene that plays when Mario dies in BBH.
8998
*/
8999
BAD_RETURN(s32) cutscene_bbh_death(struct Camera *c) {
9000
cutscene_event(cutscene_bbh_death_start, c, 0, 0);
9001
cutscene_event(cutscene_bbh_death_goto_mario, c, 0, -1);
9002
sStatusFlags |= CAM_FLAG_SMOOTH_MOVEMENT;
9003
set_handheld_shake(HAND_CAM_SHAKE_CUTSCENE);
9004
}
9005
9006
/**
9007
* Copy the camera's focus to cvar0
9008
*/
9009
BAD_RETURN(s32) cutscene_quicksand_death_start(struct Camera *c) {
9010
vec3f_copy(sCutsceneVars[0].point, c->focus);
9011
}
9012
9013
/**
9014
* Fly closer to Mario. In WATER_DEATH, move to Mario's side.
9015
*/
9016
BAD_RETURN(s32) cutscene_quicksand_death_goto_mario(struct Camera *c) {
9017
cutscene_goto_cvar_pos(c, 400.f, 0x2800, 0x200, 0);
9018
9019
if (c->cutscene == CUTSCENE_WATER_DEATH) {
9020
water_death_move_to_mario_side(c);
9021
}
9022
}
9023
9024
/**
9025
* Cutscene that plays when Mario dies in quicksand.
9026
*/
9027
BAD_RETURN(s32) cutscene_quicksand_death(struct Camera *c) {
9028
sCutsceneVars[3].point[0] = sMarioCamState->pos[0];
9029
sCutsceneVars[3].point[1] = sMarioCamState->pos[1] + 20.f;
9030
sCutsceneVars[3].point[2] = sMarioCamState->pos[2];
9031
9032
cutscene_event(cutscene_quicksand_death_start, c, 0, 0);
9033
cutscene_event(cutscene_quicksand_death_goto_mario, c, 0, -1);
9034
sStatusFlags |= CAM_FLAG_SMOOTH_MOVEMENT;
9035
set_handheld_shake(HAND_CAM_SHAKE_HIGH);
9036
}
9037
9038
/**
9039
* Fly away from Mario near the end of the cutscene.
9040
*/
9041
BAD_RETURN(s32) cutscene_suffocation_fly_away(UNUSED struct Camera *c) {
9042
Vec3f target;
9043
Vec3f offset = { 0, 20.f, 120.f };
9044
9045
offset_rotated(target, sMarioCamState->pos, offset, sMarioCamState->faceAngle);
9046
approach_vec3f_asymptotic(sCutsceneVars[3].point, target, 0.1f, 0.1f, 0.1f);
9047
}
9048
9049
/**
9050
* Keep Lakitu above the gas level.
9051
*/
9052
BAD_RETURN(s32) cutscene_suffocation_stay_above_gas(struct Camera *c) {
9053
UNUSED f32 unused1;
9054
f32 gasLevel;
9055
UNUSED f32 unused2;
9056
9057
cutscene_goto_cvar_pos(c, 400.f, 0x2800, 0x200, 0);
9058
gasLevel = find_poison_gas_level(sMarioCamState->pos[0], sMarioCamState->pos[2]);
9059
9060
if (gasLevel != FLOOR_LOWER_LIMIT) {
9061
if ((gasLevel += 130.f) > c->pos[1]) {
9062
c->pos[1] = gasLevel;
9063
}
9064
}
9065
}
9066
9067
/**
9068
* Quickly rotate around Mario.
9069
*/
9070
BAD_RETURN(s32) cutscene_suffocation_rotate(struct Camera *c) {
9071
f32 dist;
9072
s16 pitch, yaw;
9073
9074
vec3f_get_dist_and_angle(sMarioCamState->pos, c->pos, &dist, &pitch, &yaw);
9075
yaw += 0x100;
9076
vec3f_set_dist_and_angle(sMarioCamState->pos, c->pos, dist, pitch, yaw);
9077
}
9078
9079
/**
9080
* Cutscene that plays when Mario dies from suffocation (ie due to HMC gas).
9081
*/
9082
BAD_RETURN(s32) cutscene_suffocation(struct Camera *c) {
9083
cutscene_event(cutscene_death_stomach_start, c, 0, 0);
9084
cutscene_event(cutscene_suffocation_rotate, c, 0, -1);
9085
cutscene_event(cutscene_suffocation_stay_above_gas, c, 0, -1);
9086
cutscene_event(cutscene_suffocation_fly_away, c, 50, -1);
9087
sStatusFlags |= CAM_FLAG_SMOOTH_MOVEMENT;
9088
set_handheld_shake(HAND_CAM_SHAKE_HIGH);
9089
}
9090
9091
BAD_RETURN(s32) cutscene_enter_pool_start(struct Camera *c) {
9092
vec3f_copy(sCutsceneVars[3].point, sMarioCamState->pos);
9093
9094
if (gCurrLevelNum == LEVEL_CASTLE) { // entering HMC
9095
vec3f_set(sCutsceneVars[3].point, 2485.f, -1589.f, -2659.f);
9096
}
9097
if (gCurrLevelNum == LEVEL_HMC) { // entering CotMC
9098
vec3f_set(sCutsceneVars[3].point, 3350.f, -4589.f, 4800.f);
9099
}
9100
9101
vec3f_copy(sCutsceneVars[0].point, c->focus);
9102
}
9103
9104
BAD_RETURN(s32) cutscene_enter_pool_loop(struct Camera *c) {
9105
UNUSED u32 pad[2];
9106
9107
cutscene_goto_cvar_pos(c, 1200.f, 0x2000, 0x200, 0);
9108
}
9109
9110
BAD_RETURN(s32) cutscene_enter_pool(struct Camera *c) {
9111
cutscene_event(cutscene_enter_pool_start, c, 0, 0);
9112
cutscene_event(cutscene_enter_pool_loop, c, 0, -1);
9113
sStatusFlags |= CAM_FLAG_SMOOTH_MOVEMENT;
9114
}
9115
9116
/**
9117
* Store the camera focus in cvar1.
9118
* Store the area's center position (which happens to be the pyramid, in SSL) in cvar3.
9119
*/
9120
BAD_RETURN(s32) cutscene_pyramid_top_explode_start(struct Camera *c) {
9121
reset_pan_distance(c);
9122
store_info_cannon(c);
9123
9124
vec3f_copy(sCutsceneVars[1].point, c->focus);
9125
vec3f_set(sCutsceneVars[3].point, c->areaCenX, 1280.f, c->areaCenZ);
9126
}
9127
9128
/**
9129
* Zoom in on the pyramid.
9130
*/
9131
BAD_RETURN(s32) cutscene_pyramid_top_explode_zoom_in(UNUSED struct Camera *c) {
9132
set_fov_function(CAM_FOV_APP_30);
9133
}
9134
9135
/**
9136
* Look at the pyramid top.
9137
*/
9138
BAD_RETURN(s32) cutscene_pyramid_top_explode_focus(struct Camera *c) {
9139
approach_vec3f_asymptotic(c->focus, sCutsceneVars[3].point, 0.02f, 0.02f, 0.02f);
9140
sStatusFlags |= CAM_FLAG_SMOOTH_MOVEMENT;
9141
}
9142
9143
/**
9144
* Store the old pos and focus, then warp to the pyramid top.
9145
*/
9146
BAD_RETURN(s32) cutscene_pyramid_top_explode_warp(struct Camera *c) {
9147
s16 pitch, yaw;
9148
f32 dist;
9149
9150
set_fov_function(CAM_FOV_DEFAULT);
9151
sFOVState.fov = 45.f;
9152
9153
vec3f_copy(sCutsceneVars[4].point, c->pos);
9154
vec3f_copy(sCutsceneVars[5].point, c->focus);
9155
vec3f_copy(c->focus, sCutsceneVars[3].point);
9156
9157
vec3f_get_dist_and_angle(sCutsceneVars[3].point, sMarioCamState[0].pos, &dist, &pitch, &yaw);
9158
vec3f_set_dist_and_angle(sCutsceneVars[3].point, c->pos, 2000.f, 0, yaw);
9159
c->pos[1] += 500.f;
9160
}
9161
9162
/**
9163
* Close up view of the spinning pyramid top as it rises.
9164
*/
9165
BAD_RETURN(s32) cutscene_pyramid_top_explode_closeup(struct Camera *c) {
9166
s16 pitch, yaw;
9167
f32 dist;
9168
9169
vec3f_get_dist_and_angle(sCutsceneVars[3].point, c->pos, &dist, &pitch, &yaw);
9170
approach_f32_asymptotic_bool(&dist, 2000.f, 0.1f);
9171
vec3f_set_dist_and_angle(sCutsceneVars[3].point, c->pos, dist, pitch, yaw);
9172
9173
c->focus[1] += 4.f;
9174
c->pos[1] -= 5.f;
9175
sFOVState.fov = 45.f;
9176
set_handheld_shake(HAND_CAM_SHAKE_CUTSCENE);
9177
}
9178
9179
/**
9180
* Shake the camera during the closeup.
9181
*/
9182
BAD_RETURN(s32) cutscene_pyramid_top_explode_cam_shake(UNUSED struct Camera *c) {
9183
set_environmental_camera_shake(SHAKE_ENV_PYRAMID_EXPLODE);
9184
}
9185
9186
/**
9187
* Warp back to the old position, and start a heavy camera shake.
9188
*/
9189
BAD_RETURN(s32) cutscene_pyramid_top_explode_warp_back(struct Camera *c) {
9190
UNUSED u32 pad[2];
9191
9192
vec3f_copy(c->pos, sCutsceneVars[4].point);
9193
vec3f_copy(c->focus, sCutsceneVars[5].point);
9194
set_environmental_camera_shake(SHAKE_ENV_BOWSER_JUMP);
9195
}
9196
9197
/**
9198
* An unused cutscene for when the pyramid explodes.
9199
*/
9200
BAD_RETURN(s32) cutscene_pyramid_top_explode(struct Camera *c) {
9201
cutscene_event(cutscene_pyramid_top_explode_start, c, 0, 0);
9202
cutscene_event(cutscene_pyramid_top_explode_focus, c, 0, 30);
9203
cutscene_event(cutscene_pyramid_top_explode_warp, c, 31, 31);
9204
cutscene_event(cutscene_pyramid_top_explode_closeup, c, 31, 139);
9205
cutscene_event(cutscene_pyramid_top_explode_zoom_in, c, 23, 23);
9206
cutscene_event(cutscene_pyramid_top_explode_warp_back, c, 140, 140);
9207
cutscene_event(cutscene_pyramid_top_explode_cam_shake, c, 31, 139);
9208
}
9209
9210
/**
9211
* End the pyramid top explosion cutscene.
9212
*/
9213
BAD_RETURN(s32) cutscene_pyramid_top_explode_end(struct Camera *c) {
9214
cutscene_stop_dialog(c);
9215
stop_cutscene_and_retrieve_stored_info(c);
9216
// Move the camera back to Mario
9217
transition_next_state(c, 30);
9218
}
9219
9220
/**
9221
* Store the camera focus in cvar0, and store the top of the pyramid in cvar3.
9222
*/
9223
BAD_RETURN(s32) cutscene_enter_pyramid_top_start(struct Camera *c) {
9224
vec3f_copy(sCutsceneVars[0].point, c->focus);
9225
vec3f_set(sCutsceneVars[3].point, c->areaCenX, 1280.f, c->areaCenZ);
9226
}
9227
9228
/**
9229
* Cutscene that plays when Mario enters the top of the pyramid.
9230
*/
9231
BAD_RETURN(s32) cutscene_enter_pyramid_top(struct Camera *c) {
9232
cutscene_event(cutscene_enter_pyramid_top_start, c, 0, 0);
9233
// Move to cvar3
9234
cutscene_goto_cvar_pos(c, 200.f, 0x3000, 0, 0);
9235
sStatusFlags |= CAM_FLAG_SMOOTH_MOVEMENT;
9236
set_handheld_shake(HAND_CAM_SHAKE_CUTSCENE);
9237
9238
if (sMarioCamState->pos[1] > 1250.f) {
9239
// End the cutscene early if Mario ledge-grabbed.
9240
// This only works because of the janky way that ledge-grabbing is implemented.
9241
cutscene_exit_to_castle_grounds_end(c);
9242
}
9243
}
9244
9245
UNUSED static void unused_cutscene_goto_cvar(struct Camera *c) {
9246
f32 dist;
9247
9248
dist = calc_abs_dist(sCutsceneVars[3].point, sMarioCamState->pos);
9249
dist = calc_abs_dist(sCutsceneVars[9].point, sMarioCamState->pos) + 200.f;
9250
cutscene_goto_cvar_pos(c, dist, 0x1000, 0x300, 0);
9251
}
9252
9253
/**
9254
* cvar8 is Mario's position and faceAngle
9255
*
9256
* cvar9.point is gCutsceneFocus's position
9257
* cvar9.angle[1] is the yaw between Mario and the gCutsceneFocus
9258
*/
9259
BAD_RETURN(s32) cutscene_dialog_start(struct Camera *c) {
9260
UNUSED f32 unused1;
9261
UNUSED s16 unused2;
9262
s16 yaw;
9263
9264
9265
cutscene_soften_music(c);
9266
set_time_stop_flags(TIME_STOP_ENABLED | TIME_STOP_DIALOG);
9267
9268
#ifndef VERSION_JP
9269
if (c->mode == CAMERA_MODE_BOSS_FIGHT) {
9270
vec3f_copy(sCameraStoreCutscene.focus, c->focus);
9271
vec3f_copy(sCameraStoreCutscene.pos, c->pos);
9272
} else {
9273
#endif
9274
store_info_star(c);
9275
#ifndef VERSION_JP
9276
}
9277
#endif
9278
9279
// Store Mario's position and faceAngle
9280
sCutsceneVars[8].angle[0] = 0;
9281
vec3f_copy(sCutsceneVars[8].point, sMarioCamState->pos);
9282
sCutsceneVars[8].point[1] += 125.f;
9283
9284
// Store gCutsceneFocus's position and yaw
9285
object_pos_to_vec3f(sCutsceneVars[9].point, gCutsceneFocus);
9286
sCutsceneVars[9].point[1] += gCutsceneFocus->hitboxHeight + 200.f;
9287
sCutsceneVars[9].angle[1] = calculate_yaw(sCutsceneVars[8].point, sCutsceneVars[9].point);
9288
9289
yaw = calculate_yaw(sMarioCamState->pos, gLakituState.curPos);
9290
if ((yaw - sCutsceneVars[9].angle[1]) & 0x8000) {
9291
sCutsceneVars[9].angle[1] -= 0x6000;
9292
} else {
9293
sCutsceneVars[9].angle[1] += 0x6000;
9294
}
9295
}
9296
9297
/**
9298
* Move closer to Mario and the object, adjusting to their difference in height.
9299
* The camera's generally ends up looking over Mario's shoulder.
9300
*/
9301
BAD_RETURN(s32) cutscene_dialog_move_mario_shoulder(struct Camera *c) {
9302
f32 dist;
9303
s16 pitch, yaw;
9304
Vec3f focus, pos;
9305
9306
scale_along_line(focus, sCutsceneVars[9].point, sMarioCamState->pos, 0.7f);
9307
vec3f_get_dist_and_angle(c->pos, focus, &dist, &pitch, &yaw);
9308
pitch = calculate_pitch(c->pos, sCutsceneVars[9].point);
9309
vec3f_set_dist_and_angle(c->pos, pos, dist, pitch, yaw);
9310
9311
focus[1] = focus[1] + (sCutsceneVars[9].point[1] - focus[1]) * 0.1f;
9312
approach_vec3f_asymptotic(c->focus, focus, 0.2f, 0.2f, 0.2f);
9313
9314
vec3f_copy(pos, c->pos);
9315
9316
// Set y pos to cvar8's y (top of focus object)
9317
pos[1] = sCutsceneVars[8].point[1];
9318
vec3f_get_dist_and_angle(sCutsceneVars[8].point, pos, &dist, &pitch, &yaw);
9319
approach_s16_asymptotic_bool(&yaw, sCutsceneVars[9].angle[1], 0x10);
9320
approach_f32_asymptotic_bool(&dist, 180.f, 0.05f);
9321
vec3f_set_dist_and_angle(sCutsceneVars[8].point, pos, dist, pitch, yaw);
9322
9323
// Move up if Mario is below the focus object, down is Mario is above
9324
pos[1] = sCutsceneVars[8].point[1]
9325
+ sins(calculate_pitch(sCutsceneVars[9].point, sCutsceneVars[8].point)) * 100.f;
9326
9327
approach_f32_asymptotic_bool(&c->pos[1], pos[1], 0.05f);
9328
c->pos[0] = pos[0];
9329
c->pos[2] = pos[2];
9330
}
9331
9332
/**
9333
* Create the dialog with sCutsceneDialogID
9334
*/
9335
BAD_RETURN(s32) cutscene_dialog_create_dialog_box(struct Camera *c) {
9336
if (c->cutscene == CUTSCENE_RACE_DIALOG) {
9337
create_dialog_box_with_response(sCutsceneDialogID);
9338
} else {
9339
create_dialog_box(sCutsceneDialogID);
9340
}
9341
9342
//! Unused. This may have been used before sCutsceneDialogResponse was implemented.
9343
sCutsceneVars[8].angle[0] = DIALOG_RESPONSE_NOT_DEFINED;
9344
}
9345
9346
/**
9347
* Cutscene that plays when Mario talks to an object.
9348
*/
9349
BAD_RETURN(s32) cutscene_dialog(struct Camera *c) {
9350
cutscene_event(cutscene_dialog_start, c, 0, 0);
9351
cutscene_event(cutscene_dialog_move_mario_shoulder, c, 0, -1);
9352
cutscene_event(cutscene_dialog_create_dialog_box, c, 10, 10);
9353
sStatusFlags |= CAM_FLAG_SMOOTH_MOVEMENT;
9354
9355
if (gDialogResponse != DIALOG_RESPONSE_NONE) {
9356
sCutsceneDialogResponse = gDialogResponse;
9357
}
9358
9359
if ((get_dialog_id() == DIALOG_NONE) && (sCutsceneVars[8].angle[0] != 0)) {
9360
if (c->cutscene != CUTSCENE_RACE_DIALOG) {
9361
sCutsceneDialogResponse = DIALOG_RESPONSE_NOT_DEFINED;
9362
}
9363
9364
gCutsceneTimer = CUTSCENE_LOOP;
9365
retrieve_info_star(c);
9366
transition_next_state(c, 15);
9367
sStatusFlags |= CAM_FLAG_UNUSED_CUTSCENE_ACTIVE;
9368
cutscene_unsoften_music(c);
9369
}
9370
}
9371
9372
/**
9373
* Sets the CAM_FLAG_UNUSED_CUTSCENE_ACTIVE flag, which does nothing.
9374
*/
9375
BAD_RETURN(s32) cutscene_dialog_set_flag(UNUSED struct Camera *c) {
9376
sStatusFlags |= CAM_FLAG_UNUSED_CUTSCENE_ACTIVE;
9377
}
9378
9379
/**
9380
* Ends the dialog cutscene.
9381
*/
9382
BAD_RETURN(s32) cutscene_dialog_end(struct Camera *c) {
9383
sStatusFlags |= CAM_FLAG_UNUSED_CUTSCENE_ACTIVE;
9384
c->cutscene = 0;
9385
clear_time_stop_flags(TIME_STOP_ENABLED | TIME_STOP_DIALOG);
9386
}
9387
9388
/**
9389
* Soften the music, clear cvar0
9390
*
9391
* In this cutscene, cvar0.angle[0] is used as a state variable.
9392
*/
9393
BAD_RETURN(s32) cutscene_read_message_start(struct Camera *c) {
9394
cutscene_soften_music(c);
9395
transition_next_state(c, 30);
9396
reset_pan_distance(c);
9397
store_info_star(c);
9398
9399
sCutsceneVars[1].angle[0] = sCUpCameraPitch;
9400
sCutsceneVars[1].angle[1] = sModeOffsetYaw;
9401
sCUpCameraPitch = -0x830;
9402
sModeOffsetYaw = 0;
9403
sCutsceneVars[0].angle[0] = 0;
9404
}
9405
9406
UNUSED static void unused_cam_to_mario(struct Camera *c) {
9407
Vec3s dir;
9408
9409
vec3s_set(dir, 0, sMarioCamState->faceAngle[1], 0);
9410
offset_rotated_coords(c->pos, sMarioCamState->pos, dir, 0, 100.f, 190.f);
9411
offset_rotated_coords(c->focus, sMarioCamState->pos, dir, 0, 70.f, -20.f);
9412
}
9413
9414
/**
9415
* Cutscene that plays when Mario is reading a message (a sign or message on the wall)
9416
*/
9417
BAD_RETURN(s32) cutscene_read_message(struct Camera *c) {
9418
UNUSED u32 pad[2];
9419
9420
cutscene_event(cutscene_read_message_start, c, 0, 0);
9421
sStatusFlags |= CAM_FLAG_SMOOTH_MOVEMENT;
9422
9423
switch (sCutsceneVars[0].angle[0]) {
9424
// Do nothing until message is gone.
9425
case 0:
9426
if (get_dialog_id() != DIALOG_NONE) {
9427
sCutsceneVars[0].angle[0] += 1;
9428
set_time_stop_flags(TIME_STOP_ENABLED | TIME_STOP_DIALOG);
9429
}
9430
break;
9431
// Leave the dialog.
9432
case 1:
9433
move_mario_head_c_up(c);
9434
update_c_up(c, c->focus, c->pos);
9435
9436
// This could cause softlocks. If a message starts one frame after another one closes, the
9437
// cutscene will never end.
9438
if (get_dialog_id() == DIALOG_NONE) {
9439
gCutsceneTimer = CUTSCENE_LOOP;
9440
retrieve_info_star(c);
9441
transition_next_state(c, 15);
9442
sStatusFlags |= CAM_FLAG_UNUSED_CUTSCENE_ACTIVE;
9443
clear_time_stop_flags(TIME_STOP_ENABLED | TIME_STOP_DIALOG);
9444
// Retrieve previous state
9445
sCUpCameraPitch = sCutsceneVars[1].angle[0];
9446
sModeOffsetYaw = sCutsceneVars[1].angle[1];
9447
cutscene_unsoften_music(c);
9448
}
9449
}
9450
sStatusFlags |= CAM_FLAG_UNUSED_CUTSCENE_ACTIVE;
9451
}
9452
9453
/**
9454
* Set CAM_FLAG_UNUSED_CUTSCENE_ACTIVE, which does nothing.
9455
*/
9456
BAD_RETURN(s32) cutscene_read_message_set_flag(UNUSED struct Camera *c) {
9457
sStatusFlags |= CAM_FLAG_UNUSED_CUTSCENE_ACTIVE;
9458
}
9459
9460
/**
9461
* End the message cutscene.
9462
*/
9463
BAD_RETURN(s32) cutscene_read_message_end(struct Camera *c) {
9464
sStatusFlags |= CAM_FLAG_UNUSED_CUTSCENE_ACTIVE;
9465
c->cutscene = 0;
9466
}
9467
9468
/**
9469
* Set cvars:
9470
* cvar7 is Mario's pos and angle
9471
* cvar6 is the focus offset
9472
* cvar5 is the position offset
9473
*/
9474
BAD_RETURN(s32) cutscene_exit_succ_start(UNUSED struct Camera *c) {
9475
vec3f_copy(sCutsceneVars[7].point, sMarioCamState->pos);
9476
vec3s_copy(sCutsceneVars[7].angle, sMarioCamState->faceAngle);
9477
vec3f_set(sCutsceneVars[6].point, 6.f, 363.f, 543.f);
9478
vec3f_set(sCutsceneVars[5].point, 137.f, 226.f, 995.f);
9479
}
9480
9481
/**
9482
* Set the camera pos depending on which level Mario exited.
9483
*/
9484
BAD_RETURN(s32) cutscene_non_painting_set_cam_pos(struct Camera *c) {
9485
UNUSED u32 unused1;
9486
struct Surface *floor;
9487
UNUSED Vec3f unused2;
9488
9489
switch (gPrevLevel) {
9490
case LEVEL_HMC:
9491
vec3f_set(c->pos, 3465.f, -1008.f, -2961.f);
9492
break;
9493
9494
case LEVEL_COTMC:
9495
vec3f_set(c->pos, 3465.f, -1008.f, -2961.f);
9496
break;
9497
9498
case LEVEL_RR:
9499
vec3f_set(c->pos, -3741.f, 3151.f, 6065.f);
9500
break;
9501
9502
case LEVEL_WMOTR:
9503
vec3f_set(c->pos, 1972.f, 3230.f, 5891.f);
9504
break;
9505
9506
default:
9507
offset_rotated(c->pos, sCutsceneVars[7].point, sCutsceneVars[5].point, sCutsceneVars[7].angle);
9508
c->pos[1] = find_floor(c->pos[0], c->pos[1] + 1000.f, c->pos[2], &floor) + 125.f;
9509
break;
9510
}
9511
}
9512
9513
/**
9514
* Update the camera focus depending on which level Mario exited.
9515
*/
9516
BAD_RETURN(s32) cutscene_non_painting_set_cam_focus(struct Camera *c) {
9517
offset_rotated(c->focus, sCutsceneVars[7].point, sCutsceneVars[6].point, sCutsceneVars[7].angle);
9518
9519
if ((gPrevLevel == LEVEL_COTMC) || (gPrevLevel == LEVEL_HMC) || (gPrevLevel == LEVEL_RR)
9520
|| (gPrevLevel == LEVEL_WMOTR)) {
9521
c->focus[0] = c->pos[0] + (sMarioCamState->pos[0] - c->pos[0]) * 0.7f;
9522
c->focus[1] = c->pos[1] + (sMarioCamState->pos[1] - c->pos[1]) * 0.4f;
9523
c->focus[2] = c->pos[2] + (sMarioCamState->pos[2] - c->pos[2]) * 0.7f;
9524
} else {
9525
c->focus[1] = c->pos[1] + (sMarioCamState->pos[1] - c->pos[1]) * 0.2f;
9526
}
9527
}
9528
9529
/**
9530
* Focus slightly left of Mario. Perhaps to keep the bowser painting in view?
9531
*/
9532
BAD_RETURN(s32) cutscene_exit_bowser_succ_focus_left(UNUSED struct Camera *c) {
9533
approach_f32_asymptotic_bool(&sCutsceneVars[6].point[0], -24.f, 0.05f);
9534
}
9535
9536
/**
9537
* Instead of focusing on the key, just start a pitch shake. Clever!
9538
* The shake lasts 32 frames.
9539
*/
9540
BAD_RETURN(s32) cutscene_exit_bowser_key_toss_shake(struct Camera *c) {
9541
//! Unnecessary check.
9542
if (c->cutscene == CUTSCENE_EXIT_BOWSER_SUCC) {
9543
set_camera_pitch_shake(0x800, 0x40, 0x800);
9544
}
9545
}
9546
9547
/**
9548
* Start a camera shake when Mario lands on the ground.
9549
*/
9550
BAD_RETURN(s32) cutscene_exit_succ_shake_landing(UNUSED struct Camera *c) {
9551
set_environmental_camera_shake(SHAKE_ENV_EXPLOSION);
9552
}
9553
9554
/**
9555
* Cutscene that plays when Mario beats bowser and exits the level.
9556
*/
9557
BAD_RETURN(s32) cutscene_exit_bowser_succ(struct Camera *c) {
9558
cutscene_event(cutscene_exit_succ_start, c, 0, 0);
9559
cutscene_event(cutscene_non_painting_set_cam_pos, c, 0, -1);
9560
cutscene_event(cutscene_exit_bowser_succ_focus_left, c, 18, -1);
9561
cutscene_event(cutscene_non_painting_set_cam_focus, c, 0, -1);
9562
cutscene_event(cutscene_exit_bowser_key_toss_shake, c, 125, 125);
9563
cutscene_event(cutscene_exit_succ_shake_landing, c, 41, 41);
9564
}
9565
9566
/**
9567
* End a non-painting exit cutscene. Used by BBH and bowser courses.
9568
*/
9569
BAD_RETURN(s32) cutscene_non_painting_end(struct Camera *c) {
9570
c->cutscene = 0;
9571
9572
if (c->defMode == CAMERA_MODE_CLOSE) {
9573
c->mode = CAMERA_MODE_CLOSE;
9574
} else {
9575
c->mode = CAMERA_MODE_FREE_ROAM;
9576
}
9577
9578
sStatusFlags |= CAM_FLAG_UNUSED_CUTSCENE_ACTIVE;
9579
sStatusFlags |= CAM_FLAG_SMOOTH_MOVEMENT;
9580
transition_next_state(c, 60);
9581
update_camera_yaw(c);
9582
}
9583
9584
/**
9585
* Override the position offset.
9586
*/
9587
BAD_RETURN(s32) cutscene_exit_non_painting_succ_override_cvar(UNUSED struct Camera *c) {
9588
vec3f_set(sCutsceneVars[5].point, 137.f, 246.f, 1115.f);
9589
}
9590
9591
/**
9592
* Cutscene that plays when Mario collects a star and leaves a non-painting course, like HMC or BBH.
9593
*/
9594
BAD_RETURN(s32) cutscene_exit_non_painting_succ(struct Camera *c) {
9595
cutscene_event(cutscene_exit_succ_start, c, 0, 0);
9596
cutscene_event(cutscene_exit_non_painting_succ_override_cvar, c, 0, 0);
9597
cutscene_event(cutscene_non_painting_set_cam_pos, c, 0, -1);
9598
cutscene_event(cutscene_exit_bowser_succ_focus_left, c, 18, -1);
9599
cutscene_event(cutscene_non_painting_set_cam_focus, c, 0, -1);
9600
cutscene_event(cutscene_exit_succ_shake_landing, c, 41, 41);
9601
update_camera_yaw(c);
9602
}
9603
9604
/**
9605
* Set cvar7 to Mario's pos and faceAngle
9606
* Set cvar6 to the focus offset from Mario.
9607
* set cvar5 to the pos offset from Mario. (This is always overwritten)
9608
*/
9609
BAD_RETURN(s32) cutscene_non_painting_death_start(UNUSED struct Camera *c) {
9610
vec3f_copy(sCutsceneVars[7].point, sMarioCamState->pos);
9611
vec3s_copy(sCutsceneVars[7].angle, sMarioCamState->faceAngle);
9612
vec3f_set(sCutsceneVars[6].point, -42.f, 350.f, 727.f);
9613
// This is always overwritten, except in the unused cutscene_exit_bowser_death()
9614
vec3f_set(sCutsceneVars[5].point, 107.f, 226.f, 1187.f);
9615
}
9616
9617
/**
9618
* This cutscene is the same as non_painting_death, but the camera is closer to Mario and lower.
9619
* Because it it doesn't call cutscene_non_painting_death_override_offset, the value from
9620
* cutscene_non_painting_death_start is used.
9621
*
9622
* This cutscene is unused, dying in bowser's arena spawns Mario near the warp pipe, not back in the
9623
* hub.
9624
*/
9625
BAD_RETURN(s32) cutscene_exit_bowser_death(struct Camera *c) {
9626
cutscene_event(cutscene_non_painting_death_start, c, 0, 0);
9627
cutscene_event(cutscene_non_painting_set_cam_pos, c, 0, -1);
9628
cutscene_event(cutscene_non_painting_set_cam_focus, c, 0, -1);
9629
}
9630
9631
/**
9632
* Set the offset from Mario depending on the course Mario exited.
9633
* This overrides cutscene_non_painting_death_start()
9634
*/
9635
BAD_RETURN(s32) cutscene_non_painting_death_override_offset(UNUSED struct Camera *c) {
9636
switch (gPrevLevel) {
9637
case LEVEL_HMC:
9638
vec3f_set(sCutsceneVars[5].point, 187.f, 369.f, -197.f);
9639
break;
9640
case LEVEL_COTMC:
9641
vec3f_set(sCutsceneVars[5].point, 187.f, 369.f, -197.f);
9642
break;
9643
default:
9644
vec3f_set(sCutsceneVars[5].point, 107.f, 246.f, 1307.f);
9645
break;
9646
}
9647
}
9648
9649
/**
9650
* Cutscene played when Mario dies in a non-painting course, like HMC or BBH.
9651
*/
9652
BAD_RETURN(s32) cutscene_non_painting_death(struct Camera *c) {
9653
cutscene_event(cutscene_non_painting_death_start, c, 0, 0);
9654
cutscene_event(cutscene_non_painting_death_override_offset, c, 0, 0);
9655
cutscene_event(cutscene_non_painting_set_cam_pos, c, 0, -1);
9656
cutscene_event(cutscene_non_painting_set_cam_focus, c, 0, -1);
9657
sStatusFlags |= CAM_FLAG_UNUSED_CUTSCENE_ACTIVE;
9658
}
9659
9660
/**
9661
* Set cvars:
9662
* cvar3 is an offset applied to the camera's rotation around Mario. It starts at 0x1200
9663
* cvar 1 is more complicated:
9664
* First the yaw from Mario to the camera is calculated. cvar1 is the high byte of the difference
9665
* between that yaw and Mario's faceAngle plus 0x1200. The reason for taking the high byte is
9666
* because cvar1 rotates until is reaches 0, so it's important that it's a multiple of 0x100.
9667
*/
9668
BAD_RETURN(s32) cutscene_cap_switch_press_start(struct Camera *c) {
9669
UNUSED s16 unused1;
9670
s16 yaw;
9671
UNUSED u32 pad[2];
9672
9673
store_info_star(c);
9674
yaw = calculate_yaw(sMarioCamState->pos, c->pos);
9675
sCutsceneVars[3].angle[1] = 0x1200;
9676
// Basically the amount of rotation to get from behind Mario to in front of Mario
9677
sCutsceneVars[1].angle[1] = (yaw - (sMarioCamState->faceAngle[1] + sCutsceneVars[3].angle[1])) & 0xFF00;
9678
}
9679
9680
/**
9681
* Rotate around Mario. As each cvar stops updating, the rotation slows until the camera ends up in
9682
* front of Mario.
9683
*/
9684
BAD_RETURN(s32) cutscene_cap_switch_press_rotate_around_mario(struct Camera *c) {
9685
f32 dist;
9686
s16 pitch, yaw;
9687
UNUSED s16 unusedYaw = sMarioCamState->faceAngle[1] + 0x1000;
9688
UNUSED s16 unused;
9689
UNUSED s32 cvar1Yaw = sCutsceneVars[1].angle[1];
9690
9691
vec3f_get_dist_and_angle(sMarioCamState->pos, c->pos, &dist, &pitch, &yaw);
9692
9693
// cvar3 wraps around until it reaches 0x1000
9694
if (sCutsceneVars[3].angle[1] != 0x1000) {
9695
sCutsceneVars[3].angle[1] += 0x100;
9696
}
9697
9698
// cvar1 wraps until 0
9699
if (sCutsceneVars[1].angle[1] != 0) {
9700
sCutsceneVars[1].angle[1] += 0x100;
9701
}
9702
9703
yaw = sMarioCamState->faceAngle[1] + sCutsceneVars[3].angle[1] + sCutsceneVars[1].angle[1];
9704
vec3f_set_dist_and_angle(sMarioCamState->pos, c->pos, dist, pitch, yaw);
9705
}
9706
9707
/**
9708
* Move the camera slightly downwards.
9709
*/
9710
BAD_RETURN(s32) cutscene_cap_switch_press_lower_cam(struct Camera *c) {
9711
rotate_and_move_vec3f(c->pos, sMarioCamState->pos, 0, -0x20, 0);
9712
}
9713
9714
/**
9715
* Move the camera closer to Mario.
9716
*/
9717
BAD_RETURN(s32) cutscene_cap_switch_press_approach_mario(struct Camera *c) {
9718
s16 pitch, yaw;
9719
f32 dist;
9720
9721
vec3f_get_dist_and_angle(sMarioCamState->pos, c->pos, &dist, &pitch, &yaw);
9722
approach_f32_asymptotic_bool(&dist, 195.f, 0.2f);
9723
approach_s16_asymptotic_bool(&pitch, 0, 0x10);
9724
vec3f_set_dist_and_angle(sMarioCamState->pos, c->pos, dist, pitch, yaw);
9725
9726
approach_f32_asymptotic_bool(&c->focus[0], sMarioCamState->pos[0], 0.1f);
9727
approach_f32_asymptotic_bool(&c->focus[1], sMarioCamState->pos[1] + 110.f, 0.1f);
9728
approach_f32_asymptotic_bool(&c->focus[2], sMarioCamState->pos[2], 0.1f);
9729
}
9730
9731
/**
9732
* Pan the camera left so that Mario is on the right side of the screen when the camera stops spinning.
9733
*/
9734
BAD_RETURN(s32) cutscene_cap_switch_press_pan_left(struct Camera *c) {
9735
vec3f_copy(c->focus, sMarioCamState->pos);
9736
c->focus[1] += 110.f;
9737
camera_approach_s16_symmetric_bool(&sCutsceneVars[0].angle[1], 0x800, 0x20);
9738
pan_camera(c, sCutsceneVars[0].angle[0], sCutsceneVars[0].angle[1]);
9739
}
9740
9741
/**
9742
* Create a dialog box with the cap switch's text.
9743
*/
9744
BAD_RETURN(s32) cutscene_cap_switch_press_create_dialog(UNUSED struct Camera *c) {
9745
create_dialog_box_with_response(gCutsceneFocus->oBehParams2ndByte + DIALOG_010);
9746
}
9747
9748
static UNUSED BAD_RETURN(s32) unused_cap_switch_retrieve_info(struct Camera *c) {
9749
retrieve_info_star(c);
9750
transition_next_state(c, 30);
9751
}
9752
9753
/**
9754
* Cutscene that plays when Mario presses a cap switch.
9755
*/
9756
BAD_RETURN(s32) cutscene_cap_switch_press(struct Camera *c) {
9757
f32 dist;
9758
s16 pitch, yaw;
9759
9760
sStatusFlags |= CAM_FLAG_SMOOTH_MOVEMENT;
9761
sStatusFlags |= CAM_FLAG_UNUSED_CUTSCENE_ACTIVE;
9762
9763
cutscene_event(cutscene_cap_switch_press_start, c, 0, 0);
9764
cutscene_event(cutscene_cap_switch_press_approach_mario, c, 0, 30);
9765
cutscene_event(cutscene_cap_switch_press_pan_left, c, 0, -1);
9766
cutscene_event(cutscene_cap_switch_press_rotate_around_mario, c, 30, -1);
9767
cutscene_event(cutscene_cap_switch_press_lower_cam, c, 10, 70);
9768
cutscene_event(cutscene_cap_switch_press_create_dialog, c, 10, 10);
9769
vec3f_get_dist_and_angle(sMarioCamState->pos, c->pos, &dist, &pitch, &yaw);
9770
9771
if (gDialogResponse != DIALOG_RESPONSE_NONE) {
9772
sCutsceneVars[4].angle[0] = gDialogResponse;
9773
}
9774
9775
if ((get_dialog_id() == DIALOG_NONE) && (sCutsceneVars[4].angle[0] != 0)) {
9776
sCutsceneDialogResponse = sCutsceneVars[4].angle[0];
9777
if (sCutsceneVars[4].angle[0] == 1) {
9778
cap_switch_save(gCutsceneFocus->oBehParams2ndByte);
9779
}
9780
stop_cutscene_and_retrieve_stored_info(c);
9781
transition_next_state(c, 30);
9782
}
9783
}
9784
9785
/**
9786
* Sets cvars:
9787
* cvar0 is the camera's position
9788
* cvar1 is the camera's focus
9789
* cvar2 is the goal position
9790
* cvar3 is the goal focus
9791
*/
9792
BAD_RETURN(s32) cutscene_unlock_key_door_start(struct Camera *c) {
9793
Vec3f posOff, focusOff;
9794
9795
vec3f_copy(sCutsceneVars[0].point, c->pos);
9796
vec3f_copy(sCutsceneVars[1].point, c->focus);
9797
vec3f_set(posOff, -206.f, 108.f, 234.f);
9798
vec3f_set(focusOff, 48.f, 104.f, -193.f);
9799
offset_rotated(sCutsceneVars[2].point, sMarioCamState->pos, posOff, sMarioCamState->faceAngle);
9800
offset_rotated(sCutsceneVars[3].point, sMarioCamState->pos, focusOff, sMarioCamState->faceAngle);
9801
}
9802
9803
/**
9804
* Move the camera to the cvars position and focus, closer to Mario.
9805
* Gives a better view of the key.
9806
*/
9807
BAD_RETURN(s32) cutscene_unlock_key_door_approach_mario(struct Camera *c) {
9808
approach_vec3f_asymptotic(c->pos, sCutsceneVars[2].point, 0.1f, 0.1f, 0.1f);
9809
approach_vec3f_asymptotic(c->focus, sCutsceneVars[3].point, 0.1f, 0.1f, 0.1f);
9810
}
9811
9812
/**
9813
* Move the camera focus up a bit, focusing on the key in the lock.
9814
*/
9815
BAD_RETURN(s32) cutscene_unlock_key_door_focus_lock(UNUSED struct Camera *c) {
9816
approach_f32_asymptotic_bool(&sCutsceneVars[3].point[1], sMarioCamState->pos[1] + 140.f, 0.07f);
9817
}
9818
9819
BAD_RETURN(s32) cutscene_unlock_key_door_stub(UNUSED struct Camera *c) {
9820
}
9821
9822
/**
9823
* Move back to the previous pos and focus, stored in cvar0 and cvar1.
9824
*/
9825
BAD_RETURN(s32) cutscene_unlock_key_door_fly_back(struct Camera *c) {
9826
approach_vec3f_asymptotic(c->pos, sCutsceneVars[0].point, 0.1f, 0.1f, 0.1f);
9827
approach_vec3f_asymptotic(c->focus, sCutsceneVars[1].point, 0.1f, 0.1f, 0.1f);
9828
}
9829
9830
/**
9831
* Shake the camera's fov when the key is put in the lock.
9832
*/
9833
BAD_RETURN(s32) cutscene_unlock_key_door_fov_shake(UNUSED struct Camera *c) {
9834
cutscene_set_fov_shake_preset(1);
9835
}
9836
9837
/**
9838
* Cutscene that plays when Mario unlocks a key door.
9839
*/
9840
BAD_RETURN(s32) cutscene_unlock_key_door(UNUSED struct Camera *c) {
9841
cutscene_event(cutscene_unlock_key_door_start, c, 0, 0);
9842
cutscene_event(cutscene_unlock_key_door_approach_mario, c, 0, 123);
9843
cutscene_event(cutscene_unlock_key_door_fly_back, c, 124, -1);
9844
cutscene_event(cutscene_unlock_key_door_fov_shake, c, 79, 79);
9845
cutscene_event(cutscene_unlock_key_door_focus_lock, c, 70, 110);
9846
cutscene_event(cutscene_unlock_key_door_stub, c, 112, 112);
9847
}
9848
9849
/**
9850
* Move the camera along `positionSpline` and point its focus at the corresponding point along
9851
* `focusSpline`. sCutsceneSplineSegmentProgress is updated after pos and focus are calculated.
9852
*/
9853
s32 intro_peach_move_camera_start_to_pipe(struct Camera *c, struct CutsceneSplinePoint positionSpline[],
9854
struct CutsceneSplinePoint focusSpline[]) {
9855
Vec3f offset;
9856
s32 posReturn = 0;
9857
s32 focusReturn = 0;
9858
9859
/**
9860
* The position spline's speed parameters are all 0, so sCutsceneSplineSegmentProgress doesn't get
9861
* updated. Otherwise position would move two frames ahead, and c->focus would always be one frame
9862
* further along the spline than c->pos.
9863
*/
9864
posReturn = move_point_along_spline(c->pos, positionSpline, &sCutsceneSplineSegment, &sCutsceneSplineSegmentProgress);
9865
focusReturn = move_point_along_spline(c->focus, focusSpline, &sCutsceneSplineSegment, &sCutsceneSplineSegmentProgress);
9866
9867
// The two splines used by this function are reflected in the horizontal plane for some reason,
9868
// so they are rotated every frame. Why do this, Nintendo?
9869
rotate_in_xz(c->focus, c->focus, DEGREES(-180));
9870
rotate_in_xz(c->pos, c->pos, DEGREES(-180));
9871
9872
vec3f_set(offset, -1328.f, 260.f, 4664.f);
9873
vec3f_add(c->focus, offset);
9874
vec3f_add(c->pos, offset);
9875
9876
posReturn += focusReturn; // Unused
9877
return focusReturn;
9878
}
9879
9880
/**
9881
* Create a dialog box with the letter text
9882
*/
9883
BAD_RETURN(s32) peach_letter_text(UNUSED struct Camera *c) {
9884
create_dialog_box(DIALOG_020);
9885
}
9886
9887
#ifndef VERSION_JP
9888
BAD_RETURN(s32) play_sound_peach_reading_letter(UNUSED struct Camera *c) {
9889
play_sound(SOUND_PEACH_DEAR_MARIO, gGlobalSoundSource);
9890
}
9891
#endif
9892
9893
/**
9894
* Move the camera from peach reading the letter all the way to Mario's warp pipe. Follow the
9895
* sIntroStartToPipe splines.
9896
*/
9897
BAD_RETURN(s32) cutscene_intro_peach_start_to_pipe_spline(struct Camera *c) {
9898
if (intro_peach_move_camera_start_to_pipe(c, sIntroStartToPipePosition, sIntroStartToPipeFocus) != 0) {
9899
gCameraMovementFlags &= ~CAM_MOVE_C_UP_MODE;
9900
gCutsceneTimer = CUTSCENE_LOOP;
9901
}
9902
}
9903
9904
/**
9905
* Loop the cutscene until Mario exits the dialog.
9906
*/
9907
BAD_RETURN(s32) cutscene_intro_peach_dialog(struct Camera *c) {
9908
if (get_dialog_id() == DIALOG_NONE) {
9909
vec3f_copy(gLakituState.goalPos, c->pos);
9910
vec3f_copy(gLakituState.goalFocus, c->focus);
9911
sStatusFlags |= (CAM_FLAG_SMOOTH_MOVEMENT | CAM_FLAG_UNUSED_CUTSCENE_ACTIVE);
9912
gCutsceneTimer = CUTSCENE_STOP;
9913
c->cutscene = 0;
9914
}
9915
}
9916
9917
BAD_RETURN(s32) cutscene_intro_peach_follow_pipe_spline(struct Camera *c) {
9918
move_point_along_spline(c->pos, sIntroPipeToDialogPosition, &sCutsceneSplineSegment, &sCutsceneSplineSegmentProgress);
9919
move_point_along_spline(c->focus, sIntroPipeToDialogFocus, &sCutsceneSplineSegment, &sCutsceneSplineSegmentProgress);
9920
}
9921
9922
BAD_RETURN(s32) cutscene_intro_peach_clear_cutscene_status(UNUSED struct Camera *c) {
9923
sMarioCamState->cameraEvent = 0;
9924
}
9925
9926
/**
9927
* Set fov to 8 degrees, then zoom out to 30.
9928
*/
9929
BAD_RETURN(s32) cutscene_intro_peach_zoom_fov(UNUSED struct Camera *c) {
9930
sFOVState.fov = 8.f;
9931
set_fov_function(CAM_FOV_ZOOM_30);
9932
}
9933
9934
/**
9935
* Reset the spline progress, turn on handheld shake.
9936
*/
9937
BAD_RETURN(s32) cutscene_intro_peach_reset_spline(UNUSED struct Camera *c) {
9938
sCutsceneSplineSegment = 0;
9939
sCutsceneSplineSegmentProgress = 0.1f;
9940
//! @bug since this event is only called for one frame, this handheld shake is turned off on the
9941
//! next frame.
9942
set_handheld_shake(HAND_CAM_SHAKE_HIGH);
9943
}
9944
9945
/**
9946
* Turn off handheld shake. This was likely written before handheld shake was changed to turn off every
9947
* frame, as it's the only instance of HAND_CAM_SHAKE_OFF.
9948
*/
9949
BAD_RETURN(s32) cutscene_intro_peach_handheld_shake_off(UNUSED struct Camera *c) {
9950
set_handheld_shake(HAND_CAM_SHAKE_OFF);
9951
}
9952
9953
BAD_RETURN(s32) intro_pipe_exit_text(UNUSED struct Camera *c) {
9954
create_dialog_box(DIALOG_033);
9955
}
9956
9957
#ifndef VERSION_JP
9958
BAD_RETURN(s32) play_sound_intro_turn_on_hud(UNUSED struct Camera *c) {
9959
play_sound_rbutton_changed();
9960
}
9961
#endif
9962
9963
/**
9964
* Fly to the pipe. Near the end, the camera jumps to Lakitu's position and the hud turns on.
9965
*/
9966
BAD_RETURN(s32) cutscene_intro_peach_fly_to_pipe(struct Camera *c) {
9967
#if defined(VERSION_US) || defined(VERSION_SH)
9968
cutscene_event(play_sound_intro_turn_on_hud, c, 818, 818);
9969
#elif defined(VERSION_EU)
9970
cutscene_event(play_sound_intro_turn_on_hud, c, 673, 673);
9971
#endif
9972
cutscene_spawn_obj(6, 1);
9973
cutscene_event(cutscene_intro_peach_start_flying_music, c, 0, 0);
9974
cutscene_event(cutscene_intro_peach_start_to_pipe_spline, c, 0, -1);
9975
#ifdef VERSION_EU
9976
cutscene_event(cutscene_intro_peach_clear_cutscene_status, c, 572, 572);
9977
#else
9978
cutscene_event(cutscene_intro_peach_clear_cutscene_status, c, 717, 717);
9979
#endif
9980
clamp_pitch(c->pos, c->focus, 0x3B00, -0x3B00);
9981
sCutsceneVars[1].point[1] = 400.f;
9982
}
9983
9984
/**
9985
* Lakitu flies around the warp pipe, then Mario jumps out.
9986
*/
9987
BAD_RETURN(s32) cutscene_intro_peach_mario_appears(struct Camera *c) {
9988
UNUSED u32 pad[2];
9989
9990
sMarioCamState->cameraEvent = 0;
9991
cutscene_event(cutscene_intro_peach_reset_spline, c, 0, 0);
9992
cutscene_event(cutscene_intro_peach_follow_pipe_spline, c, 0, -1);
9993
cutscene_event(cutscene_intro_peach_handheld_shake_off, c, 70, 70);
9994
cutscene_event(intro_pipe_exit_text, c, 250, 250);
9995
9996
approach_f32_asymptotic_bool(&sCutsceneVars[1].point[1], 80.f + sMarioGeometry.currFloorHeight +
9997
(sMarioCamState->pos[1] - sMarioGeometry.currFloorHeight) * 1.1f, 0.4f);
9998
9999
// Make the camera look up as Mario jumps out of the pipe
10000
if (c->focus[1] < sCutsceneVars[1].point[1]) {
10001
c->focus[1] = sCutsceneVars[1].point[1];
10002
}
10003
10004
sStatusFlags |= CAM_FLAG_UNUSED_CUTSCENE_ACTIVE;
10005
}
10006
10007
/**
10008
* Reset the fov. This gives the effect of peach zooming out as she fades.
10009
*/
10010
BAD_RETURN(s32) cutscene_intro_peach_reset_fov(UNUSED struct Camera *c) {
10011
set_fov_function(CAM_FOV_DEFAULT);
10012
}
10013
10014
/**
10015
* Peach reads the letter to Mario.
10016
*/
10017
BAD_RETURN(s32) cutscene_intro_peach_letter(struct Camera *c) {
10018
cutscene_spawn_obj(5, 0);
10019
cutscene_event(cutscene_intro_peach_zoom_fov, c, 0, 0);
10020
cutscene_event(cutscene_intro_peach_start_letter_music, c, 65, 65);
10021
#ifdef VERSION_EU
10022
cutscene_event(cutscene_intro_peach_eu_lower_volume, c, 68, 68);
10023
#endif
10024
cutscene_event(cutscene_intro_peach_start_to_pipe_spline, c, 0, 0);
10025
cutscene_event(peach_letter_text, c, 65, 65);
10026
#ifndef VERSION_JP
10027
cutscene_event(play_sound_peach_reading_letter, c, 83, 83);
10028
#endif
10029
10030
if ((gCutsceneTimer > 120) && (get_dialog_id() == DIALOG_NONE)) {
10031
// Start the next scene
10032
gCutsceneTimer = CUTSCENE_LOOP;
10033
}
10034
10035
clamp_pitch(c->pos, c->focus, 0x3B00, -0x3B00);
10036
}
10037
10038
/**
10039
* Reset the spline progress.
10040
*/
10041
BAD_RETURN(s32) cutscene_end_waving_start(UNUSED struct Camera *c) {
10042
cutscene_reset_spline();
10043
}
10044
10045
// 3rd part of data
10046
struct CutsceneSplinePoint gIntroLakituStartToPipeFocus[] = {
10047
{ 0, 32, { 58, -250, 346 } }, { 1, 50, { -159, -382, 224 } }, { 2, 37, { 0, -277, 237 } },
10048
{ 3, 15, { 1, -44, 245 } }, { 4, 35, { 0, -89, 228 } }, { 5, 15, { 28, 3, 259 } },
10049
{ 6, 25, { -38, -201, 371 } }, { 7, 20, { -642, 118, 652 } }, { 8, 25, { 103, -90, 861 } },
10050
{ 9, 25, { 294, 145, 579 } }, { 10, 30, { 220, -42, 500 } }, { 11, 20, { 10, -134, 200 } },
10051
{ 12, 20, { -143, -145, 351 } }, { 13, 14, { -256, -65, 528 } }, { 14, 20, { -251, -52, 459 } },
10052
{ 15, 25, { -382, 520, 395 } }, { 16, 25, { -341, 240, 653 } }, { 17, 5, { -262, 700, 143 } },
10053
{ 18, 15, { -760, 32, 27 } }, { 19, 20, { -756, -6, -26 } }, { 20, 20, { -613, 5, 424 } },
10054
{ 21, 20, { -22, -100, 312 } }, { 22, 25, { 212, 80, 61 } }, { 23, 20, { 230, -28, 230 } },
10055
{ 24, 35, { -83, -51, 303 } }, { 25, 17, { 126, 90, 640 } }, { 26, 9, { 158, 95, 763 } },
10056
{ 27, 8, { 113, -25, 1033 } }, { 28, 20, { 57, -53, 1291 } }, { 29, 15, { 73, -34, 1350 } },
10057
{ 30, 7, { 0, 96, 1400 } }, { 31, 8, { -59, 269, 1450 } }, { 32, 15, { 57, 1705, 1500 } },
10058
{ 0, 15, { -227, 511, 1550 } }, { -1, 15, { -227, 511, 1600 } }
10059
};
10060
10061
struct CutsceneSplinePoint gIntroLakituStartToPipeOffsetFromCamera[] = {
10062
{ 0, 0, { -46, 87, -15 } }, { 1, 0, { -38, 91, -11 } }, { 2, 0, { -31, 93, -13 } },
10063
{ 3, 0, { -50, 84, -16 } }, { 4, 0, { -52, 83, -17 } }, { 5, 0, { -10, 99, 3 } },
10064
{ 6, 0, { -54, 83, -10 } }, { 7, 0, { -31, 85, -40 } }, { 8, 0, { -34, 91, 19 } },
10065
{ 9, 0, { -9, 95, 28 } }, { 10, 0, { 17, 72, 66 } }, { 11, 0, { 88, -7, 45 } },
10066
{ 12, 0, { 96, -6, -26 } }, { 13, 0, { 56, -1, -82 } }, { 14, 0, { 40, 65, -63 } },
10067
{ 15, 0, { -26, -3, -96 } }, { 16, 0, { 92, 82, 19 } }, { 17, 0, { 92, 32, 19 } },
10068
{ 18, 0, { 92, 32, 19 } }, { 19, 0, { 92, 102, 19 } }, { 20, 0, { -69, 59, -70 } },
10069
{ 21, 0, { -77, 109, -61 } }, { 22, 0, { -87, 59, -46 } }, { 23, 0, { -99, -3, 11 } },
10070
{ 24, 0, { -99, -11, 5 } }, { 25, 0, { -97, -6, 19 } }, { 26, 0, { -97, 22, -7 } },
10071
{ 27, 0, { -98, -11, -13 } }, { 28, 0, { -97, -11, 19 } }, { 29, 0, { -91, -11, 38 } },
10072
{ 30, 0, { -76, -11, 63 } }, { 31, 0, { -13, 33, 93 } }, { 32, 0, { 51, -11, 84 } },
10073
{ 33, 0, { 51, -11, 84 } }, { -1, 0, { 51, -11, 84 } }
10074
};
10075
10076
struct CutsceneSplinePoint gEndWavingPos[] = {
10077
{ 0, 0, { -5, 975, -917 } }, { 0, 0, { -5, 975, -917 } }, { 0, 0, { -5, 975, -917 } },
10078
{ 0, 0, { -76, 1067, 742 } }, { 0, 0, { -105, 1576, 3240 } }, { 0, 0, { -177, 1709, 5586 } },
10079
{ 0, 0, { -177, 1709, 5586 } }, { 0, 0, { -177, 1709, 5586 } }, { 0, 0, { -177, 1709, 5586 } }
10080
};
10081
10082
struct CutsceneSplinePoint gEndWavingFocus[] = {
10083
{ 0, 50, { 18, 1013, -1415 } }, { 0, 100, { 17, 1037, -1412 } }, { 0, 100, { 16, 1061, -1408 } },
10084
{ 0, 100, { -54, 1053, 243 } }, { 0, 100, { -84, 1575, 2740 } }, { 0, 50, { -156, 1718, 5086 } },
10085
{ 0, 0, { -156, 1718, 5086 } }, { 0, 0, { -156, 1718, 5086 } }, { 0, 0, { -156, 1718, 5086 } }
10086
};
10087
10088
BAD_RETURN(s32) cutscene_end_waving(struct Camera *c) {
10089
cutscene_event(cutscene_end_waving_start, c, 0, 0);
10090
move_point_along_spline(c->pos, gEndWavingPos, &sCutsceneSplineSegment, &sCutsceneSplineSegmentProgress);
10091
move_point_along_spline(c->focus, gEndWavingFocus, &sCutsceneSplineSegment, &sCutsceneSplineSegmentProgress);
10092
cutscene_spawn_obj(6, 120);
10093
}
10094
10095
/**
10096
* Called on the first frame of the credits. Resets the spline progress.
10097
*/
10098
BAD_RETURN(s32) cutscene_credits_reset_spline(UNUSED struct Camera *c) {
10099
cutscene_reset_spline();
10100
}
10101
10102
extern struct CutsceneSplinePoint sBobCreditsSplinePositions[];
10103
extern struct CutsceneSplinePoint sBobCreditsSplineFocus[];
10104
extern struct CutsceneSplinePoint sWfCreditsSplinePositions[];
10105
extern struct CutsceneSplinePoint sWfCreditsSplineFocus[];
10106
extern struct CutsceneSplinePoint sJrbCreditsSplinePositions[];
10107
extern struct CutsceneSplinePoint sJrbCreditsSplineFocus[];
10108
extern struct CutsceneSplinePoint sCcmSlideCreditsSplinePositions[];
10109
extern struct CutsceneSplinePoint sCcmSlideCreditsSplineFocus[];
10110
extern struct CutsceneSplinePoint sBbhCreditsSplinePositions[];
10111
extern struct CutsceneSplinePoint sBbhCreditsSplineFocus[];
10112
extern struct CutsceneSplinePoint sHmcCreditsSplinePositions[];
10113
extern struct CutsceneSplinePoint sHmcCreditsSplineFocus[];
10114
extern struct CutsceneSplinePoint sThiWigglerCreditsSplinePositions[];
10115
extern struct CutsceneSplinePoint sThiWigglerCreditsSplineFocus[];
10116
extern struct CutsceneSplinePoint sVolcanoCreditsSplinePositions[];
10117
extern struct CutsceneSplinePoint sVolcanoCreditsSplineFocus[];
10118
extern struct CutsceneSplinePoint sSslCreditsSplinePositions[];
10119
extern struct CutsceneSplinePoint sSslCreditsSplineFocus[];
10120
extern struct CutsceneSplinePoint sDddCreditsSplinePositions[];
10121
extern struct CutsceneSplinePoint sDddCreditsSplineFocus[];
10122
extern struct CutsceneSplinePoint sSlCreditsSplinePositions[];
10123
extern struct CutsceneSplinePoint sSlCreditsSplineFocus[];
10124
extern struct CutsceneSplinePoint sWdwCreditsSplinePositions[];
10125
extern struct CutsceneSplinePoint sWdwCreditsSplineFocus[];
10126
extern struct CutsceneSplinePoint sTtmCreditsSplinePositions[];
10127
extern struct CutsceneSplinePoint sTtmCreditsSplineFocus[];
10128
extern struct CutsceneSplinePoint sThiHugeCreditsSplinePositions[];
10129
extern struct CutsceneSplinePoint sThiHugeCreditsSplineFocus[];
10130
extern struct CutsceneSplinePoint sTtcCreditsSplinePositions[];
10131
extern struct CutsceneSplinePoint sTtcCreditsSplineFocus[];
10132
extern struct CutsceneSplinePoint sRrCreditsSplinePositions[];
10133
extern struct CutsceneSplinePoint sRrCreditsSplineFocus[];
10134
extern struct CutsceneSplinePoint sSaCreditsSplinePositions[];
10135
extern struct CutsceneSplinePoint sSaCreditsSplineFocus[];
10136
extern struct CutsceneSplinePoint sCotmcCreditsSplinePositions[];
10137
extern struct CutsceneSplinePoint sCotmcCreditsSplineFocus[];
10138
extern struct CutsceneSplinePoint sDddSubCreditsSplinePositions[];
10139
extern struct CutsceneSplinePoint sDddSubCreditsSplineFocus[];
10140
extern struct CutsceneSplinePoint sCcmOutsideCreditsSplinePositions[];
10141
extern struct CutsceneSplinePoint sCcmOutsideCreditsSplineFocus[];
10142
10143
/**
10144
* Follow splines through the courses of the game.
10145
*/
10146
BAD_RETURN(s32) cutscene_credits(struct Camera *c) {
10147
struct CutsceneSplinePoint *focus, *pos;
10148
10149
cutscene_event(cutscene_credits_reset_spline, c, 0, 0);
10150
10151
switch (gCurrLevelArea) {
10152
case AREA_BOB:
10153
pos = sBobCreditsSplinePositions;
10154
focus = sBobCreditsSplineFocus;
10155
break;
10156
case AREA_WF:
10157
pos = sWfCreditsSplinePositions;
10158
focus = sWfCreditsSplineFocus;
10159
break;
10160
case AREA_JRB_MAIN:
10161
pos = sJrbCreditsSplinePositions;
10162
focus = sJrbCreditsSplineFocus;
10163
break;
10164
case AREA_CCM_SLIDE:
10165
pos = sCcmSlideCreditsSplinePositions;
10166
focus = sCcmSlideCreditsSplineFocus;
10167
break;
10168
case AREA_BBH:
10169
pos = sBbhCreditsSplinePositions;
10170
focus = sBbhCreditsSplineFocus;
10171
break;
10172
case AREA_HMC:
10173
pos = sHmcCreditsSplinePositions;
10174
focus = sHmcCreditsSplineFocus;
10175
break;
10176
case AREA_THI_WIGGLER:
10177
pos = sThiWigglerCreditsSplinePositions;
10178
focus = sThiWigglerCreditsSplineFocus;
10179
break;
10180
case AREA_LLL_VOLCANO:
10181
pos = sVolcanoCreditsSplinePositions;
10182
focus = sVolcanoCreditsSplineFocus;
10183
break;
10184
case AREA_SSL_OUTSIDE:
10185
pos = sSslCreditsSplinePositions;
10186
focus = sSslCreditsSplineFocus;
10187
break;
10188
case AREA_DDD_WHIRLPOOL:
10189
pos = sDddCreditsSplinePositions;
10190
focus = sDddCreditsSplineFocus;
10191
break;
10192
case AREA_SL_OUTSIDE:
10193
pos = sSlCreditsSplinePositions;
10194
focus = sSlCreditsSplineFocus;
10195
break;
10196
case AREA_WDW_MAIN:
10197
pos = sWdwCreditsSplinePositions;
10198
focus = sWdwCreditsSplineFocus;
10199
break;
10200
case AREA_TTM_OUTSIDE:
10201
pos = sTtmCreditsSplinePositions;
10202
focus = sTtmCreditsSplineFocus;
10203
break;
10204
case AREA_THI_HUGE:
10205
pos = sThiHugeCreditsSplinePositions;
10206
focus = sThiHugeCreditsSplineFocus;
10207
break;
10208
case AREA_TTC:
10209
pos = sTtcCreditsSplinePositions;
10210
focus = sTtcCreditsSplineFocus;
10211
break;
10212
case AREA_RR:
10213
pos = sRrCreditsSplinePositions;
10214
focus = sRrCreditsSplineFocus;
10215
break;
10216
case AREA_SA:
10217
pos = sSaCreditsSplinePositions;
10218
focus = sSaCreditsSplineFocus;
10219
break;
10220
case AREA_COTMC:
10221
pos = sCotmcCreditsSplinePositions;
10222
focus = sCotmcCreditsSplineFocus;
10223
break;
10224
case AREA_DDD_SUB:
10225
pos = sDddSubCreditsSplinePositions;
10226
focus = sDddSubCreditsSplineFocus;
10227
break;
10228
case AREA_CCM_OUTSIDE:
10229
//! Checks if the "Snowman's Lost His Head" star was collected. The credits likely would
10230
//! have avoided the snowman if the player didn't collect that star, but in the end the
10231
//! developers decided against it.
10232
if (save_file_get_star_flags(gCurrSaveFileNum - 1, gCurrCourseNum - 1) & 0x10) {
10233
pos = sCcmOutsideCreditsSplinePositions;
10234
focus = sCcmOutsideCreditsSplineFocus;
10235
} else {
10236
pos = sCcmOutsideCreditsSplinePositions;
10237
focus = sCcmOutsideCreditsSplineFocus;
10238
}
10239
break;
10240
default:
10241
pos = sCcmOutsideCreditsSplinePositions;
10242
focus = sCcmOutsideCreditsSplineFocus;
10243
}
10244
10245
copy_spline_segment(sCurCreditsSplinePos, pos);
10246
copy_spline_segment(sCurCreditsSplineFocus, focus);
10247
move_point_along_spline(c->pos, sCurCreditsSplinePos, &sCutsceneSplineSegment, &sCutsceneSplineSegmentProgress);
10248
move_point_along_spline(c->focus, sCurCreditsSplineFocus, &sCutsceneSplineSegment, &sCutsceneSplineSegmentProgress);
10249
player2_rotate_cam(c, -0x2000, 0x2000, -0x4000, 0x4000);
10250
}
10251
10252
/**
10253
* Set the camera pos relative to Mario.
10254
*/
10255
BAD_RETURN(s32) cutscene_sliding_doors_open_start(struct Camera *c) {
10256
f32 dist;
10257
s16 pitch, yaw;
10258
10259
vec3f_get_dist_and_angle(sMarioCamState->pos, c->pos, &dist, &pitch, &yaw);
10260
10261
// If the camera is too close, warp it backwards set it to a better angle.
10262
if (dist < 500.f) {
10263
dist = 500.f;
10264
yaw = sMarioCamState->faceAngle[1] + 0x8800;
10265
pitch = 0x800;
10266
}
10267
10268
vec3f_set_dist_and_angle(sMarioCamState->pos, c->pos, dist, pitch, yaw);
10269
}
10270
10271
/**
10272
* cvar1: Mario's position
10273
* cvar0.angle: Mario's angle
10274
* cvar0.point: offset from Mario
10275
*/
10276
BAD_RETURN(s32) cutscene_sliding_doors_open_set_cvars(UNUSED struct Camera *c) {
10277
vec3f_copy(sCutsceneVars[1].point, sMarioCamState->pos);
10278
vec3s_copy(sCutsceneVars[0].angle, sMarioCamState->faceAngle);
10279
vec3f_set(sCutsceneVars[0].point, 80.f, 325.f, 200.f);
10280
}
10281
10282
/**
10283
* Decrease the cvar0 y offset to 75, which would simulate Lakitu flying under the doorway.
10284
* However, the initial y offset is too high for Lakitu to reach 75 in time.
10285
*/
10286
BAD_RETURN(s32) cutscene_sliding_doors_go_under_doorway(UNUSED struct Camera *c) {
10287
camera_approach_f32_symmetric_bool(&sCutsceneVars[0].point[1], 75.f, 10.f);
10288
}
10289
10290
/**
10291
* Approach a y offset of 125 again.
10292
*/
10293
BAD_RETURN(s32) cutscene_sliding_doors_fly_back_up(UNUSED struct Camera *c) {
10294
camera_approach_f32_symmetric_bool(&sCutsceneVars[0].point[1], 125.f, 10.f);
10295
}
10296
10297
/**
10298
* Follow Mario through the door, by approaching cvar1.point.
10299
*/
10300
BAD_RETURN(s32) cutscene_sliding_doors_follow_mario(struct Camera *c) {
10301
Vec3f pos;
10302
UNUSED u32 pad[5];
10303
10304
vec3f_copy(pos, c->pos);
10305
// Update cvar1 with Mario's position (the y value doesn't change)
10306
sCutsceneVars[1].point[0] = sMarioCamState->pos[0];
10307
sCutsceneVars[1].point[2] = sMarioCamState->pos[2];
10308
10309
// Decrease cvar0's offsets, moving the camera behind Mario at his eye height.
10310
approach_f32_asymptotic_bool(&sCutsceneVars[0].point[0], 0, 0.1f);
10311
camera_approach_f32_symmetric_bool(&sCutsceneVars[0].point[2], 125.f, 50.f);
10312
// Update cvar0's angle
10313
approach_vec3s_asymptotic(sCutsceneVars[0].angle, sMarioCamState->faceAngle, 16, 16, 16);
10314
10315
// Apply the offset to the camera's position
10316
offset_rotated(pos, sCutsceneVars[1].point, sCutsceneVars[0].point, sCutsceneVars[0].angle);
10317
approach_vec3f_asymptotic(c->pos, pos, 0.15f, 0.05f, 0.15f);
10318
10319
// Focus on Mario's eye height
10320
set_focus_rel_mario(c, 0, 125.f, 0, 0);
10321
}
10322
10323
/**
10324
* Plays when Mario opens the sliding doors.
10325
* Note: the star door unlocking event is not a cutscene, it's handled by Mario separately.
10326
*/
10327
BAD_RETURN(s32) cutscene_sliding_doors_open(struct Camera *c) {
10328
UNUSED u32 pad[2];
10329
10330
reset_pan_distance(c);
10331
cutscene_event(cutscene_sliding_doors_open_start, c, 0, 8);
10332
cutscene_event(cutscene_sliding_doors_open_set_cvars, c, 8, 8);
10333
cutscene_event(cutscene_sliding_doors_go_under_doorway, c, 8, 28);
10334
cutscene_event(cutscene_sliding_doors_fly_back_up, c, 29, -1);
10335
cutscene_event(cutscene_sliding_doors_follow_mario, c, 8, -1);
10336
}
10337
10338
/**
10339
* Ends the double door cutscene.
10340
*/
10341
BAD_RETURN(s32) cutscene_double_doors_end(struct Camera *c) {
10342
set_flag_post_door(c);
10343
c->cutscene = 0;
10344
sStatusFlags |= CAM_FLAG_SMOOTH_MOVEMENT;
10345
}
10346
10347
BAD_RETURN(s32) cutscene_enter_painting_stub(UNUSED struct Camera *c) {
10348
}
10349
10350
/**
10351
* Plays when Mario enters a painting. The camera flies up to the painting's center, then it slowly
10352
* zooms in until the star select screen appears.
10353
*/
10354
BAD_RETURN(s32) cutscene_enter_painting(struct Camera *c) {
10355
struct Surface *floor, *highFloor;
10356
Vec3f paintingPos, focus, focusOffset;
10357
Vec3s paintingAngle;
10358
f32 floorHeight;
10359
10360
cutscene_event(cutscene_enter_painting_stub, c, 0, 0);
10361
10362
if (configBetaLikeCamera) {
10363
sStatusFlags |= CAM_FLAG_SMOOTH_MOVEMENT;
10364
}
10365
else {
10366
// Zoom in
10367
set_fov_function(CAM_FOV_APP_20);
10368
sStatusFlags |= CAM_FLAG_SMOOTH_MOVEMENT;
10369
10370
if (gRipplingPainting != NULL) {
10371
paintingAngle[0] = 0;
10372
paintingAngle[1] = (s32)((gRipplingPainting->yaw / 360.f) * 65536.f); // convert degrees to IAU
10373
paintingAngle[2] = 0;
10374
10375
focusOffset[0] = gRipplingPainting->size / 2;
10376
focusOffset[1] = focusOffset[0];
10377
focusOffset[2] = 0;
10378
10379
paintingPos[0] = gRipplingPainting->posX;
10380
paintingPos[1] = gRipplingPainting->posY;
10381
paintingPos[2] = gRipplingPainting->posZ;
10382
10383
offset_rotated(focus, paintingPos, focusOffset, paintingAngle);
10384
approach_vec3f_asymptotic(c->focus, focus, 0.1f, 0.1f, 0.1f);
10385
focusOffset[2] = -(((gRipplingPainting->size * 1000.f) / 2) / 307.f);
10386
offset_rotated(focus, paintingPos, focusOffset, paintingAngle);
10387
floorHeight = find_floor(focus[0], focus[1] + 500.f, focus[2], &highFloor) + 125.f;
10388
10389
if (focus[1] < floorHeight) {
10390
focus[1] = floorHeight;
10391
}
10392
10393
if (c->cutscene == CUTSCENE_ENTER_PAINTING) {
10394
approach_vec3f_asymptotic(c->pos, focus, 0.2f, 0.1f, 0.2f);
10395
} else {
10396
approach_vec3f_asymptotic(c->pos, focus, 0.9f, 0.9f, 0.9f);
10397
}
10398
10399
find_floor(sMarioCamState->pos[0], sMarioCamState->pos[1] + 50.f, sMarioCamState->pos[2], &floor);
10400
10401
if ((floor->type < SURFACE_PAINTING_WOBBLE_A6) || (floor->type > SURFACE_PAINTING_WARP_F9)) {
10402
c->cutscene = 0;
10403
gCutsceneTimer = CUTSCENE_STOP;
10404
sStatusFlags |= CAM_FLAG_SMOOTH_MOVEMENT;
10405
}
10406
}
10407
c->mode = CAMERA_MODE_CLOSE;
10408
}
10409
}
10410
10411
/**
10412
* Warp the camera to Mario, then use his faceAngle to calculate the right relative position.
10413
*
10414
* cvar0.point is Mario's position
10415
* cvar0.angle is Mario's faceAngle
10416
*
10417
* cvar1 is the camera's position relative to Mario
10418
* cvar2 is the camera's focus relative to Mario
10419
*/
10420
BAD_RETURN(s32) cutscene_exit_painting_start(struct Camera *c) {
10421
struct Surface *floor;
10422
f32 floorHeight;
10423
10424
vec3f_set(sCutsceneVars[2].point, 258.f, -352.f, 1189.f);
10425
vec3f_set(sCutsceneVars[1].point, 65.f, -155.f, 444.f);
10426
10427
if (gPrevLevel == LEVEL_TTM) {
10428
sCutsceneVars[1].point[1] = 0.f;
10429
sCutsceneVars[1].point[2] = 0.f;
10430
}
10431
vec3f_copy(sCutsceneVars[0].point, sMarioCamState->pos);
10432
sCutsceneVars[0].angle[0] = 0;
10433
sCutsceneVars[0].angle[1] = sMarioCamState->faceAngle[1];
10434
sCutsceneVars[0].angle[2] = 0;
10435
offset_rotated(c->focus, sCutsceneVars[0].point, sCutsceneVars[1].point, sCutsceneVars[0].angle);
10436
offset_rotated(c->pos, sCutsceneVars[0].point, sCutsceneVars[2].point, sCutsceneVars[0].angle);
10437
floorHeight = find_floor(c->pos[0], c->pos[1] + 10.f, c->pos[2], &floor);
10438
10439
if (floorHeight != FLOOR_LOWER_LIMIT) {
10440
if (c->pos[1] < (floorHeight += 60.f)) {
10441
c->pos[1] = floorHeight;
10442
}
10443
}
10444
}
10445
10446
/**
10447
* Decrease cvar2's x and z offset, moving closer to Mario.
10448
*/
10449
BAD_RETURN(s32) cutscene_exit_painting_move_to_mario(struct Camera *c) {
10450
Vec3f pos;
10451
10452
//! Tricky math: Since offset_rotated() flips Z offsets, you'd expect a positive Z offset to move
10453
//! the camera into the wall. However, Mario's faceAngle always points into the painting, so a
10454
//! positive Z offset moves the camera "behind" Mario, away from the painting.
10455
//!
10456
//! In the success cutscene, when Mario jumps out face-first, only his gfx angle is updated. His
10457
//! actual face angle isn't updated until after the cutscene.
10458
approach_f32_asymptotic_bool(&sCutsceneVars[2].point[0], 178.f, 0.05f);
10459
approach_f32_asymptotic_bool(&sCutsceneVars[2].point[2], 889.f, 0.05f);
10460
offset_rotated(pos, sCutsceneVars[0].point, sCutsceneVars[2].point, sCutsceneVars[0].angle);
10461
c->pos[0] = pos[0];
10462
c->pos[2] = pos[2];
10463
}
10464
10465
/**
10466
* Move the camera down to the floor Mario lands on.
10467
*/
10468
BAD_RETURN(s32) cutscene_exit_painting_move_to_floor(struct Camera *c) {
10469
struct Surface *floor;
10470
Vec3f floorHeight;
10471
10472
vec3f_copy(floorHeight, sMarioCamState->pos);
10473
floorHeight[1] = find_floor(sMarioCamState->pos[0], sMarioCamState->pos[1] + 10.f, sMarioCamState->pos[2], &floor);
10474
10475
if (floor != NULL) {
10476
floorHeight[1] = floorHeight[1] + (sMarioCamState->pos[1] - floorHeight[1]) * 0.7f + 125.f;
10477
approach_vec3f_asymptotic(c->focus, floorHeight, 0.2f, 0.2f, 0.2f);
10478
10479
if (floorHeight[1] < c->pos[1]) {
10480
approach_f32_asymptotic_bool(&c->pos[1], floorHeight[1], 0.05f);
10481
}
10482
}
10483
}
10484
10485
/**
10486
* Cutscene played when Mario leaves a painting, either due to death or collecting a star.
10487
*/
10488
BAD_RETURN(s32) cutscene_exit_painting(struct Camera *c) {
10489
cutscene_event(cutscene_exit_painting_start, c, 0, 0);
10490
cutscene_event(cutscene_exit_painting_move_to_mario, c, 5, -1);
10491
cutscene_event(cutscene_exit_painting_move_to_floor, c, 5, -1);
10492
10493
//! Hardcoded position. TTM's painting is close to an opposite wall, so just fix the pos.
10494
if (gPrevLevel == LEVEL_TTM) {
10495
vec3f_set(c->pos, -296.f, 1261.f, 3521.f);
10496
}
10497
10498
update_camera_yaw(c);
10499
}
10500
10501
/**
10502
* Unused. Warp the camera to Mario.
10503
*/
10504
BAD_RETURN(s32) cutscene_unused_exit_start(struct Camera *c) {
10505
UNUSED Vec3f unused1;
10506
UNUSED Vec3s unused2;
10507
Vec3f offset;
10508
Vec3s marioAngle;
10509
10510
// Fixes clipping
10511
if (configBetaLikeCamera)
10512
vec3f_set(offset, 10.f, 0.f, 1200.f);
10513
else
10514
vec3f_set(offset, 200.f, 300.f, 200.f);
10515
10516
vec3s_set(marioAngle, 0, sMarioCamState->faceAngle[1], 0);
10517
offset_rotated(c->pos, sMarioCamState->pos, offset, marioAngle);
10518
set_focus_rel_mario(c, 0.f, 125.f, 0.f, 0);
10519
}
10520
10521
/**
10522
* Unused. Focus on Mario as he exits.
10523
*/
10524
BAD_RETURN(s32) cutscene_unused_exit_focus_mario(struct Camera *c) {
10525
Vec3f focus;
10526
10527
vec3f_set(focus, sMarioCamState->pos[0], sMarioCamState->pos[1] + 125.f, sMarioCamState->pos[2]);
10528
set_focus_rel_mario(c, 0.f, 125.f, 0.f, 0);
10529
approach_vec3f_asymptotic(c->focus, focus, 0.02f, 0.001f, 0.02f);
10530
update_camera_yaw(c);
10531
}
10532
10533
/**
10534
* Give control back to the player.
10535
*/
10536
BAD_RETURN(s32) cutscene_exit_painting_end(struct Camera *c) {
10537
c->mode = CAMERA_MODE_CLOSE;
10538
c->cutscene = 0;
10539
gCutsceneTimer = CUTSCENE_STOP;
10540
sStatusFlags |= CAM_FLAG_SMOOTH_MOVEMENT;
10541
sStatusFlags &= ~CAM_FLAG_BLOCK_SMOOTH_MOVEMENT;
10542
update_camera_yaw(c);
10543
}
10544
10545
/**
10546
* End the cutscene, starting cannon mode.
10547
*/
10548
BAD_RETURN(s32) cutscene_enter_cannon_end(struct Camera *c) {
10549
sStatusFlags &= ~CAM_FLAG_SMOOTH_MOVEMENT;
10550
sStatusFlags |= CAM_FLAG_BLOCK_SMOOTH_MOVEMENT;
10551
c->mode = CAMERA_MODE_INSIDE_CANNON;
10552
c->cutscene = 0;
10553
sCannonYOffset = 800.f;
10554
}
10555
10556
/**
10557
* Rotate around the cannon as it rises out of the hole.
10558
*/
10559
BAD_RETURN(s32) cutscene_enter_cannon_raise(struct Camera *c) {
10560
struct Object *o;
10561
UNUSED u32 pad[2];
10562
f32 floorHeight;
10563
struct Surface *floor;
10564
Vec3f cannonFocus;
10565
Vec3s cannonAngle;
10566
10567
// Shake the camera when the cannon is fully raised
10568
cutscene_event(cutscene_shake_explosion, c, 70, 70);
10569
sStatusFlags |= CAM_FLAG_SMOOTH_MOVEMENT;
10570
camera_approach_s16_symmetric_bool(&sCutsceneVars[1].angle[0], 0, 0x80);
10571
camera_approach_s16_symmetric_bool(&sCutsceneVars[2].angle[0], 0, 0x80);
10572
// Move the camera around the cannon, gradually rotating and moving closer
10573
vec3f_set_dist_and_angle(sCutsceneVars[0].point, c->pos, sCutsceneVars[1].point[2], sCutsceneVars[1].angle[0],
10574
sCutsceneVars[1].angle[1]);
10575
sCutsceneVars[1].point[2] = approach_f32(sCutsceneVars[1].point[2], 400.f, 5.f, 5.f);
10576
sCutsceneVars[1].angle[1] += 0x40;
10577
sCutsceneVars[3].point[1] += 2.f;
10578
c->pos[1] += sCutsceneVars[3].point[1];
10579
10580
if ((o = sMarioCamState->usedObj) != NULL) {
10581
sCutsceneVars[0].point[1] = o->oPosY;
10582
cannonAngle[0] = o->oMoveAnglePitch;
10583
cannonAngle[1] = o->oMoveAngleYaw;
10584
cannonAngle[2] = o->oMoveAngleRoll;
10585
c->focus[0] = o->oPosX;
10586
c->focus[1] = o->oPosY;
10587
c->focus[2] = o->oPosZ;
10588
cannonFocus[0] = 0.f;
10589
cannonFocus[1] = 100.f;
10590
cannonFocus[2] = 0.f;
10591
offset_rotated(c->focus, c->focus, cannonFocus, cannonAngle);
10592
}
10593
10594
floorHeight = find_floor(c->pos[0], c->pos[1] + 500.f, c->pos[2], &floor) + 100.f;
10595
10596
if (c->pos[1] < floorHeight) {
10597
c->pos[1] = floorHeight;
10598
}
10599
}
10600
10601
/**
10602
* Start the cannon entering cutscene
10603
*/
10604
BAD_RETURN(s32) cutscene_enter_cannon_start(struct Camera *c) {
10605
UNUSED u32 cvar3Start;
10606
UNUSED u32 cvar4Start;
10607
struct Object *o;
10608
10609
sStatusFlags |= CAM_FLAG_SMOOTH_MOVEMENT;
10610
sMarioCamState->cameraEvent = 0;
10611
10612
// Store the cannon's position and angle in cvar0
10613
if ((o = sMarioCamState->usedObj) != NULL) {
10614
sCutsceneVars[0].point[0] = o->oPosX;
10615
sCutsceneVars[0].point[1] = o->oPosY;
10616
sCutsceneVars[0].point[2] = o->oPosZ;
10617
sCutsceneVars[0].angle[0] = o->oMoveAnglePitch;
10618
sCutsceneVars[0].angle[1] = o->oMoveAngleYaw;
10619
sCutsceneVars[0].angle[2] = o->oMoveAngleRoll;
10620
}
10621
10622
// Store the camera's polar offset from the cannon in cvar1
10623
vec3f_get_dist_and_angle(sCutsceneVars[0].point, c->pos, &sCutsceneVars[1].point[2],
10624
&sCutsceneVars[1].angle[0], &sCutsceneVars[1].angle[1]);
10625
sCutsceneVars[3].point[1] = 0.f;
10626
//! cvar4 is unused in this cutscene
10627
sCutsceneVars[4].point[1] = 0.f;
10628
}
10629
10630
/**
10631
* Store the camera's pos and focus for the door cutscene
10632
*/
10633
BAD_RETURN(s32) cutscene_door_start(struct Camera *c) {
10634
vec3f_copy(sCutsceneVars[0].point, c->pos);
10635
vec3f_copy(sCutsceneVars[1].point, c->focus);
10636
}
10637
10638
/**
10639
* Fix the camera in place while the door opens.
10640
*/
10641
BAD_RETURN(s32) cutscene_door_fix_cam(struct Camera *c) {
10642
vec3f_copy(c->pos, sCutsceneVars[0].point);
10643
vec3f_copy(c->focus, sCutsceneVars[1].point);
10644
skip_camera_interpolation();
10645
}
10646
10647
/**
10648
* Loop until Mario is no longer using the door.
10649
*/
10650
BAD_RETURN(s32) cutscene_door_loop(struct Camera *c) {
10651
//! bitwise AND instead of boolean
10652
if ((sMarioCamState->action != ACT_PULLING_DOOR) & (sMarioCamState->action != ACT_PUSHING_DOOR)) {
10653
gCutsceneTimer = CUTSCENE_STOP;
10654
c->cutscene = 0;
10655
}
10656
}
10657
10658
/**
10659
* Warp the camera behind Mario.
10660
*/
10661
BAD_RETURN(s32) cutscene_door_move_behind_mario(struct Camera *c) {
10662
Vec3f camOffset;
10663
s16 doorRotation;
10664
10665
reset_pan_distance(c);
10666
determine_pushing_or_pulling_door(&doorRotation);
10667
set_focus_rel_mario(c, 0.f, 125.f, 0.f, 0);
10668
vec3s_set(sCutsceneVars[0].angle, 0, sMarioCamState->faceAngle[1] + doorRotation, 0);
10669
vec3f_set(camOffset, 0.f, 125.f, 250.f);
10670
10671
if (doorRotation == 0) { //! useless code
10672
camOffset[0] = 0.f;
10673
} else {
10674
camOffset[0] = 0.f;
10675
}
10676
10677
offset_rotated(c->pos, sMarioCamState->pos, camOffset, sCutsceneVars[0].angle);
10678
skip_camera_interpolation();
10679
}
10680
10681
/**
10682
* Follow Mario through the door.
10683
*/
10684
BAD_RETURN(s32) cutscene_door_follow_mario(struct Camera *c) {
10685
s16 pitch, yaw;
10686
f32 dist;
10687
10688
set_focus_rel_mario(c, 0.f, 125.f, 0.f, 0);
10689
vec3f_get_dist_and_angle(c->focus, c->pos, &dist, &pitch, &yaw);
10690
camera_approach_f32_symmetric_bool(&dist, 150.f, 7.f);
10691
vec3f_set_dist_and_angle(c->focus, c->pos, dist, pitch, yaw);
10692
update_camera_yaw(c);
10693
}
10694
10695
/**
10696
* Ends the door cutscene. Sets the camera mode to close mode unless the default is free roam.
10697
*/
10698
BAD_RETURN(s32) cutscene_door_end(struct Camera *c) {
10699
if (c->defMode == CAMERA_MODE_FREE_ROAM) {
10700
c->mode = CAMERA_MODE_FREE_ROAM;
10701
} else {
10702
c->mode = CAMERA_MODE_CLOSE;
10703
}
10704
10705
c->cutscene = 0;
10706
gCutsceneTimer = CUTSCENE_STOP;
10707
sStatusFlags |= CAM_FLAG_SMOOTH_MOVEMENT;
10708
sStatusFlags &= ~CAM_FLAG_BLOCK_SMOOTH_MOVEMENT;
10709
set_flag_post_door(c);
10710
update_camera_yaw(c);
10711
}
10712
10713
/**
10714
* Used for entering a room that uses a specific camera mode, like the castle lobby or BBH
10715
*/
10716
BAD_RETURN(s32) cutscene_door_mode(struct Camera *c) {
10717
UNUSED u32 pad[2];
10718
10719
reset_pan_distance(c);
10720
camera_course_processing(c);
10721
10722
if (c->mode == CAMERA_MODE_FIXED) {
10723
c->nextYaw = update_fixed_camera(c, c->focus, c->pos);
10724
}
10725
if (c->mode == CAMERA_MODE_PARALLEL_TRACKING) {
10726
c->nextYaw = update_parallel_tracking_camera(c, c->focus, c->pos);
10727
}
10728
10729
c->yaw = c->nextYaw;
10730
10731
// Loop until Mario is no longer using the door
10732
if (sMarioCamState->action != ACT_ENTERING_STAR_DOOR &&
10733
sMarioCamState->action != ACT_PULLING_DOOR &&
10734
sMarioCamState->action != ACT_PUSHING_DOOR) {
10735
gCutsceneTimer = CUTSCENE_STOP;
10736
c->cutscene = 0;
10737
}
10738
}
10739
10740
/******************************************************************************************************
10741
* Cutscenes
10742
******************************************************************************************************/
10743
10744
/**
10745
* Cutscene that plays when Mario beats the game.
10746
*/
10747
struct Cutscene sCutsceneEnding[] = {
10748
{ cutscene_ending_mario_fall, 170 },
10749
{ cutscene_ending_mario_land, 70 },
10750
#ifdef VERSION_EU
10751
{ cutscene_ending_mario_land_closeup, 0x44 },
10752
{ cutscene_ending_stars_free_peach, 0x15c },
10753
{ cutscene_ending_peach_appears, 0x6d },
10754
{ cutscene_ending_peach_descends, 0x212 },
10755
{ cutscene_ending_mario_to_peach, 0x69 },
10756
{ cutscene_ending_peach_wakeup, 0x1a4 },
10757
{ cutscene_ending_dialog, 0x114 },
10758
{ cutscene_ending_kiss, 0x10b },
10759
#else
10760
{ cutscene_ending_mario_land_closeup, 75 },
10761
#ifdef VERSION_SH
10762
{ cutscene_ending_stars_free_peach, 431 },
10763
#else
10764
{ cutscene_ending_stars_free_peach, 386 },
10765
#endif
10766
{ cutscene_ending_peach_appears, 139 },
10767
{ cutscene_ending_peach_descends, 590 },
10768
{ cutscene_ending_mario_to_peach, 95 },
10769
#ifdef VERSION_SH
10770
{ cutscene_ending_peach_wakeup, 455 },
10771
{ cutscene_ending_dialog, 286 },
10772
#else
10773
{ cutscene_ending_peach_wakeup, 425 },
10774
{ cutscene_ending_dialog, 236 },
10775
#endif
10776
{ cutscene_ending_kiss, 245 },
10777
#endif
10778
{ cutscene_ending_cake_for_mario, CUTSCENE_LOOP },
10779
{ cutscene_ending_stop, 0 }
10780
};
10781
10782
/**
10783
* Cutscene that plays when Mario collects the grand star from bowser.
10784
*/
10785
struct Cutscene sCutsceneGrandStar[] = {
10786
{ cutscene_grand_star, 360 },
10787
{ cutscene_grand_star_fly, CUTSCENE_LOOP }
10788
};
10789
10790
struct Cutscene sCutsceneUnused[] = {
10791
{ cutscene_unused_start, 1 },
10792
{ cutscene_unused_loop, CUTSCENE_LOOP }
10793
};
10794
10795
/**
10796
* Cutscene that plays when Mario enters a door that warps to another area.
10797
*/
10798
struct Cutscene sCutsceneDoorWarp[] = {
10799
{ cutscene_door_start, 1 },
10800
{ cutscene_door_loop, CUTSCENE_LOOP }
10801
};
10802
10803
/**
10804
* Cutscene that plays after the credits, when Lakitu is flying away from the castle.
10805
*/
10806
struct Cutscene sCutsceneEndWaving[] = {
10807
{ cutscene_end_waving, CUTSCENE_LOOP }
10808
};
10809
10810
/**
10811
* The game's credits.
10812
*/
10813
struct Cutscene sCutsceneCredits[] = {
10814
{ cutscene_credits, CUTSCENE_LOOP }
10815
};
10816
10817
/**
10818
* Cutscene that plays when Mario pulls open a door.
10819
*/
10820
struct Cutscene sCutsceneDoorPull[] = {
10821
{ cutscene_door_start, 1 },
10822
{ cutscene_door_fix_cam, 30 },
10823
{ cutscene_door_move_behind_mario, 1 },
10824
{ cutscene_door_follow_mario, 50 },
10825
{ cutscene_door_end, 0 }
10826
};
10827
10828
/**
10829
* Cutscene that plays when Mario pushes open a door.
10830
*/
10831
struct Cutscene sCutsceneDoorPush[] = {
10832
{ cutscene_door_start, 1 },
10833
{ cutscene_door_fix_cam, 20 },
10834
{ cutscene_door_move_behind_mario, 1 },
10835
{ cutscene_door_follow_mario, 50 },
10836
{ cutscene_door_end, 0 }
10837
};
10838
10839
/**
10840
* Cutscene that plays when Mario pulls open a door that has some special mode requirement on the other
10841
* side.
10842
*/
10843
struct Cutscene sCutsceneDoorPullMode[] = {
10844
{ cutscene_door_start, 1 },
10845
{ cutscene_door_fix_cam, 30 },
10846
{ cutscene_door_mode, CUTSCENE_LOOP }
10847
};
10848
10849
/**
10850
* Cutscene that plays when Mario pushes open a door that has some special mode requirement on the other
10851
* side.
10852
*/
10853
struct Cutscene sCutsceneDoorPushMode[] = {
10854
{ cutscene_door_start, 1 },
10855
{ cutscene_door_fix_cam, 20 },
10856
{ cutscene_door_mode, CUTSCENE_LOOP }
10857
};
10858
10859
/**
10860
* Cutscene that plays when Mario enters the cannon and it rises out of the hole.
10861
*/
10862
struct Cutscene sCutsceneEnterCannon[] = {
10863
{ cutscene_enter_cannon_start, 1 },
10864
{ cutscene_enter_cannon_raise, 121 },
10865
{ cutscene_enter_cannon_end, 0 }
10866
};
10867
10868
/**
10869
* Cutscene that plays when a star spawns from ie a box or after a boss fight.
10870
*/
10871
struct Cutscene sCutsceneStarSpawn[] = {
10872
{ cutscene_star_spawn, CUTSCENE_LOOP },
10873
{ cutscene_star_spawn_back, 15 },
10874
{ cutscene_star_spawn_end, 0 }
10875
};
10876
10877
/**
10878
* Cutscene for the red coin star spawning. Compared to a regular star, this cutscene can warp long
10879
* distances.
10880
*/
10881
struct Cutscene sCutsceneRedCoinStarSpawn[] = {
10882
{ cutscene_red_coin_star, CUTSCENE_LOOP },
10883
{ cutscene_red_coin_star_end, 0 }
10884
};
10885
10886
/**
10887
* Cutscene that plays when Mario enters a course painting.
10888
*/
10889
struct Cutscene sCutsceneEnterPainting[] = {
10890
{ cutscene_enter_painting, CUTSCENE_LOOP }
10891
};
10892
10893
/**
10894
* Cutscene that plays when Mario dies and warps back to the castle.
10895
*/
10896
struct Cutscene sCutsceneDeathExit[] = {
10897
{ cutscene_exit_painting, 118 },
10898
{ cutscene_exit_painting_end, 0 }
10899
};
10900
10901
/**
10902
* Cutscene that plays when Mario warps to the castle after collecting a star.
10903
*/
10904
struct Cutscene sCutsceneExitPaintingSuccess[] = {
10905
{ cutscene_exit_painting, 180 },
10906
{ cutscene_exit_painting_end, 0 }
10907
};
10908
10909
struct Cutscene sCutsceneUnusedExit[] = {
10910
{ cutscene_unused_exit_start, 1 },
10911
{ cutscene_unused_exit_focus_mario, 60 },
10912
{ cutscene_exit_painting_end, 0 }
10913
};
10914
10915
/**
10916
* The intro of the game. Peach reads her letter and Lakitu flies down to Mario's warp pipe.
10917
*/
10918
struct Cutscene sCutsceneIntroPeach[] = {
10919
{ cutscene_intro_peach_letter, CUTSCENE_LOOP },
10920
{ cutscene_intro_peach_reset_fov, 35 },
10921
#ifdef VERSION_EU
10922
{ cutscene_intro_peach_fly_to_pipe, 675 },
10923
#else
10924
{ cutscene_intro_peach_fly_to_pipe, 820 },
10925
#endif
10926
{ cutscene_intro_peach_mario_appears, 270 },
10927
{ cutscene_intro_peach_dialog, CUTSCENE_LOOP }
10928
};
10929
10930
/**
10931
* Cutscene that plays when a cannon door is opened.
10932
*/
10933
struct Cutscene sCutscenePrepareCannon[] = {
10934
{ cutscene_prepare_cannon, 170 },
10935
{ cutscene_prepare_cannon_end, 0 }
10936
};
10937
10938
/**
10939
* Cutscene that plays when Mario enters the castle grounds after leaving CotMC through the waterfall.
10940
*/
10941
struct Cutscene sCutsceneExitWaterfall[] = {
10942
{ cutscene_exit_waterfall, 52 },
10943
{ cutscene_exit_to_castle_grounds_end, 0 }
10944
};
10945
10946
/**
10947
* Cutscene that plays when Mario falls from WMOTR.
10948
*/
10949
struct Cutscene sCutsceneFallToCastleGrounds[] = {
10950
{ cutscene_exit_fall_to_castle_grounds, 73 },
10951
{ cutscene_exit_to_castle_grounds_end, 0 }
10952
};
10953
10954
/**
10955
* Cutscene that plays when Mario enters the pyramid through the hole at the top.
10956
*/
10957
struct Cutscene sCutsceneEnterPyramidTop[] = {
10958
{ cutscene_enter_pyramid_top, 90 },
10959
{ cutscene_exit_to_castle_grounds_end, 0 }
10960
};
10961
10962
/**
10963
* Unused cutscene for when the pyramid explodes.
10964
*/
10965
struct Cutscene sCutscenePyramidTopExplode[] = {
10966
{ cutscene_mario_dialog, CUTSCENE_LOOP },
10967
{ cutscene_pyramid_top_explode, 150 },
10968
{ cutscene_pyramid_top_explode_end, 0 }
10969
};
10970
10971
/**
10972
* Cutscene that plays when Mario dies while standing, or from electrocution.
10973
*/
10974
struct Cutscene sCutsceneStandingDeath[] = {
10975
{ cutscene_death_standing, CUTSCENE_LOOP }
10976
};
10977
10978
/**
10979
* Cutscene that plays when Mario enters HMC or CotMC.
10980
*/
10981
struct Cutscene sCutsceneEnterPool[] = {
10982
{ cutscene_enter_pool, 100 },
10983
{ cutscene_exit_to_castle_grounds_end, 0 }
10984
};
10985
10986
/**
10987
* Cutscene that plays when Mario dies on his stomach.
10988
*/
10989
struct Cutscene sCutsceneDeathStomach[] = {
10990
{ cutscene_death_stomach, CUTSCENE_LOOP }
10991
};
10992
10993
/**
10994
* Cutscene that plays when Mario dies on his back.
10995
*/
10996
struct Cutscene sCutsceneDeathOnBack[] = {
10997
{ cutscene_bbh_death, CUTSCENE_LOOP }
10998
};
10999
11000
/**
11001
* Cutscene that plays when Mario dies in quicksand.
11002
*/
11003
struct Cutscene sCutsceneQuicksandDeath[] = {
11004
{ cutscene_quicksand_death, CUTSCENE_LOOP },
11005
};
11006
11007
/**
11008
* Unused cutscene for ACT_WATER_DEATH, which happens when Mario gets hit by an enemy under water.
11009
*/
11010
struct Cutscene sCutsceneWaterDeath[] = {
11011
{ cutscene_quicksand_death, CUTSCENE_LOOP }
11012
};
11013
11014
/**
11015
* Cutscene that plays when Mario suffocates.
11016
*/
11017
struct Cutscene sCutsceneSuffocation[] = {
11018
{ cutscene_suffocation, CUTSCENE_LOOP }
11019
};
11020
11021
/**
11022
* Cutscene that plays when entering bowser's arenas.
11023
*/
11024
struct Cutscene sCutsceneEnterBowserArena[] = {
11025
{ cutscene_bowser_arena, 180 },
11026
{ cutscene_bowser_arena_dialog, CUTSCENE_LOOP },
11027
{ cutscene_bowser_arena_end, 0 }
11028
};
11029
11030
// The dance cutscenes are automatically stopped since reset_camera() is called after Mario warps.
11031
11032
/**
11033
* Star dance cutscene.
11034
* For the default dance, the camera moves closer to Mario, then stays in place.
11035
* For the rotate dance, the camera moves closer and rotates clockwise around Mario.
11036
*/
11037
struct Cutscene sCutsceneDanceDefaultRotate[] = {
11038
{ cutscene_dance_default_rotate, CUTSCENE_LOOP }
11039
};
11040
11041
/**
11042
* Star dance cutscene.
11043
* The camera moves closer and rotates clockwise around Mario.
11044
*/
11045
struct Cutscene sCutsceneDanceFlyAway[] = {
11046
{ cutscene_dance_fly_away, CUTSCENE_LOOP }
11047
};
11048
11049
/**
11050
* Star dance cutscene.
11051
* The camera moves in for a closeup on Mario. Used in tight spaces and underwater.
11052
*/
11053
struct Cutscene sCutsceneDanceCloseup[] = {
11054
{ cutscene_dance_closeup, CUTSCENE_LOOP }
11055
};
11056
11057
/**
11058
* Star dance cutscene.
11059
* The camera moves closer and rotates clockwise around Mario.
11060
*/
11061
struct Cutscene sCutsceneKeyDance[] = {
11062
{ cutscene_key_dance, CUTSCENE_LOOP }
11063
};
11064
11065
/**
11066
* Cutscene that plays when Mario presses a cap switch.
11067
*/
11068
struct Cutscene sCutsceneCapSwitchPress[] = {
11069
{ cutscene_cap_switch_press, CUTSCENE_LOOP }
11070
};
11071
11072
/**
11073
* Cutscene that plays when Mario opens a sliding star door.
11074
*/
11075
struct Cutscene sCutsceneSlidingDoorsOpen[] = {
11076
{ cutscene_sliding_doors_open, 50 },
11077
{ cutscene_double_doors_end, 0 }
11078
};
11079
11080
/**
11081
* Cutscene that plays when Mario unlocks the basement or upstairs key door.
11082
*/
11083
struct Cutscene sCutsceneUnlockKeyDoor[] = {
11084
{ cutscene_unlock_key_door, 200 },
11085
{ cutscene_double_doors_end, 0 }
11086
};
11087
11088
/**
11089
* Cutscene that plays when Mario exits bowser's arena after getting the key.
11090
*/
11091
struct Cutscene sCutsceneExitBowserSuccess[] = {
11092
{ cutscene_exit_bowser_succ, 190 },
11093
{ cutscene_non_painting_end, 0 }
11094
};
11095
11096
/**
11097
* Unused cutscene for when Mario dies in bowser's arena. Instead, Mario just respawns at the warp pipe.
11098
*/
11099
struct Cutscene sCutsceneExitBowserDeath[] = {
11100
{ cutscene_exit_bowser_death, 120 },
11101
{ cutscene_non_painting_end, 0 }
11102
};
11103
11104
/**
11105
* Cutscene that plays when Mario exits a non-painting course, like HMC.
11106
*/
11107
struct Cutscene sCutsceneExitSpecialSuccess[] = {
11108
{ cutscene_exit_non_painting_succ, 163 },
11109
{ cutscene_non_painting_end, 0 }
11110
};
11111
11112
/**
11113
* Cutscene that plays when Mario exits from dying in a non-painting course, like HMC.
11114
*/
11115
struct Cutscene sCutsceneNonPaintingDeath[] = {
11116
{ cutscene_non_painting_death, 120 },
11117
{ cutscene_non_painting_end, 0 }
11118
};
11119
11120
/**
11121
* Cutscene that plays when Mario talks to a creature.
11122
*/
11123
struct Cutscene sCutsceneDialog[] = {
11124
{ cutscene_dialog, CUTSCENE_LOOP },
11125
{ cutscene_dialog_set_flag, 12 },
11126
{ cutscene_dialog_end, 0 }
11127
};
11128
11129
/**
11130
* Cutscene that plays when Mario reads a sign or message.
11131
*/
11132
struct Cutscene sCutsceneReadMessage[] = {
11133
{ cutscene_read_message, CUTSCENE_LOOP },
11134
{ cutscene_read_message_set_flag, 15 },
11135
{ cutscene_read_message_end, 0 }
11136
};
11137
11138
/* TODO:
11139
* The next two arrays are both related to levels, and they look generated.
11140
* These should be split into their own file.
11141
*/
11142
11143
/**
11144
* Converts the u32 given in DEFINE_COURSE to a u8 with the odd and even digits rotated into the right
11145
* order for sDanceCutsceneIndexTable
11146
*/
11147
#define DROT(value, index) ((value >> (32 - (index + 1) * 8)) & 0xF0) >> 4 | \
11148
((value >> (32 - (index + 1) * 8)) & 0x0F) << 4
11149
11150
#define DANCE_ENTRY(c) { DROT(c, 0), DROT(c, 1), DROT(c, 2), DROT(c, 3) },
11151
11152
#define DEFINE_COURSE(_0, cutscenes) DANCE_ENTRY(cutscenes)
11153
#define DEFINE_COURSES_END()
11154
#define DEFINE_BONUS_COURSE(_0, cutscenes) DANCE_ENTRY(cutscenes)
11155
11156
/**
11157
* Each hex digit is an index into sDanceCutsceneTable.
11158
*
11159
* 0: Lakitu flies away after the dance
11160
* 1: Only rotates the camera, doesn't zoom out
11161
* 2: The camera goes to a close up of Mario
11162
* 3: Bowser keys and the grand star
11163
* 4: Default, used for 100 coin stars, 8 red coin stars in bowser levels, and secret stars
11164
*/
11165
u8 sDanceCutsceneIndexTable[][4] = {
11166
#include "levels/course_defines.h"
11167
{ 0x44, 0x44, 0x44, 0x04 }, // (26) Why go to all this trouble to save bytes and do this?!
11168
};
11169
#undef DEFINE_COURSE
11170
#undef DEFINE_COURSES_END
11171
#undef DEFINE_BONUS_COURSE
11172
11173
#undef DANCE_ENTRY
11174
#undef DROT
11175
11176
/**
11177
* These masks set whether or not the camera zooms out when game is paused.
11178
*
11179
* Each entry is used by two levels. Even levels use the low 4 bits, odd levels use the high 4 bits
11180
* Because areas are 1-indexed, a mask of 0x1 will make area 1 (not area 0) zoom out.
11181
*
11182
* In zoom_out_if_paused_and_outside(), the current area is converted to a shift.
11183
* Then the value of (1 << shift) is &'d with the level's mask,
11184
* and if the result is non-zero, the camera will zoom out.
11185
*/
11186
u8 sZoomOutAreaMasks[] = {
11187
ZOOMOUT_AREA_MASK(0,0,0,0, 0,0,0,0), // Unused | Unused
11188
ZOOMOUT_AREA_MASK(0,0,0,0, 0,0,0,0), // Unused | Unused
11189
ZOOMOUT_AREA_MASK(0,0,0,0, 1,0,0,0), // BBH | CCM
11190
ZOOMOUT_AREA_MASK(0,0,0,0, 0,0,0,0), // CASTLE_INSIDE | HMC
11191
ZOOMOUT_AREA_MASK(1,0,0,0, 1,0,0,0), // SSL | BOB
11192
ZOOMOUT_AREA_MASK(1,0,0,0, 1,0,0,0), // SL | WDW
11193
ZOOMOUT_AREA_MASK(0,0,0,0, 1,1,0,0), // JRB | THI
11194
ZOOMOUT_AREA_MASK(0,0,0,0, 1,0,0,0), // TTC | RR
11195
ZOOMOUT_AREA_MASK(1,0,0,0, 1,0,0,0), // CASTLE_GROUNDS | BITDW
11196
ZOOMOUT_AREA_MASK(0,0,0,0, 1,0,0,0), // VCUTM | BITFS
11197
ZOOMOUT_AREA_MASK(0,0,0,0, 1,0,0,0), // SA | BITS
11198
ZOOMOUT_AREA_MASK(1,0,0,0, 0,0,0,0), // LLL | DDD
11199
ZOOMOUT_AREA_MASK(1,0,0,0, 0,0,0,0), // WF | ENDING
11200
ZOOMOUT_AREA_MASK(0,0,0,0, 0,0,0,0), // COURTYARD | PSS
11201
ZOOMOUT_AREA_MASK(0,0,0,0, 1,0,0,0), // COTMC | TOTWC
11202
ZOOMOUT_AREA_MASK(1,0,0,0, 1,0,0,0), // BOWSER_1 | WMOTR
11203
ZOOMOUT_AREA_MASK(0,0,0,0, 1,0,0,0), // Unused | BOWSER_2
11204
ZOOMOUT_AREA_MASK(1,0,0,0, 0,0,0,0), // BOWSER_3 | Unused
11205
ZOOMOUT_AREA_MASK(1,0,0,0, 0,0,0,0), // TTM | Unused
11206
ZOOMOUT_AREA_MASK(0,0,0,0, 0,0,0,0), // Unused | Unused
11207
};
11208
11209
STATIC_ASSERT(ARRAY_COUNT(sZoomOutAreaMasks) - 1 == LEVEL_MAX / 2, "Make sure you edit sZoomOutAreaMasks when adding / removing courses.");
11210
11211
/*
11212
* credits spline paths.
11213
* TODO: Separate these into their own file(s)
11214
*/
11215
11216
struct CutsceneSplinePoint sBobCreditsSplinePositions[] = {
11217
{ 1, 0, { 5984, 3255, 4975 } },
11218
{ 2, 0, { 4423, 3315, 1888 } },
11219
{ 3, 0, { 776, 2740, -1825 } },
11220
{ 4, 0, { -146, 3894, -3167 } },
11221
{ -1, 0, { 741, 4387, -5474 } }
11222
};
11223
11224
struct CutsceneSplinePoint sBobCreditsSplineFocus[] = {
11225
{ 0, 30, { 5817, 3306, 4507 } },
11226
{ 0, 40, { 4025, 3378, 1593 } },
11227
{ 0, 50, { 1088, 2652, -2205 } },
11228
{ 0, 60, { 205, 3959, -3517 } },
11229
{ -1, 60, { 1231, 4400, -5649 } }
11230
};
11231
11232
struct CutsceneSplinePoint sWfCreditsSplinePositions[] = {
11233
{ 0, 0, { -301, 1399, 2643 } },
11234
{ 0, 0, { -182, 2374, 4572 } },
11235
{ 0, 0, { 4696, 3864, 413 } },
11236
{ 0, 0, { 1738, 4891, -1516 } },
11237
{ -1, 0, { 1783, 4891, -1516 } }
11238
};
11239
11240
struct CutsceneSplinePoint sWfCreditsSplineFocus[] = {
11241
{ 1, 30, { -249, 1484, 2153 } },
11242
{ 2, 40, { -200, 2470, 4082 } },
11243
{ 3, 40, { 4200, 3916, 370 } },
11244
{ 4, 40, { 1523, 4976, -1072 } },
11245
{ -1, 40, { 1523, 4976, -1072 } }
11246
};
11247
11248
struct CutsceneSplinePoint sJrbCreditsSplinePositions[] = {
11249
{ 0, 0, { 5538, -4272, 2376 } },
11250
{ 0, 0, { 5997, -3303, 2261 } },
11251
{ 0, 0, { 6345, -3255, 2179 } },
11252
{ 0, 0, { 6345, -3255, 2179 } },
11253
{ -1, 0, { 6694, -3203, 2116 } }
11254
};
11255
11256
struct CutsceneSplinePoint sJrbCreditsSplineFocus[] = {
11257
{ 0, 50, { 5261, -4683, 2443 } },
11258
{ 0, 50, { 5726, -3675, 2456 } },
11259
{ 0, 50, { 6268, -2817, 2409 } },
11260
{ 0, 50, { 6596, -2866, 2369 } },
11261
{ -1, 50, { 7186, -3153, 2041 } }
11262
};
11263
11264
struct CutsceneSplinePoint sCcmSlideCreditsSplinePositions[] = {
11265
{ 0, 0, { -6324, 6745, -5626 } },
11266
{ 1, 0, { -6324, 6745, -5626 } },
11267
{ 2, 0, { -6108, 6762, -5770 } },
11268
{ 3, 0, { -5771, 6787, -5962 } },
11269
{ -1, 0, { -5672, 6790, -5979 } }
11270
};
11271
11272
struct CutsceneSplinePoint sCcmSlideCreditsSplineFocus[] = {
11273
{ 0, 50, { -5911, 6758, -5908 } },
11274
{ 1, 50, { -5911, 6758, -5908 } },
11275
{ 2, 50, { -5652, 6814, -5968 } },
11276
{ 3, 50, { -5277, 6801, -6043 } },
11277
{ -1, 50, { -5179, 6804, -6060 } }
11278
};
11279
11280
struct CutsceneSplinePoint sBbhCreditsSplinePositions[] = {
11281
{ 1, 0, { 1088, 341, 2447 } },
11282
{ 2, 0, { 1338, 610, 2808 } },
11283
{ 3, 0, { 2267, 1612, 2966 } },
11284
{ -1, 0, { 2296, 1913, 2990 } }
11285
};
11286
11287
struct CutsceneSplinePoint sBbhCreditsSplineFocus[] = {
11288
{ 1, 50, { 1160, 263, 1958 } },
11289
{ 2, 50, { 1034, 472, 2436 } },
11290
{ 3, 50, { 1915, 1833, 2688 } },
11291
{ -1, 50, { 2134, 2316, 2742 } }
11292
};
11293
11294
struct CutsceneSplinePoint sHmcCreditsSplinePositions[] = {
11295
{ 1, 0, { -5952, 1807, -5882 } },
11296
{ 2, 0, { -5623, 1749, -4863 } },
11297
{ 3, 0, { -5472, 1955, -2520 } },
11298
{ 4, 0, { -5544, 1187, -1085 } },
11299
{ -1, 0, { -5547, 391, -721 } }
11300
};
11301
11302
struct CutsceneSplinePoint sHmcCreditsSplineFocus[] = {
11303
{ 1, 210, { -5952, 1884, -6376 } },
11304
{ 2, 58, { -5891, 1711, -5283 } },
11305
{ 3, 30, { -5595, 1699, -2108 } },
11306
{ 4, 31, { -5546, 794, -777 } },
11307
{ -1, 31, { -5548, -85, -572 } }
11308
};
11309
11310
struct CutsceneSplinePoint sThiWigglerCreditsSplinePositions[] = {
11311
{ 1, 0, { -1411, 2474, -1276 } },
11312
{ 2, 0, { -1606, 2479, -434 } },
11313
{ -1, 0, { -1170, 2122, 1337 } }
11314
};
11315
11316
struct CutsceneSplinePoint sThiWigglerCreditsSplineFocus[] = {
11317
{ 1, 50, { -1053, 2512, -928 } },
11318
{ 2, 50, { -1234, 2377, -114 } },
11319
{ -1, 50, { -758, 2147, 1054 } }
11320
};
11321
11322
struct CutsceneSplinePoint sVolcanoCreditsSplinePositions[] = {
11323
{ 0, 0, { -1445, 1094, 1617 } },
11324
{ 0, 0, { -1509, 649, 871 } },
11325
{ 0, 0, { -1133, 420, -248 } },
11326
{ 0, 0, { -778, 359, -1052 } },
11327
{ 0, 0, { -565, 260, -1730 } },
11328
{ -1, 0, { 1274, 473, -275 } }
11329
};
11330
11331
struct CutsceneSplinePoint sVolcanoCreditsSplineFocus[] = {
11332
{ 0, 50, { -1500, 757, 1251 } },
11333
{ 0, 50, { -1401, 439, 431 } },
11334
{ 0, 50, { -749, 270, -532 } },
11335
{ 0, 50, { -396, 270, -1363 } },
11336
{ 0, 50, { -321, 143, -2151 } },
11337
{ -1, 50, { 1002, 460, -694 } }
11338
};
11339
11340
struct CutsceneSplinePoint sSslCreditsSplinePositions[] = {
11341
{ 0, 0, { -4262, 4658, -5015 } },
11342
{ 0, 0, { -3274, 2963, -4661 } },
11343
{ 0, 0, { -2568, 812, -6528 } },
11344
{ 0, 0, { -414, 660, -7232 } },
11345
{ 0, 0, { 1466, 660, -6898 } },
11346
{ -1, 0, { 2724, 660, -6298 } }
11347
};
11348
11349
struct CutsceneSplinePoint sSslCreditsSplineFocus[] = {
11350
{ 0, 50, { -4083, 4277, -4745 } },
11351
{ 0, 50, { -2975, 2574, -4759 } },
11352
{ 0, 50, { -2343, 736, -6088 } },
11353
{ 0, 50, { -535, 572, -6755 } },
11354
{ 0, 50, { 1311, 597, -6427 } },
11355
{ -1, 50, { 2448, 612, -5884 } }
11356
};
11357
11358
struct CutsceneSplinePoint sDddCreditsSplinePositions[] = {
11359
{ 0, 0, { -874, -4933, 366 } },
11360
{ 0, 0, { -1463, -4782, 963 } },
11361
{ 0, 0, { -1893, -4684, 1303 } },
11362
{ 0, 0, { -2818, -4503, 1583 } },
11363
{ 0, 0, { -4095, -2924, 730 } },
11364
{ 0, 0, { -4737, -1594, -63 } },
11365
{ -1, 0, { -4681, -1084, -623 } }
11366
};
11367
11368
struct CutsceneSplinePoint sDddCreditsSplineFocus[] = {
11369
{ 0, 50, { -1276, -4683, 622 } },
11370
{ 0, 50, { -1858, -4407, 1097 } },
11371
{ 0, 50, { -2324, -4332, 1318 } },
11372
{ 0, 50, { -3138, -4048, 1434 } },
11373
{ 0, 50, { -4353, -2444, 533 } },
11374
{ 0, 50, { -4807, -1169, -436 } },
11375
{ -1, 50, { -4665, -664, -1007 } }
11376
};
11377
11378
struct CutsceneSplinePoint sSlCreditsSplinePositions[] = {
11379
{ 0, 0, { 939, 6654, 6196 } },
11380
{ 0, 0, { 1873, 5160, 3714 } },
11381
{ 0, 0, { 3120, 3564, 1314 } },
11382
{ -1, 0, { 2881, 4231, 573 } }
11383
};
11384
11385
struct CutsceneSplinePoint sSlCreditsSplineFocus[] = {
11386
{ 0, 50, { 875, 6411, 5763 } },
11387
{ 0, 50, { 1659, 4951, 3313 } },
11388
{ 0, 50, { 2630, 3565, 1215 } },
11389
{ -1, 50, { 2417, 4056, 639 } }
11390
};
11391
11392
struct CutsceneSplinePoint sWdwCreditsSplinePositions[] = {
11393
{ 0, 0, { 3927, 2573, 3685 } },
11394
{ 0, 0, { 2389, 2054, 1210 } },
11395
{ 0, 0, { 2309, 2069, 22 } },
11396
{ -1, 0, { 2122, 2271, -979 } }
11397
};
11398
11399
struct CutsceneSplinePoint sWdwCreditsSplineFocus[] = {
11400
{ 0, 50, { 3637, 2460, 3294 } },
11401
{ 0, 50, { 1984, 2067, 918 } },
11402
{ 0, 50, { 1941, 2255, -261 } },
11403
{ -1, 50, { 1779, 2587, -1158 } }
11404
};
11405
11406
struct CutsceneSplinePoint sTtmCreditsSplinePositions[] = {
11407
{ 0, 0, { 386, 2535, 644 } },
11408
{ 0, 0, { 1105, 2576, 918 } },
11409
{ 0, 0, { 3565, 2261, 2098 } },
11410
{ 0, 0, { 6715, -2791, 4554 } },
11411
{ 0, 0, { 3917, -3130, 3656 } },
11412
{ -1, 0, { 3917, -3130, 3656 } }
11413
};
11414
11415
struct CutsceneSplinePoint sTtmCreditsSplineFocus[] = {
11416
{ 1, 50, { 751, 2434, 318 } },
11417
{ 2, 50, { 768, 2382, 603 } },
11418
{ 3, 60, { 3115, 2086, 1969 } },
11419
{ 4, 30, { 6370, -3108, 4727 } },
11420
{ 5, 50, { 4172, -3385, 4001 } },
11421
{ -1, 50, { 4172, -3385, 4001 } }
11422
};
11423
11424
struct CutsceneSplinePoint sThiHugeCreditsSplinePositions[] = {
11425
{ 0, 0, { 6990, -1000, -4858 } },
11426
{ 0, 0, { 7886, -1055, 2878 } },
11427
{ 0, 0, { 1952, -1481, 10920 } },
11428
{ 0, 0, { -1684, -219, 2819 } },
11429
{ 0, 0, { -2427, -131, 2755 } },
11430
{ 0, 0, { -3246, 416, 3286 } },
11431
{ -1, 0, { -3246, 416, 3286 } }
11432
};
11433
11434
struct CutsceneSplinePoint sThiHugeCreditsSplineFocus[] = {
11435
{ 1, 70, { 7022, -965, -5356 } },
11436
{ 2, 40, { 7799, -915, 2405 } },
11437
{ 3, 60, { 1878, -1137, 10568 } },
11438
{ 4, 50, { -1931, -308, 2394 } },
11439
{ 5, 50, { -2066, -386, 2521 } },
11440
{ 6, 50, { -2875, 182, 3045 } },
11441
{ -1, 50, { -2875, 182, 3045 } }
11442
};
11443
11444
struct CutsceneSplinePoint sTtcCreditsSplinePositions[] = {
11445
{ 1, 0, { -1724, 277, -994 } },
11446
{ 2, 0, { -1720, 456, -995 } },
11447
{ 3, 0, { -1655, 810, -1014 } },
11448
{ -1, 0, { -1753, 883, -1009 } }
11449
};
11450
11451
struct CutsceneSplinePoint sTtcCreditsSplineFocus[] = {
11452
{ 1, 50, { -1554, 742, -1063 } },
11453
{ 2, 50, { -1245, 571, -1102 } },
11454
{ 3, 50, { -1220, 603, -1151 } },
11455
{ -1, 50, { -1412, 520, -1053 } }
11456
};
11457
11458
struct CutsceneSplinePoint sRrCreditsSplinePositions[] = {
11459
{ 0, 0, { -1818, 4036, 97 } },
11460
{ 0, 0, { -575, 3460, -505 } },
11461
{ 0, 0, { 1191, 3611, -1134 } },
11462
{ -1, 0, { 2701, 3777, -3686 } }
11463
};
11464
11465
struct CutsceneSplinePoint sRrCreditsSplineFocus[] = {
11466
{ 0, 50, { -1376, 3885, -81 } },
11467
{ 0, 50, { -146, 3343, -734 } },
11468
{ 0, 50, { 1570, 3446, -1415 } },
11469
{ -1, 50, { 2794, 3627, -3218 } }
11470
};
11471
11472
struct CutsceneSplinePoint sSaCreditsSplinePositions[] = {
11473
{ 0, 0, { -295, -396, -585 } },
11474
{ 1, 0, { -295, -396, -585 } },
11475
{ 2, 0, { -292, -856, -573 } },
11476
{ 3, 0, { -312, -856, -541 } },
11477
{ -1, 0, { 175, -856, -654 } }
11478
};
11479
11480
struct CutsceneSplinePoint sSaCreditsSplineFocus[] = {
11481
{ 0, 50, { -175, -594, -142 } },
11482
{ 1, 50, { -175, -594, -142 } },
11483
{ 2, 50, { -195, -956, -92 } },
11484
{ 3, 50, { -572, -956, -150 } },
11485
{ -1, 50, { -307, -956, -537 } }
11486
};
11487
11488
struct CutsceneSplinePoint sCotmcCreditsSplinePositions[] = {
11489
{ 0, 0, { -296, 495, 1607 } },
11490
{ 0, 0, { -430, 541, 654 } },
11491
{ 0, 0, { -466, 601, -359 } },
11492
{ 0, 0, { -217, 433, -1549 } },
11493
{ -1, 0, { -95, 366, -2922 } }
11494
};
11495
11496
struct CutsceneSplinePoint sCotmcCreditsSplineFocus[] = {
11497
{ 0, 50, { -176, 483, 2092 } },
11498
{ 0, 50, { -122, 392, 1019 } },
11499
{ 0, 50, { -268, 450, -792 } },
11500
{ 0, 50, { -172, 399, -2046 } },
11501
{ -1, 50, { -51, 355, -3420 } }
11502
};
11503
11504
struct CutsceneSplinePoint sDddSubCreditsSplinePositions[] = {
11505
{ 0, 0, { 4656, 2171, 5028 } },
11506
{ 0, 0, { 4548, 1182, 4596 } },
11507
{ 0, 0, { 5007, 813, 3257 } },
11508
{ 0, 0, { 5681, 648, 1060 } },
11509
{ -1, 0, { 4644, 774, 113 } }
11510
};
11511
11512
struct CutsceneSplinePoint sDddSubCreditsSplineFocus[] = {
11513
{ 0, 50, { 4512, 2183, 4549 } },
11514
{ 0, 50, { 4327, 838, 4308 } },
11515
{ 0, 50, { 4774, 749, 2819 } },
11516
{ 0, 50, { 5279, 660, 763 } },
11517
{ -1, 50, { 4194, 885, -75 } }
11518
};
11519
11520
struct CutsceneSplinePoint sCcmOutsideCreditsSplinePositions[] = {
11521
{ 1, 0, { 1427, -1387, 5409 } },
11522
{ 2, 0, { -1646, -1536, 4526 } },
11523
{ 3, 0, { -3852, -1448, 3913 } },
11524
{ -1, 0, { -5199, -1366, 1886 } }
11525
};
11526
11527
struct CutsceneSplinePoint sCcmOutsideCreditsSplineFocus[] = {
11528
{ 1, 50, { 958, -1481, 5262 } },
11529
{ 2, 50, { -2123, -1600, 4391 } },
11530
{ 3, 50, { -3957, -1401, 3426 } },
11531
{ -1, 50, { -4730, -1215, 1795 } }
11532
};
11533
11534
/**
11535
* Play the current cutscene until either gCutsceneTimer reaches the max time, or c->cutscene is set to 0
11536
*
11537
* Note that CAM_FLAG_SMOOTH_MOVEMENT is cleared while a cutscene is playing, so cutscenes set it for
11538
* the duration they want the flag to be active.
11539
*/
11540
void play_cutscene(struct Camera *c) {
11541
UNUSED u32 pad[3];
11542
UNUSED s16 unusedYawFocToMario;
11543
s16 cutsceneDuration;
11544
u8 oldCutscene;
11545
11546
unusedYawFocToMario = sAreaYaw;
11547
oldCutscene = c->cutscene;
11548
sStatusFlags &= ~CAM_FLAG_SMOOTH_MOVEMENT;
11549
gCameraMovementFlags &= ~CAM_MOVING_INTO_MODE;
11550
11551
#define CUTSCENE(id, cutscene) \
11552
case id: \
11553
cutsceneDuration = cutscene[sCutsceneShot].duration; \
11554
cutscene[sCutsceneShot].shot(c); \
11555
break;
11556
11557
switch (c->cutscene) {
11558
CUTSCENE(CUTSCENE_STAR_SPAWN, sCutsceneStarSpawn)
11559
CUTSCENE(CUTSCENE_RED_COIN_STAR_SPAWN, sCutsceneRedCoinStarSpawn)
11560
CUTSCENE(CUTSCENE_ENDING, sCutsceneEnding)
11561
CUTSCENE(CUTSCENE_GRAND_STAR, sCutsceneGrandStar)
11562
CUTSCENE(CUTSCENE_DOOR_WARP, sCutsceneDoorWarp)
11563
CUTSCENE(CUTSCENE_DOOR_PULL, sCutsceneDoorPull)
11564
CUTSCENE(CUTSCENE_DOOR_PUSH, sCutsceneDoorPush)
11565
CUTSCENE(CUTSCENE_DOOR_PULL_MODE, sCutsceneDoorPullMode)
11566
CUTSCENE(CUTSCENE_DOOR_PUSH_MODE, sCutsceneDoorPushMode)
11567
CUTSCENE(CUTSCENE_ENTER_CANNON, sCutsceneEnterCannon)
11568
CUTSCENE(CUTSCENE_ENTER_PAINTING, sCutsceneEnterPainting)
11569
CUTSCENE(CUTSCENE_DEATH_EXIT, sCutsceneDeathExit)
11570
CUTSCENE(CUTSCENE_EXIT_PAINTING_SUCC, sCutsceneExitPaintingSuccess)
11571
CUTSCENE(CUTSCENE_UNUSED_EXIT, sCutsceneUnusedExit)
11572
CUTSCENE(CUTSCENE_INTRO_PEACH, sCutsceneIntroPeach)
11573
CUTSCENE(CUTSCENE_ENTER_BOWSER_ARENA, sCutsceneEnterBowserArena)
11574
CUTSCENE(CUTSCENE_DANCE_ROTATE, sCutsceneDanceDefaultRotate)
11575
CUTSCENE(CUTSCENE_DANCE_DEFAULT, sCutsceneDanceDefaultRotate)
11576
CUTSCENE(CUTSCENE_DANCE_FLY_AWAY, sCutsceneDanceFlyAway)
11577
CUTSCENE(CUTSCENE_DANCE_CLOSEUP, sCutsceneDanceCloseup)
11578
CUTSCENE(CUTSCENE_KEY_DANCE, sCutsceneKeyDance)
11579
CUTSCENE(CUTSCENE_0F_UNUSED, sCutsceneUnused)
11580
CUTSCENE(CUTSCENE_END_WAVING, sCutsceneEndWaving)
11581
CUTSCENE(CUTSCENE_CREDITS, sCutsceneCredits)
11582
CUTSCENE(CUTSCENE_CAP_SWITCH_PRESS, sCutsceneCapSwitchPress)
11583
CUTSCENE(CUTSCENE_SLIDING_DOORS_OPEN, sCutsceneSlidingDoorsOpen)
11584
CUTSCENE(CUTSCENE_PREPARE_CANNON, sCutscenePrepareCannon)
11585
CUTSCENE(CUTSCENE_UNLOCK_KEY_DOOR, sCutsceneUnlockKeyDoor)
11586
CUTSCENE(CUTSCENE_STANDING_DEATH, sCutsceneStandingDeath)
11587
CUTSCENE(CUTSCENE_ENTER_POOL, sCutsceneEnterPool)
11588
CUTSCENE(CUTSCENE_DEATH_ON_STOMACH, sCutsceneDeathStomach)
11589
CUTSCENE(CUTSCENE_DEATH_ON_BACK, sCutsceneDeathOnBack)
11590
CUTSCENE(CUTSCENE_QUICKSAND_DEATH, sCutsceneQuicksandDeath)
11591
CUTSCENE(CUTSCENE_SUFFOCATION_DEATH, sCutsceneSuffocation)
11592
CUTSCENE(CUTSCENE_EXIT_BOWSER_SUCC, sCutsceneExitBowserSuccess)
11593
CUTSCENE(CUTSCENE_EXIT_BOWSER_DEATH, sCutsceneExitBowserDeath)
11594
CUTSCENE(CUTSCENE_EXIT_SPECIAL_SUCC, sCutsceneExitSpecialSuccess)
11595
CUTSCENE(CUTSCENE_EXIT_WATERFALL, sCutsceneExitWaterfall)
11596
CUTSCENE(CUTSCENE_EXIT_FALL_WMOTR, sCutsceneFallToCastleGrounds)
11597
CUTSCENE(CUTSCENE_NONPAINTING_DEATH, sCutsceneNonPaintingDeath)
11598
CUTSCENE(CUTSCENE_DIALOG, sCutsceneDialog)
11599
CUTSCENE(CUTSCENE_READ_MESSAGE, sCutsceneReadMessage)
11600
CUTSCENE(CUTSCENE_RACE_DIALOG, sCutsceneDialog)
11601
CUTSCENE(CUTSCENE_ENTER_PYRAMID_TOP, sCutsceneEnterPyramidTop)
11602
CUTSCENE(CUTSCENE_SSL_PYRAMID_EXPLODE, sCutscenePyramidTopExplode)
11603
}
11604
11605
#undef CUTSCENE
11606
11607
if ((cutsceneDuration != 0) && !(gCutsceneTimer & CUTSCENE_STOP)) {
11608
//! @bug This should check for 0x7FFF (CUTSCENE_LOOP)
11609
//! instead, cutscenes that last longer than 0x3FFF frames will never end on their own
11610
if (gCutsceneTimer < 0x3FFF) {
11611
gCutsceneTimer += 1;
11612
}
11613
//! Because gCutsceneTimer is often set to 0x7FFF (CUTSCENE_LOOP), this conditional can only
11614
//! check for == due to overflow
11615
if (gCutsceneTimer == cutsceneDuration) {
11616
sCutsceneShot += 1;
11617
gCutsceneTimer = 0;
11618
}
11619
} else {
11620
sMarioCamState->cameraEvent = 0;
11621
sCutsceneShot = 0;
11622
gCutsceneTimer = 0;
11623
}
11624
11625
sAreaYawChange = 0;
11626
11627
// The cutscene just ended
11628
if ((c->cutscene == 0) && (oldCutscene != 0)) {
11629
gRecentCutscene = oldCutscene;
11630
}
11631
}
11632
11633
/**
11634
* Call the event while `start` <= gCutsceneTimer <= `end`
11635
* If `end` is -1, call for the rest of the shot.
11636
*/
11637
s32 cutscene_event(CameraEvent event, struct Camera *c, s16 start, s16 end) {
11638
if (start <= gCutsceneTimer) {
11639
if (end == -1 || end >= gCutsceneTimer) {
11640
event(c);
11641
}
11642
}
11643
return 0;
11644
}
11645
11646
/**
11647
* Set gCutsceneObjSpawn when gCutsceneTimer == `frame`.
11648
*
11649
* @see intro_scene.inc.c for details on which objects are spawned.
11650
*/
11651
s32 cutscene_spawn_obj(u32 obj, s16 frame) {
11652
if (frame == gCutsceneTimer) {
11653
gCutsceneObjSpawn = obj;
11654
}
11655
return 0;
11656
}
11657
11658
/**
11659
* Start shaking the camera's field of view.
11660
*
11661
* @param shakeSpeed How fast the shake should progress through its period. The shake offset is
11662
* calculated from coss(), so this parameter can be thought of as an angular velocity.
11663
*/
11664
void set_fov_shake(s16 amplitude, s16 decay, s16 shakeSpeed) {
11665
if (amplitude > sFOVState.shakeAmplitude) {
11666
sFOVState.shakeAmplitude = amplitude;
11667
sFOVState.decay = decay;
11668
sFOVState.shakeSpeed = shakeSpeed;
11669
}
11670
}
11671
11672
/**
11673
* Start shaking the camera's field of view, but reduce `amplitude` by distance from camera
11674
*/
11675
void set_fov_shake_from_point(s16 amplitude, s16 decay, s16 shakeSpeed, f32 maxDist, f32 posX, f32 posY, f32 posZ) {
11676
amplitude = reduce_by_dist_from_camera(amplitude, maxDist, posX, posY, posZ);
11677
11678
if (amplitude != 0) {
11679
if (amplitude > sFOVState.shakeAmplitude) { // literally use the function above you silly nintendo, smh
11680
sFOVState.shakeAmplitude = amplitude;
11681
sFOVState.decay = decay;
11682
sFOVState.shakeSpeed = shakeSpeed;
11683
}
11684
}
11685
}
11686
11687
/**
11688
* Add a cyclic offset to the camera's field of view based on a cosine wave
11689
*/
11690
void shake_camera_fov(struct GraphNodePerspective *perspective) {
11691
if (sFOVState.shakeAmplitude != 0.f) {
11692
sFOVState.fovOffset = coss(sFOVState.shakePhase) * sFOVState.shakeAmplitude / 0x100;
11693
sFOVState.shakePhase += sFOVState.shakeSpeed;
11694
camera_approach_f32_symmetric_bool(&sFOVState.shakeAmplitude, 0.f, sFOVState.decay);
11695
perspective->fov += sFOVState.fovOffset;
11696
} else {
11697
sFOVState.shakePhase = 0;
11698
}
11699
}
11700
11701
static UNUSED void unused_deactivate_sleeping_camera(UNUSED struct MarioState *m) {
11702
sStatusFlags &= ~CAM_FLAG_SLEEPING;
11703
}
11704
11705
void set_fov_30(UNUSED struct MarioState *m) {
11706
sFOVState.fov = 30.f;
11707
}
11708
11709
void approach_fov_20(UNUSED struct MarioState *m) {
11710
camera_approach_f32_symmetric_bool(&sFOVState.fov, 20.f, 0.3f);
11711
}
11712
11713
void set_fov_45(UNUSED struct MarioState *m) {
11714
sFOVState.fov = 45.f;
11715
}
11716
11717
void set_fov_29(UNUSED struct MarioState *m) {
11718
sFOVState.fov = 29.f;
11719
}
11720
11721
void zoom_fov_30(UNUSED struct MarioState *m) {
11722
// Pretty sure approach_f32_asymptotic_bool would do a much nicer job here, but you do you,
11723
// Nintendo.
11724
camera_approach_f32_symmetric_bool(&sFOVState.fov, 30.f, (30.f - sFOVState.fov) / 60.f);
11725
}
11726
11727
/**
11728
* This is the default fov function. It makes fov approach 45 degrees, and it handles zooming in when
11729
* Mario falls a sleep.
11730
*/
11731
void fov_default(struct MarioState *m) {
11732
sStatusFlags &= ~CAM_FLAG_SLEEPING;
11733
11734
if ((m->action == ACT_SLEEPING) || (m->action == ACT_START_SLEEPING)) {
11735
camera_approach_f32_symmetric_bool(&sFOVState.fov, 30.f, (30.f - sFOVState.fov) / 30.f);
11736
sStatusFlags |= CAM_FLAG_SLEEPING;
11737
} else {
11738
camera_approach_f32_symmetric_bool(&sFOVState.fov, 45.f, (45.f - sFOVState.fov) / 30.f);
11739
sFOVState.unusedIsSleeping = 0;
11740
}
11741
if (m->area->camera->cutscene == CUTSCENE_0F_UNUSED) {
11742
sFOVState.fov = 45.f;
11743
}
11744
}
11745
11746
//??! Literally the exact same as below
11747
static UNUSED void unused_approach_fov_30(UNUSED struct MarioState *m) {
11748
camera_approach_f32_symmetric_bool(&sFOVState.fov, 30.f, 1.f);
11749
}
11750
11751
void approach_fov_30(UNUSED struct MarioState *m) {
11752
camera_approach_f32_symmetric_bool(&sFOVState.fov, 30.f, 1.f);
11753
}
11754
11755
void approach_fov_60(UNUSED struct MarioState *m) {
11756
camera_approach_f32_symmetric_bool(&sFOVState.fov, 60.f, 1.f);
11757
}
11758
11759
void approach_fov_45(struct MarioState *m) {
11760
f32 targetFoV = sFOVState.fov;
11761
11762
if (m->area->camera->mode == CAMERA_MODE_FIXED && m->area->camera->cutscene == 0) {
11763
targetFoV = 45.f;
11764
} else {
11765
targetFoV = 45.f;
11766
}
11767
11768
sFOVState.fov = approach_f32(sFOVState.fov, targetFoV, 2.f, 2.f);
11769
}
11770
11771
void approach_fov_80(UNUSED struct MarioState *m) {
11772
camera_approach_f32_symmetric_bool(&sFOVState.fov, 80.f, 3.5f);
11773
}
11774
11775
/**
11776
* Sets the fov in BBH.
11777
* If there's a cutscene, sets fov to 45. Otherwise sets fov to 60.
11778
*/
11779
void set_fov_bbh(struct MarioState *m) {
11780
f32 targetFoV = sFOVState.fov;
11781
11782
if (m->area->camera->mode == CAMERA_MODE_FIXED && m->area->camera->cutscene == 0) {
11783
targetFoV = 60.f;
11784
} else {
11785
targetFoV = 45.f;
11786
}
11787
11788
sFOVState.fov = approach_f32(sFOVState.fov, targetFoV, 2.f, 2.f);
11789
}
11790
11791
/**
11792
* Sets the field of view for the GraphNodeCamera
11793
*/
11794
Gfx *geo_camera_fov(s32 callContext, struct GraphNode *g, UNUSED void *context) {
11795
struct GraphNodePerspective *perspective = (struct GraphNodePerspective *) g;
11796
struct MarioState *marioState = &gMarioStates[0];
11797
u8 fovFunc = sFOVState.fovFunc;
11798
11799
if (callContext == GEO_CONTEXT_RENDER) {
11800
switch (fovFunc) {
11801
case CAM_FOV_SET_45:
11802
set_fov_45(marioState);
11803
break;
11804
case CAM_FOV_SET_29:
11805
set_fov_29(marioState);
11806
break;
11807
case CAM_FOV_ZOOM_30:
11808
zoom_fov_30(marioState);
11809
break;
11810
case CAM_FOV_DEFAULT:
11811
fov_default(marioState);
11812
break;
11813
case CAM_FOV_BBH:
11814
set_fov_bbh(marioState);
11815
break;
11816
case CAM_FOV_APP_45:
11817
approach_fov_45(marioState);
11818
break;
11819
case CAM_FOV_SET_30:
11820
set_fov_30(marioState);
11821
break;
11822
case CAM_FOV_APP_20:
11823
approach_fov_20(marioState);
11824
break;
11825
case CAM_FOV_APP_80:
11826
approach_fov_80(marioState);
11827
break;
11828
case CAM_FOV_APP_30:
11829
approach_fov_30(marioState);
11830
break;
11831
case CAM_FOV_APP_60:
11832
approach_fov_60(marioState);
11833
break;
11834
//! No default case
11835
}
11836
}
11837
11838
perspective->fov = sFOVState.fov + configAdditionalFOV;
11839
shake_camera_fov(perspective);
11840
return NULL;
11841
}
11842
11843
/**
11844
* Change the camera's FOV mode.
11845
*
11846
* @see geo_camera_fov
11847
*/
11848
void set_fov_function(u8 func) {
11849
sFOVState.fovFunc = func;
11850
}
11851
11852
/**
11853
* Start a preset fov shake. Used in cutscenes
11854
*/
11855
void cutscene_set_fov_shake_preset(u8 preset) {
11856
switch (preset) {
11857
case 1:
11858
set_fov_shake(0x100, 0x30, 0x8000);
11859
break;
11860
case 2:
11861
set_fov_shake(0x400, 0x20, 0x4000);
11862
break;
11863
}
11864
}
11865
11866
/**
11867
* Start a preset fov shake that is reduced by the point's distance from the camera.
11868
* Used in set_camera_shake_from_point
11869
*
11870
* @see set_camera_shake_from_point
11871
*/
11872
void set_fov_shake_from_point_preset(u8 preset, f32 posX, f32 posY, f32 posZ) {
11873
switch (preset) {
11874
case SHAKE_FOV_SMALL:
11875
set_fov_shake_from_point(0x100, 0x30, 0x8000, 3000.f, posX, posY, posZ);
11876
break;
11877
case SHAKE_FOV_MEDIUM:
11878
set_fov_shake_from_point(0x200, 0x30, 0x8000, 4000.f, posX, posY, posZ);
11879
break;
11880
case SHAKE_FOV_LARGE:
11881
set_fov_shake_from_point(0x300, 0x30, 0x8000, 6000.f, posX, posY, posZ);
11882
break;
11883
case SHAKE_FOV_UNUSED:
11884
set_fov_shake_from_point(0x800, 0x20, 0x4000, 3000.f, posX, posY, posZ);
11885
break;
11886
}
11887
}
11888
11889
/**
11890
* Offset an object's position in a random direction within the given bounds.
11891
*/
11892
static UNUSED void unused_displace_obj_randomly(struct Object *o, f32 xRange, f32 yRange, f32 zRange) {
11893
f32 rnd = random_float();
11894
11895
o->oPosX += (rnd * xRange - xRange / 2.f);
11896
o->oPosY += (rnd * yRange - yRange / 2.f);
11897
o->oPosZ += (rnd * zRange - zRange / 2.f);
11898
}
11899
11900
/**
11901
* Rotate an object in a random direction within the given bounds.
11902
*/
11903
static UNUSED void unused_rotate_obj_randomly(struct Object *o, f32 pitchRange, f32 yawRange) {
11904
f32 rnd = random_float();
11905
11906
o->oMoveAnglePitch += (s16)(rnd * pitchRange - pitchRange / 2.f);
11907
o->oMoveAngleYaw += (s16)(rnd * yawRange - yawRange / 2.f);
11908
}
11909
11910
/**
11911
* Rotate the object towards the point `point`.
11912
*/
11913
void obj_rotate_towards_point(struct Object *o, Vec3f point, s16 pitchOff, s16 yawOff, s16 pitchDiv, s16 yawDiv) {
11914
f32 dist;
11915
s16 pitch, yaw;
11916
Vec3f oPos;
11917
11918
object_pos_to_vec3f(oPos, o);
11919
vec3f_get_dist_and_angle(oPos, point, &dist, &pitch, &yaw);
11920
o->oMoveAnglePitch = approach_s16_asymptotic(o->oMoveAnglePitch, pitchOff - pitch, pitchDiv);
11921
o->oMoveAngleYaw = approach_s16_asymptotic(o->oMoveAngleYaw, yaw + yawOff, yawDiv);
11922
}
11923
11924
#include "behaviors/intro_peach.inc.c"
11925
#include "behaviors/intro_lakitu.inc.c"
11926
#include "behaviors/end_birds_1.inc.c"
11927
#include "behaviors/end_birds_2.inc.c"
11928
#include "behaviors/intro_scene.inc.c"
11929
11930