sm64coopdx/src/game/behaviors/coffin.inc.c
MysterD d2a2a80d56 Synchronized Big Boo's Haunt + major changes
Synchronized currentRoom per-player
Synchronized haunted bookshelf, and the bookshelf manager
Synchronized haunted chairs
Synchronized mad piano
Synchronized BBH's tilting trap, and made the physics multiple-player-aware
Synchronized scuttlebugs
Synchronized every variety of Boo
Synchronized elevators
Synchronized flamethrowers
Synchronized the various types of enemy books
Synchronized the book switches
Synchronized jumping box
Made coffins multiple-player-aware

Fixed everything that used gMarioState as an array instead of gMarioStates
Prevented some NPC-dialog softlocks
Prevented the remote player from messing up the local's camera settings
Possibly fixed the relatively rare chain chomp softlock
Possibly fixed the relatively rare chain hoot softlock
Fixed the first-person-camera softlock
Forced camera code to use the correct mario struct
2020-08-26 23:29:40 -07:00

171 lines
5.7 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);
struct MarioState* marioState = nearest_mario_state_to_object(o);
struct Object* player = marioState->marioObj;
int distanceToPlayer = dist_between_objects(o, player);
dx = player->oPosX - o->oPosX;
dz = player->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
&& (distanceToPlayer > 100.0f || marioState->action == ACT_SQUISHED)) {
if (player->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();
}
}