From 5812d64aa5061cee337a80c9ec8553f7c9343d71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emily=E2=99=A5?= Date: Tue, 13 May 2025 16:32:11 -0400 Subject: [PATCH 1/4] Fix Eyerok pounding in multiplayer Eyerok now only enters the double pound state if ALL players stand on the pedestal rather than just one. Players standing on the pedestal will be ignored. I had to write a new function for this, I hope this is acceptable. --- src/game/behaviors/eyerok.inc.c | 44 +++++++++++++++++++++++++-------- 1 file changed, 34 insertions(+), 10 deletions(-) diff --git a/src/game/behaviors/eyerok.inc.c b/src/game/behaviors/eyerok.inc.c index a781638de..8e2a16fc2 100644 --- a/src/game/behaviors/eyerok.inc.c +++ b/src/game/behaviors/eyerok.inc.c @@ -14,12 +14,36 @@ s8 D_80331BA4[] = { 0, 1, 3, 2, 1, 0 }; static u8 eyerokBossImmediateUpdate = FALSE; static s32 eyerok_check_mario_relative_z(s32 arg0) { - struct Object* player = nearest_player_to_object(o); - if (player && player->oPosZ - o->oHomeZ < arg0) { - return TRUE; - } else { - return FALSE; + for (s32 i = 0; i < MAX_PLAYERS; i++) { + struct MarioState* m = &gMarioStates[i]; + if (m->marioObj == NULL) { continue; } + if (is_player_active(m) && m->marioObj->oPosZ - o->oHomeZ >= arg0) { + return FALSE; + } } + return TRUE; +} + +static struct Object* eyerok_nearest_targettable_player_to_object(s32 arg0) { + if (!o) { return NULL; } + struct MarioState* nearest = NULL; + f32 nearestDist = 0; + for (s32 i = 0; i < MAX_PLAYERS; i++) { + if (!gMarioStates[i].marioObj) { continue; } + if (gMarioStates[i].marioObj == o) { continue; } + if (!gMarioStates[i].visibleToEnemies) { continue; } + if (!is_player_active(&gMarioStates[i])) { continue; } + float dist = dist_between_objects(o, gMarioStates[i].marioObj); + if (gMarioStates[i].marioObj->oPosZ - o->oHomeZ < arg0) { + dist += 10000; // always prefer players that are not past z position + } + if (nearest == NULL || dist < nearestDist) { + nearest = &gMarioStates[i]; + nearestDist = dist; + } + } + + return nearest->marioObj; } static struct Object* eyerok_spawn_hand(s16 side, s32 model, const BehaviorScript *behavior) { @@ -172,7 +196,7 @@ static void eyerok_boss_act_fight(void) { o->oEyerokBossUnk108 = 1.0f; } - struct Object* player = nearest_player_to_object(o); + struct Object* player = eyerok_nearest_targettable_player_to_object(400); if (player) { o->oEyerokBossUnk10C = player->oPosZ; } @@ -311,7 +335,7 @@ static void eyerok_hand_act_sleep(void) { static void eyerok_hand_act_idle(void) { if (!o->parentObj) { return; } - struct Object* player = nearest_player_to_object(o); + struct Object* player = eyerok_nearest_targettable_player_to_object(400); s32 angleToPlayer = player ? obj_angle_to_object(o, player) : 0; cur_obj_init_animation_with_sound(2); @@ -502,7 +526,7 @@ static void eyerok_hand_act_retreat(void) { static void eyerok_hand_act_target_mario(void) { if (!o->parentObj) { return; } - struct Object* player = nearest_player_to_object(o); + struct Object* player = eyerok_nearest_targettable_player_to_object(400); s32 angleToPlayer = player ? obj_angle_to_object(o, player) : 0; if (eyerok_check_mario_relative_z(400) != 0 || (player && o->oPosZ - player->oPosZ > 0.0f) || o->oPosZ - o->parentObj->oPosZ > 1700.0f || absf(o->oPosX - o->parentObj->oPosX) > 900.0f @@ -519,7 +543,7 @@ static void eyerok_hand_act_target_mario(void) { } static void eyerok_hand_act_smash(void) { - struct Object* player = nearest_player_to_object(o); + struct Object* player = eyerok_nearest_targettable_player_to_object(400); s32 distanceToPlayer = player ? dist_between_objects(o, player) : 10000; s32 angleToPlayer = player ? obj_angle_to_object(o, player) : 0; s16 sp1E; @@ -549,7 +573,7 @@ static void eyerok_hand_act_smash(void) { } static void eyerok_hand_act_fist_push(void) { - struct Object* player = nearest_player_to_object(o); + struct Object* player = eyerok_nearest_targettable_player_to_object(400); if (o->oTimer > 5 && ((player && o->oPosZ - player->oPosZ > 0.0f) || (o->oMoveFlags & OBJ_MOVE_HIT_EDGE))) { o->oAction = EYEROK_HAND_ACT_FIST_SWEEP; o->oForwardVel = 0.0f; From 206417f2cf9fe9e10739e74060505beca022bd80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emily=E2=99=A5?= Date: Wed, 14 May 2025 13:46:10 -0400 Subject: [PATCH 2/4] Suggested changes I didn't want to change the name of arg0 in eyerok_check_mario_relative_z because it was a vanilla function, but I suppose I can. --- src/game/behaviors/eyerok.inc.c | 35 +++++++++++++++++---------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/src/game/behaviors/eyerok.inc.c b/src/game/behaviors/eyerok.inc.c index 8e2a16fc2..59f5868aa 100644 --- a/src/game/behaviors/eyerok.inc.c +++ b/src/game/behaviors/eyerok.inc.c @@ -13,37 +13,38 @@ struct ObjectHitbox sEyerokHitbox = { s8 D_80331BA4[] = { 0, 1, 3, 2, 1, 0 }; static u8 eyerokBossImmediateUpdate = FALSE; -static s32 eyerok_check_mario_relative_z(s32 arg0) { +static s32 eyerok_check_mario_relative_z(s32 zDist) { for (s32 i = 0; i < MAX_PLAYERS; i++) { struct MarioState* m = &gMarioStates[i]; if (m->marioObj == NULL) { continue; } - if (is_player_active(m) && m->marioObj->oPosZ - o->oHomeZ >= arg0) { + if (is_player_active(m) && m->marioObj->oPosZ - o->oHomeZ >= zDist) { return FALSE; } } return TRUE; } -static struct Object* eyerok_nearest_targettable_player_to_object(s32 arg0) { +static struct Object* eyerok_nearest_targetable_player_to_object(s32 zDist) { if (!o) { return NULL; } - struct MarioState* nearest = NULL; + struct Object* nearest = NULL; f32 nearestDist = 0; for (s32 i = 0; i < MAX_PLAYERS; i++) { - if (!gMarioStates[i].marioObj) { continue; } - if (gMarioStates[i].marioObj == o) { continue; } - if (!gMarioStates[i].visibleToEnemies) { continue; } - if (!is_player_active(&gMarioStates[i])) { continue; } - float dist = dist_between_objects(o, gMarioStates[i].marioObj); - if (gMarioStates[i].marioObj->oPosZ - o->oHomeZ < arg0) { + struct MarioState *m = &gMarioStates[i]; + if (!m->marioObj) { continue; } + if (m->marioObj == o) { continue; } + if (!m->visibleToEnemies) { continue; } + if (!is_player_active(m)) { continue; } + f32 dist = dist_between_objects(o, m->marioObj); + if (m->marioObj->oPosZ - o->oHomeZ < zDist) { dist += 10000; // always prefer players that are not past z position } if (nearest == NULL || dist < nearestDist) { - nearest = &gMarioStates[i]; + nearest = m->marioObj; nearestDist = dist; } } - return nearest->marioObj; + return nearest; } static struct Object* eyerok_spawn_hand(s16 side, s32 model, const BehaviorScript *behavior) { @@ -196,7 +197,7 @@ static void eyerok_boss_act_fight(void) { o->oEyerokBossUnk108 = 1.0f; } - struct Object* player = eyerok_nearest_targettable_player_to_object(400); + struct Object* player = eyerok_nearest_targetable_player_to_object(400); if (player) { o->oEyerokBossUnk10C = player->oPosZ; } @@ -335,7 +336,7 @@ static void eyerok_hand_act_sleep(void) { static void eyerok_hand_act_idle(void) { if (!o->parentObj) { return; } - struct Object* player = eyerok_nearest_targettable_player_to_object(400); + struct Object* player = eyerok_nearest_targetable_player_to_object(400); s32 angleToPlayer = player ? obj_angle_to_object(o, player) : 0; cur_obj_init_animation_with_sound(2); @@ -526,7 +527,7 @@ static void eyerok_hand_act_retreat(void) { static void eyerok_hand_act_target_mario(void) { if (!o->parentObj) { return; } - struct Object* player = eyerok_nearest_targettable_player_to_object(400); + struct Object* player = eyerok_nearest_targetable_player_to_object(400); s32 angleToPlayer = player ? obj_angle_to_object(o, player) : 0; if (eyerok_check_mario_relative_z(400) != 0 || (player && o->oPosZ - player->oPosZ > 0.0f) || o->oPosZ - o->parentObj->oPosZ > 1700.0f || absf(o->oPosX - o->parentObj->oPosX) > 900.0f @@ -543,7 +544,7 @@ static void eyerok_hand_act_target_mario(void) { } static void eyerok_hand_act_smash(void) { - struct Object* player = eyerok_nearest_targettable_player_to_object(400); + struct Object* player = eyerok_nearest_targetable_player_to_object(400); s32 distanceToPlayer = player ? dist_between_objects(o, player) : 10000; s32 angleToPlayer = player ? obj_angle_to_object(o, player) : 0; s16 sp1E; @@ -573,7 +574,7 @@ static void eyerok_hand_act_smash(void) { } static void eyerok_hand_act_fist_push(void) { - struct Object* player = eyerok_nearest_targettable_player_to_object(400); + struct Object* player = eyerok_nearest_targetable_player_to_object(400); if (o->oTimer > 5 && ((player && o->oPosZ - player->oPosZ > 0.0f) || (o->oMoveFlags & OBJ_MOVE_HIT_EDGE))) { o->oAction = EYEROK_HAND_ACT_FIST_SWEEP; o->oForwardVel = 0.0f; From d43575093be6046ba1d1cd67ba2811b7293cd302 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emily=E2=99=A5?= Date: Mon, 8 Sep 2025 22:12:27 -0400 Subject: [PATCH 3/4] Remove interaction limit for PVP Fixes issues with certain mods --- src/game/object_collision.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/game/object_collision.c b/src/game/object_collision.c index 9288cb4b0..92c46608d 100644 --- a/src/game/object_collision.c +++ b/src/game/object_collision.c @@ -52,12 +52,6 @@ int detect_player_hitbox_overlap(struct MarioState* local, struct MarioState* re if (sp20 < sp38) { return FALSE; } - if (a->numCollidedObjs >= 4) { - return FALSE; - } - if (b->numCollidedObjs >= 4) { - return FALSE; - } return TRUE; } @@ -196,6 +190,8 @@ void check_player_object_collision(void) { if (detect_player_hitbox_overlap(&gMarioStates[0], &gMarioStates[i], 1.0f)) { struct Object* a = gMarioStates[0].marioObj; struct Object* b = gMarioStates[i].marioObj; + if (a->numCollidedObjs >= 4) { continue; } + if (b->numCollidedObjs >= 4) { continue; } a->collidedObjs[a->numCollidedObjs] = b; b->collidedObjs[b->numCollidedObjs] = a; a->collidedObjInteractTypes |= b->oInteractType; From fe92f542b5e41eedf669edb7b9fcdff263996982 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emily=E2=99=A5?= Date: Thu, 23 Oct 2025 21:05:39 -0400 Subject: [PATCH 4/4] Fixes for Bowser and Heave Ho Hopefully this makes things a bit better. --- src/game/behaviors/bowser.inc.c | 30 ++++++++++++++++++++++++++++-- src/game/behaviors/heave_ho.inc.c | 2 +- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/src/game/behaviors/bowser.inc.c b/src/game/behaviors/bowser.inc.c index 78a0daac8..52c474577 100644 --- a/src/game/behaviors/bowser.inc.c +++ b/src/game/behaviors/bowser.inc.c @@ -3,6 +3,7 @@ static u32 networkBowserAnimationIndex = 0; static u8 bowserIsDying = FALSE; static u8 bowserCutscenePlayed = FALSE; static u8 bowserIsCutscenePlayer = FALSE; +static u8 bowserCutsceneGlobalIndex = UNKNOWN_GLOBAL_INDEX; void bowser_tail_anchor_act_0(void) { struct Object* bowser = o->parentObj; @@ -777,6 +778,10 @@ void bowser_act_thrown_dropped(void) o->oAction = 4; else o->oAction = 12; + + if (is_nearest_mario_state_to_object(gMarioState, o)) { + network_send_object(o); + } } } @@ -1125,8 +1130,17 @@ void bowser_act_ride_tilting_platform(void) { cur_obj_extend_animation_if_at_end(); } -void bowser_act_nothing(void) { - +void bowser_act_nothing(void) { // start moving if cutscene player is inactive + if (bowserCutsceneGlobalIndex == UNKNOWN_GLOBAL_INDEX) { + return; + } + + struct NetworkPlayer* np = network_player_from_global_index(bowserCutsceneGlobalIndex); + if (np == NULL || !is_player_active(&gMarioStates[np->localIndex])) { + bowserCutscenePlayed = TRUE; + bowser_initialize_action(); + return; + } } s32 bowser_check_fallen_off_stage(void) // bowser off stage? @@ -1232,6 +1246,7 @@ void bowser_held_update(void) { return; } + o->parentObj = player; o->oBowserUnkF4 &= ~0x20000; cur_obj_become_intangible(); @@ -1385,6 +1400,13 @@ static u8 bhv_bowser_ignore_if_true(void) { return FALSE; } +static void bhv_bowser_on_received_post(UNUSED u8 localIndex) { + // prevent sync from putting bowser in text action instead of nothing action + if (!(bowserIsCutscenePlayer || bowserCutscenePlayed) && (o->oAction == 5 || o->oAction == 6)) { + o->oAction = 20; + } +} + void bhv_bowser_init(void) { bowserIsDying = FALSE; s32 level; // 0 is dw, 1 is fs, 2 is sky @@ -1408,9 +1430,11 @@ void bhv_bowser_init(void) { // Make sure we're the first to trigger Bowser. if (!is_other_player_active()) { bowserIsCutscenePlayer = TRUE; + bowserCutsceneGlobalIndex = gNetworkPlayerLocal->globalIndex; o->oAction = 5; // bowser_act_text_wait } else { // If we aren't do nothing till we get our sync. bowserIsCutscenePlayer = FALSE; + bowserCutsceneGlobalIndex = UNKNOWN_GLOBAL_INDEX; o->oAction = 20; // bowser_act_nothing } @@ -1419,9 +1443,11 @@ void bhv_bowser_init(void) { if (so) { so->override_ownership = bhv_bowser_override_ownership; so->ignore_if_true = bhv_bowser_ignore_if_true; + so->on_received_post = bhv_bowser_on_received_post; so->fullObjectSync = TRUE; sync_object_init_field_with_size(o, &o->header.gfx.node.flags, 16); sync_object_init_field_with_size(o, &o->header.gfx.animInfo.animFrame, 16); + sync_object_init_field_with_size(o, &bowserCutsceneGlobalIndex, 8); sync_object_init_field(o, &networkBowserAnimationIndex); sync_object_init_field(o, &o->header.gfx.scale[0]); sync_object_init_field(o, &o->header.gfx.scale[1]); diff --git a/src/game/behaviors/heave_ho.inc.c b/src/game/behaviors/heave_ho.inc.c index 94f8be6a7..62f27e81e 100644 --- a/src/game/behaviors/heave_ho.inc.c +++ b/src/game/behaviors/heave_ho.inc.c @@ -23,7 +23,7 @@ void bhv_heave_ho_throw_mario_loop(void) { if (player) { player->oInteractStatus |= INT_STATUS_MARIO_UNK2; } - if (marioState) { + if (marioState && marioState->action == ACT_GRABBED) { marioState->forwardVel = -45.0f; marioState->vel[1] = 95.0f; }