mips.inc.c (9331B)
1 2 /** 3 * Behavior for MIPS (everyone's favorite yellow rabbit). 4 */ 5 6 /** 7 * Initializes MIPS' physics parameters and checks if he should be active, 8 * hiding him if necessary. 9 */ 10 void bhv_mips_init(void) { 11 // Retrieve star flags for Castle Secret Stars on current save file. 12 u8 starFlags = save_file_get_star_flags(gCurrSaveFileNum - 1, COURSE_NUM_TO_INDEX(COURSE_NONE)); 13 14 // If the player has >= 15 stars and hasn't collected first MIPS star... 15 if (save_file_get_total_star_count(gCurrSaveFileNum - 1, COURSE_MIN - 1, COURSE_MAX - 1) >= 15 16 && !(starFlags & SAVE_FLAG_TO_STAR_FLAG(SAVE_FLAG_COLLECTED_MIPS_STAR_1))) { 17 o->oBhvParams2ndByte = MIPS_BP_15_STARS; 18 #ifndef VERSION_JP 19 o->oMipsForwardVelocity = 40.0f; 20 #endif 21 } 22 // If the player has >= 50 stars and hasn't collected second MIPS star... 23 else if (save_file_get_total_star_count(gCurrSaveFileNum - 1, COURSE_MIN - 1, COURSE_MAX - 1) >= 50 24 && !(starFlags & SAVE_FLAG_TO_STAR_FLAG(SAVE_FLAG_COLLECTED_MIPS_STAR_2))) { 25 o->oBhvParams2ndByte = MIPS_BP_50_STARS; 26 #ifndef VERSION_JP 27 o->oMipsForwardVelocity = 45.0f; 28 #endif 29 } else { 30 // No MIPS stars are available, hide MIPS. 31 o->activeFlags = ACTIVE_FLAG_DEACTIVATED; 32 } 33 34 o->oInteractionSubtype = INT_SUBTYPE_HOLDABLE_NPC; 35 36 #ifndef VERSION_JP 37 o->oGravity = 15.0f; 38 #else 39 o->oGravity = 2.5f; 40 #endif 41 o->oFriction = 0.89f; 42 o->oBuoyancy = 1.2f; 43 44 cur_obj_init_animation(0); 45 } 46 47 /** 48 * Helper function that finds the waypoint that is both within 800 units of MIPS 49 * and furthest from Mario's current location. 50 */ 51 s16 bhv_mips_find_furthest_waypoint_to_mario(void) { 52 s8 i; 53 s16 x, y, z; 54 s16 furthestWaypointIndex = -1; 55 f32 furthestWaypointDistance = -10000.0f; 56 f32 distanceToMario; 57 struct Waypoint **pathBase = segmented_to_virtual(&inside_castle_seg7_trajectory_mips); 58 59 // For each waypoint in MIPS path... 60 for (i = 0; i < 10; i++) { 61 struct Waypoint *waypoint = segmented_to_virtual(pathBase[i]); 62 x = waypoint->pos[0]; 63 y = waypoint->pos[1]; 64 z = waypoint->pos[2]; 65 66 // Is the waypoint within 800 units of MIPS? 67 if (is_point_close_to_object(o, x, y, z, 800)) { 68 // Is this further from Mario than the last waypoint? 69 distanceToMario = 70 sqr(x - gMarioObject->header.gfx.pos[0]) + sqr(z - gMarioObject->header.gfx.pos[2]); 71 if (furthestWaypointDistance < distanceToMario) { 72 furthestWaypointIndex = i; 73 furthestWaypointDistance = distanceToMario; 74 } 75 } 76 } 77 78 // Set MIPS' next waypoint to be the closest waypoint to Mario. 79 o->oMipsStartWaypointIndex = furthestWaypointIndex; 80 return (s16) o->oMipsStartWaypointIndex; 81 } 82 83 /** 84 * Wait until Mario comes close, then resume following our path. 85 */ 86 void bhv_mips_act_wait_for_nearby_mario(void) { 87 UNUSED s16 collisionFlags = 0; 88 89 o->oForwardVel = 0.0f; 90 collisionFlags = object_step(); 91 92 // If Mario is within 500 units... 93 if (is_point_within_radius_of_mario(o->oPosX, o->oPosY, o->oPosZ, 500)) { 94 // If we fail to find a suitable waypoint... 95 if (bhv_mips_find_furthest_waypoint_to_mario() == -1) { 96 // Call it quits. 97 o->oAction = MIPS_ACT_WAIT_FOR_ANIMATION_DONE; 98 } else { 99 // Resume path following. 100 cur_obj_init_animation(1); 101 o->oAction = MIPS_ACT_FOLLOW_PATH; 102 } 103 } 104 } 105 106 /** 107 * Continue to follow our path around the basement area. 108 */ 109 void bhv_mips_act_follow_path(void) { 110 s16 collisionFlags = 0; 111 s32 followStatus; 112 113 // Retrieve current waypoint. 114 struct Waypoint **pathBase = segmented_to_virtual(&inside_castle_seg7_trajectory_mips); 115 struct Waypoint *waypoint = segmented_to_virtual(*(pathBase + o->oMipsStartWaypointIndex)); 116 117 #ifdef AVOID_UB 118 followStatus = 0; 119 #endif 120 121 // Set start waypoint and follow the path from there. 122 o->oPathedStartWaypoint = waypoint; 123 //! Uninitialized parameter, but the parameter is unused in the called function 124 followStatus = cur_obj_follow_path(followStatus); 125 126 // Update velocity and angle and do movement. 127 #ifndef VERSION_JP 128 o->oForwardVel = o->oMipsForwardVelocity; 129 #else 130 o->oForwardVel = 45.0f; 131 #endif 132 o->oMoveAngleYaw = o->oPathedTargetYaw; 133 collisionFlags = object_step(); 134 135 // If we are at the end of the path, do idle animation and wait for Mario. 136 if (followStatus == PATH_REACHED_END) { 137 cur_obj_init_animation(0); 138 o->oAction = MIPS_ACT_WAIT_FOR_NEARBY_MARIO; 139 } 140 141 // Play sounds during walk animation. 142 if (cur_obj_check_if_near_animation_end() == TRUE && (collisionFlags & OBJ_COL_FLAG_UNDERWATER)) { 143 cur_obj_play_sound_2(SOUND_OBJ_MIPS_RABBIT_WATER); 144 spawn_object(o, MODEL_NONE, bhvShallowWaterSplash); 145 } else if (cur_obj_check_if_near_animation_end() == TRUE) { 146 cur_obj_play_sound_2(SOUND_OBJ_MIPS_RABBIT); 147 } 148 } 149 150 /** 151 * Seems to wait until the current animation is done, then go idle. 152 */ 153 void bhv_mips_act_wait_for_animation_done(void) { 154 if (cur_obj_check_if_near_animation_end() == TRUE) { 155 cur_obj_init_animation(0); 156 o->oAction = MIPS_ACT_IDLE; 157 } 158 } 159 160 /** 161 * Handles MIPS falling down after being thrown. 162 */ 163 void bhv_mips_act_fall_down(void) { 164 s16 collisionFlags = 0; 165 166 collisionFlags = object_step(); 167 o->header.gfx.animInfo.animFrame = 0; 168 169 if ((collisionFlags & OBJ_COL_FLAG_GROUNDED) == OBJ_COL_FLAG_GROUNDED) { 170 o->oAction = MIPS_ACT_WAIT_FOR_ANIMATION_DONE; 171 172 o->oFlags |= OBJ_FLAG_SET_FACE_YAW_TO_MOVE_YAW; 173 o->oMoveAngleYaw = o->oFaceAngleYaw; 174 175 if (collisionFlags & OBJ_COL_FLAG_UNDERWATER) { 176 spawn_object(o, MODEL_NONE, bhvShallowWaterSplash); 177 } 178 } 179 } 180 181 /** 182 * Idle loop, after you catch MIPS and put him down. 183 */ 184 void bhv_mips_act_idle(void) { 185 UNUSED s16 collisionFlags = 0; 186 187 o->oForwardVel = 0.0f; 188 collisionFlags = object_step(); 189 190 // Spawn a star if he was just picked up for the first time. 191 if (o->oMipsStarStatus == MIPS_STAR_STATUS_SHOULD_SPAWN_STAR) { 192 bhv_spawn_star_no_level_exit(STAR_INDEX_ACT_4 + o->oBhvParams2ndByte); 193 o->oMipsStarStatus = MIPS_STAR_STATUS_ALREADY_SPAWNED_STAR; 194 } 195 } 196 197 /** 198 * Handles all the actions MIPS does when he is not held. 199 */ 200 void bhv_mips_free(void) { 201 switch (o->oAction) { 202 case MIPS_ACT_WAIT_FOR_NEARBY_MARIO: 203 bhv_mips_act_wait_for_nearby_mario(); 204 break; 205 206 case MIPS_ACT_FOLLOW_PATH: 207 bhv_mips_act_follow_path(); 208 break; 209 210 case MIPS_ACT_WAIT_FOR_ANIMATION_DONE: 211 bhv_mips_act_wait_for_animation_done(); 212 break; 213 214 case MIPS_ACT_FALL_DOWN: 215 bhv_mips_act_fall_down(); 216 break; 217 218 case MIPS_ACT_IDLE: 219 bhv_mips_act_idle(); 220 break; 221 } 222 } 223 224 /** 225 * Handles MIPS being held by Mario. 226 */ 227 void bhv_mips_held(void) { 228 s16 dialogID; 229 230 o->header.gfx.node.flags |= GRAPH_RENDER_INVISIBLE; 231 cur_obj_init_animation(4); // Held animation. 232 cur_obj_set_pos_relative(gMarioObject, 0, 60.0f, 100.0f); 233 cur_obj_become_intangible(); 234 235 // If MIPS hasn't spawned his star yet... 236 if (o->oMipsStarStatus == MIPS_STAR_STATUS_HAVENT_SPAWNED_STAR) { 237 // Choose dialog based on which MIPS encounter this is. 238 if (o->oBhvParams2ndByte == MIPS_BP_15_STARS) { 239 dialogID = DIALOG_084; 240 } else { // MIPS_BP_50_STARS 241 dialogID = DIALOG_162; 242 } 243 244 if (set_mario_npc_dialog(MARIO_DIALOG_LOOK_FRONT) == MARIO_DIALOG_STATUS_SPEAK) { 245 o->activeFlags |= ACTIVE_FLAG_INITIATED_TIME_STOP; 246 if (cutscene_object_with_dialog(CUTSCENE_DIALOG, o, dialogID) != 0) { 247 o->oInteractionSubtype |= INT_SUBTYPE_DROP_IMMEDIATELY; 248 o->activeFlags &= ~ACTIVE_FLAG_INITIATED_TIME_STOP; 249 o->oMipsStarStatus = MIPS_STAR_STATUS_SHOULD_SPAWN_STAR; 250 set_mario_npc_dialog(MARIO_DIALOG_STOP); 251 } 252 } 253 } 254 } 255 256 /** 257 * Handles MIPS being dropped by Mario. 258 */ 259 void bhv_mips_dropped(void) { 260 cur_obj_get_dropped(); 261 o->header.gfx.node.flags &= ~GRAPH_RENDER_INVISIBLE; 262 cur_obj_init_animation(0); 263 o->oHeldState = HELD_FREE; 264 cur_obj_become_tangible(); 265 o->oForwardVel = 3.0f; 266 o->oAction = MIPS_ACT_IDLE; 267 } 268 269 /** 270 * Handles MIPS being thrown by Mario. 271 */ 272 void bhv_mips_thrown(void) { 273 cur_obj_enable_rendering_2(); 274 o->header.gfx.node.flags &= ~GRAPH_RENDER_INVISIBLE; 275 o->oHeldState = HELD_FREE; 276 o->oFlags &= ~OBJ_FLAG_SET_FACE_YAW_TO_MOVE_YAW; 277 cur_obj_init_animation(2); 278 cur_obj_become_tangible(); 279 o->oForwardVel = 25.0f; 280 o->oVelY = 20.0f; 281 o->oAction = MIPS_ACT_FALL_DOWN; 282 } 283 284 /** 285 * MIPS' main loop. 286 */ 287 void bhv_mips_loop(void) { 288 // Determine what to do based on MIPS' held status. 289 switch (o->oHeldState) { 290 case HELD_FREE: 291 bhv_mips_free(); 292 break; 293 294 case HELD_HELD: 295 bhv_mips_held(); 296 break; 297 298 case HELD_THROWN: 299 bhv_mips_thrown(); 300 break; 301 302 case HELD_DROPPED: 303 bhv_mips_dropped(); 304 break; 305 } 306 }