sm64

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

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 }