sm64

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

bobomb.inc.c (12877B)


      1 // bobomb.inc.c
      2 
      3 static struct ObjectHitbox sBobombHitbox = {
      4     /* interactType:      */ INTERACT_GRABBABLE,
      5     /* downOffset:        */ 0,
      6     /* damageOrCoinValue: */ 0,
      7     /* health:            */ 0,
      8     /* numLootCoins:      */ 0,
      9     /* radius:            */ 65,
     10     /* height:            */ 113,
     11     /* hurtboxRadius:     */ 0,
     12     /* hurtboxHeight:     */ 0,
     13 };
     14 
     15 void bhv_bobomb_init(void) {
     16     o->oGravity = 2.5f;
     17     o->oFriction = 0.8f;
     18     o->oBuoyancy = 1.3f;
     19     o->oInteractionSubtype = INT_SUBTYPE_KICKABLE;
     20 }
     21 
     22 void bobomb_spawn_coin(void) {
     23     if (!((o->oBhvParams >> 8) & 0x01)) {
     24         obj_spawn_yellow_coins(o, 1);
     25         o->oBhvParams = 0x100;
     26         set_object_respawn_info_bits(o, 1);
     27     }
     28 }
     29 
     30 void bobomb_act_explode(void) {
     31     if (o->oTimer < 5) {
     32         cur_obj_scale(1.0 + (f32) o->oTimer / 5.0);
     33     } else {
     34         struct Object *explosion = spawn_object(o, MODEL_EXPLOSION, bhvExplosion);
     35         explosion->oGraphYOffset += 100.0f;
     36 
     37         bobomb_spawn_coin();
     38         create_respawner(MODEL_BLACK_BOBOMB, bhvBobomb, 3000);
     39 
     40         o->activeFlags = ACTIVE_FLAG_DEACTIVATED;
     41     }
     42 }
     43 
     44 void bobomb_check_interactions(void) {
     45     obj_set_hitbox(o, &sBobombHitbox);
     46 
     47     if (o->oInteractStatus & INT_STATUS_INTERACTED) {
     48         if (o->oInteractStatus & INT_STATUS_MARIO_KNOCKBACK_DMG) {
     49             o->oMoveAngleYaw = gMarioObject->header.gfx.angle[1];
     50             o->oForwardVel = 25.0f;
     51             o->oVelY = 30.0f;
     52             o->oAction = BOBOMB_ACT_LAUNCHED;
     53         }
     54 
     55         if (o->oInteractStatus & INT_STATUS_TOUCHED_BOB_OMB) {
     56             o->oAction = BOBOMB_ACT_EXPLODE;
     57         }
     58 
     59         o->oInteractStatus = 0;
     60     }
     61 
     62     if (obj_attack_collided_from_other_object(o) == TRUE) {
     63         o->oAction = BOBOMB_ACT_EXPLODE;
     64     }
     65 }
     66 
     67 void bobomb_act_patrol(void) {
     68     UNUSED u8 filler[4];
     69     UNUSED s16 animFrame = o->header.gfx.animInfo.animFrame;
     70     s16 collisionFlags;
     71 
     72     o->oForwardVel = 5.0f;
     73     collisionFlags = object_step();
     74 
     75     if ((obj_return_home_if_safe(o, o->oHomeX, o->oHomeY, o->oHomeZ, 400) == TRUE)
     76         && (obj_check_if_facing_toward_angle(o->oMoveAngleYaw, o->oAngleToMario, 0x2000) == TRUE)) {
     77         o->oBobombFuseLit = 1;
     78         o->oAction = BOBOMB_ACT_CHASE_MARIO;
     79     }
     80 
     81     obj_check_floor_death(collisionFlags, sObjFloor);
     82 }
     83 
     84 void bobomb_act_chase_mario(void) {
     85     UNUSED u8 filler[4];
     86     s16 animFrame = ++o->header.gfx.animInfo.animFrame;
     87     s16 collisionFlags;
     88 
     89     o->oForwardVel = 20.0f;
     90     collisionFlags = object_step();
     91 
     92     if (animFrame == 5 || animFrame == 16) {
     93         cur_obj_play_sound_2(SOUND_OBJ_BOBOMB_WALK);
     94     }
     95 
     96     obj_turn_toward_object(o, gMarioObject, 16, 0x800);
     97     obj_check_floor_death(collisionFlags, sObjFloor);
     98 }
     99 
    100 void bobomb_act_launched(void) {
    101     s16 collisionFlags = 0;
    102     collisionFlags = object_step();
    103     if ((collisionFlags & OBJ_COL_FLAG_GROUNDED) == OBJ_COL_FLAG_GROUNDED) {
    104         o->oAction = BOBOMB_ACT_EXPLODE;
    105     }
    106 }
    107 
    108 void generic_bobomb_free_loop(void) {
    109     switch (o->oAction) {
    110         case BOBOMB_ACT_PATROL:
    111             bobomb_act_patrol();
    112             break;
    113 
    114         case BOBOMB_ACT_LAUNCHED:
    115             bobomb_act_launched();
    116             break;
    117 
    118         case BOBOMB_ACT_CHASE_MARIO:
    119             bobomb_act_chase_mario();
    120             break;
    121 
    122         case BOBOMB_ACT_EXPLODE:
    123             bobomb_act_explode();
    124             break;
    125 
    126         case BOBOMB_ACT_LAVA_DEATH:
    127             if (obj_lava_death() == TRUE) {
    128                 create_respawner(MODEL_BLACK_BOBOMB, bhvBobomb, 3000);
    129             }
    130             break;
    131 
    132         case BOBOMB_ACT_DEATH_PLANE_DEATH:
    133             o->activeFlags = ACTIVE_FLAG_DEACTIVATED;
    134             create_respawner(MODEL_BLACK_BOBOMB, bhvBobomb, 3000);
    135             break;
    136     }
    137 
    138     bobomb_check_interactions();
    139 
    140     if (o->oBobombFuseTimer > 150) {
    141         o->oAction = 3;
    142     }
    143 }
    144 
    145 void stationary_bobomb_free_loop(void) {
    146     switch (o->oAction) {
    147         case BOBOMB_ACT_LAUNCHED:
    148             bobomb_act_launched();
    149             break;
    150 
    151         case BOBOMB_ACT_EXPLODE:
    152             bobomb_act_explode();
    153             break;
    154 
    155         case BOBOMB_ACT_LAVA_DEATH:
    156             if (obj_lava_death() == TRUE) {
    157                 create_respawner(MODEL_BLACK_BOBOMB, bhvBobomb, 3000);
    158             }
    159             break;
    160 
    161         case BOBOMB_ACT_DEATH_PLANE_DEATH:
    162             o->activeFlags = ACTIVE_FLAG_DEACTIVATED;
    163             create_respawner(MODEL_BLACK_BOBOMB, bhvBobomb, 3000);
    164             break;
    165     }
    166 
    167     bobomb_check_interactions();
    168 
    169     if (o->oBobombFuseTimer > 150) {
    170         o->oAction = 3;
    171     }
    172 }
    173 
    174 void bobomb_free_loop(void) {
    175     if (o->oBhvParams2ndByte == BOBOMB_BP_STYPE_GENERIC) {
    176         generic_bobomb_free_loop();
    177     } else {
    178         stationary_bobomb_free_loop();
    179     }
    180 }
    181 
    182 void bobomb_held_loop(void) {
    183     o->header.gfx.node.flags |= GRAPH_RENDER_INVISIBLE;
    184     cur_obj_init_animation(1);
    185     cur_obj_set_pos_relative(gMarioObject, 0, 60.0f, 100.0);
    186 
    187     o->oBobombFuseLit = 1;
    188     if (o->oBobombFuseTimer > 150) {
    189         //! Although the Bob-omb's action is set to explode when the fuse timer expires,
    190         //  bobomb_act_explode() will not execute until the bob-omb's held state changes.
    191         //  This allows the Bob-omb to be regrabbed indefinitely.
    192         gMarioObject->oInteractStatus |= INT_STATUS_MARIO_DROP_OBJECT;
    193         o->oAction = BOBOMB_ACT_EXPLODE;
    194     }
    195 }
    196 
    197 void bobomb_dropped_loop(void) {
    198     cur_obj_get_dropped();
    199 
    200     o->header.gfx.node.flags &= ~GRAPH_RENDER_INVISIBLE;
    201     cur_obj_init_animation(0);
    202 
    203     o->oHeldState = 0;
    204     o->oAction = BOBOMB_ACT_PATROL;
    205 }
    206 
    207 void bobomb_thrown_loop(void) {
    208     cur_obj_enable_rendering_2();
    209 
    210     o->header.gfx.node.flags &= ~GRAPH_RENDER_INVISIBLE;
    211     o->oHeldState = 0;
    212     o->oFlags &= ~OBJ_FLAG_SET_FACE_YAW_TO_MOVE_YAW;
    213     o->oForwardVel = 25.0f;
    214     o->oVelY = 20.0f;
    215     o->oAction = BOBOMB_ACT_LAUNCHED;
    216 }
    217 
    218 void curr_obj_random_blink(s32 *blinkTimer) {
    219     if (*blinkTimer == 0) {
    220         if ((s16)(random_float() * 100.0f) == 0) {
    221             o->oAnimState = 1;
    222             *blinkTimer = 1;
    223         }
    224     } else {
    225         (*blinkTimer)++;
    226 
    227         if (*blinkTimer > 5) {
    228             o->oAnimState = 0;
    229         }
    230 
    231         if (*blinkTimer > 10) {
    232             o->oAnimState = 1;
    233         }
    234 
    235         if (*blinkTimer > 15) {
    236             o->oAnimState = 0;
    237             *blinkTimer = 0;
    238         }
    239     }
    240 }
    241 
    242 void bhv_bobomb_loop(void) {
    243     s8 dustPeriodMinus1;
    244 
    245     if (is_point_within_radius_of_mario(o->oPosX, o->oPosY, o->oPosZ, 4000)) {
    246         switch (o->oHeldState) {
    247             case HELD_FREE:
    248                 bobomb_free_loop();
    249                 break;
    250 
    251             case HELD_HELD:
    252                 bobomb_held_loop();
    253                 break;
    254 
    255             case HELD_THROWN:
    256                 bobomb_thrown_loop();
    257                 break;
    258 
    259             case HELD_DROPPED:
    260                 bobomb_dropped_loop();
    261                 break;
    262         }
    263 
    264         curr_obj_random_blink(&o->oBobombBlinkTimer);
    265 
    266         if (o->oBobombFuseLit == 1) {
    267             if (o->oBobombFuseTimer > 120) {
    268                 dustPeriodMinus1 = 1;
    269             } else {
    270                 dustPeriodMinus1 = 7;
    271             }
    272 
    273             // oBobombFuseTimer % 2 or oBobombFuseTimer % 8
    274             if (!(dustPeriodMinus1 & o->oBobombFuseTimer)) {
    275                 spawn_object(o, MODEL_SMOKE, bhvBobombFuseSmoke);
    276             }
    277 
    278             cur_obj_play_sound_1(SOUND_AIR_BOBOMB_LIT_FUSE);
    279 
    280             o->oBobombFuseTimer++;
    281         }
    282     }
    283 }
    284 
    285 void bhv_bobomb_fuse_smoke_init(void) {
    286     o->oPosX += (s32)(random_float() * 80.0f) - 40;
    287     o->oPosY += (s32)(random_float() * 80.0f) + 60;
    288     o->oPosZ += (s32)(random_float() * 80.0f) - 40;
    289     cur_obj_scale(1.2f);
    290 }
    291 
    292 void bhv_bobomb_buddy_init(void) {
    293     o->oGravity = 2.5f;
    294     o->oFriction = 0.8f;
    295     o->oBuoyancy = 1.3f;
    296     o->oInteractionSubtype = INT_SUBTYPE_NPC;
    297 }
    298 
    299 void bobomb_buddy_act_idle(void) {
    300     UNUSED u8 filler[4];
    301     s16 animFrame = o->header.gfx.animInfo.animFrame;
    302     UNUSED s16 collisionFlags = 0;
    303 
    304     o->oBobombBuddyPosXCopy = o->oPosX;
    305     o->oBobombBuddyPosYCopy = o->oPosY;
    306     o->oBobombBuddyPosZCopy = o->oPosZ;
    307 
    308     collisionFlags = object_step();
    309 
    310     if (animFrame == 5 || animFrame == 16) {
    311         cur_obj_play_sound_2(SOUND_OBJ_BOBOMB_WALK);
    312     }
    313 
    314     if (o->oDistanceToMario < 1000.0f) {
    315         o->oMoveAngleYaw = approach_s16_symmetric(o->oMoveAngleYaw, o->oAngleToMario, 0x140);
    316     }
    317 
    318     if (o->oInteractStatus == INT_STATUS_INTERACTED) {
    319         o->oAction = BOBOMB_BUDDY_ACT_TURN_TO_TALK;
    320     }
    321 }
    322 
    323 /**
    324  * Function for the Bob-omb Buddy cannon guy.
    325  * dialogFirstText is the first dialogID called when Bob-omb Buddy
    326  * starts to talk to Mario to prepare the cannon(s) for him.
    327  * Then the camera goes to the nearest cannon, to play the "prepare cannon" cutscene
    328  * dialogSecondText is called after Bob-omb Buddy has the cannon(s) ready and
    329  * then tells Mario that is "Ready for blastoff".
    330  */
    331 void bobomb_buddy_cannon_dialog(s16 dialogFirstText, s16 dialogSecondText) {
    332     struct Object *cannonClosed;
    333     s16 buddyText, cutscene;
    334 
    335     switch (o->oBobombBuddyCannonStatus) {
    336         case BOBOMB_BUDDY_CANNON_UNOPENED:
    337             buddyText = cutscene_object_with_dialog(CUTSCENE_DIALOG, o, dialogFirstText);
    338             if (buddyText != DIALOG_RESPONSE_NONE) {
    339                 save_file_set_cannon_unlocked();
    340                 cannonClosed = cur_obj_nearest_object_with_behavior(bhvCannonClosed);
    341                 if (cannonClosed != NULL) {
    342                     o->oBobombBuddyCannonStatus = BOBOMB_BUDDY_CANNON_OPENING;
    343                 } else {
    344                     o->oBobombBuddyCannonStatus = BOBOMB_BUDDY_CANNON_STOP_TALKING;
    345                 }
    346             }
    347             break;
    348 
    349         case BOBOMB_BUDDY_CANNON_OPENING:
    350             cannonClosed = cur_obj_nearest_object_with_behavior(bhvCannonClosed);
    351             cutscene = cutscene_object(CUTSCENE_PREPARE_CANNON, cannonClosed);
    352             if (cutscene == -1) {
    353                 o->oBobombBuddyCannonStatus = BOBOMB_BUDDY_CANNON_OPENED;
    354             }
    355             break;
    356 
    357         case BOBOMB_BUDDY_CANNON_OPENED:
    358             buddyText = cutscene_object_with_dialog(CUTSCENE_DIALOG, o, dialogSecondText);
    359             if (buddyText != DIALOG_RESPONSE_NONE) {
    360                 o->oBobombBuddyCannonStatus = BOBOMB_BUDDY_CANNON_STOP_TALKING;
    361             }
    362             break;
    363 
    364         case BOBOMB_BUDDY_CANNON_STOP_TALKING:
    365             set_mario_npc_dialog(MARIO_DIALOG_STOP);
    366 
    367             o->activeFlags &= ~ACTIVE_FLAG_INITIATED_TIME_STOP;
    368             o->oBobombBuddyHasTalkedToMario = BOBOMB_BUDDY_HAS_TALKED;
    369             o->oInteractStatus = 0;
    370             o->oAction = BOBOMB_BUDDY_ACT_IDLE;
    371             o->oBobombBuddyCannonStatus = BOBOMB_BUDDY_CANNON_OPENED;
    372             break;
    373     }
    374 }
    375 
    376 void bobomb_buddy_act_talk(void) {
    377     if (set_mario_npc_dialog(MARIO_DIALOG_LOOK_FRONT) == MARIO_DIALOG_STATUS_SPEAK) {
    378         o->activeFlags |= ACTIVE_FLAG_INITIATED_TIME_STOP;
    379 
    380         switch (o->oBobombBuddyRole) {
    381             case BOBOMB_BUDDY_ROLE_ADVICE:
    382                 if (cutscene_object_with_dialog(CUTSCENE_DIALOG, o, o->oBhvParams2ndByte)
    383                     != BOBOMB_BUDDY_BP_STYPE_GENERIC) {
    384                     set_mario_npc_dialog(MARIO_DIALOG_STOP);
    385 
    386                     o->activeFlags &= ~ACTIVE_FLAG_INITIATED_TIME_STOP;
    387                     o->oBobombBuddyHasTalkedToMario = BOBOMB_BUDDY_HAS_TALKED;
    388                     o->oInteractStatus = 0;
    389                     o->oAction = BOBOMB_BUDDY_ACT_IDLE;
    390                 }
    391                 break;
    392 
    393             case BOBOMB_BUDDY_ROLE_CANNON:
    394                 if (gCurrCourseNum == COURSE_BOB) {
    395                     bobomb_buddy_cannon_dialog(DIALOG_004, DIALOG_105);
    396                 } else {
    397                     bobomb_buddy_cannon_dialog(DIALOG_047, DIALOG_106);
    398                 }
    399                 break;
    400         }
    401     }
    402 }
    403 
    404 void bobomb_buddy_act_turn_to_talk(void) {
    405     s16 animFrame = o->header.gfx.animInfo.animFrame;
    406 
    407     if (animFrame == 5 || animFrame == 16) {
    408         cur_obj_play_sound_2(SOUND_OBJ_BOBOMB_WALK);
    409     }
    410 
    411     o->oMoveAngleYaw = approach_s16_symmetric(o->oMoveAngleYaw, o->oAngleToMario, 0x1000);
    412 
    413     if ((s16) o->oMoveAngleYaw == (s16) o->oAngleToMario) {
    414         o->oAction = BOBOMB_BUDDY_ACT_TALK;
    415     }
    416 
    417     cur_obj_play_sound_2(SOUND_ACTION_READ_SIGN);
    418 }
    419 
    420 void bobomb_buddy_actions(void) {
    421     switch (o->oAction) {
    422         case BOBOMB_BUDDY_ACT_IDLE:
    423             bobomb_buddy_act_idle();
    424             break;
    425 
    426         case BOBOMB_BUDDY_ACT_TURN_TO_TALK:
    427             bobomb_buddy_act_turn_to_talk();
    428             break;
    429 
    430         case BOBOMB_BUDDY_ACT_TALK:
    431             bobomb_buddy_act_talk();
    432             break;
    433     }
    434 
    435     set_object_visibility(o, 3000);
    436 }
    437 
    438 void bhv_bobomb_buddy_loop(void) {
    439     bobomb_buddy_actions();
    440 
    441     curr_obj_random_blink(&o->oBobombBuddyBlinkTimer);
    442 
    443     o->oInteractStatus = 0;
    444 }