168 lines
5.5 KiB
C
168 lines
5.5 KiB
C
/**
|
|
* Behavior for bhvCoffinSpawner and bhvCoffin.
|
|
* The coffins are spawned by a singular spawner,
|
|
* with half being able to stand up.
|
|
* Coffins unload after leaving the room.
|
|
*/
|
|
|
|
/**
|
|
* Struct with s16 values for a horizontal position.
|
|
*/
|
|
struct LateralPosition {
|
|
s16 x;
|
|
s16 z;
|
|
};
|
|
|
|
/**
|
|
* Array of positions for all coffins relative to their spawner.
|
|
*/
|
|
struct LateralPosition coffinRelativePos[] = {
|
|
{ 412, -150 }, { 762, -150 }, { 1112, -150 },
|
|
{ 412, 150 }, { 762, 150 }, { 1112, 150 },
|
|
};
|
|
|
|
/**
|
|
* Loop behavior for the object that spawns the six coffins in BBH.
|
|
* Loads the coffins when in the room, they unload themselves.
|
|
*/
|
|
void bhv_coffin_spawner_loop(void) {
|
|
struct Object *coffin;
|
|
s32 i;
|
|
s16 relativeZ;
|
|
|
|
if (o->oAction == COFFIN_SPAWNER_ACT_COFFINS_UNLOADED) {
|
|
if (!(o->activeFlags & ACTIVE_FLAG_IN_DIFFERENT_ROOM)) {
|
|
for (i = 0; i < 6; i++) {
|
|
relativeZ = coffinRelativePos[i].z;
|
|
|
|
// Behavior param of 0 for all even i, 1 for all odd
|
|
coffin = spawn_object_relative(i & 1, coffinRelativePos[i].x, 0, relativeZ, o,
|
|
MODEL_BBH_WOODEN_TOMB, bhvCoffin);
|
|
|
|
// Never true, game would enter a while(1) before it could.
|
|
// Possible a remnant of days this didn't happen.
|
|
if (coffin != NULL) {
|
|
// Rotate the coffin 180 degrees if its on the other side of the room.
|
|
if (relativeZ > 0) {
|
|
coffin->oFaceAngleYaw = 0x8000;
|
|
}
|
|
}
|
|
}
|
|
|
|
o->oAction += 1;
|
|
}
|
|
} else if (o->activeFlags & ACTIVE_FLAG_IN_DIFFERENT_ROOM) {
|
|
o->oAction = COFFIN_SPAWNER_ACT_COFFINS_UNLOADED;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* The main action for the coffins. Coffins with COFFIN_BP_STATIC skip the behavior, while
|
|
* the other coffins will enter a standing action when Mario is near.
|
|
* Also controls laying the coffin down after it has stood up.
|
|
*/
|
|
void coffin_act_idle(void) {
|
|
f32 yawCos;
|
|
f32 yawSin;
|
|
f32 dx;
|
|
f32 dz;
|
|
f32 distForwards;
|
|
f32 distSideways;
|
|
|
|
if (o->oBehParams2ndByte != COFFIN_BP_STATIC) {
|
|
// Lay down if standing
|
|
if (o->oFaceAnglePitch != 0) {
|
|
o->oAngleVelPitch = approach_s16_symmetric(o->oAngleVelPitch, -2000, 200);
|
|
|
|
// If the coffin landed...
|
|
if (obj_face_pitch_approach(0, -o->oAngleVelPitch)) {
|
|
cur_obj_play_sound_2(SOUND_GENERAL_ELEVATOR_MOVE_2);
|
|
|
|
// This bit changes the coffin's position,
|
|
// spawns dust there, then resets the position.
|
|
obj_perform_position_op(POS_OP_SAVE_POSITION);
|
|
o->oMoveAngleYaw = o->oFaceAngleYaw - 0x4000;
|
|
obj_set_dist_from_home(200.0f);
|
|
spawn_mist_from_global();
|
|
obj_perform_position_op(POS_OP_RESTORE_POSITION);
|
|
}
|
|
|
|
o->oTimer = 0;
|
|
} else {
|
|
// Yaw never changes and is aligned, so yawCos = 1 or -1, yawSin = 0
|
|
yawCos = coss(o->oFaceAngleYaw);
|
|
yawSin = sins(o->oFaceAngleYaw);
|
|
|
|
dx = gMarioObject->oPosX - o->oPosX;
|
|
dz = gMarioObject->oPosZ - o->oPosZ;
|
|
|
|
distForwards = dx * yawCos + dz * yawSin;
|
|
distSideways = dz * yawCos - dx * yawSin;
|
|
|
|
// This checks a box around the coffin and if it has been a bit since it stood up.
|
|
// It also checks in the case Mario is squished, so he doesn't get permanently squished.
|
|
if (o->oTimer > 60
|
|
&& (o->oDistanceToMario > 100.0f || gMarioState->action == ACT_SQUISHED)) {
|
|
if (gMarioObject->oPosY - o->oPosY < 200.0f && absf(distForwards) < 140.0f) {
|
|
if (distSideways < 150.0f && distSideways > -450.0f) {
|
|
cur_obj_play_sound_2(SOUND_GENERAL_BUTTON_PRESS_2_LOWPRIO);
|
|
o->oAction = COFFIN_ACT_STAND_UP;
|
|
}
|
|
}
|
|
}
|
|
|
|
o->oAngleVelPitch = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Stand up the coffin and keep it standing until the timer hits 60.
|
|
*/
|
|
void coffin_act_stand_up(void) {
|
|
// Stand up
|
|
if (o->oFaceAnglePitch != 0x4000) {
|
|
o->oAngleVelPitch = approach_s16_symmetric(o->oAngleVelPitch, 1000, 200);
|
|
obj_face_pitch_approach(0x4000, o->oAngleVelPitch);
|
|
} else {
|
|
// Stay standing
|
|
if (o->oTimer > 60) {
|
|
o->oAction = COFFIN_ACT_IDLE;
|
|
o->oFaceAngleRoll = 0;
|
|
} else if (o->oTimer > 30) {
|
|
if (gGlobalTimer % 4 == 0) {
|
|
cur_obj_play_sound_2(SOUND_GENERAL_ELEVATOR_MOVE_2);
|
|
}
|
|
// Shake the coffin while its standing
|
|
o->oFaceAngleRoll = 400 * (gGlobalTimer % 2) - 200;
|
|
}
|
|
|
|
o->oAngleVelPitch = 0;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Main behavior for each coffin. Unloads the coffin if the spawner enters
|
|
* that action.
|
|
*/
|
|
void bhv_coffin_loop(void) {
|
|
// Gotta save those 6 object slots
|
|
if (o->parentObj->oAction == COFFIN_SPAWNER_ACT_COFFINS_UNLOADED) {
|
|
obj_mark_for_deletion(o);
|
|
} else {
|
|
// Scale the coffin vertically? Must have thought it was too short?
|
|
o->header.gfx.scale[1] = 1.1f;
|
|
|
|
switch (o->oAction) {
|
|
case COFFIN_ACT_IDLE:
|
|
coffin_act_idle();
|
|
break;
|
|
case COFFIN_ACT_STAND_UP:
|
|
coffin_act_stand_up();
|
|
break;
|
|
}
|
|
|
|
load_object_collision_model();
|
|
}
|
|
}
|