Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
MorsGames
GitHub Repository: MorsGames/sm64plus
Path: blob/master/src/game/mario.c
7858 views
1
#include <PR/ultratypes.h>
2
3
#include "sm64.h"
4
#include "area.h"
5
#include "audio/external.h"
6
#include "behavior_actions.h"
7
#include "behavior_data.h"
8
#include "camera.h"
9
#include "engine/graph_node.h"
10
#include "engine/math_util.h"
11
#include "engine/surface_collision.h"
12
#include "game_init.h"
13
#include "interaction.h"
14
#include "level_table.h"
15
#include "level_update.h"
16
#include "main.h"
17
#include "mario.h"
18
#include "mario_actions_airborne.h"
19
#include "mario_actions_automatic.h"
20
#include "mario_actions_cutscene.h"
21
#include "mario_actions_moving.h"
22
#include "mario_actions_object.h"
23
#include "mario_actions_stationary.h"
24
#include "mario_actions_submerged.h"
25
#include "mario_misc.h"
26
#include "mario_step.h"
27
#include "memory.h"
28
#include "object_fields.h"
29
#include "object_helpers.h"
30
#include "object_list_processor.h"
31
#include "print.h"
32
#include "save_file.h"
33
#include "sound_init.h"
34
#include "rumble_init.h"
35
36
#include "audio/external.h"
37
#include "seq_ids.h"
38
39
#include "debug.h"
40
#include "settings.h"
41
42
u32 unused80339F10;
43
s8 filler80339F1C[20];
44
45
/**************************************************
46
* ANIMATIONS *
47
**************************************************/
48
49
/**
50
* Checks if Mario's animation has reached its end point.
51
*/
52
s32 is_anim_at_end(struct MarioState *m) {
53
struct Object *o = m->marioObj;
54
55
return (o->header.gfx.animInfo.animFrame + 1) == o->header.gfx.animInfo.curAnim->loopEnd;
56
}
57
58
/**
59
* Checks if Mario's animation has surpassed 2 frames before its end point.
60
*/
61
s32 is_anim_past_end(struct MarioState *m) {
62
struct Object *o = m->marioObj;
63
64
return o->header.gfx.animInfo.animFrame >= (o->header.gfx.animInfo.curAnim->loopEnd - 2);
65
}
66
67
/**
68
* Sets Mario's animation without any acceleration, running at its default rate.
69
*/
70
s16 set_mario_animation(struct MarioState *m, s32 targetAnimID) {
71
struct Object *o = m->marioObj;
72
struct Animation *targetAnim = m->animList->bufTarget;
73
74
if (load_patchable_table(m->animList, targetAnimID)) {
75
targetAnim->values = (void *) VIRTUAL_TO_PHYSICAL((u8 *) targetAnim + (uintptr_t) targetAnim->values);
76
targetAnim->index = (void *) VIRTUAL_TO_PHYSICAL((u8 *) targetAnim + (uintptr_t) targetAnim->index);
77
}
78
79
if (o->header.gfx.animInfo.animID != targetAnimID) {
80
o->header.gfx.animInfo.animID = targetAnimID;
81
o->header.gfx.animInfo.curAnim = targetAnim;
82
o->header.gfx.animInfo.animAccel = 0;
83
o->header.gfx.animInfo.animYTrans = m->unkB0;
84
85
if (targetAnim->flags & ANIM_FLAG_2) {
86
o->header.gfx.animInfo.animFrame = targetAnim->startFrame;
87
} else {
88
if (targetAnim->flags & ANIM_FLAG_FORWARD) {
89
o->header.gfx.animInfo.animFrame = targetAnim->startFrame + 1;
90
} else {
91
o->header.gfx.animInfo.animFrame = targetAnim->startFrame - 1;
92
}
93
}
94
}
95
96
return o->header.gfx.animInfo.animFrame;
97
}
98
99
/**
100
* Sets Mario's animation where the animation is sped up or
101
* slowed down via acceleration.
102
*/
103
s16 set_mario_anim_with_accel(struct MarioState *m, s32 targetAnimID, s32 accel) {
104
struct Object *o = m->marioObj;
105
struct Animation *targetAnim = m->animList->bufTarget;
106
107
if (load_patchable_table(m->animList, targetAnimID)) {
108
targetAnim->values = (void *) VIRTUAL_TO_PHYSICAL((u8 *) targetAnim + (uintptr_t) targetAnim->values);
109
targetAnim->index = (void *) VIRTUAL_TO_PHYSICAL((u8 *) targetAnim + (uintptr_t) targetAnim->index);
110
}
111
112
if (o->header.gfx.animInfo.animID != targetAnimID) {
113
o->header.gfx.animInfo.animID = targetAnimID;
114
o->header.gfx.animInfo.curAnim = targetAnim;
115
o->header.gfx.animInfo.animYTrans = m->unkB0;
116
117
if (targetAnim->flags & ANIM_FLAG_2) {
118
o->header.gfx.animInfo.animFrameAccelAssist = (targetAnim->startFrame << 0x10);
119
} else {
120
if (targetAnim->flags & ANIM_FLAG_FORWARD) {
121
o->header.gfx.animInfo.animFrameAccelAssist = (targetAnim->startFrame << 0x10) + accel;
122
} else {
123
o->header.gfx.animInfo.animFrameAccelAssist = (targetAnim->startFrame << 0x10) - accel;
124
}
125
}
126
127
o->header.gfx.animInfo.animFrame = (o->header.gfx.animInfo.animFrameAccelAssist >> 0x10);
128
}
129
130
o->header.gfx.animInfo.animAccel = accel;
131
132
return o->header.gfx.animInfo.animFrame;
133
}
134
135
/**
136
* Sets the animation to a specific "next" frame from the frame given.
137
*/
138
void set_anim_to_frame(struct MarioState *m, s16 animFrame) {
139
struct AnimInfo *animInfo = &m->marioObj->header.gfx.animInfo;
140
struct Animation *curAnim = animInfo->curAnim;
141
142
if (animInfo->animAccel) {
143
if (curAnim->flags & ANIM_FLAG_FORWARD) {
144
animInfo->animFrameAccelAssist = (animFrame << 0x10) + animInfo->animAccel;
145
} else {
146
animInfo->animFrameAccelAssist = (animFrame << 0x10) - animInfo->animAccel;
147
}
148
} else {
149
if (curAnim->flags & ANIM_FLAG_FORWARD) {
150
animInfo->animFrame = animFrame + 1;
151
} else {
152
animInfo->animFrame = animFrame - 1;
153
}
154
}
155
}
156
157
s32 is_anim_past_frame(struct MarioState *m, s16 animFrame) {
158
s32 isPastFrame;
159
s32 acceleratedFrame = animFrame << 0x10;
160
struct AnimInfo *animInfo = &m->marioObj->header.gfx.animInfo;
161
struct Animation *curAnim = animInfo->curAnim;
162
163
if (animInfo->animAccel) {
164
if (curAnim->flags & ANIM_FLAG_FORWARD) {
165
isPastFrame =
166
(animInfo->animFrameAccelAssist > acceleratedFrame)
167
&& (acceleratedFrame >= (animInfo->animFrameAccelAssist - animInfo->animAccel));
168
} else {
169
isPastFrame =
170
(animInfo->animFrameAccelAssist < acceleratedFrame)
171
&& (acceleratedFrame <= (animInfo->animFrameAccelAssist + animInfo->animAccel));
172
}
173
} else {
174
if (curAnim->flags & ANIM_FLAG_FORWARD) {
175
isPastFrame = (animInfo->animFrame == (animFrame + 1));
176
} else {
177
isPastFrame = ((animInfo->animFrame + 1) == animFrame);
178
}
179
}
180
181
return isPastFrame;
182
}
183
184
/**
185
* Rotates the animation's translation into the global coordinate system
186
* and returns the animation's flags.
187
*/
188
s16 find_mario_anim_flags_and_translation(struct Object *obj, s32 yaw, Vec3s translation) {
189
f32 dx;
190
f32 dz;
191
192
struct Animation *curAnim = (void *) obj->header.gfx.animInfo.curAnim;
193
s16 animFrame = geo_update_animation_frame(&obj->header.gfx.animInfo, NULL);
194
u16 *animIndex = segmented_to_virtual((void *) curAnim->index);
195
s16 *animValues = segmented_to_virtual((void *) curAnim->values);
196
197
f32 s = (f32) sins(yaw);
198
f32 c = (f32) coss(yaw);
199
200
dx = *(animValues + (retrieve_animation_index(animFrame, &animIndex))) / 4.0f;
201
translation[1] = *(animValues + (retrieve_animation_index(animFrame, &animIndex))) / 4.0f;
202
dz = *(animValues + (retrieve_animation_index(animFrame, &animIndex))) / 4.0f;
203
204
translation[0] = (dx * c) + (dz * s);
205
translation[2] = (-dx * s) + (dz * c);
206
207
return curAnim->flags;
208
}
209
210
/**
211
* Updates Mario's position from his animation's translation.
212
*/
213
void update_mario_pos_for_anim(struct MarioState *m) {
214
Vec3s translation;
215
s16 flags;
216
217
flags = find_mario_anim_flags_and_translation(m->marioObj, m->faceAngle[1], translation);
218
219
if (flags & (ANIM_FLAG_HOR_TRANS | ANIM_FLAG_6)) {
220
m->pos[0] += (f32) translation[0];
221
m->pos[2] += (f32) translation[2];
222
}
223
224
if (flags & (ANIM_FLAG_VERT_TRANS | ANIM_FLAG_6)) {
225
m->pos[1] += (f32) translation[1];
226
}
227
}
228
229
/**
230
* Finds the vertical translation from Mario's animation.
231
*/
232
s16 return_mario_anim_y_translation(struct MarioState *m) {
233
Vec3s translation;
234
find_mario_anim_flags_and_translation(m->marioObj, 0, translation);
235
236
return translation[1];
237
}
238
239
/**************************************************
240
* AUDIO *
241
**************************************************/
242
243
/**
244
* Plays a sound if if Mario doesn't have the flag being checked.
245
*/
246
void play_sound_if_no_flag(struct MarioState *m, u32 soundBits, u32 flags) {
247
if (!(m->flags & flags)) {
248
play_sound(soundBits, m->marioObj->header.gfx.cameraToObject);
249
m->flags |= flags;
250
}
251
}
252
253
/**
254
* Plays a jump sound if one has not been played since the last action change.
255
*/
256
void play_mario_jump_sound(struct MarioState *m) {
257
if (!(m->flags & MARIO_MARIO_SOUND_PLAYED)) {
258
#ifndef VERSION_JP
259
if (m->action == ACT_TRIPLE_JUMP) {
260
play_sound(SOUND_MARIO_YAHOO_WAHA_YIPPEE + ((gAudioRandom % 5) << 16),
261
m->marioObj->header.gfx.cameraToObject);
262
} else {
263
#endif
264
play_sound(SOUND_MARIO_YAH_WAH_HOO + ((gAudioRandom % 3) << 16),
265
m->marioObj->header.gfx.cameraToObject);
266
#ifndef VERSION_JP
267
}
268
#endif
269
m->flags |= MARIO_MARIO_SOUND_PLAYED;
270
}
271
}
272
273
/**
274
* Adjusts the volume/pitch of sounds from Mario's speed.
275
*/
276
void adjust_sound_for_speed(struct MarioState *m) {
277
s32 absForwardVel = (m->forwardVel > 0.0f) ? m->forwardVel : -m->forwardVel;
278
set_sound_moving_speed(SOUND_BANK_MOVING, (absForwardVel > 100) ? 100 : absForwardVel);
279
}
280
281
/**
282
* Spawns particles if the step sound says to, then either plays a step sound or relevant other sound.
283
*/
284
void play_sound_and_spawn_particles(struct MarioState *m, u32 soundBits, u32 waveParticleType) {
285
if (m->terrainSoundAddend == (SOUND_TERRAIN_WATER << 16)) {
286
if (waveParticleType != 0) {
287
m->particleFlags |= PARTICLE_SHALLOW_WATER_SPLASH;
288
} else {
289
m->particleFlags |= PARTICLE_SHALLOW_WATER_WAVE;
290
}
291
} else {
292
if (m->terrainSoundAddend == (SOUND_TERRAIN_SAND << 16)) {
293
m->particleFlags |= PARTICLE_DIRT;
294
} else if (m->terrainSoundAddend == (SOUND_TERRAIN_SNOW << 16)) {
295
m->particleFlags |= PARTICLE_SNOW;
296
}
297
}
298
299
if ((m->flags & MARIO_METAL_CAP) || soundBits == SOUND_ACTION_UNSTUCK_FROM_GROUND
300
|| soundBits == SOUND_MARIO_PUNCH_HOO) {
301
play_sound(soundBits, m->marioObj->header.gfx.cameraToObject);
302
} else {
303
play_sound(m->terrainSoundAddend + soundBits, m->marioObj->header.gfx.cameraToObject);
304
}
305
}
306
307
/**
308
* Plays an environmental sound if one has not been played since the last action change.
309
*/
310
void play_mario_action_sound(struct MarioState *m, u32 soundBits, u32 waveParticleType) {
311
if (!(m->flags & MARIO_ACTION_SOUND_PLAYED)) {
312
play_sound_and_spawn_particles(m, soundBits, waveParticleType);
313
m->flags |= MARIO_ACTION_SOUND_PLAYED;
314
}
315
}
316
317
/**
318
* Plays a landing sound, accounting for metal cap.
319
*/
320
void play_mario_landing_sound(struct MarioState *m, u32 soundBits) {
321
play_sound_and_spawn_particles(
322
m, (m->flags & MARIO_METAL_CAP) ? SOUND_ACTION_METAL_LANDING : soundBits, 1);
323
}
324
325
/**
326
* Plays a landing sound, accounting for metal cap. Unlike play_mario_landing_sound,
327
* this function uses play_mario_action_sound, making sure the sound is only
328
* played once per action.
329
*/
330
void play_mario_landing_sound_once(struct MarioState *m, u32 soundBits) {
331
play_mario_action_sound(
332
m, (m->flags & MARIO_METAL_CAP) ? SOUND_ACTION_METAL_LANDING : soundBits, 1);
333
}
334
335
/**
336
* Plays a heavy landing (ground pound, etc.) sound, accounting for metal cap.
337
*/
338
void play_mario_heavy_landing_sound(struct MarioState *m, u32 soundBits) {
339
play_sound_and_spawn_particles(
340
m, (m->flags & MARIO_METAL_CAP) ? SOUND_ACTION_METAL_HEAVY_LANDING : soundBits, 1);
341
}
342
343
/**
344
* Plays a heavy landing (ground pound, etc.) sound, accounting for metal cap.
345
* Unlike play_mario_heavy_landing_sound, this function uses play_mario_action_sound,
346
* making sure the sound is only played once per action.
347
*/
348
void play_mario_heavy_landing_sound_once(struct MarioState *m, u32 soundBits) {
349
play_mario_action_sound(
350
m, (m->flags & MARIO_METAL_CAP) ? SOUND_ACTION_METAL_HEAVY_LANDING : soundBits, 1);
351
}
352
353
/**
354
* Plays action and Mario sounds relevant to what was passed into the function.
355
*/
356
void play_mario_sound(struct MarioState *m, s32 actionSound, s32 marioSound) {
357
if (actionSound == SOUND_ACTION_TERRAIN_JUMP) {
358
play_mario_action_sound(m, (m->flags & MARIO_METAL_CAP) ? (s32) SOUND_ACTION_METAL_JUMP
359
: (s32) SOUND_ACTION_TERRAIN_JUMP, 1);
360
} else {
361
play_sound_if_no_flag(m, actionSound, MARIO_ACTION_SOUND_PLAYED);
362
}
363
364
if (marioSound == 0) {
365
play_mario_jump_sound(m);
366
}
367
368
if (marioSound != -1) {
369
play_sound_if_no_flag(m, marioSound, MARIO_MARIO_SOUND_PLAYED);
370
}
371
}
372
373
/**************************************************
374
* ACTIONS *
375
**************************************************/
376
377
/**
378
* Sets Mario's other velocities from his forward speed.
379
*/
380
void mario_set_forward_vel(struct MarioState *m, f32 forwardVel) {
381
m->forwardVel = forwardVel;
382
383
m->slideVelX = sins(m->faceAngle[1]) * m->forwardVel;
384
m->slideVelZ = coss(m->faceAngle[1]) * m->forwardVel;
385
386
m->vel[0] = (f32) m->slideVelX;
387
m->vel[2] = (f32) m->slideVelZ;
388
}
389
390
/**
391
* Returns the slipperiness class of Mario's floor.
392
*/
393
s32 mario_get_floor_class(struct MarioState *m) {
394
s32 floorClass;
395
396
// The slide terrain type defaults to slide slipperiness.
397
// This doesn't matter too much since normally the slide terrain
398
// is checked for anyways.
399
if ((m->area->terrainType & TERRAIN_MASK) == TERRAIN_SLIDE) {
400
floorClass = SURFACE_CLASS_VERY_SLIPPERY;
401
} else {
402
floorClass = SURFACE_CLASS_DEFAULT;
403
}
404
405
if (m->floor != NULL) {
406
switch (m->floor->type) {
407
case SURFACE_NOT_SLIPPERY:
408
case SURFACE_HARD_NOT_SLIPPERY:
409
case SURFACE_SWITCH:
410
floorClass = SURFACE_CLASS_NOT_SLIPPERY;
411
break;
412
413
case SURFACE_SLIPPERY:
414
case SURFACE_NOISE_SLIPPERY:
415
case SURFACE_HARD_SLIPPERY:
416
case SURFACE_NO_CAM_COL_SLIPPERY:
417
floorClass = SURFACE_CLASS_SLIPPERY;
418
break;
419
420
case SURFACE_VERY_SLIPPERY:
421
case SURFACE_ICE:
422
case SURFACE_HARD_VERY_SLIPPERY:
423
case SURFACE_NOISE_VERY_SLIPPERY_73:
424
case SURFACE_NOISE_VERY_SLIPPERY_74:
425
case SURFACE_NOISE_VERY_SLIPPERY:
426
case SURFACE_NO_CAM_COL_VERY_SLIPPERY:
427
floorClass = SURFACE_CLASS_VERY_SLIPPERY;
428
break;
429
}
430
}
431
432
// Crawling allows Mario to not slide on certain steeper surfaces.
433
if (m->action == ACT_CRAWLING && m->floor->normal.y > 0.5f && floorClass == SURFACE_CLASS_DEFAULT) {
434
floorClass = SURFACE_CLASS_NOT_SLIPPERY;
435
}
436
437
return floorClass;
438
}
439
440
// clang-format off
441
s8 sTerrainSounds[7][6] = {
442
// default, hard, slippery,
443
// very slippery, noisy default, noisy slippery
444
{ SOUND_TERRAIN_DEFAULT, SOUND_TERRAIN_STONE, SOUND_TERRAIN_GRASS,
445
SOUND_TERRAIN_GRASS, SOUND_TERRAIN_GRASS, SOUND_TERRAIN_DEFAULT }, // TERRAIN_GRASS
446
{ SOUND_TERRAIN_STONE, SOUND_TERRAIN_STONE, SOUND_TERRAIN_STONE,
447
SOUND_TERRAIN_STONE, SOUND_TERRAIN_GRASS, SOUND_TERRAIN_GRASS }, // TERRAIN_STONE
448
{ SOUND_TERRAIN_SNOW, SOUND_TERRAIN_ICE, SOUND_TERRAIN_SNOW,
449
SOUND_TERRAIN_ICE, SOUND_TERRAIN_STONE, SOUND_TERRAIN_STONE }, // TERRAIN_SNOW
450
{ SOUND_TERRAIN_SAND, SOUND_TERRAIN_STONE, SOUND_TERRAIN_SAND,
451
SOUND_TERRAIN_SAND, SOUND_TERRAIN_STONE, SOUND_TERRAIN_STONE }, // TERRAIN_SAND
452
{ SOUND_TERRAIN_SPOOKY, SOUND_TERRAIN_SPOOKY, SOUND_TERRAIN_SPOOKY,
453
SOUND_TERRAIN_SPOOKY, SOUND_TERRAIN_STONE, SOUND_TERRAIN_STONE }, // TERRAIN_SPOOKY
454
{ SOUND_TERRAIN_DEFAULT, SOUND_TERRAIN_STONE, SOUND_TERRAIN_GRASS,
455
SOUND_TERRAIN_ICE, SOUND_TERRAIN_STONE, SOUND_TERRAIN_ICE }, // TERRAIN_WATER
456
{ SOUND_TERRAIN_STONE, SOUND_TERRAIN_STONE, SOUND_TERRAIN_STONE,
457
SOUND_TERRAIN_STONE, SOUND_TERRAIN_ICE, SOUND_TERRAIN_ICE }, // TERRAIN_SLIDE
458
};
459
// clang-format on
460
461
/**
462
* Computes a value that should be added to terrain sounds before playing them.
463
* This depends on surfaces and terrain.
464
*/
465
u32 mario_get_terrain_sound_addend(struct MarioState *m) {
466
s16 floorSoundType;
467
s16 terrainType = m->area->terrainType & TERRAIN_MASK;
468
s32 ret = SOUND_TERRAIN_DEFAULT << 16;
469
s32 floorType;
470
471
if (m->floor != NULL) {
472
floorType = m->floor->type;
473
474
if ((gCurrLevelNum != LEVEL_LLL) && (m->floorHeight < (m->waterLevel - 10))) {
475
// Water terrain sound, excluding LLL since it uses water in the volcano.
476
ret = SOUND_TERRAIN_WATER << 16;
477
} else if (SURFACE_IS_QUICKSAND(floorType)) {
478
ret = SOUND_TERRAIN_SAND << 16;
479
} else {
480
switch (floorType) {
481
default:
482
floorSoundType = 0;
483
break;
484
485
case SURFACE_NOT_SLIPPERY:
486
case SURFACE_HARD:
487
case SURFACE_HARD_NOT_SLIPPERY:
488
case SURFACE_SWITCH:
489
floorSoundType = 1;
490
break;
491
492
case SURFACE_SLIPPERY:
493
case SURFACE_HARD_SLIPPERY:
494
case SURFACE_NO_CAM_COL_SLIPPERY:
495
floorSoundType = 2;
496
break;
497
498
case SURFACE_VERY_SLIPPERY:
499
case SURFACE_ICE:
500
case SURFACE_HARD_VERY_SLIPPERY:
501
case SURFACE_NOISE_VERY_SLIPPERY_73:
502
case SURFACE_NOISE_VERY_SLIPPERY_74:
503
case SURFACE_NOISE_VERY_SLIPPERY:
504
case SURFACE_NO_CAM_COL_VERY_SLIPPERY:
505
floorSoundType = 3;
506
break;
507
508
case SURFACE_NOISE_DEFAULT:
509
floorSoundType = 4;
510
break;
511
512
case SURFACE_NOISE_SLIPPERY:
513
floorSoundType = 5;
514
break;
515
}
516
517
ret = sTerrainSounds[terrainType][floorSoundType] << 16;
518
}
519
}
520
521
return ret;
522
}
523
524
/**
525
* Collides with walls and returns the most recent wall.
526
*/
527
struct Surface *resolve_and_return_wall_collisions(Vec3f pos, f32 offset, f32 radius) {
528
struct WallCollisionData collisionData;
529
struct Surface *wall = NULL;
530
531
collisionData.x = pos[0];
532
collisionData.y = pos[1];
533
collisionData.z = pos[2];
534
collisionData.radius = radius;
535
collisionData.offsetY = offset;
536
537
if (find_wall_collisions(&collisionData)) {
538
wall = collisionData.walls[collisionData.numWalls - 1];
539
}
540
541
pos[0] = collisionData.x;
542
pos[1] = collisionData.y;
543
pos[2] = collisionData.z;
544
545
// This only returns the most recent wall and can also return NULL
546
// there are no wall collisions.
547
return wall;
548
}
549
550
/**
551
* Finds the ceiling from a vec3f horizontally and a height (with 80 vertical buffer).
552
*/
553
f32 vec3f_find_ceil(Vec3f pos, f32 height, struct Surface **ceil) {
554
UNUSED f32 unused;
555
556
if (configApplyBugFixes > 1)
557
return find_ceil(pos[0], height + 4.0f, pos[2], ceil);
558
else
559
return find_ceil(pos[0], height + 80.0f, pos[2], ceil);
560
}
561
562
/**
563
* Determines if Mario is facing "downhill."
564
*/
565
s32 mario_facing_downhill(struct MarioState *m, s32 turnYaw) {
566
s16 faceAngleYaw = m->faceAngle[1];
567
568
// This is never used in practice, as turnYaw is
569
// always passed as zero.
570
if (turnYaw && m->forwardVel < 0.0f) {
571
faceAngleYaw += 0x8000;
572
}
573
574
faceAngleYaw = m->floorAngle - faceAngleYaw;
575
576
return (-0x4000 < faceAngleYaw) && (faceAngleYaw < 0x4000);
577
}
578
579
/**
580
* Determines if a surface is slippery based on the surface class.
581
*/
582
u32 mario_floor_is_slippery(struct MarioState *m) {
583
f32 normY;
584
585
if ((m->area->terrainType & TERRAIN_MASK) == TERRAIN_SLIDE
586
&& m->floor->normal.y < 0.9998477f //~cos(1 deg)
587
) {
588
return TRUE;
589
}
590
591
switch (mario_get_floor_class(m)) {
592
case SURFACE_VERY_SLIPPERY:
593
normY = 0.9848077f; //~cos(10 deg)
594
break;
595
596
case SURFACE_SLIPPERY:
597
normY = 0.9396926f; //~cos(20 deg)
598
break;
599
600
default:
601
normY = 0.7880108f; //~cos(38 deg)
602
break;
603
604
case SURFACE_NOT_SLIPPERY:
605
normY = 0.0f;
606
break;
607
}
608
609
return m->floor->normal.y <= normY;
610
}
611
612
/**
613
* Determines if a surface is a slope based on the surface class.
614
*/
615
s32 mario_floor_is_slope(struct MarioState *m) {
616
f32 normY;
617
618
if ((m->area->terrainType & TERRAIN_MASK) == TERRAIN_SLIDE
619
&& m->floor->normal.y < 0.9998477f) { // ~cos(1 deg)
620
return TRUE;
621
}
622
623
switch (mario_get_floor_class(m)) {
624
case SURFACE_VERY_SLIPPERY:
625
normY = 0.9961947f; // ~cos(5 deg)
626
break;
627
628
case SURFACE_SLIPPERY:
629
normY = 0.9848077f; // ~cos(10 deg)
630
break;
631
632
default:
633
normY = 0.9659258f; // ~cos(15 deg)
634
break;
635
636
case SURFACE_NOT_SLIPPERY:
637
normY = 0.9396926f; // ~cos(20 deg)
638
break;
639
}
640
641
return m->floor->normal.y <= normY;
642
}
643
644
/**
645
* Determines if a surface is steep based on the surface class.
646
*/
647
s32 mario_floor_is_steep(struct MarioState *m) {
648
f32 normY;
649
s32 result = FALSE;
650
651
// Interestingly, this function does not check for the
652
// slide terrain type. This means that steep behavior persists for
653
// non-slippery and slippery surfaces.
654
// This does not matter in vanilla game practice.
655
if (!mario_facing_downhill(m, FALSE)) {
656
switch (mario_get_floor_class(m)) {
657
case SURFACE_VERY_SLIPPERY:
658
normY = 0.9659258f; // ~cos(15 deg)
659
break;
660
661
case SURFACE_SLIPPERY:
662
normY = 0.9396926f; // ~cos(20 deg)
663
break;
664
665
default:
666
normY = 0.8660254f; // ~cos(30 deg)
667
break;
668
669
case SURFACE_NOT_SLIPPERY:
670
normY = 0.8660254f; // ~cos(30 deg)
671
break;
672
}
673
674
result = m->floor->normal.y <= normY;
675
}
676
677
return result;
678
}
679
680
/**
681
* Finds the floor height relative from Mario given polar displacement.
682
*/
683
f32 find_floor_height_relative_polar(struct MarioState *m, s16 angleFromMario, f32 distFromMario) {
684
struct Surface *floor;
685
f32 floorY;
686
687
f32 y = sins(m->faceAngle[1] + angleFromMario) * distFromMario;
688
f32 x = coss(m->faceAngle[1] + angleFromMario) * distFromMario;
689
690
floorY = find_floor(m->pos[0] + y, m->pos[1] + 100.0f, m->pos[2] + x, &floor);
691
692
return floorY;
693
}
694
695
/**
696
* Returns the slope of the floor based off points around Mario.
697
*/
698
s16 find_floor_slope(struct MarioState *m, s16 yawOffset) {
699
struct Surface *floor;
700
f32 forwardFloorY, backwardFloorY;
701
f32 forwardYDelta, backwardYDelta;
702
s16 result;
703
704
f32 x = sins(m->faceAngle[1] + yawOffset) * 5.0f;
705
f32 z = coss(m->faceAngle[1] + yawOffset) * 5.0f;
706
707
forwardFloorY = find_floor(m->pos[0] + x, m->pos[1] + 100.0f, m->pos[2] + z, &floor);
708
backwardFloorY = find_floor(m->pos[0] - x, m->pos[1] + 100.0f, m->pos[2] - z, &floor);
709
710
//! If Mario is near OOB, these floorY's can sometimes be -11000.
711
// This will cause these to be off and give improper slopes.
712
forwardYDelta = forwardFloorY - m->pos[1];
713
backwardYDelta = m->pos[1] - backwardFloorY;
714
715
if (forwardYDelta * forwardYDelta < backwardYDelta * backwardYDelta) {
716
result = atan2s(5.0f, forwardYDelta);
717
} else {
718
result = atan2s(5.0f, backwardYDelta);
719
}
720
721
return result;
722
}
723
724
/**
725
* Adjusts Mario's camera and sound based on his action status.
726
*/
727
void update_mario_sound_and_camera(struct MarioState *m) {
728
u32 action = m->action;
729
s32 camPreset = m->area->camera->mode;
730
731
if (action == ACT_FIRST_PERSON) {
732
raise_background_noise(2);
733
gCameraMovementFlags &= ~CAM_MOVE_C_UP_MODE;
734
// Go back to the last camera mode
735
set_camera_mode(m->area->camera, -1, 1);
736
} else if (action == ACT_SLEEPING) {
737
raise_background_noise(2);
738
}
739
740
if (!(action & (ACT_FLAG_SWIMMING | ACT_FLAG_METAL_WATER))) {
741
if (camPreset == CAMERA_MODE_BEHIND_MARIO || camPreset == CAMERA_MODE_WATER_SURFACE) {
742
set_camera_mode(m->area->camera, m->area->camera->defMode, 1);
743
}
744
}
745
}
746
747
/**
748
* Transitions Mario to a steep jump action.
749
*/
750
void set_steep_jump_action(struct MarioState *m) {
751
m->marioObj->oMarioSteepJumpYaw = m->faceAngle[1];
752
753
if (m->forwardVel > 0.0f) {
754
//! ((s16)0x8000) has undefined behavior. Therefore, this downcast has
755
// undefined behavior if m->floorAngle >= 0.
756
s16 angleTemp = m->floorAngle + 0x8000;
757
s16 faceAngleTemp = m->faceAngle[1] - angleTemp;
758
759
f32 y = sins(faceAngleTemp) * m->forwardVel;
760
f32 x = coss(faceAngleTemp) * m->forwardVel * 0.75f;
761
762
m->forwardVel = sqrtf(y * y + x * x);
763
m->faceAngle[1] = atan2s(x, y) + angleTemp;
764
}
765
766
drop_and_set_mario_action(m, ACT_STEEP_JUMP, 0);
767
}
768
769
/**
770
* Sets Mario's vertical speed from his forward speed.
771
*/
772
static void set_mario_y_vel_based_on_fspeed(struct MarioState *m, f32 initialVelY, f32 multiplier) {
773
// get_additive_y_vel_for_jumps is always 0 and a stubbed function.
774
// It was likely trampoline related based on code location.
775
m->vel[1] = initialVelY + get_additive_y_vel_for_jumps() + m->forwardVel * multiplier;
776
777
if (m->squishTimer != 0 || m->quicksandDepth > 1.0f) {
778
m->vel[1] *= 0.5f;
779
}
780
}
781
782
/**
783
* Transitions for a variety of airborne actions.
784
*/
785
static u32 set_mario_action_airborne(struct MarioState *m, u32 action, u32 actionArg) {
786
f32 fowardVel;
787
788
if ((m->squishTimer != 0 || m->quicksandDepth >= 1.0f)
789
&& (action == ACT_DOUBLE_JUMP || action == ACT_TWIRLING)) {
790
action = ACT_JUMP;
791
}
792
793
switch (action) {
794
case ACT_DOUBLE_JUMP:
795
set_mario_y_vel_based_on_fspeed(m, 52.0f, 0.25f);
796
m->forwardVel *= 0.8f;
797
break;
798
799
case ACT_BACKFLIP:
800
m->marioObj->header.gfx.animInfo.animID = -1;
801
m->forwardVel = -16.0f;
802
set_mario_y_vel_based_on_fspeed(m, 62.0f, 0.0f);
803
break;
804
805
case ACT_TRIPLE_JUMP:
806
set_mario_y_vel_based_on_fspeed(m, 69.0f, 0.0f);
807
m->forwardVel *= 0.8f;
808
break;
809
810
case ACT_FLYING_TRIPLE_JUMP:
811
set_mario_y_vel_based_on_fspeed(m, 82.0f, 0.0f);
812
break;
813
814
case ACT_WATER_JUMP:
815
case ACT_HOLD_WATER_JUMP:
816
if (actionArg == 0) {
817
if (configImprovedSwimming) {
818
set_mario_y_vel_based_on_fspeed(m, 48.0f, 0.0f);
819
}
820
else {
821
set_mario_y_vel_based_on_fspeed(m, 42.0f, 0.0f);
822
}
823
}
824
break;
825
826
case ACT_BURNING_JUMP:
827
m->vel[1] = 31.5f;
828
m->forwardVel = 8.0f;
829
break;
830
831
case ACT_RIDING_SHELL_JUMP:
832
set_mario_y_vel_based_on_fspeed(m, 42.0f, 0.25f);
833
break;
834
835
case ACT_JUMP:
836
case ACT_HOLD_JUMP:
837
m->marioObj->header.gfx.animInfo.animID = -1;
838
set_mario_y_vel_based_on_fspeed(m, 42.0f, 0.25f);
839
m->forwardVel *= 0.8f;
840
break;
841
842
case ACT_WALL_KICK_AIR:
843
set_mario_y_vel_based_on_fspeed(m, 62.0f, 0.0f);
844
if (configImprovedControls) {
845
if (m->forwardVel < 28.0f) {
846
m->forwardVel = 28.0f;
847
}
848
}
849
else {
850
if (m->forwardVel < 24.0f) {
851
m->forwardVel = 24.0f;
852
}
853
}
854
m->wallKickTimer = 0;
855
break;
856
case ACT_TOP_OF_POLE_JUMP:
857
set_mario_y_vel_based_on_fspeed(m, 62.0f, 0.0f);
858
if (m->forwardVel < 24.0f) {
859
m->forwardVel = 24.0f;
860
}
861
m->wallKickTimer = 0;
862
break;
863
864
case ACT_SIDE_FLIP:
865
set_mario_y_vel_based_on_fspeed(m, 62.0f, 0.0f);
866
m->forwardVel = 8.0f;
867
m->faceAngle[1] = m->intendedYaw;
868
break;
869
870
case ACT_STEEP_JUMP:
871
m->marioObj->header.gfx.animInfo.animID = -1;
872
set_mario_y_vel_based_on_fspeed(m, 42.0f, 0.25f);
873
m->faceAngle[0] = -0x2000;
874
break;
875
876
case ACT_LAVA_BOOST:
877
m->vel[1] = 84.0f;
878
if (actionArg == 0) {
879
m->forwardVel = 0.0f;
880
}
881
break;
882
883
case ACT_DIVE:
884
if ((fowardVel = m->forwardVel + 15.0f) > 48.0f) {
885
fowardVel = 48.0f;
886
}
887
mario_set_forward_vel(m, fowardVel);
888
break;
889
890
case ACT_LONG_JUMP:
891
m->marioObj->header.gfx.animInfo.animID = -1;
892
set_mario_y_vel_based_on_fspeed(m, 30.0f, 0.0f);
893
m->marioObj->oMarioLongJumpIsSlow = m->forwardVel > 16.0f ? FALSE : TRUE;
894
895
//! (BLJ's) This properly handles long jumps from getting forward speed with
896
// too much velocity, but misses backwards longs allowing high negative speeds.
897
if ((m->forwardVel *= 1.5f) > 48.0f) {
898
m->forwardVel = 48.0f;
899
}
900
break;
901
902
case ACT_SLIDE_KICK:
903
if (configImprovedControls) {
904
m->vel[1] = 14.0f;
905
if (m->forwardVel < 36.0f) {
906
m->forwardVel = 36.0f;
907
}
908
}
909
else {
910
m->vel[1] = 12.0f;
911
if (m->forwardVel < 32.0f) {
912
m->forwardVel = 32.0f;
913
}
914
}
915
break;
916
917
case ACT_JUMP_KICK:
918
m->vel[1] = 20.0f;
919
break;
920
921
case ACT_WALL_SLIDE:
922
m->vel[1] = 4.0f;
923
mario_set_forward_vel(m, 8.0f);
924
break;
925
}
926
927
m->peakHeight = m->pos[1];
928
m->flags |= MARIO_UNKNOWN_08;
929
930
return action;
931
}
932
933
/**
934
* Transitions for a variety of moving actions.
935
*/
936
static u32 set_mario_action_moving(struct MarioState *m, u32 action, UNUSED u32 actionArg) {
937
s16 floorClass = mario_get_floor_class(m);
938
f32 forwardVel = m->forwardVel;
939
f32 mag = min(m->intendedMag, 8.0f);
940
941
switch (action) {
942
case ACT_WALKING:
943
if (floorClass != SURFACE_CLASS_VERY_SLIPPERY) {
944
if (0.0f <= forwardVel && forwardVel < mag) {
945
m->forwardVel = mag;
946
}
947
}
948
949
m->marioObj->oMarioWalkingPitch = 0;
950
break;
951
952
case ACT_HOLD_WALKING:
953
if (0.0f <= forwardVel && forwardVel < mag / 2.0f) {
954
m->forwardVel = mag / 2.0f;
955
}
956
break;
957
958
case ACT_BEGIN_SLIDING:
959
if (mario_facing_downhill(m, FALSE)) {
960
action = ACT_BUTT_SLIDE;
961
} else {
962
action = ACT_STOMACH_SLIDE;
963
}
964
break;
965
966
case ACT_HOLD_BEGIN_SLIDING:
967
if (mario_facing_downhill(m, FALSE)) {
968
action = ACT_HOLD_BUTT_SLIDE;
969
} else {
970
action = ACT_HOLD_STOMACH_SLIDE;
971
}
972
break;
973
}
974
975
return action;
976
}
977
978
/**
979
* Transition for certain submerged actions, which is actually just the metal jump actions.
980
*/
981
static u32 set_mario_action_submerged(struct MarioState *m, u32 action, UNUSED u32 actionArg) {
982
if (action == ACT_METAL_WATER_JUMP || action == ACT_HOLD_METAL_WATER_JUMP) {
983
m->vel[1] = 32.0f;
984
}
985
986
return action;
987
}
988
989
/**
990
* Transitions for a variety of cutscene actions.
991
*/
992
static u32 set_mario_action_cutscene(struct MarioState *m, u32 action, UNUSED u32 actionArg) {
993
switch (action) {
994
case ACT_EMERGE_FROM_PIPE:
995
m->vel[1] = 52.0f;
996
break;
997
998
case ACT_FALL_AFTER_STAR_GRAB:
999
mario_set_forward_vel(m, 0.0f);
1000
break;
1001
1002
case ACT_SPAWN_SPIN_AIRBORNE:
1003
mario_set_forward_vel(m, 2.0f);
1004
break;
1005
1006
case ACT_SPECIAL_EXIT_AIRBORNE:
1007
case ACT_SPECIAL_DEATH_EXIT:
1008
m->vel[1] = 64.0f;
1009
break;
1010
}
1011
1012
return action;
1013
}
1014
1015
/**
1016
* Puts Mario into a given action, putting Mario through the appropriate
1017
* specific function if needed.
1018
*/
1019
u32 set_mario_action(struct MarioState *m, u32 action, u32 actionArg) {
1020
switch (action & ACT_GROUP_MASK) {
1021
case ACT_GROUP_MOVING:
1022
action = set_mario_action_moving(m, action, actionArg);
1023
break;
1024
1025
case ACT_GROUP_AIRBORNE:
1026
action = set_mario_action_airborne(m, action, actionArg);
1027
break;
1028
1029
case ACT_GROUP_SUBMERGED:
1030
action = set_mario_action_submerged(m, action, actionArg);
1031
break;
1032
1033
case ACT_GROUP_CUTSCENE:
1034
action = set_mario_action_cutscene(m, action, actionArg);
1035
break;
1036
}
1037
1038
// Resets the sound played flags, meaning Mario can play those sound types again.
1039
m->flags &= ~(MARIO_ACTION_SOUND_PLAYED | MARIO_MARIO_SOUND_PLAYED);
1040
1041
if (!(m->action & ACT_FLAG_AIR)) {
1042
m->flags &= ~MARIO_UNKNOWN_18;
1043
}
1044
1045
// Initialize the action information.
1046
m->prevAction = m->action;
1047
m->action = action;
1048
m->actionArg = actionArg;
1049
m->actionState = 0;
1050
m->actionTimer = 0;
1051
1052
return TRUE;
1053
}
1054
1055
/**
1056
* Puts Mario into a specific jumping action from a landing action.
1057
*/
1058
s32 set_jump_from_landing(struct MarioState *m) {
1059
if (m->quicksandDepth >= 11.0f) {
1060
if (m->heldObj == NULL) {
1061
return set_mario_action(m, ACT_QUICKSAND_JUMP_LAND, 0);
1062
} else {
1063
return set_mario_action(m, ACT_HOLD_QUICKSAND_JUMP_LAND, 0);
1064
}
1065
}
1066
1067
if (mario_floor_is_steep(m)) {
1068
set_steep_jump_action(m);
1069
} else {
1070
if ((m->doubleJumpTimer == 0) || (m->squishTimer != 0)) {
1071
set_mario_action(m, ACT_JUMP, 0);
1072
} else {
1073
switch (m->prevAction) {
1074
case ACT_JUMP_LAND:
1075
set_mario_action(m, ACT_DOUBLE_JUMP, 0);
1076
break;
1077
1078
case ACT_FREEFALL_LAND:
1079
set_mario_action(m, ACT_DOUBLE_JUMP, 0);
1080
break;
1081
1082
case ACT_SIDE_FLIP_LAND_STOP:
1083
set_mario_action(m, ACT_DOUBLE_JUMP, 0);
1084
break;
1085
1086
case ACT_DOUBLE_JUMP_LAND:
1087
// If Mario has a wing cap, he ignores the typical speed
1088
// requirement for a triple jump.
1089
if (m->flags & MARIO_WING_CAP) {
1090
set_mario_action(m, ACT_FLYING_TRIPLE_JUMP, 0);
1091
} else if (m->forwardVel > 20.0f) {
1092
set_mario_action(m, ACT_TRIPLE_JUMP, 0);
1093
} else {
1094
set_mario_action(m, ACT_JUMP, 0);
1095
}
1096
break;
1097
1098
default:
1099
set_mario_action(m, ACT_JUMP, 0);
1100
break;
1101
}
1102
}
1103
}
1104
1105
m->doubleJumpTimer = 0;
1106
1107
return TRUE;
1108
}
1109
1110
/**
1111
* Puts Mario in a given action, as long as it is not overruled by
1112
* either a quicksand or steep jump.
1113
*/
1114
s32 set_jumping_action(struct MarioState *m, u32 action, u32 actionArg) {
1115
UNUSED u32 currAction = m->action;
1116
1117
if (m->quicksandDepth >= 11.0f) {
1118
// Checks whether Mario is holding an object or not.
1119
if (m->heldObj == NULL) {
1120
return set_mario_action(m, ACT_QUICKSAND_JUMP_LAND, 0);
1121
} else {
1122
return set_mario_action(m, ACT_HOLD_QUICKSAND_JUMP_LAND, 0);
1123
}
1124
}
1125
1126
if (mario_floor_is_steep(m)) {
1127
set_steep_jump_action(m);
1128
} else {
1129
set_mario_action(m, action, actionArg);
1130
}
1131
1132
return TRUE;
1133
}
1134
1135
/**
1136
* Drop anything Mario is holding and set a new action.
1137
*/
1138
s32 drop_and_set_mario_action(struct MarioState *m, u32 action, u32 actionArg) {
1139
mario_stop_riding_and_holding(m);
1140
1141
return set_mario_action(m, action, actionArg);
1142
}
1143
1144
/**
1145
* Increment Mario's hurt counter and set a new action.
1146
*/
1147
s32 hurt_and_set_mario_action(struct MarioState *m, u32 action, u32 actionArg, s16 hurtCounter) {
1148
m->hurtCounter = hurtCounter;
1149
1150
return set_mario_action(m, action, actionArg);
1151
}
1152
1153
/**
1154
* Checks a variety of inputs for common transitions between many different
1155
* actions. A common variant of the below function.
1156
*/
1157
s32 check_common_action_exits(struct MarioState *m) {
1158
if (m->input & INPUT_A_PRESSED) {
1159
return set_mario_action(m, ACT_JUMP, 0);
1160
}
1161
if (m->input & INPUT_OFF_FLOOR) {
1162
return set_mario_action(m, ACT_FREEFALL, 0);
1163
}
1164
if (m->input & INPUT_NONZERO_ANALOG) {
1165
return set_mario_action(m, ACT_WALKING, 0);
1166
}
1167
if (m->input & INPUT_ABOVE_SLIDE) {
1168
return set_mario_action(m, ACT_BEGIN_SLIDING, 0);
1169
}
1170
1171
return FALSE;
1172
}
1173
1174
/**
1175
* Checks a variety of inputs for common transitions between many different
1176
* object holding actions. A holding variant of the above function.
1177
*/
1178
s32 check_common_hold_action_exits(struct MarioState *m) {
1179
if (m->input & INPUT_A_PRESSED) {
1180
return set_mario_action(m, ACT_HOLD_JUMP, 0);
1181
}
1182
if (m->input & INPUT_OFF_FLOOR) {
1183
return set_mario_action(m, ACT_HOLD_FREEFALL, 0);
1184
}
1185
if (m->input & INPUT_NONZERO_ANALOG) {
1186
return set_mario_action(m, ACT_HOLD_WALKING, 0);
1187
}
1188
if (m->input & INPUT_ABOVE_SLIDE) {
1189
return set_mario_action(m, ACT_HOLD_BEGIN_SLIDING, 0);
1190
}
1191
1192
return FALSE;
1193
}
1194
1195
/**
1196
* Transitions Mario from a submerged action to a walking action.
1197
*/
1198
s32 transition_submerged_to_walking(struct MarioState *m) {
1199
set_camera_mode(m->area->camera, m->area->camera->defMode, 1);
1200
1201
vec3s_set(m->angleVel, 0, 0, 0);
1202
1203
if (m->heldObj == NULL) {
1204
return set_mario_action(m, ACT_WALKING, 0);
1205
} else {
1206
return set_mario_action(m, ACT_HOLD_WALKING, 0);
1207
}
1208
}
1209
1210
/**
1211
* This is the transition function typically for entering a submerged action for a
1212
* non-submerged action. This also applies the water surface camera preset.
1213
*/
1214
s32 set_water_plunge_action(struct MarioState *m) {
1215
m->forwardVel = m->forwardVel / 4.0f;
1216
m->vel[1] = m->vel[1] / 2.0f;
1217
1218
m->pos[1] = m->waterLevel - 100;
1219
1220
m->faceAngle[2] = 0;
1221
1222
vec3s_set(m->angleVel, 0, 0, 0);
1223
1224
if (!(m->action & ACT_FLAG_DIVING)) {
1225
m->faceAngle[0] = 0;
1226
}
1227
1228
if (m->area->camera->mode != CAMERA_MODE_WATER_SURFACE) {
1229
set_camera_mode(m->area->camera, CAMERA_MODE_WATER_SURFACE, 1);
1230
}
1231
1232
return set_mario_action(m, ACT_WATER_PLUNGE, 0);
1233
}
1234
1235
/**
1236
* These are the scaling values for the x and z axis for Mario
1237
* when he is close to unsquishing.
1238
*/
1239
u8 sSquishScaleOverTime[16] = { 0x46, 0x32, 0x32, 0x3C, 0x46, 0x50, 0x50, 0x3C,
1240
0x28, 0x14, 0x14, 0x1E, 0x32, 0x3C, 0x3C, 0x28 };
1241
1242
/**
1243
* Applies the squish to Mario's model via scaling.
1244
*/
1245
void squish_mario_model(struct MarioState *m) {
1246
if (m->squishTimer != 0xFF) {
1247
// If no longer squished, scale back to default.
1248
if (m->squishTimer == 0) {
1249
vec3f_set(m->marioObj->header.gfx.scale, 1.0f, 1.0f, 1.0f);
1250
}
1251
// If timer is less than 16, rubber-band Mario's size scale up and down.
1252
else if (m->squishTimer <= 16) {
1253
m->squishTimer -= 1;
1254
1255
m->marioObj->header.gfx.scale[1] =
1256
1.0f - ((sSquishScaleOverTime[15 - m->squishTimer] * 0.6f) / 100.0f);
1257
m->marioObj->header.gfx.scale[0] =
1258
((sSquishScaleOverTime[15 - m->squishTimer] * 0.4f) / 100.0f) + 1.0f;
1259
1260
m->marioObj->header.gfx.scale[2] = m->marioObj->header.gfx.scale[0];
1261
} else {
1262
m->squishTimer -= 1;
1263
1264
vec3f_set(m->marioObj->header.gfx.scale, 1.4f, 0.4f, 1.4f);
1265
}
1266
if (configPaperMode) {
1267
m->marioObj->header.gfx.scale[0] *= 1.0625f;
1268
m->marioObj->header.gfx.scale[1] *= 1.0625f;
1269
m->marioObj->header.gfx.scale[2] *= 0.03125f;
1270
}
1271
}
1272
}
1273
1274
/**
1275
* Debug function that prints floor normal, velocity, and action information.
1276
*/
1277
void debug_print_speed_action_normal(struct MarioState *m) {
1278
f32 steepness;
1279
f32 floor_nY;
1280
1281
if (gShowDebugText) {
1282
steepness = sqrtf(
1283
((m->floor->normal.x * m->floor->normal.x) + (m->floor->normal.z * m->floor->normal.z)));
1284
floor_nY = m->floor->normal.y;
1285
1286
print_text_fmt_int(210, 88, "ANG %d", (atan2s(floor_nY, steepness) * 180.0f) / 32768.0f);
1287
1288
print_text_fmt_int(210, 72, "SPD %d", m->forwardVel);
1289
1290
// STA short for "status," the official action name via SMS map.
1291
print_text_fmt_int(210, 56, "STA %x", (m->action & ACT_ID_MASK));
1292
}
1293
}
1294
1295
/**
1296
* Update the button inputs for Mario.
1297
*/
1298
void update_mario_button_inputs(struct MarioState *m) {
1299
if (m->controller->buttonPressed & A_BUTTON) {
1300
m->input |= INPUT_A_PRESSED;
1301
}
1302
1303
if (m->controller->buttonDown & A_BUTTON) {
1304
m->input |= INPUT_A_DOWN;
1305
}
1306
1307
// Don't update for these buttons if squished.
1308
if (m->squishTimer == 0) {
1309
if (m->controller->buttonPressed & B_BUTTON) {
1310
m->input |= INPUT_B_PRESSED;
1311
}
1312
1313
if (m->controller->buttonDown & Z_TRIG) {
1314
m->input |= INPUT_Z_DOWN;
1315
}
1316
1317
if (m->controller->buttonPressed & Z_TRIG) {
1318
m->input |= INPUT_Z_PRESSED;
1319
}
1320
}
1321
1322
if (m->input & INPUT_A_PRESSED) {
1323
m->framesSinceA = 0;
1324
} else if (m->framesSinceA < 0xFF) {
1325
m->framesSinceA += 1;
1326
}
1327
1328
if (m->input & INPUT_B_PRESSED) {
1329
m->framesSinceB = 0;
1330
} else if (m->framesSinceB < 0xFF) {
1331
m->framesSinceB += 1;
1332
}
1333
}
1334
1335
/**
1336
* Updates the joystick intended magnitude.
1337
*/
1338
void update_mario_joystick_inputs(struct MarioState *m) {
1339
struct Controller *controller = m->controller;
1340
f32 mag = ((controller->stickMag / 64.0f) * (controller->stickMag / 64.0f)) * 64.0f;
1341
1342
if (m->squishTimer == 0) {
1343
m->intendedMag = mag / 2.0f;
1344
} else {
1345
m->intendedMag = mag / 8.0f;
1346
}
1347
1348
if (m->intendedMag > 0.0f) {
1349
m->intendedYaw = atan2s(-controller->stickY, controller->stickX) + m->area->camera->yaw;
1350
m->input |= INPUT_NONZERO_ANALOG;
1351
} else {
1352
m->intendedYaw = m->faceAngle[1];
1353
}
1354
}
1355
1356
/**
1357
* Resolves wall collisions, and updates a variety of inputs.
1358
*/
1359
void update_mario_geometry_inputs(struct MarioState *m) {
1360
f32 gasLevel;
1361
f32 ceilToFloorDist;
1362
1363
f32_find_wall_collision(&m->pos[0], &m->pos[1], &m->pos[2], 60.0f, 50.0f);
1364
f32_find_wall_collision(&m->pos[0], &m->pos[1], &m->pos[2], 30.0f, 24.0f);
1365
1366
m->floorHeight = find_floor(m->pos[0], m->pos[1], m->pos[2], &m->floor);
1367
1368
// If Mario is OOB, move his position to his graphical position (which was not updated)
1369
// and check for the floor there.
1370
// This can cause errant behavior when combined with astral projection,
1371
// since the graphical position was not Mario's previous location.
1372
if (m->floor == NULL) {
1373
vec3f_copy(m->pos, m->marioObj->header.gfx.pos);
1374
m->floorHeight = find_floor(m->pos[0], m->pos[1], m->pos[2], &m->floor);
1375
}
1376
if (configApplyBugFixes > 1)
1377
m->ceilHeight = vec3f_find_ceil(m->pos, m->pos[1], &m->ceil);
1378
else
1379
m->ceilHeight = vec3f_find_ceil(&m->pos[0], m->floorHeight, &m->ceil);
1380
gasLevel = find_poison_gas_level(m->pos[0], m->pos[2]);
1381
m->waterLevel = find_water_level(m->pos[0], m->pos[2]);
1382
1383
if (m->floor != NULL) {
1384
m->floorAngle = atan2s(m->floor->normal.z, m->floor->normal.x);
1385
m->terrainSoundAddend = mario_get_terrain_sound_addend(m);
1386
1387
if ((m->pos[1] > m->waterLevel - 40) && mario_floor_is_slippery(m)) {
1388
m->input |= INPUT_ABOVE_SLIDE;
1389
}
1390
1391
if ((m->floor->flags & SURFACE_FLAG_DYNAMIC)
1392
|| (m->ceil && m->ceil->flags & SURFACE_FLAG_DYNAMIC)) {
1393
ceilToFloorDist = m->ceilHeight - m->floorHeight;
1394
1395
if ((0.0f <= ceilToFloorDist) && (ceilToFloorDist <= 150.0f)) {
1396
m->input |= INPUT_SQUISHED;
1397
}
1398
}
1399
1400
if (m->pos[1] > m->floorHeight + 100.0f) {
1401
m->input |= INPUT_OFF_FLOOR;
1402
}
1403
1404
if (m->pos[1] < (m->waterLevel - 10)) {
1405
m->input |= INPUT_IN_WATER;
1406
}
1407
1408
if (m->pos[1] < (gasLevel - 100.0f)) {
1409
m->input |= INPUT_IN_POISON_GAS;
1410
}
1411
1412
} else {
1413
level_trigger_warp(m, WARP_OP_DEATH);
1414
}
1415
}
1416
1417
/**
1418
* Handles Mario's input flags as well as a couple timers.
1419
*/
1420
void update_mario_inputs(struct MarioState *m) {
1421
m->particleFlags = 0;
1422
m->input = 0;
1423
m->collidedObjInteractTypes = m->marioObj->collidedObjInteractTypes;
1424
m->flags &= 0xFFFFFF;
1425
1426
update_mario_button_inputs(m);
1427
update_mario_joystick_inputs(m);
1428
update_mario_geometry_inputs(m);
1429
1430
debug_print_speed_action_normal(m);
1431
1432
if (gCameraMovementFlags & CAM_MOVE_C_UP_MODE) {
1433
if (m->action & ACT_FLAG_ALLOW_FIRST_PERSON) {
1434
m->input |= INPUT_FIRST_PERSON;
1435
} else {
1436
gCameraMovementFlags &= ~CAM_MOVE_C_UP_MODE;
1437
}
1438
}
1439
1440
if (!(m->input & (INPUT_NONZERO_ANALOG | INPUT_A_PRESSED))) {
1441
m->input |= INPUT_UNKNOWN_5;
1442
}
1443
1444
// These 3 flags are defined by Bowser stomping attacks
1445
if (m->marioObj->oInteractStatus
1446
& (INT_STATUS_MARIO_STUNNED | INT_STATUS_MARIO_KNOCKBACK_DMG | INT_STATUS_MARIO_SHOCKWAVE)) {
1447
m->input |= INPUT_STOMPED;
1448
}
1449
1450
// This function is located near other unused trampoline functions,
1451
// perhaps logically grouped here with the timers.
1452
stub_mario_step_1(m);
1453
1454
if (m->wallKickTimer > 0) {
1455
m->wallKickTimer--;
1456
}
1457
1458
if (m->doubleJumpTimer > 0) {
1459
m->doubleJumpTimer--;
1460
}
1461
}
1462
1463
/**
1464
* Set's the camera preset for submerged action behaviors.
1465
*/
1466
void set_submerged_cam_preset_and_spawn_bubbles(struct MarioState *m) {
1467
f32 heightBelowWater;
1468
s16 camPreset;
1469
1470
if ((m->action & ACT_GROUP_MASK) == ACT_GROUP_SUBMERGED) {
1471
heightBelowWater = (f32)(m->waterLevel - 80) - m->pos[1];
1472
camPreset = m->area->camera->mode;
1473
1474
if (m->action & ACT_FLAG_METAL_WATER) {
1475
if (camPreset != CAMERA_MODE_CLOSE) {
1476
set_camera_mode(m->area->camera, CAMERA_MODE_CLOSE, 1);
1477
}
1478
} else {
1479
if ((heightBelowWater > 800.0f) && (camPreset != CAMERA_MODE_BEHIND_MARIO)) {
1480
set_camera_mode(m->area->camera, CAMERA_MODE_BEHIND_MARIO, 1);
1481
}
1482
1483
if ((heightBelowWater < 400.0f) && (camPreset != CAMERA_MODE_WATER_SURFACE)) {
1484
set_camera_mode(m->area->camera, CAMERA_MODE_WATER_SURFACE, 1);
1485
}
1486
1487
// As long as Mario isn't drowning or at the top
1488
// of the water with his head out, spawn bubbles.
1489
if (!(m->action & ACT_FLAG_INTANGIBLE)) {
1490
if ((m->pos[1] < (f32)(m->waterLevel - 160)) || (m->faceAngle[0] < -0x800)) {
1491
m->particleFlags |= PARTICLE_BUBBLE;
1492
}
1493
}
1494
}
1495
}
1496
}
1497
1498
/**
1499
* Both increments and decrements Mario's HP.
1500
*/
1501
void update_mario_health(struct MarioState *m) {
1502
s32 terrainIsSnow;
1503
1504
if (m->health >= 0x100) {
1505
// When already healing or hurting Mario, Mario's HP is not changed any more here.
1506
if (((u32) m->healCounter | (u32) m->hurtCounter) == 0) {
1507
if ((m->input & INPUT_IN_POISON_GAS) && !(m->action & ACT_FLAG_INTANGIBLE)) {
1508
if (!(m->flags & MARIO_METAL_CAP) && !gDebugLevelSelect) {
1509
m->health -= (save_file_get_flags() & SAVE_FLAG_HARD_MODE) ? 8 : 4;
1510
}
1511
} else {
1512
if ((m->action & ACT_FLAG_SWIMMING) && !(m->action & ACT_FLAG_INTANGIBLE) && (!mario_has_improved_metal_cap(m))) {
1513
terrainIsSnow = (m->area->terrainType & TERRAIN_MASK) == TERRAIN_SNOW;
1514
1515
// When Mario is near the water surface, recover health (unless in snow),
1516
// when in snow terrains lose 3 health.
1517
// If using the debug level select, do not lose any HP to water.
1518
if ((m->pos[1] >= (m->waterLevel - 140)) && !terrainIsSnow) {
1519
if ((!(save_file_get_flags() & SAVE_FLAG_HARD_MODE)) && (!configNoHealingMode)) {
1520
m->health += 0x1A;
1521
}
1522
} else if (!(save_file_get_flags() & SAVE_FLAG_DAREDEVIL_MODE) && !configNoHealingMode) {
1523
if (save_file_get_flags() & SAVE_FLAG_HARD_MODE) {
1524
m->health -= (terrainIsSnow ? 4 : 2);
1525
}
1526
else if (configCasualMode) {
1527
if (terrainIsSnow)
1528
m->health -= 1;
1529
}
1530
else {
1531
m->health -= (terrainIsSnow ? 3 : 1);
1532
}
1533
}
1534
}
1535
}
1536
}
1537
1538
if (m->healCounter > 0) {
1539
m->health += 0x40;
1540
m->healCounter--;
1541
}
1542
if (m->hurtCounter > 0) {
1543
if (configCasualMode)
1544
m->health -= 0x20;
1545
else
1546
m->health -= 0x40;
1547
m->hurtCounter--;
1548
}
1549
1550
if (configGodMode) {
1551
m->health = 0x880;
1552
}
1553
else if (save_file_get_flags() & SAVE_FLAG_DAREDEVIL_MODE) {
1554
if (m->health > 0x180) {
1555
m->health = 0x180;
1556
}
1557
}
1558
else {
1559
if (m->health > 0x880) {
1560
m->health = 0x880;
1561
}
1562
}
1563
if (m->health < 0x100) {
1564
m->health = 0xFF;
1565
}
1566
1567
// Play a noise to alert the player when Mario is close to drowning.
1568
if (((m->action & ACT_GROUP_MASK) == ACT_GROUP_SUBMERGED) && (m->health < 0x300) && (!(save_file_get_flags() & SAVE_FLAG_DAREDEVIL_MODE)) && (!mario_has_improved_metal_cap(m))) {
1569
play_sound(SOUND_MOVING_ALMOST_DROWNING, gGlobalSoundSource);
1570
#if ENABLE_RUMBLE
1571
if (!gRumblePakTimer) {
1572
gRumblePakTimer = 36;
1573
if (is_rumble_finished_and_queue_empty()) {
1574
queue_rumble_data(3, 30);
1575
}
1576
}
1577
} else {
1578
gRumblePakTimer = 0;
1579
#endif
1580
}
1581
}
1582
}
1583
1584
/**
1585
* Updates some basic info for camera usage.
1586
*/
1587
void update_mario_info_for_cam(struct MarioState *m) {
1588
m->marioBodyState->action = m->action;
1589
m->statusForCamera->action = m->action;
1590
1591
vec3s_copy(m->statusForCamera->faceAngle, m->faceAngle);
1592
1593
if (!(m->flags & MARIO_UNKNOWN_25)) {
1594
vec3f_copy(m->statusForCamera->pos, m->pos);
1595
}
1596
}
1597
1598
/**
1599
* Resets Mario's model, done every time an action is executed.
1600
*/
1601
void mario_reset_bodystate(struct MarioState *m) {
1602
struct MarioBodyState *bodyState = m->marioBodyState;
1603
1604
bodyState->capState = MARIO_HAS_DEFAULT_CAP_OFF;
1605
bodyState->eyeState = MARIO_EYES_BLINK;
1606
bodyState->handState = MARIO_HAND_FISTS;
1607
bodyState->modelState = 0;
1608
bodyState->wingFlutter = FALSE;
1609
1610
m->flags &= ~MARIO_METAL_SHOCK;
1611
}
1612
1613
/**
1614
* Adjusts Mario's graphical height for quicksand.
1615
*/
1616
void sink_mario_in_quicksand(struct MarioState *m) {
1617
struct Object *o = m->marioObj;
1618
1619
if (o->header.gfx.throwMatrix) {
1620
(*o->header.gfx.throwMatrix)[3][1] -= m->quicksandDepth;
1621
}
1622
1623
o->header.gfx.pos[1] -= m->quicksandDepth;
1624
}
1625
1626
/**
1627
* Is a binary representation of the frames to flicker Mario's cap when the timer
1628
* is running out.
1629
*
1630
* Equals [1000]^5 . [100]^8 . [10]^9 . [1] in binary, which is
1631
* 100010001000100010001001001001001001001001001010101010101010101.
1632
*/
1633
u64 sCapFlickerFrames = 0x4444449249255555;
1634
1635
/**
1636
* Updates the cap flags mainly based on the cap timer.
1637
*/
1638
u32 update_and_return_cap_flags(struct MarioState *m) {
1639
u32 flags = m->flags;
1640
u32 action;
1641
1642
if (m->capTimer > 0) {
1643
action = m->action;
1644
1645
if ((m->capTimer <= 60)
1646
|| ((action != ACT_READING_AUTOMATIC_DIALOG) && (action != ACT_READING_NPC_DIALOG)
1647
&& (action != ACT_READING_SIGN) && (action != ACT_IN_CANNON))) {
1648
m->capTimer -= 1;
1649
}
1650
1651
if (m->capTimer == 0) {
1652
stop_cap_music();
1653
1654
m->flags &= ~MARIO_SPECIAL_CAPS;
1655
if (!(m->flags & MARIO_CAPS)) {
1656
m->flags &= ~MARIO_CAP_ON_HEAD;
1657
}
1658
}
1659
1660
if (m->capTimer == 60) {
1661
fadeout_cap_music();
1662
}
1663
1664
// This code flickers the cap through a long binary string, increasing in how
1665
// common it flickers near the end.
1666
if ((m->capTimer < 64) && ((1ULL << m->capTimer) & sCapFlickerFrames)) {
1667
flags &= ~MARIO_SPECIAL_CAPS;
1668
if (!(flags & MARIO_CAPS)) {
1669
flags &= ~MARIO_CAP_ON_HEAD;
1670
}
1671
}
1672
}
1673
1674
return flags;
1675
}
1676
1677
/**
1678
* Updates the Mario's cap, rendering, and hitbox.
1679
*/
1680
void mario_update_hitbox_and_cap_model(struct MarioState *m) {
1681
struct MarioBodyState *bodyState = m->marioBodyState;
1682
s32 flags = update_and_return_cap_flags(m);
1683
1684
if (flags & MARIO_VANISH_CAP) {
1685
bodyState->modelState = MODEL_STATE_NOISE_ALPHA;
1686
}
1687
1688
if (flags & MARIO_METAL_CAP) {
1689
bodyState->modelState |= MODEL_STATE_METAL;
1690
}
1691
1692
if (flags & MARIO_METAL_SHOCK) {
1693
bodyState->modelState |= MODEL_STATE_METAL;
1694
}
1695
1696
//! (Pause buffered hitstun) Since the global timer increments while paused,
1697
// this can be paused through to give continual invisibility. This leads to
1698
// no interaction with objects.
1699
if ((m->invincTimer >= 3) && (gGlobalTimer & 1)) {
1700
gMarioState->marioObj->header.gfx.node.flags |= GRAPH_RENDER_INVISIBLE;
1701
}
1702
1703
if (flags & MARIO_CAP_IN_HAND) {
1704
if (flags & MARIO_WING_CAP) {
1705
bodyState->handState = MARIO_HAND_HOLDING_WING_CAP;
1706
} else {
1707
bodyState->handState = MARIO_HAND_HOLDING_CAP;
1708
}
1709
}
1710
1711
if (flags & MARIO_CAP_ON_HEAD) {
1712
if (flags & MARIO_WING_CAP) {
1713
bodyState->capState = MARIO_HAS_WING_CAP_ON;
1714
} else {
1715
bodyState->capState = MARIO_HAS_DEFAULT_CAP_ON;
1716
}
1717
}
1718
1719
// Short hitbox for crouching/crawling/etc.
1720
if (m->action & ACT_FLAG_SHORT_HITBOX
1721
|| (configApplyBugFixes > 1 && m->action & ACT_FLAG_BUTT_OR_STOMACH_SLIDE)) {
1722
m->marioObj->hitboxHeight = 100.0f;
1723
} else {
1724
m->marioObj->hitboxHeight = 160.0f;
1725
}
1726
1727
if ((m->flags & MARIO_TELEPORTING) && (m->fadeWarpOpacity != 0xFF)) {
1728
bodyState->modelState &= ~0xFF;
1729
bodyState->modelState |= (0x100 | m->fadeWarpOpacity);
1730
}
1731
1732
if (configInvisibleMode)
1733
{
1734
gMarioState->marioObj->header.gfx.node.flags |= GRAPH_RENDER_INVISIBLE;
1735
}
1736
}
1737
1738
/**
1739
* An unused and possibly a debug function. Z + another button input
1740
* sets Mario with a different cap.
1741
*/
1742
UNUSED static void debug_update_mario_cap(u16 button, s32 flags, u16 capTimer, u16 capMusic) {
1743
// This checks for Z_TRIG instead of Z_DOWN flag
1744
// (which is also what other debug functions do),
1745
// so likely debug behavior rather than unused behavior.
1746
if ((gPlayer1Controller->buttonDown & L_TRIG) && (gPlayer1Controller->buttonPressed & button)
1747
&& !(gMarioState->flags & flags)) {
1748
gMarioState->flags |= (flags + MARIO_CAP_ON_HEAD);
1749
1750
if (capTimer > gMarioState->capTimer) {
1751
gMarioState->capTimer = capTimer;
1752
}
1753
1754
play_cap_music(capMusic);
1755
}
1756
}
1757
1758
#if ENABLE_RUMBLE
1759
void func_sh_8025574C(void) {
1760
if (gMarioState->particleFlags & PARTICLE_HORIZONTAL_STAR) {
1761
queue_rumble_data(5, 80);
1762
} else if (gMarioState->particleFlags & PARTICLE_VERTICAL_STAR) {
1763
queue_rumble_data(5, 80);
1764
} else if (gMarioState->particleFlags & PARTICLE_TRIANGLE) {
1765
queue_rumble_data(5, 80);
1766
}
1767
if (gMarioState->heldObj && gMarioState->heldObj->behavior == segmented_to_virtual(bhvBobomb)) {
1768
reset_rumble_timers();
1769
}
1770
}
1771
#endif
1772
1773
/**
1774
* Main function for executing Mario's behavior.
1775
*/
1776
s32 execute_mario_action(UNUSED struct Object *o) {
1777
s32 inLoop = TRUE;
1778
1779
if (configDebugCapChanger) {
1780
1781
debug_update_mario_cap(CONT_LEFT, MARIO_WING_CAP, 1800, SEQUENCE_ARGS(4, SEQ_EVENT_POWERUP));
1782
debug_update_mario_cap(CONT_UP, MARIO_METAL_CAP, 600, SEQUENCE_ARGS(4, SEQ_EVENT_METAL_CAP));
1783
debug_update_mario_cap(CONT_RIGHT, MARIO_VANISH_CAP, 600, SEQUENCE_ARGS(4, SEQ_EVENT_POWERUP));
1784
}
1785
1786
if (gMarioState->action) {
1787
gMarioState->marioObj->header.gfx.node.flags &= ~GRAPH_RENDER_INVISIBLE;
1788
mario_reset_bodystate(gMarioState);
1789
update_mario_inputs(gMarioState);
1790
mario_handle_special_floors(gMarioState);
1791
mario_process_interactions(gMarioState);
1792
1793
// If Mario is OOB, stop executing actions.
1794
if (gMarioState->floor == NULL) {
1795
return 0;
1796
}
1797
1798
// The function can loop through many action shifts in one frame,
1799
// which can lead to unexpected sub-frame behavior. Could potentially hang
1800
// if a loop of actions were found, but there has not been a situation found.
1801
while (inLoop) {
1802
switch (gMarioState->action & ACT_GROUP_MASK) {
1803
case ACT_GROUP_STATIONARY:
1804
inLoop = mario_execute_stationary_action(gMarioState);
1805
break;
1806
1807
case ACT_GROUP_MOVING:
1808
inLoop = mario_execute_moving_action(gMarioState);
1809
break;
1810
1811
case ACT_GROUP_AIRBORNE:
1812
inLoop = mario_execute_airborne_action(gMarioState);
1813
break;
1814
1815
case ACT_GROUP_SUBMERGED:
1816
inLoop = mario_execute_submerged_action(gMarioState);
1817
break;
1818
1819
case ACT_GROUP_CUTSCENE:
1820
inLoop = mario_execute_cutscene_action(gMarioState);
1821
break;
1822
1823
case ACT_GROUP_AUTOMATIC:
1824
inLoop = mario_execute_automatic_action(gMarioState);
1825
break;
1826
1827
case ACT_GROUP_OBJECT:
1828
inLoop = mario_execute_object_action(gMarioState);
1829
break;
1830
}
1831
}
1832
1833
sink_mario_in_quicksand(gMarioState);
1834
squish_mario_model(gMarioState);
1835
set_submerged_cam_preset_and_spawn_bubbles(gMarioState);
1836
update_mario_health(gMarioState);
1837
update_mario_info_for_cam(gMarioState);
1838
mario_update_hitbox_and_cap_model(gMarioState);
1839
1840
// Both of the wind handling portions play wind audio only in
1841
// non-Japanese releases.
1842
if (gMarioState->floor->type == SURFACE_HORIZONTAL_WIND) {
1843
spawn_wind_particles(0, (gMarioState->floor->force << 8));
1844
#ifndef VERSION_JP
1845
play_sound(SOUND_ENV_WIND2, gMarioState->marioObj->header.gfx.cameraToObject);
1846
#endif
1847
}
1848
1849
if (gMarioState->floor->type == SURFACE_VERTICAL_WIND) {
1850
spawn_wind_particles(1, 0);
1851
#ifndef VERSION_JP
1852
play_sound(SOUND_ENV_WIND2, gMarioState->marioObj->header.gfx.cameraToObject);
1853
#endif
1854
}
1855
1856
play_infinite_stairs_music();
1857
gMarioState->marioObj->oInteractStatus = 0;
1858
#if ENABLE_RUMBLE
1859
func_sh_8025574C();
1860
#endif
1861
1862
handle_cheats();
1863
1864
return gMarioState->particleFlags;
1865
}
1866
1867
return 0;
1868
}
1869
1870
void handle_cheats() {
1871
1872
// A very direct port of the famous GS code
1873
// Used https://github.com/sm64gs2pc/sm64gs2pc, later cleaned up by hand
1874
if (configMoonJump) {
1875
if ((gControllers[0].buttonDown & 0xff) == 0x20) {
1876
*(uint32_t *) &gMarioStates[0].vel[1] = (*(uint32_t *) &gMarioStates[0].vel[1] & 0xffffffff0000ffff) | 0x42200000;
1877
if (configMoonJump > 1 && ((gMarioState->action & ACT_GROUP_MASK) != ACT_GROUP_AIRBORNE))
1878
set_mario_action(gMarioState, ACT_JUMP, 0);
1879
}
1880
if (configMoonJump == 1) {
1881
if ((*(uint32_t *) &gMarioStates[0].vel[1] & 0xff0000) == 0x200000)
1882
gMarioStates[0].action = (gMarioStates[0].action & 0xffffffff0000ffff) | 0x3000000;
1883
if ((*(uint32_t *) &gMarioStates[0].vel[1] & 0xff0000) == 0x200000)
1884
gMarioStates[0].action = (gMarioStates[0].action & 0xffffffffffff0000) | 0x880;
1885
}
1886
}
1887
1888
// Also a very direct port of Kaze's thing
1889
if (configBLJEverywhere) {
1890
/* D033AFA0 00A0 */ if ((gControllers[0].buttonDown & 0xff00) == 0xa000)
1891
/* D033B1C4 00C1 */ if ((*(uint32_t *) &gMarioStates[0].forwardVel & 0xff000000) == 0xc1000000)
1892
/* 8133B1BC C220 */ *(uint32_t *) &gMarioStates[0].vel[1] = (*(uint32_t *) &gMarioStates[0].vel[1] & 0xffffffff0000ffff) | 0xc2200000;
1893
/* D033AFA0 00A0 */ if ((gControllers[0].buttonDown & 0xff00) == 0xa000)
1894
/* D033B1C4 00C2 */ if ((*(uint32_t *) &gMarioStates[0].forwardVel & 0xff000000) == 0xc2000000)
1895
/* 8133B1BC C220 */ *(uint32_t *) &gMarioStates[0].vel[1] = (*(uint32_t *) &gMarioStates[0].vel[1] & 0xffffffff0000ffff) | 0xc2200000;
1896
1897
// Grounded longer
1898
if (configBLJEverywhere == 2) {
1899
/* D033B1C4 00C3 */ if ((*(uint32_t *) &gMarioStates[0].forwardVel & 0xff000000) == 0xc3000000)
1900
/* 8133B1BC C220 */ *(uint32_t *) &gMarioStates[0].vel[1] = (*(uint32_t *) &gMarioStates[0].vel[1] & 0xffffffff0000ffff) | 0xc2200000;
1901
/* 8033B21D 0004 */ gMarioStates[0].numLives = (gMarioStates[0].numLives & 0xffffffffffffff00) | 0x4;
1902
/* D033B1C4 00C4 */ if ((*(uint32_t *) &gMarioStates[0].forwardVel & 0xff000000) == 0xc4000000)
1903
/* 8133B1BC C220 */ *(uint32_t *) &gMarioStates[0].vel[1] = (*(uint32_t *) &gMarioStates[0].vel[1] & 0xffffffff0000ffff) | 0xc2200000;
1904
/* 8033B21D 0004 */ gMarioStates[0].numLives = (gMarioStates[0].numLives & 0xffffffffffffff00) | 0x4;
1905
}
1906
// Rapidfire mode
1907
if (configBLJEverywhere == 3) {
1908
/* D033AFA0 00A0 */ if ((gControllers[0].buttonDown & 0xff00) == 0xa000)
1909
/* 8133AFA0 0000 */ gControllers[0].buttonDown = (gControllers[0].buttonDown & 0xffffffffffff0000) | 0x0;
1910
}
1911
}
1912
}
1913
1914
u32 mario_has_improved_metal_cap(struct MarioState *m) {
1915
return (configBetterPowerups) && (m->flags & MARIO_METAL_CAP);
1916
}
1917
1918
/**************************************************
1919
* INITIALIZATION *
1920
**************************************************/
1921
1922
void init_mario(void) {
1923
Vec3s capPos;
1924
struct Object *capObject;
1925
1926
unused80339F10 = 0;
1927
1928
gMarioState->actionTimer = 0;
1929
gMarioState->framesSinceA = 0xFF;
1930
gMarioState->framesSinceB = 0xFF;
1931
1932
gMarioState->invincTimer = 0;
1933
1934
if (save_file_get_flags()
1935
& (SAVE_FLAG_CAP_ON_GROUND | SAVE_FLAG_CAP_ON_KLEPTO | SAVE_FLAG_CAP_ON_UKIKI
1936
| SAVE_FLAG_CAP_ON_MR_BLIZZARD | SAVE_FLAG_HARD_MODE)) {
1937
gMarioState->flags = 0;
1938
} else {
1939
gMarioState->flags = (MARIO_NORMAL_CAP | MARIO_CAP_ON_HEAD);
1940
}
1941
1942
gMarioState->forwardVel = 0.0f;
1943
gMarioState->squishTimer = 0;
1944
1945
gMarioState->hurtCounter = 0;
1946
gMarioState->healCounter = 0;
1947
1948
gMarioState->capTimer = 0;
1949
gMarioState->quicksandDepth = 0.0f;
1950
1951
gMarioState->heldObj = NULL;
1952
gMarioState->riddenObj = NULL;
1953
gMarioState->usedObj = NULL;
1954
1955
gMarioState->waterLevel =
1956
find_water_level(gMarioSpawnInfo->startPos[0], gMarioSpawnInfo->startPos[2]);
1957
1958
gMarioState->area = gCurrentArea;
1959
gMarioState->marioObj = gMarioObject;
1960
gMarioState->marioObj->header.gfx.animInfo.animID = -1;
1961
vec3s_copy(gMarioState->faceAngle, gMarioSpawnInfo->startAngle);
1962
vec3s_set(gMarioState->angleVel, 0, 0, 0);
1963
vec3s_to_vec3f(gMarioState->pos, gMarioSpawnInfo->startPos);
1964
vec3f_set(gMarioState->vel, 0, 0, 0);
1965
gMarioState->floorHeight =
1966
find_floor(gMarioState->pos[0], gMarioState->pos[1], gMarioState->pos[2], &gMarioState->floor);
1967
1968
if (gMarioState->pos[1] < gMarioState->floorHeight) {
1969
gMarioState->pos[1] = gMarioState->floorHeight;
1970
}
1971
1972
gMarioState->marioObj->header.gfx.pos[1] = gMarioState->pos[1];
1973
1974
gMarioState->action =
1975
(gMarioState->pos[1] <= (gMarioState->waterLevel - 100)) ? ACT_WATER_IDLE : ACT_IDLE;
1976
1977
mario_reset_bodystate(gMarioState);
1978
update_mario_info_for_cam(gMarioState);
1979
gMarioState->marioBodyState->punchState = 0;
1980
1981
gMarioState->marioObj->oPosX = gMarioState->pos[0];
1982
gMarioState->marioObj->oPosY = gMarioState->pos[1];
1983
gMarioState->marioObj->oPosZ = gMarioState->pos[2];
1984
1985
gMarioState->marioObj->oMoveAnglePitch = gMarioState->faceAngle[0];
1986
gMarioState->marioObj->oMoveAngleYaw = gMarioState->faceAngle[1];
1987
gMarioState->marioObj->oMoveAngleRoll = gMarioState->faceAngle[2];
1988
1989
vec3f_copy(gMarioState->marioObj->header.gfx.pos, gMarioState->pos);
1990
vec3s_set(gMarioState->marioObj->header.gfx.angle, 0, gMarioState->faceAngle[1], 0);
1991
1992
if (save_file_get_cap_pos(capPos)) {
1993
capObject = spawn_object(gMarioState->marioObj, MODEL_MARIOS_CAP, bhvNormalCap);
1994
1995
if (!configSaveLives) {
1996
capObject->oPosX = capPos[0];
1997
capObject->oPosY = capPos[1];
1998
capObject->oPosZ = capPos[2];
1999
}
2000
2001
capObject->oForwardVelS32 = 0;
2002
2003
capObject->oMoveAngleYaw = 0;
2004
}
2005
}
2006
2007
void init_mario_from_save_file(void) {
2008
gMarioState->unk00 = 0;
2009
gMarioState->flags = 0;
2010
gMarioState->action = 0;
2011
gMarioState->spawnInfo = &gPlayerSpawnInfos[0];
2012
gMarioState->statusForCamera = &gPlayerCameraState[0];
2013
gMarioState->marioBodyState = &gBodyStates[0];
2014
gMarioState->controller = &gControllers[0];
2015
gMarioState->animList = &gMarioAnimsBuf;
2016
2017
gMarioState->numCoins = 0;
2018
gMarioState->numStars =
2019
save_file_get_total_star_count(gCurrSaveFileNum - 1, COURSE_MIN - 1, COURSE_MAX - 1);
2020
gMarioState->numKeys = 0;
2021
2022
s8 savedLives = save_file_get_num_lives();
2023
gMarioState->numLives = ((savedLives > 0) ? savedLives : (configLifeMode ? 0 : 4));
2024
2025
if (save_file_get_flags() & SAVE_FLAG_DAREDEVIL_MODE) {
2026
gMarioState->health = 0x180;
2027
}
2028
else {
2029
gMarioState->health = 0x880;
2030
}
2031
2032
gMarioState->prevNumStarsForDialog = gMarioState->numStars;
2033
gMarioState->unkB0 = 0xBD;
2034
2035
gHudDisplay.coins = 0;
2036
gHudDisplay.wedges = 8;
2037
}
2038