sm64coopdx/src/game/behaviors/boo.inc.c

1044 lines
28 KiB
C
Raw Normal View History

2019-08-25 04:46:40 +00:00
// boo.c.inc
2019-10-05 19:08:05 +00:00
static struct ObjectHitbox sBooGivingStarHitbox = {
/* interactType: */ 0,
/* downOffset: */ 0,
2019-08-25 04:46:40 +00:00
/* damageOrCoinValue: */ 3,
2019-10-05 19:08:05 +00:00
/* health: */ 3,
/* numLootCoins: */ 0,
/* radius: */ 140,
/* height: */ 80,
/* hurtboxRadius: */ 40,
/* hurtboxHeight: */ 60,
2019-08-25 04:46:40 +00:00
};
// Relative positions
2019-10-05 19:08:05 +00:00
static s16 sCourtyardBooTripletPositions[][3] = {
{0, 50, 0},
{210, 110, 210},
{-210, 70, -210}
};
2019-08-25 04:46:40 +00:00
static u8 boo_ignore_update(void) {
return (o->oHealth == 0);
}
struct SyncObject* boo_network_init_object(void) {
struct SyncObject* so = network_init_object(o, 4000.0f);
so->ignore_if_true = boo_ignore_update;
2020-08-25 04:38:49 +00:00
network_init_object_field(o, &o->oBooBaseScale);
network_init_object_field(o, &o->oBooNegatedAggressiveness);
network_init_object_field(o, &o->oBooOscillationTimer);
network_init_object_field(o, &o->oBooTargetOpacity);
network_init_object_field(o, &o->oBooTurningSpeed);
network_init_object_field(o, &o->oFaceAngleRoll);
network_init_object_field(o, &o->oFaceAngleYaw);
network_init_object_field(o, &o->oFlags);
network_init_object_field(o, &o->oForwardVel);
network_init_object_field(o, &o->oHealth);
network_init_object_field(o, &o->oInteractStatus);
network_init_object_field(o, &o->oInteractType);
network_init_object_field(o, &o->oOpacity);
network_init_object_field(o, &o->oRoom);
return so;
2020-08-25 04:38:49 +00:00
}
2019-10-05 19:08:05 +00:00
static void boo_stop(void) {
2019-08-25 04:46:40 +00:00
o->oForwardVel = 0.0f;
o->oVelY = 0.0f;
o->oGravity = 0.0f;
}
void bhv_boo_init(void) {
2019-10-05 19:08:05 +00:00
o->oBooInitialMoveYaw = o->oMoveAngleYaw;
2019-08-25 04:46:40 +00:00
}
2019-10-05 19:08:05 +00:00
static s32 boo_should_be_stopped(void) {
2020-03-02 03:42:52 +00:00
if (cur_obj_has_behavior(bhvMerryGoRoundBigBoo) || cur_obj_has_behavior(bhvMerryGoRoundBoo)) {
for (int i = 0; i < MAX_PLAYERS; i++) {
if (!is_player_active(&gMarioStates[i])) { continue; }
if (gMarioStates[i].currentRoom == BBH_DYNAMIC_SURFACE_ROOM || gMarioStates[i].currentRoom == BBH_NEAR_MERRY_GO_ROUND_ROOM) { return FALSE; }
}
return TRUE;
/*if (gMarioOnMerryGoRound == FALSE) {
2019-08-25 04:46:40 +00:00
return TRUE;
} else {
return FALSE;
}*/
2019-08-25 04:46:40 +00:00
} else {
if (o->activeFlags & ACTIVE_FLAG_IN_DIFFERENT_ROOM) {
return TRUE;
}
if (o->oRoom == 10) {
if (gTimeStopState & TIME_STOP_MARIO_OPENED_DOOR) {
return TRUE;
}
}
}
return FALSE;
}
2019-10-05 19:08:05 +00:00
static s32 boo_should_be_active(void) {
2020-08-25 04:38:49 +00:00
struct MarioState* marioState = nearest_mario_state_to_object(o);
int distanceToPlayer = dist_between_objects(o, marioState->marioObj);
u8 inRoom = FALSE;
for (int i = 0; i < MAX_PLAYERS; i++) {
if (!is_player_active(&gMarioStates[i])) { continue; }
if (gMarioStates[i].currentRoom == o->oRoom || gMarioStates[i].currentRoom == 0) { inRoom = TRUE; }
2020-08-25 04:38:49 +00:00
}
2019-08-25 04:46:40 +00:00
f32 activationRadius;
2020-03-02 03:42:52 +00:00
if (cur_obj_has_behavior(bhvBalconyBigBoo)) {
2019-08-25 04:46:40 +00:00
activationRadius = 5000.0f;
} else {
activationRadius = 1500.0f;
}
2020-03-02 03:42:52 +00:00
if (cur_obj_has_behavior(bhvMerryGoRoundBigBoo) || cur_obj_has_behavior(bhvMerryGoRoundBoo)) {
2019-08-25 04:46:40 +00:00
if (gMarioOnMerryGoRound == TRUE) {
return TRUE;
} else {
return FALSE;
}
} else if (o->oRoom == -1) {
2020-08-25 04:38:49 +00:00
if (distanceToPlayer < activationRadius) {
2019-08-25 04:46:40 +00:00
return TRUE;
}
} else if (!boo_should_be_stopped()) {
if (distanceToPlayer < activationRadius && inRoom) {
2019-08-25 04:46:40 +00:00
return TRUE;
}
}
return FALSE;
}
void bhv_courtyard_boo_triplet_init(void) {
s32 i;
struct Object *boo;
if (gHudDisplay.stars < 12) {
2020-03-02 03:42:52 +00:00
obj_mark_for_deletion(o);
2019-08-25 04:46:40 +00:00
} else {
for (i = 0; i < 3; i++) {
boo = spawn_object_relative(
2019-10-05 19:08:05 +00:00
0x01,
sCourtyardBooTripletPositions[i][0],
sCourtyardBooTripletPositions[i][1],
sCourtyardBooTripletPositions[i][2],
o,
MODEL_BOO,
bhvGhostHuntBoo
);
2019-08-25 04:46:40 +00:00
2020-04-03 18:57:26 +00:00
boo->oMoveAngleYaw = random_u16();
2019-08-25 04:46:40 +00:00
}
}
}
2019-10-05 19:08:05 +00:00
static void boo_approach_target_opacity_and_update_scale(void) {
2019-08-25 04:46:40 +00:00
f32 scale;
if (o->oBooTargetOpacity != o->oOpacity) {
if (o->oBooTargetOpacity > o->oOpacity) {
o->oOpacity += 20;
if (o->oBooTargetOpacity < o->oOpacity) {
o->oOpacity = o->oBooTargetOpacity;
}
} else {
o->oOpacity -= 20;
if (o->oBooTargetOpacity > o->oOpacity) {
o->oOpacity = o->oBooTargetOpacity;
}
}
}
2019-10-05 19:08:05 +00:00
scale = (o->oOpacity/255.0f * 0.4 + 0.6) * o->oBooBaseScale;
2020-03-02 03:42:52 +00:00
obj_scale(o, scale); // why no cur_obj_scale? was cur_obj_scale written later?
2019-08-25 04:46:40 +00:00
}
2019-10-05 19:08:05 +00:00
static void boo_oscillate(s32 ignoreOpacity) {
2019-08-25 04:46:40 +00:00
o->oFaceAnglePitch = sins(o->oBooOscillationTimer) * 0x400;
if (o->oOpacity == 0xFF || ignoreOpacity == TRUE) {
o->header.gfx.scale[0] = sins(o->oBooOscillationTimer) * 0.08 + o->oBooBaseScale;
o->header.gfx.scale[1] = -sins(o->oBooOscillationTimer) * 0.08 + o->oBooBaseScale;
o->header.gfx.scale[2] = o->header.gfx.scale[0];
o->oGravity = sins(o->oBooOscillationTimer) * o->oBooBaseScale;
o->oBooOscillationTimer += 0x400;
}
}
2019-10-05 19:08:05 +00:00
static s32 boo_vanish_or_appear(void) {
2020-08-25 04:38:49 +00:00
struct Object* player = nearest_player_to_object(o);
int angleToPlayer = obj_angle_to_object(o, player);
s16 relativeAngleToMario = abs_angle_diff(angleToPlayer, o->oMoveAngleYaw);
s16 relativeMarioFaceAngle = abs_angle_diff(o->oMoveAngleYaw, player->oFaceAngleYaw);
2019-08-25 04:46:40 +00:00
// magic?
s16 relativeAngleToMarioThreshhold = 0x1568;
s16 relativeMarioFaceAngleThreshhold = 0x6b58;
s32 doneAppearing = FALSE;
o->oVelY = 0.0f;
2020-08-25 04:38:49 +00:00
if (relativeAngleToMario > relativeAngleToMarioThreshhold || relativeMarioFaceAngle < relativeMarioFaceAngleThreshhold) {
2019-08-25 04:46:40 +00:00
if (o->oOpacity == 40) {
o->oBooTargetOpacity = 255;
2020-03-02 03:42:52 +00:00
cur_obj_play_sound_2(SOUND_OBJ_BOO_LAUGH_LONG);
2019-08-25 04:46:40 +00:00
}
if (o->oOpacity > 180) {
doneAppearing = TRUE;
}
} else if (o->oOpacity == 255) {
o->oBooTargetOpacity = 40;
}
return doneAppearing;
}
2019-10-05 19:08:05 +00:00
static void boo_set_move_yaw_for_during_hit(s32 hurt) {
2020-08-25 04:38:49 +00:00
struct Object* player = nearest_player_to_object(o);
int angleToPlayer = obj_angle_to_object(o, player);
2020-03-02 03:42:52 +00:00
cur_obj_become_intangible();
2019-08-25 04:46:40 +00:00
o->oFlags &= ~OBJ_FLAG_SET_FACE_YAW_TO_MOVE_YAW;
2019-10-05 19:08:05 +00:00
o->oBooMoveYawBeforeHit = (f32) o->oMoveAngleYaw;
2019-08-25 04:46:40 +00:00
2019-10-05 19:08:05 +00:00
if (hurt != FALSE) {
2020-08-25 04:38:49 +00:00
o->oBooMoveYawDuringHit = player->oMoveAngleYaw;
} else if (coss((s16)o->oMoveAngleYaw - (s16)angleToPlayer) < 0.0f) {
2019-10-05 19:08:05 +00:00
o->oBooMoveYawDuringHit = o->oMoveAngleYaw;
2019-08-25 04:46:40 +00:00
} else {
2019-10-05 19:08:05 +00:00
o->oBooMoveYawDuringHit = (s16)(o->oMoveAngleYaw + 0x8000);
2019-08-25 04:46:40 +00:00
}
}
2019-10-05 19:08:05 +00:00
static void boo_move_during_hit(s32 roll, f32 fVel) {
// Boos seem to have been supposed to oscillate up then down then back again
// when hit. However it seems the programmers forgot to scale the cosine,
// so the Y velocity goes from 1 to -1 and back to 1 over 32 frames.
// This is such a small change that the Y position only changes by 5 units.
// It's completely unnoticable in-game.
s32 oscillationVel = o->oTimer * 0x800 + 0x800;
2020-06-02 16:44:34 +00:00
2019-08-25 04:46:40 +00:00
o->oForwardVel = fVel;
2019-10-05 19:08:05 +00:00
o->oVelY = coss(oscillationVel);
o->oMoveAngleYaw = o->oBooMoveYawDuringHit;
2019-08-25 04:46:40 +00:00
if (roll != FALSE) {
2019-10-05 19:08:05 +00:00
o->oFaceAngleYaw += D_8032F0CC[o->oTimer];
2019-08-25 04:46:40 +00:00
o->oFaceAngleRoll += D_8032F0CC[o->oTimer];
}
}
2019-10-05 19:08:05 +00:00
static void big_boo_shake_after_hit(void) {
// Oscillate yaw
s32 oscillationVel = o->oTimer * 0x2000 - 0x3E000;
o->oFaceAngleYaw += coss(oscillationVel) * 0x400;
2019-08-25 04:46:40 +00:00
}
2019-10-05 19:08:05 +00:00
static void boo_reset_after_hit(void) {
o->oMoveAngleYaw = o->oBooMoveYawBeforeHit;
2019-08-25 04:46:40 +00:00
o->oFlags |= OBJ_FLAG_SET_FACE_YAW_TO_MOVE_YAW;
o->oInteractStatus = 0;
}
2019-10-05 19:08:05 +00:00
// called iff boo/big boo/cage boo is in action 2, which only occurs if it was non-attack-ly interacted with/bounced on?
static s32 boo_update_after_bounced_on(f32 a0) {
2019-08-25 04:46:40 +00:00
boo_stop();
if (o->oTimer == 0) {
2019-10-05 19:08:05 +00:00
boo_set_move_yaw_for_during_hit(FALSE);
2019-08-25 04:46:40 +00:00
}
if (o->oTimer < 32) {
2019-10-05 19:08:05 +00:00
boo_move_during_hit(FALSE, D_8032F0CC[o->oTimer]/5000.0f * a0);
2019-08-25 04:46:40 +00:00
} else {
2020-03-02 03:42:52 +00:00
cur_obj_become_tangible();
2019-10-05 19:08:05 +00:00
boo_reset_after_hit();
2019-08-25 04:46:40 +00:00
o->oAction = 1;
2019-10-05 19:08:05 +00:00
return TRUE;
2019-08-25 04:46:40 +00:00
}
2019-10-05 19:08:05 +00:00
return FALSE;
2019-08-25 04:46:40 +00:00
}
// called iff big boo nonlethally hit
2019-10-05 19:08:05 +00:00
static s32 big_boo_update_during_nonlethal_hit(f32 a0) {
2019-08-25 04:46:40 +00:00
boo_stop();
2020-06-02 16:44:34 +00:00
2019-10-05 19:08:05 +00:00
if (o->oTimer == 0) {
boo_set_move_yaw_for_during_hit(TRUE);
}
2020-06-02 16:44:34 +00:00
2019-10-05 19:08:05 +00:00
if (o->oTimer < 32) {
boo_move_during_hit(TRUE, D_8032F0CC[o->oTimer]/5000.0f * a0);
} else if (o->oTimer < 48) {
big_boo_shake_after_hit();
} else {
2020-03-02 03:42:52 +00:00
cur_obj_become_tangible();
2019-10-05 19:08:05 +00:00
boo_reset_after_hit();
2020-06-02 16:44:34 +00:00
2019-08-25 04:46:40 +00:00
o->oAction = 1;
2020-06-02 16:44:34 +00:00
2019-10-05 19:08:05 +00:00
return TRUE;
2019-08-25 04:46:40 +00:00
}
2020-06-02 16:44:34 +00:00
2019-10-05 19:08:05 +00:00
return FALSE;
2019-08-25 04:46:40 +00:00
}
2019-10-05 19:08:05 +00:00
// called every frame once mario lethally hits the boo until the boo is deleted,
// returns whether death is complete
static s32 boo_update_during_death(void) {
2020-08-25 04:38:49 +00:00
struct Object* player = nearest_player_to_object(o);
2019-08-25 04:46:40 +00:00
struct Object *parentBigBoo;
if (o->oTimer == 0) {
o->oForwardVel = 40.0f;
2020-08-25 04:38:49 +00:00
o->oMoveAngleYaw = player->oMoveAngleYaw;
2019-08-25 04:46:40 +00:00
o->oBooDeathStatus = BOO_DEATH_STATUS_DYING;
2019-10-05 19:08:05 +00:00
o->oFlags &= ~OBJ_FLAG_SET_FACE_YAW_TO_MOVE_YAW;
2019-08-25 04:46:40 +00:00
} else {
if (o->oTimer == 5) {
o->oBooTargetOpacity = 0;
}
2020-07-04 15:18:55 +00:00
if (o->oTimer > 30 || o->oMoveFlags & OBJ_MOVE_HIT_WALL) {
2020-03-02 03:42:52 +00:00
spawn_mist_particles();
2019-08-25 04:46:40 +00:00
o->oBooDeathStatus = BOO_DEATH_STATUS_DEAD;
2019-10-05 19:08:05 +00:00
2019-08-25 04:46:40 +00:00
if (o->oBooParentBigBoo != NULL) {
parentBigBoo = o->oBooParentBigBoo;
2020-06-02 16:44:34 +00:00
2019-10-05 19:08:05 +00:00
#ifndef VERSION_JP
if (!cur_obj_has_behavior(bhvBoo)) {
2020-08-25 04:38:49 +00:00
parentBigBoo->oBigBooNumMinionBoosKilled++;
}
#else
parentBigBoo->oBigBooNumMinionBoosKilled++;
#endif
2019-10-05 19:08:05 +00:00
}
2020-06-02 16:44:34 +00:00
2019-08-25 04:46:40 +00:00
return TRUE;
}
}
o->oVelY = 5.0f;
o->oFaceAngleRoll += 0x800;
o->oFaceAngleYaw += 0x800;
return FALSE;
}
2019-10-05 19:08:05 +00:00
static s32 obj_has_attack_type(u32 attackType) {
2019-08-25 04:46:40 +00:00
if ((o->oInteractStatus & INT_STATUS_ATTACK_MASK) == attackType) {
return TRUE;
} else {
return FALSE;
}
}
2019-10-05 19:08:05 +00:00
static s32 boo_get_attack_status(void) {
s32 attackStatus = BOO_NOT_ATTACKED;
2020-06-02 16:44:34 +00:00
2019-08-25 04:46:40 +00:00
if (o->oInteractStatus & INT_STATUS_INTERACTED) {
2019-10-05 19:08:05 +00:00
if ((o->oInteractStatus & INT_STATUS_WAS_ATTACKED) && obj_has_attack_type(ATTACK_FROM_ABOVE) == FALSE) {
2020-03-02 03:42:52 +00:00
cur_obj_become_intangible();
2020-06-02 16:44:34 +00:00
2019-08-25 04:46:40 +00:00
o->oInteractStatus = 0;
2020-06-02 16:44:34 +00:00
2020-03-02 03:42:52 +00:00
cur_obj_play_sound_2(SOUND_OBJ_BOO_LAUGH_SHORT);
2020-06-02 16:44:34 +00:00
2019-10-05 19:08:05 +00:00
attackStatus = BOO_ATTACKED;
2019-08-25 04:46:40 +00:00
} else {
2020-03-02 03:42:52 +00:00
cur_obj_play_sound_2(SOUND_OBJ_BOO_BOUNCE_TOP);
2020-06-02 16:44:34 +00:00
2019-08-25 04:46:40 +00:00
o->oInteractStatus = 0;
2020-06-02 16:44:34 +00:00
2019-10-05 19:08:05 +00:00
attackStatus = BOO_BOUNCED_ON;
2019-08-25 04:46:40 +00:00
}
}
2020-06-02 16:44:34 +00:00
2019-10-05 19:08:05 +00:00
return attackStatus;
2019-08-25 04:46:40 +00:00
}
// boo idle/chasing movement?
2019-10-05 19:08:05 +00:00
static void boo_chase_mario(f32 a0, s16 a1, f32 a2) {
2020-08-25 04:38:49 +00:00
struct MarioState* marioState = nearest_mario_state_to_object(o);
struct Object* player = marioState->marioObj;
int angleToPlayer = obj_angle_to_object(o, player);
2019-08-25 04:46:40 +00:00
f32 sp1C;
s16 sp1A;
2020-06-02 16:44:34 +00:00
2019-10-05 19:08:05 +00:00
if (boo_vanish_or_appear()) {
2019-08-25 04:46:40 +00:00
o->oInteractType = 0x8000;
2020-06-02 16:44:34 +00:00
u8 isMerryGoRoundBoo = (cur_obj_has_behavior(bhvMerryGoRoundBigBoo) || cur_obj_has_behavior(bhvMerryGoRoundBoo));
if (!isMerryGoRoundBoo && cur_obj_lateral_dist_from_obj_to_home(player) > 1500.0f) {
2020-03-02 03:42:52 +00:00
sp1A = cur_obj_angle_to_home();
2019-10-05 19:08:05 +00:00
} else {
2020-08-25 04:38:49 +00:00
sp1A = angleToPlayer;
2019-10-05 19:08:05 +00:00
}
2020-06-02 16:44:34 +00:00
2020-03-02 03:42:52 +00:00
cur_obj_rotate_yaw_toward(sp1A, a1);
2019-08-25 04:46:40 +00:00
o->oVelY = 0.0f;
2020-06-02 16:44:34 +00:00
2020-08-25 04:38:49 +00:00
if (mario_is_in_air_action(marioState) == 0) {
sp1C = o->oPosY - player->oPosY;
2019-10-05 19:08:05 +00:00
if (a0 < sp1C && sp1C < 500.0f) {
2020-08-25 04:38:49 +00:00
o->oVelY = increment_velocity_toward_range(o->oPosY, player->oPosY + 50.0f, 10.f, 2.0f);
2019-10-05 19:08:05 +00:00
}
2019-08-25 04:46:40 +00:00
}
2020-06-02 16:44:34 +00:00
2020-08-25 04:38:49 +00:00
cur_obj_set_vel_from_mario_vel(marioState, 10.0f - o->oBooNegatedAggressiveness, a2);
2020-06-02 16:44:34 +00:00
2019-10-05 19:08:05 +00:00
if (o->oForwardVel != 0.0f) {
2019-08-25 04:46:40 +00:00
boo_oscillate(FALSE);
2019-10-05 19:08:05 +00:00
}
2019-08-25 04:46:40 +00:00
} else {
o->oInteractType = 0;
2019-10-05 19:08:05 +00:00
// why is boo_stop not used here
2019-08-25 04:46:40 +00:00
o->oForwardVel = 0.0f;
o->oVelY = 0.0f;
o->oGravity = 0.0f;
}
}
2020-03-02 03:42:52 +00:00
static void boo_act_0(void) {
2019-10-05 19:08:05 +00:00
o->activeFlags |= ACTIVE_FLAG_MOVE_THROUGH_GRATE;
2020-06-02 16:44:34 +00:00
2019-10-05 19:08:05 +00:00
if (o->oBehParams2ndByte == 2) {
2019-08-25 04:46:40 +00:00
o->oRoom = 10;
2019-10-05 19:08:05 +00:00
}
2020-06-02 16:44:34 +00:00
2020-03-02 03:42:52 +00:00
cur_obj_set_pos_to_home();
2019-10-05 19:08:05 +00:00
o->oMoveAngleYaw = o->oBooInitialMoveYaw;
2019-08-25 04:46:40 +00:00
boo_stop();
2020-06-02 16:44:34 +00:00
2020-03-02 03:42:52 +00:00
o->oBooParentBigBoo = cur_obj_nearest_object_with_behavior(bhvGhostHuntBigBoo);
2019-08-25 04:46:40 +00:00
o->oBooBaseScale = 1.0f;
o->oBooTargetOpacity = 0xFF;
2020-06-02 16:44:34 +00:00
2019-08-25 04:46:40 +00:00
if (boo_should_be_active()) {
// Condition is met if the object is bhvBalconyBigBoo or bhvMerryGoRoundBoo
if (o->oBehParams2ndByte == 2) {
o->oBooParentBigBoo = NULL;
o->oAction = 5;
2019-10-05 19:08:05 +00:00
} else {
2019-08-25 04:46:40 +00:00
o->oAction = 1;
2019-10-05 19:08:05 +00:00
}
2019-08-25 04:46:40 +00:00
}
}
2020-03-02 03:42:52 +00:00
static void boo_act_5(void) {
2019-08-25 04:46:40 +00:00
if (o->oTimer < 30) {
o->oVelY = 0.0f;
o->oForwardVel = 13.0f;
boo_oscillate(FALSE);
o->oWallHitboxRadius = 0.0f;
} else {
o->oAction = 1;
o->oWallHitboxRadius = 30.0f;
}
}
2020-03-02 03:42:52 +00:00
static void boo_act_1(void) {
2019-10-05 19:08:05 +00:00
s32 attackStatus;
2020-06-02 16:44:34 +00:00
2019-08-25 04:46:40 +00:00
if (o->oTimer == 0) {
2020-04-03 18:57:26 +00:00
o->oBooNegatedAggressiveness = -random_float() * 5.0f;
o->oBooTurningSpeed = (s32)(random_float() * 128.0f);
2019-08-25 04:46:40 +00:00
}
2020-06-02 16:44:34 +00:00
2019-10-05 19:08:05 +00:00
boo_chase_mario(-100.0f, o->oBooTurningSpeed + 0x180, 0.5f);
attackStatus = boo_get_attack_status();
2020-06-02 16:44:34 +00:00
2019-10-05 19:08:05 +00:00
if (boo_should_be_stopped()) {
2019-08-25 04:46:40 +00:00
o->oAction = 0;
2019-10-05 19:08:05 +00:00
}
2020-06-02 16:44:34 +00:00
2019-10-05 19:08:05 +00:00
if (attackStatus == BOO_BOUNCED_ON) {
2019-08-25 04:46:40 +00:00
o->oAction = 2;
2019-10-05 19:08:05 +00:00
}
2020-06-02 16:44:34 +00:00
2019-10-05 19:08:05 +00:00
if (attackStatus == BOO_ATTACKED) {
2019-08-25 04:46:40 +00:00
o->oAction = 3;
2019-10-05 19:08:05 +00:00
}
2020-06-02 16:44:34 +00:00
2019-10-05 19:08:05 +00:00
if (attackStatus == BOO_ATTACKED) {
create_sound_spawner(SOUND_OBJ_DYING_ENEMY1);
}
2019-08-25 04:46:40 +00:00
}
2020-03-02 03:42:52 +00:00
static void boo_act_2(void) {
2019-10-05 19:08:05 +00:00
if (boo_update_after_bounced_on(20.0f)) {
2019-08-25 04:46:40 +00:00
o->oAction = 1;
2019-10-05 19:08:05 +00:00
}
2019-08-25 04:46:40 +00:00
}
2020-03-02 03:42:52 +00:00
static void boo_act_3(void) {
2019-10-05 19:08:05 +00:00
if (boo_update_during_death()) {
if (o->oBehParams2ndByte != 0) {
2020-03-02 03:42:52 +00:00
obj_mark_for_deletion(o);
2019-10-05 19:08:05 +00:00
} else {
2019-08-25 04:46:40 +00:00
o->oAction = 4;
2020-03-02 03:42:52 +00:00
cur_obj_disable();
2019-08-25 04:46:40 +00:00
}
}
}
u8 boo_act_4_continue_dialog(void) { return o->oAction == 4; }
2019-08-25 04:46:40 +00:00
// Called when a Go on a Ghost Hunt boo dies
2020-03-02 03:42:52 +00:00
static void boo_act_4(void) {
2019-08-25 04:46:40 +00:00
s32 dialogID;
// If there are no remaining "minion" boos, show the dialog of the Big Boo
2020-03-02 03:42:52 +00:00
if (cur_obj_nearest_object_with_behavior(bhvGhostHuntBoo) == NULL) {
2019-12-02 02:52:53 +00:00
dialogID = DIALOG_108;
2019-10-05 19:08:05 +00:00
} else {
2019-12-02 02:52:53 +00:00
dialogID = DIALOG_107;
2019-10-05 19:08:05 +00:00
}
2019-08-25 04:46:40 +00:00
2020-08-25 04:38:49 +00:00
struct MarioState* marioState = nearest_mario_state_to_object(o);
if (marioState->playerIndex != 0 || cur_obj_update_dialog(&gMarioStates[0], 2, 2, dialogID, 0, boo_act_4_continue_dialog)) {
2019-10-05 19:08:05 +00:00
create_sound_spawner(SOUND_OBJ_DYING_ENEMY1);
2020-03-02 03:42:52 +00:00
obj_mark_for_deletion(o);
2020-06-02 16:44:34 +00:00
2019-12-02 02:52:53 +00:00
if (dialogID == DIALOG_108) { // If the Big Boo should spawn, play the jingle
2019-08-25 04:46:40 +00:00
play_puzzle_jingle();
2019-10-05 19:08:05 +00:00
}
2019-08-25 04:46:40 +00:00
}
}
2019-10-05 19:08:05 +00:00
static void (*sBooActions[])(void) = {
2020-03-02 03:42:52 +00:00
boo_act_0,
boo_act_1,
boo_act_2,
boo_act_3,
boo_act_4,
boo_act_5
2019-08-25 04:46:40 +00:00
};
void bhv_boo_loop(void) {
if (o->oAction < 3) {
if (!network_sync_object_initialized(o)) {
struct SyncObject* so = boo_network_init_object();
so->syncDeathEvent = FALSE;
}
}
else {
if (network_sync_object_initialized(o)) {
network_send_object_reliability(o, TRUE);
network_forget_sync_object(&gSyncObjects[o->oSyncID]);
}
}
2019-10-05 19:08:05 +00:00
//PARTIAL_UPDATE
2020-06-02 16:44:34 +00:00
2020-03-02 03:42:52 +00:00
cur_obj_update_floor_and_walls();
cur_obj_call_action_function(sBooActions);
cur_obj_move_standard(78);
2019-08-25 04:46:40 +00:00
boo_approach_target_opacity_and_update_scale();
2020-06-02 16:44:34 +00:00
2020-03-02 03:42:52 +00:00
if (obj_has_behavior(o->parentObj, bhvMerryGoRoundBooManager)) {
2020-06-02 16:44:34 +00:00
if (o->activeFlags == ACTIVE_FLAG_DEACTIVATED) {
2019-10-05 19:08:05 +00:00
o->parentObj->oMerryGoRoundBooManagerNumBoosKilled++;
}
2019-08-25 04:46:40 +00:00
}
2020-06-02 16:44:34 +00:00
2019-08-25 04:46:40 +00:00
o->oInteractStatus = 0;
}
static u8 bigBooActivated = FALSE;
2020-03-02 03:42:52 +00:00
static void big_boo_act_0(void) {
if (cur_obj_has_behavior(bhvBalconyBigBoo)) {
2019-10-05 19:08:05 +00:00
obj_set_secondary_camera_focus();
2019-08-25 04:46:40 +00:00
// number of killed boos set > 5 so that boo always loads
// redundant? this is also done in behavior_data.s
o->oBigBooNumMinionBoosKilled = 10;
}
2020-06-02 16:44:34 +00:00
2019-08-25 04:46:40 +00:00
o->oBooParentBigBoo = NULL;
2020-06-02 16:44:34 +00:00
2019-08-25 04:46:40 +00:00
#ifndef VERSION_JP
2019-10-05 19:08:05 +00:00
if (boo_should_be_active() && gDebugInfo[5][0] + 5 <= o->oBigBooNumMinionBoosKilled) {
2019-08-25 04:46:40 +00:00
#else
2019-10-05 19:08:05 +00:00
if (boo_should_be_active() && o->oBigBooNumMinionBoosKilled >= 5) {
2019-08-25 04:46:40 +00:00
#endif
o->oAction = 1;
bigBooActivated = TRUE;
2020-06-02 16:44:34 +00:00
2020-03-02 03:42:52 +00:00
cur_obj_set_pos_to_home();
2019-10-05 19:08:05 +00:00
o->oMoveAngleYaw = o->oBooInitialMoveYaw;
2020-06-02 16:44:34 +00:00
2020-03-02 03:42:52 +00:00
cur_obj_unhide();
2020-06-02 16:44:34 +00:00
2019-08-25 04:46:40 +00:00
o->oBooTargetOpacity = 0xFF;
o->oBooBaseScale = 3.0f;
o->oHealth = 3;
2020-06-02 16:44:34 +00:00
2020-03-02 03:42:52 +00:00
cur_obj_scale(3.0f);
cur_obj_become_tangible();
2019-08-25 04:46:40 +00:00
} else {
2020-03-02 03:42:52 +00:00
cur_obj_hide();
cur_obj_become_intangible();
2019-08-25 04:46:40 +00:00
boo_stop();
}
}
2020-03-02 03:42:52 +00:00
static void big_boo_act_1(void) {
2019-10-05 19:08:05 +00:00
s32 attackStatus;
2019-08-25 04:46:40 +00:00
s16 sp22;
f32 sp1C;
2020-06-02 16:44:34 +00:00
2019-08-25 04:46:40 +00:00
if (o->oHealth == 3) {
2020-02-03 05:51:26 +00:00
sp22 = 0x180; sp1C = 0.5f;
2019-08-25 04:46:40 +00:00
} else if (o->oHealth == 2) {
2020-02-03 05:51:26 +00:00
sp22 = 0x240; sp1C = 0.6f;
2019-08-25 04:46:40 +00:00
} else {
2020-02-03 05:51:26 +00:00
sp22 = 0x300; sp1C = 0.8f;
2019-08-25 04:46:40 +00:00
}
2020-06-02 16:44:34 +00:00
2019-10-05 19:08:05 +00:00
boo_chase_mario(-100.0f, sp22, sp1C);
2020-06-02 16:44:34 +00:00
2019-10-05 19:08:05 +00:00
attackStatus = boo_get_attack_status();
2020-06-02 16:44:34 +00:00
2019-10-05 19:08:05 +00:00
// redundant; this check is in boo_should_be_stopped
2020-03-02 03:42:52 +00:00
if (cur_obj_has_behavior(bhvMerryGoRoundBigBoo)) {
u8 inRoom = FALSE;
for (int i = 0; i < MAX_PLAYERS; i++) {
if (!is_player_active(&gMarioStates[i])) { continue; }
if (gMarioStates[i].currentRoom == BBH_DYNAMIC_SURFACE_ROOM || gMarioStates[i].currentRoom == BBH_NEAR_MERRY_GO_ROUND_ROOM) { inRoom = TRUE; }
}
//if (gMarioOnMerryGoRound == FALSE) {
if (!inRoom) {
2019-08-25 04:46:40 +00:00
o->oAction = 0;
2019-10-05 19:08:05 +00:00
}
} else if (boo_should_be_stopped()) {
2019-08-25 04:46:40 +00:00
o->oAction = 0;
2019-10-05 19:08:05 +00:00
}
2020-06-02 16:44:34 +00:00
2019-10-05 19:08:05 +00:00
if (attackStatus == BOO_BOUNCED_ON) {
2019-08-25 04:46:40 +00:00
o->oAction = 2;
2019-10-05 19:08:05 +00:00
}
2020-06-02 16:44:34 +00:00
2019-10-05 19:08:05 +00:00
if (attackStatus == BOO_ATTACKED) {
2019-08-25 04:46:40 +00:00
o->oAction = 3;
2019-10-05 19:08:05 +00:00
}
2020-06-02 16:44:34 +00:00
2019-10-05 19:08:05 +00:00
if (attackStatus == 1) {
create_sound_spawner(SOUND_OBJ_THWOMP);
}
2019-08-25 04:46:40 +00:00
}
2020-03-02 03:42:52 +00:00
static void big_boo_act_2(void) {
2019-10-05 19:08:05 +00:00
if (boo_update_after_bounced_on(20.0f)) {
2019-08-25 04:46:40 +00:00
o->oAction = 1;
2019-10-05 19:08:05 +00:00
}
2019-08-25 04:46:40 +00:00
}
2019-10-05 19:08:05 +00:00
static void big_boo_spawn_ghost_hunt_star(void) {
2020-03-02 03:42:52 +00:00
spawn_default_star(980.0f, 1100.0f, 250.0f);
2019-08-25 04:46:40 +00:00
}
2019-10-05 19:08:05 +00:00
static void big_boo_spawn_balcony_star(void) {
2020-03-02 03:42:52 +00:00
spawn_default_star(700.0f, 3200.0f, 1900.0f);
2019-08-25 04:46:40 +00:00
}
2019-10-05 19:08:05 +00:00
static void big_boo_spawn_merry_go_round_star(void) {
2019-08-25 04:46:40 +00:00
struct Object *merryGoRound;
2020-03-02 03:42:52 +00:00
spawn_default_star(-1600.0f, -2100.0f, 205.0f);
2019-08-25 04:46:40 +00:00
2020-03-02 03:42:52 +00:00
merryGoRound = cur_obj_nearest_object_with_behavior(bhvMerryGoRound);
2019-08-25 04:46:40 +00:00
2019-10-05 19:08:05 +00:00
if (merryGoRound != NULL) {
2019-08-25 04:46:40 +00:00
merryGoRound->oMerryGoRoundStopped = TRUE;
2019-10-05 19:08:05 +00:00
}
2019-08-25 04:46:40 +00:00
}
2020-03-02 03:42:52 +00:00
static void big_boo_act_3(void) {
2019-10-05 19:08:05 +00:00
if (o->oTimer == 0) {
2019-08-25 04:46:40 +00:00
o->oHealth--;
2019-10-05 19:08:05 +00:00
}
2020-06-02 16:44:34 +00:00
if (o->oHealth <= 0) {
2019-10-05 19:08:05 +00:00
if (boo_update_during_death()) {
2020-03-02 03:42:52 +00:00
cur_obj_disable();
2020-06-02 16:44:34 +00:00
2019-08-25 04:46:40 +00:00
o->oAction = 4;
2020-06-02 16:44:34 +00:00
2020-03-02 03:42:52 +00:00
obj_set_angle(o, 0, 0, 0);
2020-06-02 16:44:34 +00:00
2019-10-05 19:08:05 +00:00
if (o->oBehParams2ndByte == 0) {
big_boo_spawn_ghost_hunt_star();
} else if (o->oBehParams2ndByte == 1) {
big_boo_spawn_merry_go_round_star();
} else {
big_boo_spawn_balcony_star();
}
2019-08-25 04:46:40 +00:00
}
} else {
if (o->oTimer == 0) {
2020-03-02 03:42:52 +00:00
spawn_mist_particles();
2019-08-25 04:46:40 +00:00
o->oBooBaseScale -= 0.5;
}
2020-06-02 16:44:34 +00:00
2019-10-05 19:08:05 +00:00
if (big_boo_update_during_nonlethal_hit(40.0f)) {
2019-08-25 04:46:40 +00:00
o->oAction = 1;
2019-10-05 19:08:05 +00:00
}
2019-08-25 04:46:40 +00:00
}
}
2020-03-02 03:42:52 +00:00
static void big_boo_act_4(void) {
2019-08-25 04:46:40 +00:00
#ifndef VERSION_JP
boo_stop();
#endif
2020-06-02 16:44:34 +00:00
2020-08-25 04:38:49 +00:00
struct Object* player = nearest_player_to_object(o);
int distanceToPlayer = dist_between_objects(o, player);
2019-08-25 04:46:40 +00:00
if (o->oBehParams2ndByte == 0) {
2020-03-02 03:42:52 +00:00
obj_set_pos(o, 973, 0, 626);
2020-06-02 16:44:34 +00:00
2020-08-25 04:38:49 +00:00
if (o->oTimer > 60 && distanceToPlayer < 600.0f) {
2020-03-02 03:42:52 +00:00
obj_set_pos(o, 973, 0, 717);
2020-06-02 16:44:34 +00:00
2019-10-05 19:08:05 +00:00
spawn_object_relative(0, 0, 0, 0, o, MODEL_BBH_STAIRCASE_STEP, bhvBooBossSpawnedBridge);
2019-08-25 04:46:40 +00:00
spawn_object_relative(1, 0, 0, -200, o, MODEL_BBH_STAIRCASE_STEP, bhvBooBossSpawnedBridge);
2019-10-05 19:08:05 +00:00
spawn_object_relative(2, 0, 0, 200, o, MODEL_BBH_STAIRCASE_STEP, bhvBooBossSpawnedBridge);
2020-06-02 16:44:34 +00:00
2020-03-02 03:42:52 +00:00
obj_mark_for_deletion(o);
2019-08-25 04:46:40 +00:00
}
2019-10-05 19:08:05 +00:00
} else {
2020-03-02 03:42:52 +00:00
obj_mark_for_deletion(o);
2019-10-05 19:08:05 +00:00
}
2019-08-25 04:46:40 +00:00
}
2019-10-05 19:08:05 +00:00
static void (*sBooGivingStarActions[])(void) = {
2020-03-02 03:42:52 +00:00
big_boo_act_0,
big_boo_act_1,
big_boo_act_2,
big_boo_act_3,
big_boo_act_4
2019-10-05 19:08:05 +00:00
};
2019-08-25 04:46:40 +00:00
u8 big_boo_ignore_update(void) {
return o->oHealth == 0 || (cur_obj_has_behavior(bhvGhostHuntBigBoo) && !bigBooActivated);
}
2019-08-25 04:46:40 +00:00
void bhv_big_boo_loop(void) {
if (o->oAction == 0) {
if (!network_sync_object_initialized(o)) {
bigBooActivated = FALSE;
struct SyncObject* so = boo_network_init_object();
so->syncDeathEvent = FALSE;
so->ignore_if_true = big_boo_ignore_update;
}
} else if (o->oHealth <= 0) {
if (network_sync_object_initialized(o)) {
network_send_object_reliability(o, TRUE);
network_forget_sync_object(&gSyncObjects[o->oSyncID]);
}
}
2019-10-05 19:08:05 +00:00
//PARTIAL_UPDATE
2020-06-02 16:44:34 +00:00
2020-03-02 03:42:52 +00:00
obj_set_hitbox(o, &sBooGivingStarHitbox);
2020-06-02 16:44:34 +00:00
2019-08-25 04:46:40 +00:00
o->oGraphYOffset = o->oBooBaseScale * 60.0f;
2020-06-02 16:44:34 +00:00
2020-03-02 03:42:52 +00:00
cur_obj_update_floor_and_walls();
cur_obj_call_action_function(sBooGivingStarActions);
cur_obj_move_standard(78);
2020-06-02 16:44:34 +00:00
2019-08-25 04:46:40 +00:00
boo_approach_target_opacity_and_update_scale();
o->oInteractStatus = 0;
}
2020-03-02 03:42:52 +00:00
static void boo_with_cage_act_0(void) {
2019-08-25 04:46:40 +00:00
o->oBooParentBigBoo = NULL;
o->oBooTargetOpacity = 0xFF;
o->oBooBaseScale = 2.0f;
2020-06-02 16:44:34 +00:00
2020-03-02 03:42:52 +00:00
cur_obj_scale(2.0f);
cur_obj_become_tangible();
2020-06-02 16:44:34 +00:00
2019-10-05 19:08:05 +00:00
if (boo_should_be_active()) {
2019-08-25 04:46:40 +00:00
o->oAction = 1;
2019-10-05 19:08:05 +00:00
}
2019-08-25 04:46:40 +00:00
}
2020-03-02 03:42:52 +00:00
static void boo_with_cage_act_1(void) {
2019-10-05 19:08:05 +00:00
s32 attackStatus;
2019-08-25 04:46:40 +00:00
2019-10-05 19:08:05 +00:00
boo_chase_mario(100.0f, 512, 0.5f);
2020-06-02 16:44:34 +00:00
2019-10-05 19:08:05 +00:00
attackStatus = boo_get_attack_status();
2020-06-02 16:44:34 +00:00
2019-10-05 19:08:05 +00:00
if (boo_should_be_stopped()) {
2019-08-25 04:46:40 +00:00
o->oAction = 0;
2019-10-05 19:08:05 +00:00
}
2020-06-02 16:44:34 +00:00
2019-10-05 19:08:05 +00:00
if (attackStatus == BOO_BOUNCED_ON) {
2019-08-25 04:46:40 +00:00
o->oAction = 2;
2019-10-05 19:08:05 +00:00
}
2020-06-02 16:44:34 +00:00
2019-10-05 19:08:05 +00:00
if (attackStatus == BOO_ATTACKED) {
2019-08-25 04:46:40 +00:00
o->oAction = 3;
2019-10-05 19:08:05 +00:00
}
2019-08-25 04:46:40 +00:00
}
2020-03-02 03:42:52 +00:00
static void boo_with_cage_act_2(void) {
2019-10-05 19:08:05 +00:00
if (boo_update_after_bounced_on(20.0f)) {
2019-08-25 04:46:40 +00:00
o->oAction = 1;
2019-10-05 19:08:05 +00:00
}
2019-08-25 04:46:40 +00:00
}
2020-03-02 03:42:52 +00:00
static void boo_with_cage_act_3(void) {
2019-10-05 19:08:05 +00:00
if (boo_update_during_death()) {
2020-03-02 03:42:52 +00:00
obj_mark_for_deletion(o);
2019-10-05 19:08:05 +00:00
}
2019-08-25 04:46:40 +00:00
}
void bhv_boo_with_cage_init(void) {
2019-10-05 19:08:05 +00:00
struct Object* cage;
2020-06-02 16:44:34 +00:00
2019-10-05 19:08:05 +00:00
if (gHudDisplay.stars < 12) {
2020-03-02 03:42:52 +00:00
obj_mark_for_deletion(o);
2019-10-05 19:08:05 +00:00
} else {
2019-08-25 04:46:40 +00:00
cage = spawn_object(o, MODEL_HAUNTED_CAGE, bhvBooCage);
cage->oBehParams = o->oBehParams;
}
}
2019-10-05 19:08:05 +00:00
static void (*sBooWithCageActions[])(void) = {
2020-03-02 03:42:52 +00:00
boo_with_cage_act_0,
boo_with_cage_act_1,
boo_with_cage_act_2,
boo_with_cage_act_3
2019-10-05 19:08:05 +00:00
};
2019-08-25 04:46:40 +00:00
2020-08-25 04:38:49 +00:00
void bhv_boo_with_cage_loop(void) {
if (!network_sync_object_initialized(o)) { boo_network_init_object(); }
2019-10-05 19:08:05 +00:00
//PARTIAL_UPDATE
2020-06-02 16:44:34 +00:00
2020-03-02 03:42:52 +00:00
cur_obj_update_floor_and_walls();
cur_obj_call_action_function(sBooWithCageActions);
cur_obj_move_standard(78);
2019-08-25 04:46:40 +00:00
boo_approach_target_opacity_and_update_scale();
o->oInteractStatus = 0;
}
void bhv_merry_go_round_boo_manager_loop(void) {
2020-08-25 04:38:49 +00:00
if (!network_sync_object_initialized(o)) {
network_init_object(o, SYNC_DISTANCE_ONLY_EVENTS);
network_init_object_field(o, &o->oAction);
network_init_object_field(o, &o->oMerryGoRoundBooManagerNumBoosSpawned);
}
struct Object* player = nearest_player_to_object(o);
int distanceToPlayer = dist_between_objects(o, player);
2019-08-25 04:46:40 +00:00
switch (o->oAction) {
case 0:
2020-08-25 04:38:49 +00:00
if (distanceToPlayer < 1000.0f) {
if (gNetworkType == NT_SERVER && o->oMerryGoRoundBooManagerNumBoosKilled < 5) {
2020-08-25 04:38:49 +00:00
if (o->oMerryGoRoundBooManagerNumBoosSpawned < 5) {
2019-10-05 19:08:05 +00:00
if (o->oMerryGoRoundBooManagerNumBoosSpawned - o->oMerryGoRoundBooManagerNumBoosKilled < 2) {
2020-08-25 04:38:49 +00:00
struct Object* boo = spawn_object(o, MODEL_BOO, bhvMerryGoRoundBoo);
network_set_sync_id(boo);
struct Object* spawn_objects[] = { boo };
u32 models[] = { MODEL_BOO };
network_send_spawn_objects(spawn_objects, models, 1);
2019-10-05 19:08:05 +00:00
o->oMerryGoRoundBooManagerNumBoosSpawned++;
2020-08-25 04:38:49 +00:00
network_send_object(o);
2019-08-25 04:46:40 +00:00
}
}
2020-06-02 16:44:34 +00:00
2019-08-25 04:46:40 +00:00
o->oAction++;
}
2020-06-02 16:44:34 +00:00
2019-10-05 19:08:05 +00:00
if (o->oMerryGoRoundBooManagerNumBoosKilled > 4) {
if (gNetworkType == NT_SERVER) {
2020-08-25 04:38:49 +00:00
struct Object* boo = spawn_object(o, MODEL_BOO, bhvMerryGoRoundBigBoo);
obj_copy_behavior_params(boo, o);
2020-06-02 16:44:34 +00:00
2020-08-25 04:38:49 +00:00
network_set_sync_id(boo);
struct Object* spawn_objects[] = { boo };
u32 models[] = { MODEL_BOO };
network_send_spawn_objects(spawn_objects, models, 1);
2020-06-02 16:44:34 +00:00
2020-08-25 04:38:49 +00:00
o->oAction = 2;
network_send_object(o);
}
2019-08-25 04:46:40 +00:00
#ifndef VERSION_JP
play_puzzle_jingle();
#else
2019-10-05 19:08:05 +00:00
play_sound(SOUND_GENERAL2_RIGHT_ANSWER, gDefaultSoundArgs);
2019-08-25 04:46:40 +00:00
#endif
}
}
2020-06-02 16:44:34 +00:00
2019-08-25 04:46:40 +00:00
break;
case 1:
2019-10-05 19:08:05 +00:00
if (o->oTimer > 60) {
2019-08-25 04:46:40 +00:00
o->oAction = 0;
2019-10-05 19:08:05 +00:00
}
2020-06-02 16:44:34 +00:00
2019-08-25 04:46:40 +00:00
break;
case 2:
break;
}
}
2019-10-05 19:08:05 +00:00
void obj_set_secondary_camera_focus(void) {
2019-08-25 04:46:40 +00:00
gSecondCameraFocus = o;
}
void bhv_animated_texture_loop(void) {
2020-03-02 03:42:52 +00:00
cur_obj_set_pos_to_home_with_debug();
2019-08-25 04:46:40 +00:00
}
void bhv_boo_in_castle_loop(void) {
2020-08-25 04:38:49 +00:00
if (!network_sync_object_initialized(o)) { boo_network_init_object(); }
struct MarioState* marioState = nearest_mario_state_to_object(o);
struct Object* player = marioState->marioObj;
int distanceToPlayer = dist_between_objects(o, player);
int angleToPlayer = obj_angle_to_object(o, player);
u8 inRoom = FALSE;
for (int i = 0; i < MAX_PLAYERS; i++) {
if (!is_player_active(&gMarioStates[i])) { continue; }
2020-08-25 04:38:49 +00:00
if (marioState->floor == NULL) { continue; }
inRoom = inRoom || (marioState->floor->room == 1);
}
2019-10-05 19:08:05 +00:00
s16 targetAngle;
2020-06-02 16:44:34 +00:00
2019-08-25 04:46:40 +00:00
o->oBooBaseScale = 2.0f;
2020-06-02 16:44:34 +00:00
2019-08-25 04:46:40 +00:00
if (o->oAction == 0) {
2020-03-02 03:42:52 +00:00
cur_obj_hide();
2020-06-02 16:44:34 +00:00
2019-10-05 19:08:05 +00:00
if (gHudDisplay.stars < 12) {
2020-03-02 03:42:52 +00:00
obj_mark_for_deletion(o);
2019-10-05 19:08:05 +00:00
}
2020-06-02 16:44:34 +00:00
2020-08-25 04:38:49 +00:00
if (inRoom) {
2019-08-25 04:46:40 +00:00
o->oAction++;
2019-10-05 19:08:05 +00:00
}
2019-08-25 04:46:40 +00:00
} else if (o->oAction == 1) {
2020-03-02 03:42:52 +00:00
cur_obj_unhide();
2020-06-02 16:44:34 +00:00
2019-08-25 04:46:40 +00:00
o->oOpacity = 180;
2020-06-02 16:44:34 +00:00
2019-10-05 19:08:05 +00:00
if (o->oTimer == 0) {
2020-03-02 03:42:52 +00:00
cur_obj_scale(o->oBooBaseScale);
2019-10-05 19:08:05 +00:00
}
2020-06-02 16:44:34 +00:00
2020-08-25 04:38:49 +00:00
if (distanceToPlayer < 1000.0f) {
2019-08-25 04:46:40 +00:00
o->oAction++;
2020-03-02 03:42:52 +00:00
cur_obj_play_sound_2(SOUND_OBJ_BOO_LAUGH_LONG);
2019-08-25 04:46:40 +00:00
}
2020-06-02 16:44:34 +00:00
2019-08-25 04:46:40 +00:00
o->oForwardVel = 0.0f;
2020-08-25 04:38:49 +00:00
targetAngle = angleToPlayer;
2019-08-25 04:46:40 +00:00
} else {
2020-03-02 03:42:52 +00:00
cur_obj_forward_vel_approach_upward(32.0f, 1.0f);
2020-06-02 16:44:34 +00:00
2019-08-25 04:46:40 +00:00
o->oHomeX = -1000.0f;
o->oHomeZ = -9000.0f;
2020-06-02 16:44:34 +00:00
2020-03-02 03:42:52 +00:00
targetAngle = cur_obj_angle_to_home();
2020-06-02 16:44:34 +00:00
2019-08-25 04:46:40 +00:00
if (o->oPosZ < -5000.0f) {
2019-10-05 19:08:05 +00:00
if (o->oOpacity > 0) {
2019-08-25 04:46:40 +00:00
o->oOpacity -= 20;
2019-10-05 19:08:05 +00:00
} else {
2019-08-25 04:46:40 +00:00
o->oOpacity = 0;
2019-10-05 19:08:05 +00:00
}
2019-08-25 04:46:40 +00:00
}
2020-06-02 16:44:34 +00:00
2019-10-05 19:08:05 +00:00
if (o->activeFlags & ACTIVE_FLAG_IN_DIFFERENT_ROOM) {
2019-08-25 04:46:40 +00:00
o->oAction = 1;
2019-10-05 19:08:05 +00:00
}
2019-08-25 04:46:40 +00:00
}
2020-06-02 16:44:34 +00:00
2019-08-25 04:46:40 +00:00
o->oVelY = 0.0f;
2020-06-02 16:44:34 +00:00
2020-03-02 03:42:52 +00:00
targetAngle = cur_obj_angle_to_home();
2020-06-02 16:44:34 +00:00
2020-03-02 03:42:52 +00:00
cur_obj_rotate_yaw_toward(targetAngle, 0x5A8);
2019-08-25 04:46:40 +00:00
boo_oscillate(TRUE);
2020-03-02 03:42:52 +00:00
cur_obj_move_using_fvel_and_gravity();
2019-08-25 04:46:40 +00:00
}
void bhv_boo_boss_spawned_bridge_loop(void) {
2019-10-05 19:08:05 +00:00
f32 targetY;
2020-06-02 16:44:34 +00:00
2019-08-25 04:46:40 +00:00
switch (o->oBehParams2ndByte) {
case 1:
2019-10-05 19:08:05 +00:00
targetY = 0.0f;
2019-08-25 04:46:40 +00:00
break;
case 0:
2019-10-05 19:08:05 +00:00
targetY = -206.0f;
2019-08-25 04:46:40 +00:00
break;
case 2:
2019-10-05 19:08:05 +00:00
targetY = -413.0f;
2019-08-25 04:46:40 +00:00
break;
}
2020-06-02 16:44:34 +00:00
2019-10-05 19:08:05 +00:00
switch(o->oAction) {
2019-08-25 04:46:40 +00:00
case 0:
o->oPosY = o->oHomeY - 620.0f;
o->oAction++;
2019-10-05 19:08:05 +00:00
// fallthrough
2019-08-25 04:46:40 +00:00
case 1:
o->oPosY += 8.0f;
2020-03-02 03:42:52 +00:00
cur_obj_play_sound_1(SOUND_ENV_ELEVATOR2);
2020-06-02 16:44:34 +00:00
2019-10-05 19:08:05 +00:00
if (o->oPosY > targetY) {
o->oPosY = targetY;
2019-08-25 04:46:40 +00:00
o->oAction++;
}
2020-06-02 16:44:34 +00:00
2019-08-25 04:46:40 +00:00
break;
case 2:
2019-10-05 19:08:05 +00:00
if (o->oTimer == 0) {
2020-03-02 03:42:52 +00:00
cur_obj_play_sound_2(SOUND_GENERAL_UNKNOWN4_LOWPRIO);
2019-10-05 19:08:05 +00:00
}
2020-06-02 16:44:34 +00:00
2020-03-02 03:42:52 +00:00
if (cur_obj_move_up_and_down(o->oTimer)) {
2019-08-25 04:46:40 +00:00
o->oAction++;
2019-10-05 19:08:05 +00:00
}
2020-06-02 16:44:34 +00:00
2019-08-25 04:46:40 +00:00
break;
case 3:
2019-10-05 19:08:05 +00:00
if (o->oTimer == 0 && o->oBehParams2ndByte == 1) {
2019-08-25 04:46:40 +00:00
play_puzzle_jingle();
2019-10-05 19:08:05 +00:00
}
2020-06-02 16:44:34 +00:00
2019-08-25 04:46:40 +00:00
break;
}
}