diff --git a/autogen/convert_functions.py b/autogen/convert_functions.py index 0ec22b12c..9a9f7d53a 100644 --- a/autogen/convert_functions.py +++ b/autogen/convert_functions.py @@ -951,7 +951,7 @@ def build_function(function, do_extern): sparam = build_param(fid, param, i) param_var, param_value = sparam.split('=') param_type = param_var.replace(pid, '').strip() - s += ' %s = (%s) NULL;\n' % (param_var.strip(), param_type) + s += ' %s = (%s) %s;\n' % (param_var.strip(), param_type, "NULL" if '*' in param_type else "0") s += ' if (top >= %d) {\n' % (i) s += ' %s = %s\n' % (pid, param_value.strip()) s += ' if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %%u for function \'%%s\'", %d, "%s"); return 0; }\n' % (i, fid) diff --git a/mods/sm74/levels/level_jrb_entry.lvl b/mods/sm74/levels/level_jrb_entry.lvl index 712df327f..fd757d73e 100644 Binary files a/mods/sm74/levels/level_jrb_entry.lvl and b/mods/sm74/levels/level_jrb_entry.lvl differ diff --git a/mods/star-road/actors/bobomb_buddy_geo.bin b/mods/star-road/actors/bobomb_buddy_geo.bin index f7f376a1a..97619e7b8 100644 Binary files a/mods/star-road/actors/bobomb_buddy_geo.bin and b/mods/star-road/actors/bobomb_buddy_geo.bin differ diff --git a/mods/star-road/textures/cannon_lid_seg8_texture_08004058.tex b/mods/star-road/textures/cannon_lid_seg8_texture_08004058.tex new file mode 100644 index 000000000..c64a1cbe1 Binary files /dev/null and b/mods/star-road/textures/cannon_lid_seg8_texture_08004058.tex differ diff --git a/src/engine/behavior_script.c b/src/engine/behavior_script.c index bd6218775..8af14f249 100644 --- a/src/engine/behavior_script.c +++ b/src/engine/behavior_script.c @@ -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; diff --git a/src/engine/surface_load.c b/src/engine/surface_load.c index d78d7999d..345a73202 100644 --- a/src/engine/surface_load.c +++ b/src/engine/surface_load.c @@ -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 diff --git a/src/game/behaviors/bbh_merry_go_round.inc.c b/src/game/behaviors/bbh_merry_go_round.inc.c index 3f38561c9..6cf25c912 100644 --- a/src/game/behaviors/bbh_merry_go_round.inc.c +++ b/src/game/behaviors/bbh_merry_go_round.inc.c @@ -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; + } + } + } } /** diff --git a/src/game/behaviors/boo.inc.c b/src/game/behaviors/boo.inc.c index 37bd4b6fe..5561e19c3 100644 --- a/src/game/behaviors/boo.inc.c +++ b/src/game/behaviors/boo.inc.c @@ -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; } diff --git a/src/game/camera.c b/src/game/camera.c index 9983130d9..962e0fb3e 100644 --- a/src/game/camera.c +++ b/src/game/camera.c @@ -1781,7 +1781,7 @@ s32 unused_update_mode_5_camera(UNUSED struct Camera *c, UNUSED Vec3f focus, UNU return 0; } -static void stub_camera_1(UNUSED s32 unused) { +UNUSED static void stub_camera_1(UNUSED s32 unused) { } void mode_boss_fight_camera(struct Camera *c) { @@ -5614,7 +5614,7 @@ void set_focus_rel_mario(struct Camera *c, f32 leftRight, f32 yOff, f32 forwBack * @param forwBack offset to Mario's front/back, relative to his faceAngle * @param yawOff offset to Mario's faceAngle, changes the direction of `leftRight` and `forwBack` */ -static void unused_set_pos_rel_mario(struct Camera *c, f32 leftRight, f32 yOff, f32 forwBack, s16 yawOff) { +UNUSED static void unused_set_pos_rel_mario(struct Camera *c, f32 leftRight, f32 yOff, f32 forwBack, s16 yawOff) { if (!c) { return; } u16 yaw = sMarioCamState->faceAngle[1] + yawOff; @@ -7606,7 +7606,7 @@ void cutscene_unsoften_music(UNUSED struct Camera *c) { seq_player_unlower_volume(SEQ_PLAYER_LEVEL, 60); } -static void stub_camera_5(UNUSED struct Camera *c) { +UNUSED static void stub_camera_5(UNUSED struct Camera *c) { } BAD_RETURN(s32) cutscene_unused_start(UNUSED struct Camera *c) { @@ -8133,7 +8133,7 @@ BAD_RETURN(s32) cutscene_dance_rotate_move_towards_mario(struct Camera *c) { /** * Speculated to be dance-related due to its proximity to the other dance functions */ -static BAD_RETURN(s32) cutscene_dance_unused(UNUSED struct Camera *c) { +UNUSED static BAD_RETURN(s32) cutscene_dance_unused(UNUSED struct Camera *c) { } /** @@ -9089,7 +9089,7 @@ BAD_RETURN(s32) cutscene_death_stomach_goto_mario(struct Camera *c) { /** * Ah, yes */ -static void unused_water_death_move_to_side_of_mario(struct Camera *c) { +UNUSED static void unused_water_death_move_to_side_of_mario(struct Camera *c) { water_death_move_to_mario_side(c); } @@ -9377,7 +9377,7 @@ BAD_RETURN(s32) cutscene_enter_pyramid_top(struct Camera *c) { } } -static void unused_cutscene_goto_cvar(struct Camera *c) { +UNUSED static void unused_cutscene_goto_cvar(struct Camera *c) { if (!c) { return; } f32 dist; @@ -9543,7 +9543,7 @@ BAD_RETURN(s32) cutscene_read_message_start(struct Camera *c) { sCutsceneVars[0].angle[0] = 0; } -static void unused_cam_to_mario(struct Camera *c) { +UNUSED static void unused_cam_to_mario(struct Camera *c) { if (!c) { return; } Vec3s dir; @@ -10972,7 +10972,7 @@ void cutscene_palette_editor(struct Camera *c) { &gDjuiPaletteToggle->base, ( m->action == ACT_IDLE || - m->action == ACT_PALETTE_EDITOR_CAP + m->action == ACT_PALETTE_EDITOR_CAP ) && !capMissing ); } diff --git a/src/game/level_update.c b/src/game/level_update.c index 7a69632d3..1ad390601 100644 --- a/src/game/level_update.c +++ b/src/game/level_update.c @@ -18,6 +18,7 @@ #include "sound_init.h" #include "mario.h" #include "camera.h" +#include "bettercamera.h" #include "object_list_processor.h" #include "ingame_menu.h" #include "obj_behaviors.h" @@ -471,6 +472,14 @@ void init_mario_after_warp(void) { if (gCurrentArea) { reset_camera(gCurrentArea->camera); + if (sWarpDest.type == WARP_TYPE_SAME_AREA && gCurrentArea->camera->mode == CAMERA_MODE_NEWCAM) { + // When we warp to a level in the same area, the camera mode never has the chance + // to reset. This is bad if our camera mode is newcam, since when init cam is called + // our old camera mode will be set to newcam, which causes newcam to not be able to be + // turned off. The fix is setting our mode to newcam's old mode + gCurrentArea->camera->mode = gNewCamera.savedMode; + gCurrentArea->camera->defMode = gNewCamera.savedDefMode; + } } sWarpDest.type = WARP_TYPE_NOT_WARPING; sDelayedWarpOp = WARP_OP_NONE; diff --git a/src/game/object_helpers.c b/src/game/object_helpers.c index 695a3fbd0..f0bf4d162 100644 --- a/src/game/object_helpers.c +++ b/src/game/object_helpers.c @@ -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; } } }