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 }