cloud.inc.c (6388B)
1 2 /** 3 * Behavior for bhvCloud and bhvCloudPart. 4 * bhvCloud includes both fwoosh and the cloud that lakitu rides (both nice and 5 * evil). 6 * bhvCloudPart is spawned by bhvCloud and is either a "chunk" of cloud, or fwoosh's 7 * face. It is purely visual. 8 * If spawned by a lakitu, its parent will be the lakitu. 9 * Processing order is lakitu -> cloud -> its cloud parts. 10 */ 11 12 /** 13 * The relative heights of each cloud part. 14 */ 15 static s8 sCloudPartHeights[] = { 11, 8, 12, 8, 9, 9 }; 16 17 /** 18 * Spawn the visual parts of the cloud, including fwoosh's face. 19 */ 20 static void cloud_act_spawn_parts(void) { 21 struct Object *cloudPart; 22 s32 i; 23 24 // Spawn the pieces of the cloud itself 25 for (i = 0; i <= 4; i++) { 26 cloudPart = spawn_object_relative(i, 0, 0, 0, o, MODEL_MIST, bhvCloudPart); 27 28 if (cloudPart != NULL) { 29 obj_set_billboard(cloudPart); 30 } 31 } 32 33 if (o->oBhvParams2ndByte == CLOUD_BP_FWOOSH) { 34 // Spawn fwoosh's face 35 spawn_object_relative(5, 0, 0, 0, o, MODEL_FWOOSH, bhvCloudPart); 36 37 cur_obj_scale(3.0f); 38 39 o->oCloudCenterX = o->oPosX; 40 o->oCloudCenterY = o->oPosY; 41 } 42 43 o->oAction = CLOUD_ACT_MAIN; 44 } 45 46 /** 47 * Wait for mario to approach, then unhide and enter the spawn parts action. 48 */ 49 static void cloud_act_fwoosh_hidden(void) { 50 if (o->oDistanceToMario < 2000.0f) { 51 cur_obj_unhide(); 52 o->oAction = CLOUD_ACT_SPAWN_PARTS; 53 } 54 } 55 56 /** 57 * Move in a circle. Unload if mario moves far away. If mario stays close for 58 * long enough, blow wind at him. 59 */ 60 static void cloud_fwoosh_update(void) { 61 if (o->oDistanceToMario > 2500.0f) { 62 o->oAction = CLOUD_ACT_UNLOAD; 63 } else { 64 if (o->oCloudBlowing) { 65 o->header.gfx.scale[0] += o->oCloudGrowSpeed; 66 67 if ((o->oCloudGrowSpeed -= 0.005f) < -0.16f) { 68 // Stop blowing once we are shrinking faster than -0.16 69 o->oCloudBlowing = o->oTimer = 0; 70 } else if (o->oCloudGrowSpeed < -0.1f) { 71 // Start blowing once we start shrinking faster than -0.1 72 cur_obj_play_sound_1(SOUND_AIR_BLOW_WIND); 73 cur_obj_spawn_strong_wind_particles(12, 3.0f, 0.0f, -50.0f, 120.0f); 74 } else { 75 cur_obj_play_sound_1(SOUND_ENV_WIND1); 76 } 77 } else { 78 // Return to normal size 79 approach_f32_ptr(&o->header.gfx.scale[0], 3.0f, 0.012f); 80 o->oCloudFwooshMovementRadius += 0xC8; 81 82 // If mario stays nearby for 100 frames, begin blowing 83 if (o->oDistanceToMario < 1000.0f) { 84 if (o->oTimer > 100) { 85 o->oCloudBlowing = TRUE; 86 o->oCloudGrowSpeed = 0.14f; 87 } 88 } else { 89 o->oTimer = 0; 90 } 91 92 o->oCloudCenterX = o->oHomeX + 100.0f * coss(o->oCloudFwooshMovementRadius); 93 o->oPosZ = o->oHomeZ + 100.0f * sins(o->oCloudFwooshMovementRadius); 94 o->oCloudCenterY = o->oHomeY; 95 } 96 97 cur_obj_scale(o->header.gfx.scale[0]); 98 } 99 } 100 101 /** 102 * Main update function for bhvCloud. This controls the cloud's movement, when it 103 * unloads, and when fwoosh blows wind. 104 */ 105 static void cloud_act_main(void) { 106 s16 localOffsetPhase = 0x800 * gGlobalTimer; 107 f32 localOffset; 108 109 if (o->parentObj != o) { 110 // Despawn if the parent lakitu does 111 if (o->parentObj->activeFlags == ACTIVE_FLAG_DEACTIVATED) { 112 o->oAction = CLOUD_ACT_UNLOAD; 113 } else { 114 o->oCloudCenterX = o->parentObj->oPosX; 115 o->oCloudCenterY = o->parentObj->oPosY; 116 o->oPosZ = o->parentObj->oPosZ; 117 118 o->oMoveAngleYaw = o->parentObj->oFaceAngleYaw; 119 } 120 } else if (o->oBhvParams2ndByte != CLOUD_BP_FWOOSH) { 121 // This code should never run, since a lakitu cloud should always have 122 // a parent 123 if (o->oDistanceToMario > 1500.0f) { 124 o->oAction = CLOUD_ACT_UNLOAD; 125 } 126 } else { 127 cloud_fwoosh_update(); 128 } 129 130 localOffset = 2 * coss(localOffsetPhase) * o->header.gfx.scale[0]; 131 132 o->oPosX = o->oCloudCenterX + localOffset; 133 o->oPosY = o->oCloudCenterY + localOffset + 12.0f * o->header.gfx.scale[0]; 134 } 135 136 /** 137 * If fwoosh, return to home and hide. If lakitu cloud, despawn. 138 * This action informs the cloud parts to despawn. 139 */ 140 static void cloud_act_unload(void) { 141 if (o->oBhvParams2ndByte != CLOUD_BP_FWOOSH) { 142 obj_mark_for_deletion(o); 143 } else { 144 o->oAction = CLOUD_ACT_FWOOSH_HIDDEN; 145 cur_obj_hide(); 146 cur_obj_set_pos_to_home(); 147 } 148 } 149 150 /** 151 * Update function for bhvCloud. 152 */ 153 void bhv_cloud_update(void) { 154 switch (o->oAction) { 155 case CLOUD_ACT_SPAWN_PARTS: 156 cloud_act_spawn_parts(); 157 break; 158 case CLOUD_ACT_MAIN: 159 cloud_act_main(); 160 break; 161 case CLOUD_ACT_UNLOAD: 162 cloud_act_unload(); 163 break; 164 case CLOUD_ACT_FWOOSH_HIDDEN: 165 cloud_act_fwoosh_hidden(); 166 break; 167 } 168 } 169 170 /** 171 * Update function for bhvCloudPart. Follow the parent cloud with some oscillation. 172 */ 173 void bhv_cloud_part_update(void) { 174 if (o->parentObj->oAction == CLOUD_ACT_UNLOAD) { 175 obj_mark_for_deletion(o); 176 } else { 177 f32 scale = 2.0f / 3.0f * o->parentObj->header.gfx.scale[0]; 178 s16 angleFromCenter = o->parentObj->oFaceAngleYaw + 0x10000 / 5 * o->oBhvParams2ndByte; 179 180 // Takes 32 frames to cycle 181 s16 localOffsetPhase = 0x800 * gGlobalTimer + 0x4000 * o->oBhvParams2ndByte; 182 f32 localOffset; 183 184 f32 cloudRadius; 185 186 cur_obj_scale(scale); 187 188 // Cap fwoosh's face size 189 if (o->oBhvParams2ndByte == 5 && scale > 2.0f) { 190 scale = o->header.gfx.scale[1] = 2.0f; 191 } 192 193 // Move back and forth along (1, 1, 1) 194 localOffset = 2 * coss(localOffsetPhase) * scale; 195 196 cloudRadius = 25.0f * scale; 197 198 o->oPosX = o->parentObj->oCloudCenterX + cloudRadius * sins(angleFromCenter) + localOffset; 199 200 o->oPosY = 201 o->parentObj->oCloudCenterY + localOffset + scale * sCloudPartHeights[o->oBhvParams2ndByte]; 202 203 o->oPosZ = o->parentObj->oPosZ + cloudRadius * coss(angleFromCenter) + localOffset; 204 205 o->oFaceAngleYaw = o->parentObj->oFaceAngleYaw; 206 } 207 }