struct TripletButterflyActivationData { s32 model; const BehaviorScript *behavior; f32 scale; }; static struct ObjectHitbox sTripletButterflyExplodeHitbox = { /* interactType: */ INTERACT_MR_BLIZZARD, /* downOffset: */ 50, /* damageOrCoinValue: */ 2, /* health: */ 1, /* numLootCoins: */ 0, /* radius: */ 100, /* height: */ 50, /* hurtboxRadius: */ 100, /* hurtboxHeight: */ 50, }; static struct TripletButterflyActivationData sTripletButterflyActivationData[] = { { MODEL_BOWLING_BALL, NULL, 0.5f }, { MODEL_1UP, bhv1upWalking, 1.0f }, }; static void triplet_butterfly_act_init(void) { s32 butterflyNum; s32 i; butterflyNum = o->oBehParams2ndByte & TRIPLET_BUTTERFLY_BP_BUTTERFLY_NUM; if (butterflyNum != 0 || o->oDistanceToMario < 200.0f) { if (butterflyNum == 0) { for (i = 1; i <= 2; i++) { spawn_object_relative(i, 0, 0, 0, o, MODEL_BUTTERFLY, bhvTripletButterfly); } o->oTripletButterflySelectedButterfly = RandomU16() % 3; } //! TODO: Describe this glitch if (o->parentObj->oTripletButterflySelectedButterfly == o->oBehParams2ndByte) { o->oTripletButterflyType = TRIPLET_BUTTERFLY_TYPE_SPAWN_1UP; } else if (o->parentObj->oBehParams2ndByte & TRIPLET_BUTTERFLY_BP_NO_BOMBS) { o->oTripletButterflyType = TRIPLET_BUTTERFLY_TYPE_NORMAL; } // Default butterfly type is TRIPLET_BUTTERFLY_TYPE_EXPLODES o->oAction = TRIPLET_BUTTERFLY_ACT_WANDER; o->oTripletButterflyBaseYaw = o->oBehParams2ndByte * (0x10000 / 3); o->oMoveAngleYaw = (s32)(o->oTripletButterflyBaseYaw + random_linear_offset(0, 0x5555)); o->oTripletButterflySpeed = random_linear_offset(15, 15); cur_obj_unhide(); } } static void triplet_butterfly_act_wander(void) { if (o->oDistanceToMario > 1500.0f) { obj_mark_for_deletion(o); } else { approach_f32_ptr(&o->oTripletButterflySpeed, 8.0f, 0.5f); if (o->oTimer < 60) { o->oTripletButterflyTargetYaw = cur_obj_angle_to_home(); } else { o->oTripletButterflyTargetYaw = (s32) o->oTripletButterflyBaseYaw; if (o->oTimer > 110 && o->oDistanceToMario < 200.0f && o->oTripletButterflyType > TRIPLET_BUTTERFLY_TYPE_NORMAL) { o->oAction = TRIPLET_BUTTERFLY_ACT_ACTIVATE; o->oTripletButterflySpeed = 0.0f; } } if (o->oHomeY < o->oFloorHeight) { o->oHomeY = o->oFloorHeight; } if (o->oPosY < o->oHomeY + random_linear_offset(50, 50)) { o->oTripletButterflyTargetPitch = -0x2000; } else { o->oTripletButterflyTargetPitch = 0x2000; } obj_move_pitch_approach(o->oTripletButterflyTargetPitch, 400); cur_obj_rotate_yaw_toward(o->oTripletButterflyTargetYaw, random_linear_offset(400, 800)); } } static void triplet_butterfly_act_activate(void) { if (o->oTimer > 20) { if (o->oTripletButterflyModel == 0) { spawn_object_relative_with_scale(0, 0, -40, 0, 1.5f, o, MODEL_SMOKE, bhvWhitePuffSmoke2); o->oTripletButterflyModel = sTripletButterflyActivationData[o->oTripletButterflyType].model; cur_obj_set_model(o->oTripletButterflyModel); obj_set_billboard(o); o->oTripletButterflyScale = 0.0f; o->oHomeY = o->oPosY; } else if (o->oTripletButterflyScale >= sTripletButterflyActivationData[o->oTripletButterflyType].scale) { if (o->oTripletButterflyType != TRIPLET_BUTTERFLY_TYPE_EXPLODES) { spawn_object(o, o->oTripletButterflyModel, sTripletButterflyActivationData[o->oTripletButterflyType].behavior); obj_mark_for_deletion(o); } else { o->oAction = TRIPLET_BUTTERFLY_ACT_EXPLODE; o->oWallHitboxRadius = 100.0f; } } o->oTripletButterflyScale += sTripletButterflyActivationData[o->oTripletButterflyType].scale / 30.0f; if (o->oTripletButterflyType == TRIPLET_BUTTERFLY_TYPE_EXPLODES) { o->oGraphYOffset = 250.0f * o->oTripletButterflyScale; o->oPosY = o->oHomeY - o->oGraphYOffset; } } } static void triplet_butterfly_act_explode(void) { f32 scaleIncrease; obj_check_attacks(&sTripletButterflyExplodeHitbox, -1); if (o->oAction == -1 || (o->oMoveFlags & 0x00000200) || o->oTimer >= 158) { o->oPosY += o->oGraphYOffset; spawn_object(o, MODEL_EXPLOSION, bhvExplosion); obj_mark_for_deletion(o); } else { if (o->oTimer > 120) { scaleIncrease = 0.04f * coss(o->oTripletButterflyScalePhase); if (scaleIncrease > 0.0f) { scaleIncrease *= 4.5f; o->oTripletButterflyScalePhase += 10000; } else { o->oTripletButterflyScalePhase += 4000; } o->oTripletButterflyScale += scaleIncrease; } approach_f32_ptr(&o->oTripletButterflySpeed, 20.0f, 1.0f); cur_obj_rotate_yaw_toward(o->oAngleToMario, 800); obj_turn_pitch_toward_mario(-100.0f, 800); } } void bhv_triplet_butterfly_update(void) { cur_obj_update_floor_and_walls(); switch (o->oAction) { case TRIPLET_BUTTERFLY_ACT_INIT: triplet_butterfly_act_init(); break; case TRIPLET_BUTTERFLY_ACT_WANDER: triplet_butterfly_act_wander(); break; case TRIPLET_BUTTERFLY_ACT_ACTIVATE: triplet_butterfly_act_activate(); break; case TRIPLET_BUTTERFLY_ACT_EXPLODE: triplet_butterfly_act_explode(); break; } cur_obj_scale(o->oTripletButterflyScale); obj_compute_vel_from_move_pitch(o->oTripletButterflySpeed); cur_obj_move_standard(78); }