Merry-Go-Round Fixes (includes fixes for rooms and remote object-spawned objects) (#1094)

This commit is contained in:
Altiami 2026-03-10 16:15:25 -07:00 committed by GitHub
parent 1f3de4fe0a
commit 52446ded91
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 69 additions and 22 deletions

View file

@ -797,7 +797,22 @@ static s32 bhv_cmd_load_collision_data(void) {
// Command 0x2D: Sets the home position of the object to its current position.
// Usage: SET_HOME()
static s32 bhv_cmd_set_home(void) {
if (!(gCurrentObject->coopFlags & (COOP_OBJ_FLAG_LUA | COOP_OBJ_FLAG_NETWORK))) {
// COOP: only set home via behavior for the following cases
if (
// if the object wasn't created via Lua
!(gCurrentObject->coopFlags & COOP_OBJ_FLAG_LUA)
// if the object wasn't created via network
// OR
// the object has never had its home set via behavior AND its home is default (e.g. (0, 0, 0))
// (this case handles an object that needs its home set via behavior after being spawned by another player)
&& (
!(gCurrentObject->coopFlags & COOP_OBJ_FLAG_NETWORK)
|| (
!gCurrentObject->setHome
&& gCurrentObject->oHomeX == 0.0f && gCurrentObject->oHomeY == 0.0f && gCurrentObject->oHomeZ == 0.0f
)
)
) {
gCurrentObject->oHomeX = gCurrentObject->oPosX;
gCurrentObject->oHomeY = gCurrentObject->oPosY;
gCurrentObject->oHomeZ = gCurrentObject->oPosZ;

View file

@ -806,7 +806,10 @@ static void load_object_collision_model_internal(bool isSOC) {
for (s32 i = 0; i < MAX_PLAYERS; i++) {
f32 dist = dist_between_objects(gCurrentObject, gMarioStates[i].marioObj);
if (dist < tangibleDist) { anyPlayerInTangibleRange = TRUE; }
if (dist < tangibleDist) {
anyPlayerInTangibleRange = TRUE;
break;
}
}
// If the object collision is supposed to be loaded more than the

View file

@ -10,6 +10,9 @@
* in the enclosure nor in the room around it.
*/
static void handle_merry_go_round_music(void) {
// COOP: raise scope of this variable since floor check is no longer strictly tied to music
u16 marioFloorType = 0;
// If the music should play, play it and check whether it still should.
// Otherwise, don't play it and check whether it should.
if (o->oMerryGoRoundMusicShouldPlay == FALSE) {
@ -23,7 +26,7 @@ static void handle_merry_go_round_music(void) {
// Get Mario's floor and floor surface type
struct Surface *marioFloor = NULL;
struct Object *marioObject = gMarioObjects[0];
u16 marioFloorType = 0;
// COOP: `marioFloorType` originally here
if (marioObject) {
find_floor(marioObject->oPosX, marioObject->oPosY, marioObject->oPosZ, &marioFloor);
@ -37,7 +40,9 @@ static void handle_merry_go_round_music(void) {
// The cur_obj_is_mario_on_platform check is redundant since the merry-go-round
// has surface type 0x1A, so Mario cannot be on the merry-go-round
// without being on a floor with surface type 0x1A (SURFACE_MGR_MUSIC).
gMarioOnMerryGoRound = cur_obj_is_any_player_on_platform();
// COOP: `gMarioOnMerryGoRound` is used to determine if the merry-go-round Boos should be active
// for co-op, this means that this check needs to be separated from the music check, since music is client-side.
if (cur_obj_is_mario_on_platform() || marioFloorType == SURFACE_MGR_MUSIC) {
// If Mario is in the merry-go-round's enclosure, play only the merry-go-round music.
play_secondary_music(SEQ_EVENT_MERRY_GO_ROUND, 0, 78, 50);
@ -60,6 +65,28 @@ static void handle_merry_go_round_music(void) {
cur_obj_play_sound_1(SOUND_ENV_MERRY_GO_ROUND_CREAKING);
}
}
// COOP: floor check happens here
// `marioFloorType` refers to the local player's character
gMarioOnMerryGoRound = marioFloorType == SURFACE_MGR_MUSIC || cur_obj_is_any_player_on_platform();
if (!gMarioOnMerryGoRound) {
// check the other Marios' floors
// starting at 1 since local player was already checked
for (s32 i = 1; i < MAX_PLAYERS; i++) {
if (!is_player_active(&gMarioStates[i])) { continue; }
struct Object *marioObject = gMarioStates[i].marioObj;
if (marioObject == NULL) { continue; }
struct Surface *marioFloor = NULL;
find_floor(marioObject->oPosX, marioObject->oPosY, marioObject->oPosZ, &marioFloor);
if (marioFloor != NULL && marioFloor->type == SURFACE_MGR_MUSIC) {
gMarioOnMerryGoRound = TRUE;
break;
}
}
}
}
/**

View file

@ -56,16 +56,11 @@ void bhv_boo_init(void) {
static s32 boo_should_be_stopped(void) {
if (cur_obj_has_behavior(bhvMerryGoRoundBigBoo) || cur_obj_has_behavior(bhvMerryGoRoundBoo)) {
for (s32 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 TRUE; }
}
return FALSE;
/*if (!gMarioOnMerryGoRound) {
if (!gMarioOnMerryGoRound) {
return TRUE;
} else {
return FALSE;
}*/
}
} else {
if (o->activeFlags & ACTIVE_FLAG_IN_DIFFERENT_ROOM) {
return TRUE;
@ -384,9 +379,7 @@ static void boo_chase_mario(f32 a0, s16 a1, f32 a2) {
if (boo_vanish_or_appear()) {
o->oInteractType = 0x8000;
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) {
if (cur_obj_lateral_dist_from_obj_to_home(player) > 1500.0f) {
sp1A = cur_obj_angle_to_home();
} else {
sp1A = angleToPlayer;
@ -535,7 +528,8 @@ static void (*sBooActions[])(void) = {
};
void bhv_boo_loop(void) {
if (o->oAction < 3) {
// COOP: only sync when Boo isn't in a death state
if (o->oAction < 3 || o->oAction == 5) {
if (!sync_object_is_initialized(o->oSyncID)) {
struct SyncObject* so = boo_sync_object_init();
if (so) { so->syncDeathEvent = FALSE; }

View file

@ -2942,19 +2942,27 @@ void bhv_init_room(void) {
void cur_obj_enable_rendering_if_mario_in_room(void) {
if (!o) { return; }
if (o->oRoom == -1) { return; }
if (gMarioCurrentRoom == 0) { return; }
// COOP: if any active player character's room is 0, then either:
// 1) There are no rooms in the area
// 2) They are on an object surface with no explicit room
// In vanilla, a room of 0 stops the game from checking if the object shouldn't be rendered
// In coop, this needs to be respected to ensure the object remains active in areas with rooms
u8 marioInRoom = FALSE;
// check if any player character can "see" the object's room
for (s32 i = 0; i < MAX_PLAYERS; i++) {
if (gMarioStates[i].currentRoom != 0) {
if (is_player_active(&gMarioStates[i])) {
// TODO: separate rendering and activation
if (gMarioStates[i].currentRoom == 0) { return; }
s16 currentRoom = gMarioStates[i].currentRoom;
if (currentRoom == o->oRoom) {
marioInRoom = TRUE;
} else if (gDoorAdjacentRooms[currentRoom][0] == o->oRoom) {
marioInRoom = TRUE;
} else if (gDoorAdjacentRooms[currentRoom][1] == o->oRoom) {
if (
currentRoom == o->oRoom
|| gDoorAdjacentRooms[currentRoom][0] == o->oRoom
|| gDoorAdjacentRooms[currentRoom][1] == o->oRoom
) {
marioInRoom = TRUE;
break;
}
}
}