sm64

A Super Mario 64 decompilation
Log | Files | Refs | README | LICENSE

mario.c (60332B)


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