sm64

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

platform_on_track.inc.c (11065B)


      1 
      2 /**
      3  * Behavior for bhvPlatformOnTrack and bhvTrackBall.
      4  * The platform spawns up to 5 track balls at a time, which then despawn
      5  * themselves as the platform moves past them.
      6  */
      7 
      8 /**
      9  * Collision models for the different types of platforms.
     10  */
     11 static Collision const *sPlatformOnTrackCollisionModels[] = {
     12     /* PLATFORM_ON_TRACK_TYPE_CARPET    */ rr_seg7_collision_07029038,
     13     /* PLATFORM_ON_TRACK_TYPE_SKI_LIFT  */ ccm_seg7_collision_070163F8,
     14     /* PLATFORM_ON_TRACK_TYPE_CHECKERED */ checkerboard_platform_seg8_collision_0800D710,
     15     /* PLATFORM_ON_TRACK_TYPE_GRATE     */ bitfs_seg7_collision_070157E0,
     16 };
     17 
     18 /**
     19  * Paths for the different instances of these platforms.
     20  */
     21 static Trajectory const *sPlatformOnTrackPaths[] = {
     22     rr_seg7_trajectory_0702EC3C,
     23     rr_seg7_trajectory_0702ECC0,
     24     ccm_seg7_trajectory_0701669C,
     25     bitfs_seg7_trajectory_070159AC,
     26     hmc_seg7_trajectory_0702B86C,
     27     lll_seg7_trajectory_0702856C,
     28     lll_seg7_trajectory_07028660,
     29     rr_seg7_trajectory_0702ED9C,
     30     rr_seg7_trajectory_0702EEE0,
     31 };
     32 
     33 /**
     34  * Despawn all track balls and enter the init action.
     35  */
     36 static void platform_on_track_reset(void) {
     37     o->oAction = PLATFORM_ON_TRACK_ACT_INIT;
     38     // This will cause the track balls to all despawn
     39     o->oPlatformOnTrackBaseBallIndex += 99;
     40 }
     41 
     42 /**
     43  * If this platform is the kind that disappears, pause for a while, then
     44  * begin blinking, and finally reset.
     45  */
     46 static void platform_on_track_mario_not_on_platform(void) {
     47     if (!((u16)(o->oBhvParams >> 16) & PLATFORM_ON_TRACK_BP_DONT_DISAPPEAR)) {
     48         // Once oTimer reaches 150, blink 40 times
     49         if (cur_obj_wait_then_blink(150, 40)) {
     50             platform_on_track_reset();
     51             o->header.gfx.node.flags &= ~GRAPH_RENDER_INVISIBLE;
     52         }
     53     }
     54 }
     55 
     56 /**
     57  * Init function for bhvPlatformOnTrack.
     58  */
     59 void bhv_platform_on_track_init(void) {
     60     if (!(o->activeFlags & ACTIVE_FLAG_IN_DIFFERENT_ROOM)) {
     61         s16 pathIndex = (u16)(o->oBhvParams >> 16) & PLATFORM_ON_TRACK_BP_MASK_PATH;
     62         o->oPlatformOnTrackType = ((u16)(o->oBhvParams >> 16) & PLATFORM_ON_TRACK_BP_MASK_TYPE) >> 4;
     63 
     64         o->oPlatformOnTrackIsNotSkiLift = o->oPlatformOnTrackType - PLATFORM_ON_TRACK_TYPE_SKI_LIFT;
     65 
     66         o->collisionData =
     67             segmented_to_virtual(sPlatformOnTrackCollisionModels[o->oPlatformOnTrackType]);
     68 
     69         o->oPlatformOnTrackStartWaypoint = segmented_to_virtual(sPlatformOnTrackPaths[pathIndex]);
     70 
     71         o->oPlatformOnTrackIsNotHMC = pathIndex - 4;
     72 
     73         o->oBhvParams2ndByte = o->oMoveAngleYaw; // TODO: Weird?
     74 
     75         if (o->oPlatformOnTrackType == PLATFORM_ON_TRACK_TYPE_CHECKERED) {
     76             o->header.gfx.scale[1] = 2.0f;
     77         }
     78     }
     79 }
     80 
     81 /**
     82  * Move to the start waypoint, spawn the first track balls, and enter the
     83  * wait for mario action.
     84  */
     85 static void platform_on_track_act_init(void) {
     86     s32 i;
     87 
     88     o->oPlatformOnTrackPrevWaypoint = o->oPlatformOnTrackStartWaypoint;
     89     o->oPlatformOnTrackPrevWaypointFlags = 0;
     90     o->oPlatformOnTrackBaseBallIndex = 0;
     91 
     92     o->oPosX = o->oHomeX = o->oPlatformOnTrackStartWaypoint->pos[0];
     93     o->oPosY = o->oHomeY = o->oPlatformOnTrackStartWaypoint->pos[1];
     94     o->oPosZ = o->oHomeZ = o->oPlatformOnTrackStartWaypoint->pos[2];
     95 
     96     o->oFaceAngleYaw = o->oBhvParams2ndByte;
     97     o->oForwardVel = o->oVelX = o->oVelY = o->oVelZ = o->oPlatformOnTrackDistMovedSinceLastBall = 0.0f;
     98 
     99     o->oPlatformOnTrackWasStoodOn = FALSE;
    100 
    101     if (o->oPlatformOnTrackIsNotSkiLift) {
    102         o->oFaceAngleRoll = 0;
    103     }
    104 
    105     // Spawn track balls
    106     for (i = 1; i < 6; i++) {
    107         platform_on_track_update_pos_or_spawn_ball(i, o->oHomeX, o->oHomeY, o->oHomeZ);
    108     }
    109 
    110     o->oAction = PLATFORM_ON_TRACK_ACT_WAIT_FOR_MARIO;
    111 }
    112 
    113 /**
    114  * Wait for mario to stand on the platform for 20 frames, then begin moving.
    115  */
    116 static void platform_on_track_act_wait_for_mario(void) {
    117     if (gMarioObject->platform == o) {
    118         if (o->oTimer > 20) {
    119             o->oAction = PLATFORM_ON_TRACK_ACT_MOVE_ALONG_TRACK;
    120         }
    121     } else {
    122         if (o->activeFlags & ACTIVE_FLAG_IN_DIFFERENT_ROOM) {
    123             platform_on_track_reset();
    124         }
    125 
    126         o->oTimer = 0;
    127     }
    128 }
    129 
    130 /**
    131  * Move along the track. After reaching the end, either start falling,
    132  * return to the init action, or continue moving back to the start waypoint.
    133  */
    134 static void platform_on_track_act_move_along_track(void) {
    135     s16 initialAngle;
    136 
    137     if (!o->oPlatformOnTrackIsNotSkiLift) {
    138         cur_obj_play_sound_1(SOUND_ENV_ELEVATOR3);
    139     } else if (!o->oPlatformOnTrackIsNotHMC) {
    140         cur_obj_play_sound_1(SOUND_ENV_ELEVATOR1);
    141     }
    142 
    143     // Fall after reaching the last waypoint if desired
    144     if (o->oPlatformOnTrackPrevWaypointFlags == WAYPOINT_FLAGS_END
    145         && !((u16)(o->oBhvParams >> 16) & PLATFORM_ON_TRACK_BP_RETURN_TO_START)) {
    146         o->oAction = PLATFORM_ON_TRACK_ACT_FALL;
    147     } else {
    148         // The ski lift should pause or stop after reaching a special waypoint
    149         if (o->oPlatformOnTrackPrevWaypointFlags != 0 && !o->oPlatformOnTrackIsNotSkiLift) {
    150             if (o->oPlatformOnTrackPrevWaypointFlags == WAYPOINT_FLAGS_END
    151                 || o->oPlatformOnTrackPrevWaypointFlags == WAYPOINT_FLAGS_PLATFORM_ON_TRACK_PAUSE) {
    152                 cur_obj_play_sound_2(SOUND_GENERAL_UNKNOWN4_LOWPRIO);
    153 
    154                 o->oForwardVel = 0.0f;
    155                 if (o->oPlatformOnTrackPrevWaypointFlags == WAYPOINT_FLAGS_END) {
    156                     o->oAction = PLATFORM_ON_TRACK_ACT_INIT;
    157                 } else {
    158                     o->oAction = PLATFORM_ON_TRACK_ACT_PAUSE_BRIEFLY;
    159                 }
    160             }
    161         } else {
    162             // The ski lift accelerates, while the others instantly start
    163             if (!o->oPlatformOnTrackIsNotSkiLift) {
    164                 obj_forward_vel_approach(10.0, 0.1f);
    165             } else {
    166                 o->oForwardVel = 10.0f;
    167             }
    168 
    169             // Spawn a new track ball if necessary
    170             if (approach_f32_ptr(&o->oPlatformOnTrackDistMovedSinceLastBall, 300.0f, o->oForwardVel)) {
    171                 o->oPlatformOnTrackDistMovedSinceLastBall -= 300.0f;
    172 
    173                 o->oHomeX = o->oPosX;
    174                 o->oHomeY = o->oPosY;
    175                 o->oHomeZ = o->oPosZ;
    176                 o->oPlatformOnTrackBaseBallIndex = (u16)(o->oPlatformOnTrackBaseBallIndex + 1);
    177 
    178                 platform_on_track_update_pos_or_spawn_ball(5, o->oHomeX, o->oHomeY, o->oHomeZ);
    179             }
    180         }
    181 
    182         platform_on_track_update_pos_or_spawn_ball(0, o->oPosX, o->oPosY, o->oPosZ);
    183 
    184         o->oMoveAnglePitch = o->oPlatformOnTrackPitch;
    185         o->oMoveAngleYaw = o->oPlatformOnTrackYaw;
    186 
    187         //! Both oAngleVelYaw and oAngleVelRoll aren't reset until the platform
    188         //  starts moving again, resulting in unexpected platform displacement
    189         //  after reappearing
    190 
    191         // Turn face yaw and compute yaw vel
    192         if (!((u16)(o->oBhvParams >> 16) & PLATFORM_ON_TRACK_BP_DONT_TURN_YAW)) {
    193             s16 targetFaceYaw = o->oMoveAngleYaw + 0x4000;
    194             s16 yawSpeed = abs_angle_diff(targetFaceYaw, o->oFaceAngleYaw) / 20;
    195 
    196             initialAngle = o->oFaceAngleYaw;
    197             clamp_s16(&yawSpeed, 100, 500);
    198             obj_face_yaw_approach(targetFaceYaw, yawSpeed);
    199             o->oAngleVelYaw = (s16) o->oFaceAngleYaw - initialAngle;
    200         }
    201 
    202         // Turn face roll and compute roll vel
    203         if (((u16)(o->oBhvParams >> 16) & PLATFORM_ON_TRACK_BP_DONT_TURN_ROLL)) {
    204             s16 rollSpeed = abs_angle_diff(o->oMoveAnglePitch, o->oFaceAngleRoll) / 20;
    205 
    206             initialAngle = o->oFaceAngleRoll;
    207             clamp_s16(&rollSpeed, 100, 500);
    208             //! If the platform is moving counterclockwise upward or
    209             //  clockwise downward, this will be backward
    210             obj_face_roll_approach(o->oMoveAnglePitch, rollSpeed);
    211             o->oAngleVelRoll = (s16) o->oFaceAngleRoll - initialAngle;
    212         }
    213     }
    214 
    215     if (gMarioObject->platform != o) {
    216         platform_on_track_mario_not_on_platform();
    217     } else {
    218         o->oTimer = 0;
    219         o->header.gfx.node.flags &= ~GRAPH_RENDER_INVISIBLE;
    220     }
    221 }
    222 
    223 /**
    224  * Wait 20 frames then continue moving.
    225  */
    226 static void platform_on_track_act_pause_briefly(void) {
    227     if (o->oTimer > 20) {
    228         o->oAction = PLATFORM_ON_TRACK_ACT_MOVE_ALONG_TRACK;
    229     }
    230 }
    231 
    232 /**
    233  * Fall downward with no terminal velocity, stopping after reaching y = -12k
    234  * and eventually blinking and disappearing.
    235  */
    236 static void platform_on_track_act_fall(void) {
    237     cur_obj_move_using_vel_and_gravity();
    238 
    239     if (gMarioObject->platform != o) {
    240         platform_on_track_mario_not_on_platform();
    241     } else {
    242         o->oTimer = 0;
    243         //! Doesn't ensure visibility
    244     }
    245 }
    246 
    247 /**
    248  * Control the rocking of the ski lift.
    249  */
    250 static void platform_on_track_rock_ski_lift(void) {
    251     s32 targetRoll = 0;
    252     UNUSED s32 initialRoll = o->oFaceAngleRoll;
    253 
    254     o->oFaceAngleRoll += (s32) o->oPlatformOnTrackSkiLiftRollVel;
    255 
    256     // Tilt away from the moving direction and toward mario
    257     if (gMarioObject->platform == o) {
    258         targetRoll = o->oForwardVel * sins(o->oMoveAngleYaw) * -50.0f
    259                      + (s32)(o->oDistanceToMario * sins(o->oAngleToMario - o->oFaceAngleYaw) * -4.0f);
    260     }
    261 
    262     oscillate_toward(
    263         /* value          */ &o->oFaceAngleRoll,
    264         /* vel            */ &o->oPlatformOnTrackSkiLiftRollVel,
    265         /* target         */ targetRoll,
    266         /* velCloseToZero */ 5.0f,
    267         /* accel          */ 6.0f,
    268         /* slowdown       */ 1.5f);
    269     clamp_f32(&o->oPlatformOnTrackSkiLiftRollVel, -100.0f, 100.0f);
    270 }
    271 
    272 /**
    273  * Update function for bhvPlatformOnTrack.
    274  */
    275 void bhv_platform_on_track_update(void) {
    276     switch (o->oAction) {
    277         case PLATFORM_ON_TRACK_ACT_INIT:
    278             platform_on_track_act_init();
    279             break;
    280         case PLATFORM_ON_TRACK_ACT_WAIT_FOR_MARIO:
    281             platform_on_track_act_wait_for_mario();
    282             break;
    283         case PLATFORM_ON_TRACK_ACT_MOVE_ALONG_TRACK:
    284             platform_on_track_act_move_along_track();
    285             break;
    286         case PLATFORM_ON_TRACK_ACT_PAUSE_BRIEFLY:
    287             platform_on_track_act_pause_briefly();
    288             break;
    289         case PLATFORM_ON_TRACK_ACT_FALL:
    290             platform_on_track_act_fall();
    291             break;
    292     }
    293 
    294     if (!o->oPlatformOnTrackIsNotSkiLift) {
    295         platform_on_track_rock_ski_lift();
    296     } else if (o->oPlatformOnTrackType == PLATFORM_ON_TRACK_TYPE_CARPET) {
    297         if (!o->oPlatformOnTrackWasStoodOn && gMarioObject->platform == o) {
    298             o->oPlatformOnTrackOffsetY = -8.0f;
    299             o->oPlatformOnTrackWasStoodOn = TRUE;
    300         }
    301 
    302         approach_f32_ptr(&o->oPlatformOnTrackOffsetY, 0.0f, 0.5f);
    303         o->oPosY += o->oPlatformOnTrackOffsetY;
    304     }
    305 }
    306 
    307 /**
    308  * Update function for bhvTrackBall.
    309  */
    310 void bhv_track_ball_update(void) {
    311     // Despawn after the elevator passes this ball
    312     s16 relativeIndex =
    313         (s16) o->oBhvParams2ndByte - (s16) o->parentObj->oPlatformOnTrackBaseBallIndex - 1;
    314     if (relativeIndex < 1 || relativeIndex > 5) {
    315         obj_mark_for_deletion(o);
    316     }
    317 }