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 }