sm64

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

spiny.inc.c (6647B)


      1 
      2 /**
      3  * Behavior for bhvSpiny.
      4  * When spawned by lakitu, its parent object is the lakitu.
      5  * Lakitu comes before it spawned spinies in processing order.
      6  */
      7 
      8 /**
      9  * Hitbox for spiny both while thrown and walking. The interaction type is
     10  * changed to INTERACT_UNKNOWN_08 while walking.
     11  */
     12 static struct ObjectHitbox sSpinyHitbox = {
     13     /* interactType:      */ INTERACT_MR_BLIZZARD,
     14     /* downOffset:        */ 0,
     15     /* damageOrCoinValue: */ 2,
     16     /* health:            */ 0,
     17     /* numLootCoins:      */ 0,
     18     /* radius:            */ 80,
     19     /* height:            */ 50,
     20     /* hurtboxRadius:     */ 40,
     21     /* hurtboxHeight:     */ 40,
     22 };
     23 
     24 /**
     25  * Attack handlers for spiny while walking.
     26  */
     27 static u8 sSpinyWalkAttackHandlers[] = {
     28     /* ATTACK_PUNCH:                 */ ATTACK_HANDLER_KNOCKBACK,
     29     /* ATTACK_KICK_OR_TRIP:          */ ATTACK_HANDLER_KNOCKBACK,
     30     /* ATTACK_FROM_ABOVE:            */ ATTACK_HANDLER_NOP,
     31     /* ATTACK_GROUND_POUND_OR_TWIRL: */ ATTACK_HANDLER_NOP,
     32     /* ATTACK_FAST_ATTACK:           */ ATTACK_HANDLER_KNOCKBACK,
     33     /* ATTACK_FROM_BELOW:            */ ATTACK_HANDLER_KNOCKBACK,
     34 };
     35 
     36 /**
     37  * If the spiny was spawned by lakitu and mario is far away, despawn.
     38  */
     39 static s32 spiny_check_active(void) {
     40     if (o->parentObj != o) {
     41         if (o->oDistanceToMario > 2500.0f) {
     42             //! It's possible for the lakitu to despawn while the spiny still
     43             //  references it. This line allows us to decrement the 0x1B field
     44             //  in an object that loads into the lakitu's former slot.
     45             //  This can be used in practice to corrupt a huge goomba to
     46             //  behave similar to a regular goomba.
     47             //  It can also be used on a bob-omb respawner to change its model
     48             //  to a butterfly or fish.
     49             o->parentObj->oEnemyLakituNumSpinies--;
     50             obj_mark_for_deletion(o);
     51             return FALSE;
     52         }
     53     }
     54 
     55     return TRUE;
     56 }
     57 
     58 /**
     59  * Walk around randomly, and dick around with oFlags, oMoveFlags, and oInteractType.
     60  */
     61 static void spiny_act_walk(void) {
     62     if (spiny_check_active()) {
     63         cur_obj_update_floor_and_walls();
     64 
     65         o->oGraphYOffset = -17.0f;
     66         cur_obj_init_animation_with_sound(0);
     67 
     68         if (o->oMoveFlags & OBJ_MOVE_MASK_ON_GROUND) {
     69             // After touching the ground for the first time, stop. From now on,
     70             // ensure that face angle and move angle agree
     71             if (!(o->oFlags & OBJ_FLAG_SET_FACE_YAW_TO_MOVE_YAW)) {
     72                 if (obj_forward_vel_approach(0.0f, 1.0f)) {
     73                     o->oFlags |= OBJ_FLAG_SET_FACE_YAW_TO_MOVE_YAW;
     74                     o->oMoveAngleYaw = o->oFaceAngleYaw;
     75                 }
     76             } else {
     77                 obj_forward_vel_approach(1.0f, 0.2f);
     78             }
     79 
     80             if (o->oSpinyTurningAwayFromWall) {
     81                 o->oSpinyTurningAwayFromWall =
     82                     obj_resolve_collisions_and_turn(o->oSpinyTargetYaw, 0x80);
     83             } else {
     84                 if (!(o->oSpinyTurningAwayFromWall =
     85                           obj_bounce_off_walls_edges_objects(&o->oSpinyTargetYaw))) {
     86                     // Walk and occasionally randomly change direction
     87                     if (o->oSpinyTimeUntilTurn != 0) {
     88                         o->oSpinyTimeUntilTurn--;
     89                     } else {
     90                         o->oSpinyTargetYaw = o->oMoveAngleYaw + (s16) random_sign() * 0x2000;
     91                         o->oSpinyTimeUntilTurn = random_linear_offset(100, 100);
     92                     }
     93                 }
     94 
     95                 cur_obj_rotate_yaw_toward(o->oSpinyTargetYaw, 0x80);
     96             }
     97 
     98         } else if (o->oMoveFlags & OBJ_MOVE_HIT_WALL) {
     99             // Bounce off walls while falling
    100             o->oMoveAngleYaw = cur_obj_reflect_move_angle_off_wall();
    101         }
    102 
    103         cur_obj_move_standard(-78);
    104 
    105         if (obj_handle_attacks(&sSpinyHitbox, SPINY_ACT_ATTACKED_MARIO, sSpinyWalkAttackHandlers)) {
    106             // When attacked by mario, lessen the knockback
    107             o->oAction = SPINY_ACT_WALK;
    108             o->oForwardVel *= 0.1f;
    109             o->oVelY *= 0.7f;
    110 
    111             o->oMoveFlags = 0; // weird flex but okay
    112 
    113             // Don't allow mario to punch the spiny two frames in a row?
    114             o->oInteractType = INTERACT_MR_BLIZZARD;
    115         } else {
    116             o->oInteractType = INTERACT_UNKNOWN_08;
    117         }
    118     }
    119 }
    120 
    121 /**
    122  * Wait for the lakitu to throw the spiny. The spiny is placed in this action
    123  * after being spawned by a lakitu.
    124  */
    125 static void spiny_act_held_by_lakitu(void) {
    126     o->oGraphYOffset = 15.0f;
    127     cur_obj_init_animation_with_sound(0);
    128 
    129     o->oParentRelativePosX = -50.0f;
    130     o->oParentRelativePosY = 35.0f;
    131     o->oParentRelativePosZ = -100.0f;
    132 
    133     if (o->parentObj->prevObj == NULL) {
    134         o->oAction = SPINY_ACT_THROWN_BY_LAKITU;
    135         o->oMoveAngleYaw = o->parentObj->oFaceAngleYaw;
    136 
    137         // Move more quickly if the lakitu is moving forward
    138         o->oForwardVel =
    139             o->parentObj->oForwardVel * coss(o->oMoveAngleYaw - o->parentObj->oMoveAngleYaw) + 10.0f;
    140         o->oVelY = 30.0f;
    141 
    142         o->oMoveFlags = 0; // you do you, spiny
    143     }
    144 }
    145 
    146 /**
    147  * Spin around. After landing, enter the walk action.
    148  */
    149 static void spiny_act_thrown_by_lakitu(void) {
    150     if (spiny_check_active()) {
    151         cur_obj_update_floor_and_walls();
    152 
    153         o->oGraphYOffset = 15.0f;
    154         o->oFaceAnglePitch -= 0x2000;
    155 
    156         cur_obj_init_animation_with_sound(0);
    157 
    158         if (o->oMoveFlags & OBJ_MOVE_LANDED) {
    159             cur_obj_play_sound_2(SOUND_OBJ_SPINY_UNK59);
    160             cur_obj_set_model(MODEL_SPINY);
    161             obj_init_animation_with_sound(o, spiny_seg5_anims_05016EAC, 0);
    162             o->oGraphYOffset = -17.0f;
    163 
    164             o->oFaceAnglePitch = 0;
    165             o->oAction = SPINY_ACT_WALK;
    166         } else if (o->oMoveFlags & OBJ_MOVE_HIT_WALL) {
    167             o->oMoveAngleYaw = cur_obj_reflect_move_angle_off_wall();
    168         }
    169 
    170         cur_obj_move_standard(-78);
    171 
    172         if (obj_check_attacks(&sSpinyHitbox, o->oAction) != 0 && o->parentObj != o) {
    173             o->parentObj->oEnemyLakituNumSpinies--;
    174         }
    175     }
    176 }
    177 
    178 /**
    179  * Update function for bhvSpiny.
    180  */
    181 void bhv_spiny_update(void) {
    182     // PARTIAL_UPDATE
    183 
    184     switch (o->oAction) {
    185         case SPINY_ACT_WALK:
    186             spiny_act_walk();
    187             break;
    188         case SPINY_ACT_HELD_BY_LAKITU:
    189             spiny_act_held_by_lakitu();
    190             break;
    191         case SPINY_ACT_THROWN_BY_LAKITU:
    192             spiny_act_thrown_by_lakitu();
    193             break;
    194         case SPINY_ACT_ATTACKED_MARIO:
    195             obj_move_for_one_second(SPINY_ACT_WALK);
    196             break;
    197     }
    198 }