sm64

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

enemy_lakitu.inc.c (5944B)


      1 
      2 /**
      3  * Behavior for bhvEnemyLakitu.
      4  * Lakitu comes before it spawned spinies in processing order.
      5  * TODO: bhvCloud processing oredr
      6  */
      7 
      8 /**
      9  * Hitbox for evil lakitu.
     10  */
     11 static struct ObjectHitbox sEnemyLakituHitbox = {
     12     /* interactType:      */ INTERACT_HIT_FROM_BELOW,
     13     /* downOffset:        */ 0,
     14     /* damageOrCoinValue: */ 2,
     15     /* health:            */ 0,
     16     /* numLootCoins:      */ 5,
     17     /* radius:            */ 50,
     18     /* height:            */ 50,
     19     /* hurtboxRadius:     */ 40,
     20     /* hurtboxHeight:     */ 50,
     21 };
     22 
     23 /**
     24  * Wait for mario to approach, then spawn the cloud and become visible.
     25  */
     26 static void enemy_lakitu_act_uninitialized(void) {
     27     if (o->oDistanceToMario < 2000.0f) {
     28         spawn_object_relative_with_scale(CLOUD_BP_LAKITU_CLOUD, 0, 0, 0, 2.0f, o, MODEL_MIST, bhvCloud);
     29 
     30         cur_obj_unhide();
     31         o->oAction = ENEMY_LAKITU_ACT_MAIN;
     32     }
     33 }
     34 
     35 /**
     36  * Accelerate toward mario vertically.
     37  */
     38 static void enemy_lakitu_update_vel_y(f32 offsetY) {
     39     // In order to encourage oscillation, pass mario by a small margin before
     40     // accelerating the opposite direction
     41     f32 margin;
     42     if (o->oVelY < 0.0f) {
     43         margin = -3.0f;
     44     } else {
     45         margin = 3.0f;
     46     }
     47 
     48     if (o->oPosY < gMarioObject->oPosY + offsetY + margin) {
     49         obj_y_vel_approach(4.0f, 0.4f);
     50     } else {
     51         obj_y_vel_approach(-4.0f, 0.4f);
     52     }
     53 }
     54 
     55 /**
     56  * Control speed based on distance to mario, turn toward mario, and change move
     57  * angle toward mario.
     58  */
     59 static void enemy_lakitu_update_speed_and_angle(void) {
     60     f32 minSpeed;
     61     s16 turnSpeed;
     62 
     63     f32 distToMario = o->oDistanceToMario;
     64     if (distToMario > 500.0f) {
     65         distToMario = 500.0f;
     66     }
     67 
     68     // Move faster the farther away mario is and the faster mario is moving
     69     if ((minSpeed = 1.2f * gMarioStates[0].forwardVel) < 8.0f) {
     70         minSpeed = 8.0f;
     71     }
     72     o->oForwardVel = distToMario * 0.04f;
     73     clamp_f32(&o->oForwardVel, minSpeed, 40.0f);
     74 
     75     // Accelerate toward mario vertically
     76     enemy_lakitu_update_vel_y(300.0f);
     77 
     78     // Turn toward mario except right after throwing a spiny
     79     if (o->oEnemyLakituFaceForwardCountdown != 0) {
     80         o->oEnemyLakituFaceForwardCountdown--;
     81     } else {
     82         obj_face_yaw_approach(o->oAngleToMario, 0x600);
     83     }
     84 
     85     // Change move angle toward mario faster when farther from mario
     86     turnSpeed = (s16)(distToMario * 2);
     87     clamp_s16(&turnSpeed, 200, 4000);
     88     cur_obj_rotate_yaw_toward(o->oAngleToMario, turnSpeed);
     89 }
     90 
     91 /**
     92  * When close enough to mario and facing roughly toward him, spawn a spiny and
     93  * hold it, then enter the hold spiny sub-action.
     94  */
     95 static void enemy_lakitu_sub_act_no_spiny(void) {
     96     cur_obj_init_animation_with_sound(1);
     97 
     98     if (o->oEnemyLakituSpinyCooldown != 0) {
     99         o->oEnemyLakituSpinyCooldown--;
    100     } else if (o->oEnemyLakituNumSpinies < 3 && o->oDistanceToMario < 800.0f
    101                && abs_angle_diff(o->oAngleToMario, o->oFaceAngleYaw) < 0x4000) {
    102         struct Object *spiny = spawn_object(o, MODEL_SPINY_BALL, bhvSpiny);
    103         if (spiny != NULL) {
    104             o->prevObj = spiny;
    105             spiny->oAction = SPINY_ACT_HELD_BY_LAKITU;
    106             obj_init_animation_with_sound(spiny, spiny_egg_seg5_anims_050157E4, 0);
    107 
    108             o->oEnemyLakituNumSpinies++;
    109             o->oSubAction = ENEMY_LAKITU_SUB_ACT_HOLD_SPINY;
    110             o->oEnemyLakituSpinyCooldown = 30;
    111         }
    112     }
    113 }
    114 
    115 /**
    116  * When close to mario and facing toward him or when mario gets far enough away,
    117  * enter the throw spiny sub-action.
    118  */
    119 static void enemy_lakitu_sub_act_hold_spiny(void) {
    120     cur_obj_init_anim_extend(3);
    121 
    122     if (o->oEnemyLakituSpinyCooldown != 0) {
    123         o->oEnemyLakituSpinyCooldown--;
    124     }
    125     // TODO: Check if anything interesting happens if we bypass this with speed
    126     else if (o->oDistanceToMario > o->oDrawingDistance - 100.0f
    127              || (o->oDistanceToMario < 500.0f
    128                  && abs_angle_diff(o->oAngleToMario, o->oFaceAngleYaw) < 0x2000)) {
    129         o->oSubAction = ENEMY_LAKITU_SUB_ACT_THROW_SPINY;
    130         o->oEnemyLakituFaceForwardCountdown = 20;
    131     }
    132 }
    133 
    134 /**
    135  * Throw the spiny, then enter the no spiny sub-action.
    136  */
    137 static void enemy_lakitu_sub_act_throw_spiny(void) {
    138     if (cur_obj_init_anim_check_frame(2, 2)) {
    139         cur_obj_play_sound_2(SOUND_OBJ_EVIL_LAKITU_THROW);
    140         o->prevObj = NULL;
    141     }
    142 
    143     if (cur_obj_check_if_near_animation_end()) {
    144         o->oSubAction = ENEMY_LAKITU_SUB_ACT_NO_SPINY;
    145         o->oEnemyLakituSpinyCooldown = random_linear_offset(100, 100);
    146     }
    147 }
    148 
    149 /**
    150  * Main update function.
    151  */
    152 static void enemy_lakitu_act_main(void) {
    153     cur_obj_play_sound_1(SOUND_AIR_LAKITU_FLY);
    154 
    155     cur_obj_update_floor_and_walls();
    156 
    157     enemy_lakitu_update_speed_and_angle();
    158     if (o->oMoveFlags & OBJ_MOVE_HIT_WALL) {
    159         o->oMoveAngleYaw = cur_obj_reflect_move_angle_off_wall();
    160     }
    161 
    162     obj_update_blinking(&o->oEnemyLakituBlinkTimer, 20, 40, 4);
    163 
    164     switch (o->oSubAction) {
    165         case ENEMY_LAKITU_SUB_ACT_NO_SPINY:
    166             enemy_lakitu_sub_act_no_spiny();
    167             break;
    168         case ENEMY_LAKITU_SUB_ACT_HOLD_SPINY:
    169             enemy_lakitu_sub_act_hold_spiny();
    170             break;
    171         case ENEMY_LAKITU_SUB_ACT_THROW_SPINY:
    172             enemy_lakitu_sub_act_throw_spiny();
    173             break;
    174     }
    175 
    176     cur_obj_move_standard(78);
    177 
    178     // Die and drop held spiny when attacked by mario
    179     if (obj_check_attacks(&sEnemyLakituHitbox, o->oAction) != 0) {
    180         // The spiny uses this as a signal to get thrown
    181         o->prevObj = NULL;
    182     }
    183 }
    184 
    185 /**
    186  * Update function for bhvEnemyLakitu.
    187  */
    188 void bhv_enemy_lakitu_update(void) {
    189     // PARTIAL_UPDATE
    190 
    191     treat_far_home_as_mario(2000.0f);
    192 
    193     switch (o->oAction) {
    194         case ENEMY_LAKITU_ACT_UNINITIALIZED:
    195             enemy_lakitu_act_uninitialized();
    196             break;
    197         case ENEMY_LAKITU_ACT_MAIN:
    198             enemy_lakitu_act_main();
    199             break;
    200     }
    201 }