From 7f5dec337e0583d93b6460ab4980d4230a68057b Mon Sep 17 00:00:00 2001 From: MysterD Date: Sat, 8 Aug 2020 17:13:11 -0700 Subject: [PATCH] Synchronized King Bobomb Tried to synchronize dialog stuff, it's way too much of a mess to do --- build-windows-visual-studio/sm64ex.vcxproj | 1 + include/types.h | 1 + src/game/behaviors/bobomb.inc.c | 6 +- src/game/behaviors/boo.inc.c | 2 +- src/game/behaviors/bowser.inc.c | 6 +- src/game/behaviors/camera_lakitu.inc.c | 6 +- src/game/behaviors/capswitch.inc.c | 2 +- src/game/behaviors/chain_chomp.inc.c | 4 +- src/game/behaviors/chuckya.inc.c | 49 +++++++------ src/game/behaviors/dorrie.inc.c | 8 +- src/game/behaviors/eyerok.inc.c | 6 +- src/game/behaviors/grand_star.inc.c | 2 +- src/game/behaviors/hoot.inc.c | 4 +- src/game/behaviors/king_bobomb.inc.c | 85 ++++++++++++++++++---- src/game/behaviors/koopa.inc.c | 10 +-- src/game/behaviors/mips.inc.c | 4 +- src/game/behaviors/racing_penguin.inc.c | 8 +- src/game/behaviors/sl_snowman_wind.inc.c | 4 +- src/game/behaviors/snowman.inc.c | 8 +- src/game/behaviors/tuxie.inc.c | 6 +- src/game/behaviors/ukiki.inc.c | 14 ++-- src/game/behaviors/whomp.inc.c | 4 +- src/game/behaviors/wiggler.inc.c | 4 +- src/game/behaviors/yoshi.inc.c | 4 +- src/game/camera.c | 2 +- src/game/mario.c | 5 +- src/game/mario_actions_automatic.c | 8 +- src/game/mario_actions_cutscene.c | 26 +++---- src/game/mario_actions_cutscene.h | 4 +- src/game/mario_misc.c | 2 +- src/game/obj_behaviors.c | 53 +++++--------- src/game/obj_behaviors_2.c | 6 +- src/game/object_helpers.c | 50 ++++++------- src/game/object_helpers.h | 8 +- src/pc/network/packets/packet_object.c | 60 ++++++++------- src/pc/network/packets/packet_player.c | 36 ++++++--- 36 files changed, 291 insertions(+), 217 deletions(-) diff --git a/build-windows-visual-studio/sm64ex.vcxproj b/build-windows-visual-studio/sm64ex.vcxproj index 64231817a..adc32307d 100644 --- a/build-windows-visual-studio/sm64ex.vcxproj +++ b/build-windows-visual-studio/sm64ex.vcxproj @@ -3952,6 +3952,7 @@ + diff --git a/include/types.h b/include/types.h index 104ca5971..a8f184a27 100644 --- a/include/types.h +++ b/include/types.h @@ -363,6 +363,7 @@ struct MarioState /*0xBC*/ f32 peakHeight; /*0xC0*/ f32 quicksandDepth; /*0xC4*/ f32 unkC4; + /*0xC8*/ struct Object *heldByObj; }; #define PLAY_MODE_NORMAL 0 diff --git a/src/game/behaviors/bobomb.inc.c b/src/game/behaviors/bobomb.inc.c index e5b5faf46..8b9afa068 100644 --- a/src/game/behaviors/bobomb.inc.c +++ b/src/game/behaviors/bobomb.inc.c @@ -350,7 +350,7 @@ void bobomb_buddy_cannon_dialog(s16 dialogFirstText, s16 dialogSecondText) { break; case BOBOMB_BUDDY_CANNON_STOP_TALKING: - set_mario_npc_dialog(0); + set_mario_npc_dialog(&gMarioStates[0], 0); o->activeFlags &= ~ACTIVE_FLAG_INITIATED_TIME_STOP; o->oBobombBuddyHasTalkedToMario = BOBOMB_BUDDY_HAS_TALKED; @@ -362,14 +362,14 @@ void bobomb_buddy_cannon_dialog(s16 dialogFirstText, s16 dialogSecondText) { } void bobomb_buddy_act_talk(void) { - if (set_mario_npc_dialog(1) == 2) { + if (set_mario_npc_dialog(&gMarioStates[0], 1) == 2) { o->activeFlags |= ACTIVE_FLAG_INITIATED_TIME_STOP; switch (o->oBobombBuddyRole) { case BOBOMB_BUDDY_ROLE_ADVICE: if (cutscene_object_with_dialog(CUTSCENE_DIALOG, o, o->oBehParams2ndByte) != BOBOMB_BUDDY_BP_STYPE_GENERIC) { - set_mario_npc_dialog(0); + set_mario_npc_dialog(&gMarioStates[0], 0); o->activeFlags &= ~ACTIVE_FLAG_INITIATED_TIME_STOP; o->oBobombBuddyHasTalkedToMario = BOBOMB_BUDDY_HAS_TALKED; diff --git a/src/game/behaviors/boo.inc.c b/src/game/behaviors/boo.inc.c index abfaba866..74592967d 100644 --- a/src/game/behaviors/boo.inc.c +++ b/src/game/behaviors/boo.inc.c @@ -464,7 +464,7 @@ static void boo_act_4(void) { dialogID = DIALOG_107; } - if (cur_obj_update_dialog(2, 2, dialogID, 0)) { + if (cur_obj_update_dialog(&gMarioState[0], 2, 2, dialogID, 0)) { create_sound_spawner(SOUND_OBJ_DYING_ENEMY1); obj_mark_for_deletion(o); diff --git a/src/game/behaviors/bowser.inc.c b/src/game/behaviors/bowser.inc.c index 582383b70..9ba7e176b 100644 --- a/src/game/behaviors/bowser.inc.c +++ b/src/game/behaviors/bowser.inc.c @@ -833,7 +833,7 @@ s32 bowser_dead_not_bits_end(void) { func_8031FFB4(SEQ_PLAYER_LEVEL, 60, 40); o->oBowserUnkF8++; } - if (cur_obj_update_dialog(2, 18, sBowserDefeatedDialogText[o->oBehParams2ndByte], 0)) { + if (cur_obj_update_dialog(&gMarioState[0], 2, 18, sBowserDefeatedDialogText[o->oBehParams2ndByte], 0)) { o->oBowserUnkF8++; cur_obj_play_sound_2(SOUND_GENERAL2_BOWSER_EXPLODE); sequence_player_unlower(SEQ_PLAYER_LEVEL, 60); @@ -843,7 +843,7 @@ s32 bowser_dead_not_bits_end(void) { bowser_dead_hide(); spawn_triangle_break_particles(20, 116, 1.0f, 0); bowser_spawn_grand_star_key(); - set_mario_npc_dialog(0); + set_mario_npc_dialog(&gMarioState[0], 0); ret = 1; } return ret; @@ -862,7 +862,7 @@ s32 bowser_dead_bits_end(void) { func_8031FFB4(SEQ_PLAYER_LEVEL, 60, 40); o->oBowserUnkF8++; } - if (cur_obj_update_dialog(2, 18, dialogID, 0)) { + if (cur_obj_update_dialog(&gMarioState[0], 2, 18, dialogID, 0)) { cur_obj_set_model(MODEL_BOWSER2); sequence_player_unlower(SEQ_PLAYER_LEVEL, 60); sequence_player_fade_out(0, 1); diff --git a/src/game/behaviors/camera_lakitu.inc.c b/src/game/behaviors/camera_lakitu.inc.c index 0f70c3398..9f1f88f92 100644 --- a/src/game/behaviors/camera_lakitu.inc.c +++ b/src/game/behaviors/camera_lakitu.inc.c @@ -32,7 +32,7 @@ static void camera_lakitu_intro_act_trigger_cutscene(void) { && gMarioObject->oPosZ > -2000.0f && gMarioObject->oPosZ < -177.0f && gMarioObject->oPosZ < -177.0f) // always double check your conditions { - if (set_mario_npc_dialog(2) == 1) { + if (set_mario_npc_dialog(&gMarioState[0], 2) == 1) { o->oAction = CAMERA_LAKITU_INTRO_ACT_SPAWN_CLOUD; } } @@ -42,7 +42,7 @@ static void camera_lakitu_intro_act_trigger_cutscene(void) { * Warp up into the air and spawn cloud, then enter the TODO action. */ static void camera_lakitu_intro_act_spawn_cloud(void) { - if (set_mario_npc_dialog(2) == 2) { + if (set_mario_npc_dialog(&gMarioState[0], 2) == 2) { o->oAction = CAMERA_LAKITU_INTRO_ACT_UNK2; o->oPosX = 1800.0f; @@ -115,7 +115,7 @@ static void camera_lakitu_intro_act_show_dialog(void) { } } } - } else if (cur_obj_update_dialog_with_cutscene(2, DIALOG_UNK2_FLAG_0, CUTSCENE_DIALOG, DIALOG_034) != 0) { + } else if (cur_obj_update_dialog_with_cutscene(&gMarioState[0], 2, DIALOG_UNK2_FLAG_0, CUTSCENE_DIALOG, DIALOG_034) != 0) { o->oCameraLakituFinishedDialog = TRUE; } } diff --git a/src/game/behaviors/capswitch.inc.c b/src/game/behaviors/capswitch.inc.c index 12fa5b82f..3220fccb2 100644 --- a/src/game/behaviors/capswitch.inc.c +++ b/src/game/behaviors/capswitch.inc.c @@ -34,7 +34,7 @@ void cap_switch_act_2(void) { queue_rumble_data(5, 80); } } else { - sp1C = cur_obj_update_dialog_with_cutscene(1, 0x0C, CUTSCENE_CAP_SWITCH_PRESS, 0); + sp1C = cur_obj_update_dialog_with_cutscene(&gMarioState[0], 1, 0x0C, CUTSCENE_CAP_SWITCH_PRESS, 0); if (sp1C) o->oAction = 3; } diff --git a/src/game/behaviors/chain_chomp.inc.c b/src/game/behaviors/chain_chomp.inc.c index 07fc57ece..9b80e55e2 100644 --- a/src/game/behaviors/chain_chomp.inc.c +++ b/src/game/behaviors/chain_chomp.inc.c @@ -270,7 +270,7 @@ static void chain_chomp_released_trigger_cutscene(void) { //! Can delay this if we get into a cutscene-unfriendly action after the // last post ground pound and before this - if (set_mario_npc_dialog(2) == 2 && (o->oMoveFlags & OBJ_MOVE_MASK_ON_GROUND) + if (set_mario_npc_dialog(&gMarioState[0], 2) == 2 && (o->oMoveFlags & OBJ_MOVE_MASK_ON_GROUND) && cutscene_object(CUTSCENE_STAR_SPAWN, o) == 1) { o->oChainChompReleaseStatus = CHAIN_CHOMP_RELEASED_LUNGE_AROUND; o->oTimer = 0; @@ -359,7 +359,7 @@ static void chain_chomp_released_jump_away(void) { */ static void chain_chomp_released_end_cutscene(void) { if (cutscene_object(CUTSCENE_STAR_SPAWN, o) == -1) { - set_mario_npc_dialog(0); + set_mario_npc_dialog(&gMarioState[0], 0); o->oAction = CHAIN_CHOMP_ACT_UNLOAD_CHAIN; } } diff --git a/src/game/behaviors/chuckya.inc.c b/src/game/behaviors/chuckya.inc.c index 99a1b5f1d..446ed2146 100644 --- a/src/game/behaviors/chuckya.inc.c +++ b/src/game/behaviors/chuckya.inc.c @@ -1,29 +1,34 @@ // chuckya.c.inc void common_anchor_mario_behavior(f32 sp28, f32 sp2C, s32 sp30) { - switch (o->parentObj->oChuckyaUnk88) { - case 0: - break; - case 1: - obj_set_gfx_pos_at_obj_pos(gMarioObject, o); - break; - case 2: - gMarioObject->oInteractStatus |= (sp30 + INT_STATUS_MARIO_UNK2); - gMarioStates->forwardVel = sp28; - gMarioStates->vel[1] = sp2C; - o->parentObj->oChuckyaUnk88 = 0; - break; - case 3: - gMarioObject->oInteractStatus |= - (INT_STATUS_MARIO_UNK2 + INT_STATUS_MARIO_UNK6); // loads 2 interactions at once? - gMarioStates->forwardVel = 10.0f; - gMarioStates->vel[1] = 10.0f; - o->parentObj->oChuckyaUnk88 = 0; - break; + for (int i = 0; i < MAX_PLAYERS; i++) { + struct MarioState* marioState = &gMarioStates[i]; + struct Object* player = gMarioStates[i].marioObj; + if (marioState->heldByObj != o->parentObj && marioState->heldByObj != o) { continue; } + switch (o->parentObj->oChuckyaUnk88) { + case 0: + break; + case 1: + obj_set_gfx_pos_at_obj_pos(player, o); + break; + case 2: + player->oInteractStatus |= (sp30 + INT_STATUS_MARIO_UNK2); + marioState->forwardVel = sp28; + marioState->vel[1] = sp2C; + o->parentObj->oChuckyaUnk88 = 0; + break; + case 3: + player->oInteractStatus |= + (INT_STATUS_MARIO_UNK2 + INT_STATUS_MARIO_UNK6); // loads 2 interactions at once? + marioState->forwardVel = 10.0f; + marioState->vel[1] = 10.0f; + o->parentObj->oChuckyaUnk88 = 0; + break; + } + o->oMoveAngleYaw = o->parentObj->oMoveAngleYaw; + if (o->parentObj->activeFlags == ACTIVE_FLAG_DEACTIVATED) + obj_mark_for_deletion(o); } - o->oMoveAngleYaw = o->parentObj->oMoveAngleYaw; - if (o->parentObj->activeFlags == ACTIVE_FLAG_DEACTIVATED) - obj_mark_for_deletion(o); } void bhv_chuckya_anchor_mario_loop(void) { diff --git a/src/game/behaviors/dorrie.inc.c b/src/game/behaviors/dorrie.inc.c index abe7ad312..26510ec82 100644 --- a/src/game/behaviors/dorrie.inc.c +++ b/src/game/behaviors/dorrie.inc.c @@ -68,7 +68,7 @@ void dorrie_act_lower_head(void) { if (o->oTimer > 150) { dorrie_begin_head_raise(FALSE); } else if (gMarioObject->platform == o) { - if (o->oDorrieForwardDistToMario > 830.0f && set_mario_npc_dialog(2) == 1) { + if (o->oDorrieForwardDistToMario > 830.0f && set_mario_npc_dialog(&gMarioState[0], 2) == 1) { dorrie_begin_head_raise(TRUE); } else if (o->oDorrieForwardDistToMario > 320.0f) { o->oTimer = 0; @@ -77,7 +77,7 @@ void dorrie_act_lower_head(void) { #else if (gMarioObject->platform == o) { if (o->oDorrieOffsetY == -17.0f && o->oDorrieForwardDistToMario > 780.0f - && set_mario_npc_dialog(2) == 1) { + && set_mario_npc_dialog(&gMarioState[0], 2) == 1) { dorrie_begin_head_raise(TRUE); } else if (o->oDorrieForwardDistToMario > 320.0f) { o->oTimer = 0; @@ -97,10 +97,10 @@ void dorrie_act_raise_head(void) { if (cur_obj_check_if_near_animation_end()) { o->oAction = DORRIE_ACT_MOVE; } else if (o->oDorrieLiftingMario && o->header.gfx.unk38.animFrame < 74) { - if (set_mario_npc_dialog(2) == 2) { + if (set_mario_npc_dialog(&gMarioState[0], 2) == 2) { o->oDorrieHeadRaiseSpeed += 0x1CC; if (cur_obj_check_anim_frame(73)) { - set_mario_npc_dialog(0); + set_mario_npc_dialog(&gMarioState[0], 0); } dorrie_raise_head(); } else { diff --git a/src/game/behaviors/eyerok.inc.c b/src/game/behaviors/eyerok.inc.c index 25047fee4..627bc574a 100644 --- a/src/game/behaviors/eyerok.inc.c +++ b/src/game/behaviors/eyerok.inc.c @@ -47,7 +47,7 @@ static void eyerok_boss_act_wake_up(void) { o->oSubAction += 1; } - if (o->oEyerokBossUnk110 == 0.0f && mario_ready_to_speak() != 0) { + if (o->oEyerokBossUnk110 == 0.0f && mario_ready_to_speak(&gMarioStates[0]) != 0) { o->oAction = EYEROK_BOSS_ACT_SHOW_INTRO_TEXT; } else if (o->oTimer > 150) { if (approach_f32_ptr(&o->oEyerokBossUnk110, 0.0f, 10.0f)) { @@ -63,7 +63,7 @@ static void eyerok_boss_act_wake_up(void) { } static void eyerok_boss_act_show_intro_text(void) { - if (cur_obj_update_dialog_with_cutscene(2, 0, CUTSCENE_DIALOG, DIALOG_117)) { + if (cur_obj_update_dialog_with_cutscene(&gMarioState[0], 2, 0, CUTSCENE_DIALOG, DIALOG_117)) { o->oAction = EYEROK_BOSS_ACT_FIGHT; } } @@ -117,7 +117,7 @@ static void eyerok_boss_act_fight(void) { static void eyerok_boss_act_die(void) { if (o->oTimer == 60) { - if (cur_obj_update_dialog_with_cutscene(2, 0, CUTSCENE_DIALOG, DIALOG_118)) { + if (cur_obj_update_dialog_with_cutscene(&gMarioState[0], 2, 0, CUTSCENE_DIALOG, DIALOG_118)) { spawn_default_star(0.0f, -900.0f, -3700.0f); } else { o->oTimer -= 1; diff --git a/src/game/behaviors/grand_star.inc.c b/src/game/behaviors/grand_star.inc.c index afdf08550..eb9ddc2d6 100644 --- a/src/game/behaviors/grand_star.inc.c +++ b/src/game/behaviors/grand_star.inc.c @@ -51,7 +51,7 @@ void bhv_grand_star_loop(void) { o->oPosY = o->oHomeY + 200.0f; grand_star_zero_velocity(); gObjCutsceneDone = 1; - set_mario_npc_dialog(0); + set_mario_npc_dialog(&gMarioState[0], 0); o->oAction++; o->oInteractStatus = 0; cur_obj_play_sound_2(SOUND_GENERAL_GRAND_STAR_JUMP); diff --git a/src/game/behaviors/hoot.inc.c b/src/game/behaviors/hoot.inc.c index ea47030ce..6e2bc9214 100644 --- a/src/game/behaviors/hoot.inc.c +++ b/src/game/behaviors/hoot.inc.c @@ -254,8 +254,8 @@ void bhv_hoot_loop(void) { case HOOT_AVAIL_WANTS_TO_TALK: hoot_awake_loop(); - if (set_mario_npc_dialog(2) == 2 && cutscene_object_with_dialog(CUTSCENE_DIALOG, o, DIALOG_044)) { - set_mario_npc_dialog(0); + if (set_mario_npc_dialog(&gMarioState[0], 2) == 2 && cutscene_object_with_dialog(CUTSCENE_DIALOG, o, DIALOG_044)) { + set_mario_npc_dialog(&gMarioState[0], 0); cur_obj_become_tangible(); diff --git a/src/game/behaviors/king_bobomb.inc.c b/src/game/behaviors/king_bobomb.inc.c index 7942b2bb8..67422a37e 100644 --- a/src/game/behaviors/king_bobomb.inc.c +++ b/src/game/behaviors/king_bobomb.inc.c @@ -1,5 +1,22 @@ // king_bobomb.c.inc +struct MarioState* king_bobomb_nearest_mario_state() { + struct MarioState* nearest = NULL; + f32 nearestDist = 0; + for (int i = 0; i < MAX_PLAYERS; i++) { + float ydiff = (o->oPosY - gMarioStates[i].marioObj->oPosY); + if (ydiff >= 1200) { continue; } + + float dist = dist_between_objects(o, gMarioState[i].marioObj); + if (nearest == NULL || dist < nearestDist) { + nearest = &gMarioState[i]; + nearestDist = dist; + } + } + + return nearest; +} + // Copy of geo_update_projectile_pos_from_parent Gfx *geo_update_held_mario_pos(s32 run, UNUSED struct GraphNode *node, Mat4 mtx) { Mat4 sp20; @@ -20,6 +37,16 @@ void bhv_bobomb_anchor_mario_loop(void) { common_anchor_mario_behavior(50.0f, 50.0f, 64); } +u8 cur_obj_update_dialog_with_cutscene_hack(s32 actionArg, s32 dialogFlags, s32 cutsceneTable, s32 dialogID) { + // disable dialogs, too weird to sync + return TRUE; + /*if (nearest_mario_state_to_object(o) == &gMarioStates[0]) { + cur_obj_update_dialog_with_cutscene(&gMarioState[0], actionArg, dialogFlags, cutsceneTable, dialogID); + } else { + return FALSE; + }*/ +} + void king_bobomb_act_0(void) { #ifndef VERSION_JP o->oForwardVel = 0; @@ -31,21 +58,21 @@ void king_bobomb_act_0(void) { cur_obj_init_animation_with_sound(5); cur_obj_set_pos_to_home(); o->oHealth = 3; - if (cur_obj_can_mario_activate_textbox_2(500.0f, 100.0f)) { + if (nearest_mario_state_to_object(o) == &gMarioStates[0] && cur_obj_can_mario_activate_textbox_2(&gMarioStates[0], 500.0f, 100.0f)) { o->oSubAction++; func_8031FFB4(SEQ_PLAYER_LEVEL, 60, 40); } - } else if (cur_obj_update_dialog_with_cutscene(2, 1, CUTSCENE_DIALOG, DIALOG_017)) { + } else if (cur_obj_update_dialog_with_cutscene_hack(2, 1, CUTSCENE_DIALOG, DIALOG_017)) { o->oAction = 2; o->oFlags |= OBJ_FLAG_HOLDABLE; } } int mario_is_far_below_object(f32 arg0) { - if (arg0 < o->oPosY - gMarioObject->oPosY) - return 1; - else - return 0; + for (int i = 0; i < MAX_PLAYERS; i++) { + if (arg0 >= o->oPosY - gMarioStates[i].marioObj->oPosY) { return FALSE; } + } + return TRUE; } void king_bobomb_act_2(void) { @@ -67,7 +94,11 @@ void king_bobomb_act_2(void) { cur_obj_init_animation_with_sound(11); if (o->oKingBobombUnk108 == 0) { o->oForwardVel = 3.0f; - cur_obj_rotate_yaw_toward(o->oAngleToMario, 0x100); + struct MarioState* marioState = king_bobomb_nearest_mario_state(); + if (marioState != NULL) { + int angleToPlayer = obj_angle_to_object(o, marioState->marioObj); + cur_obj_rotate_yaw_toward(angleToPlayer, 0x100); + } } else { o->oForwardVel = 0.0f; o->oKingBobombUnk108--; @@ -127,9 +158,17 @@ void king_bobomb_act_1(void) { o->oForwardVel = 0; o->oVelY = 0; cur_obj_init_animation_with_sound(11); - o->oMoveAngleYaw = approach_s16_symmetric(o->oMoveAngleYaw, o->oAngleToMario, 512); - if (o->oDistanceToMario < 2500.0f) + struct MarioState* marioState = king_bobomb_nearest_mario_state(); + int distanceToPlayer = (marioState != NULL) ? dist_between_objects(o, marioState->marioObj) : 3000; + + if (marioState != NULL) { + int angleToPlayer = obj_angle_to_object(o, marioState->marioObj); + o->oMoveAngleYaw = approach_s16_symmetric(o->oMoveAngleYaw, angleToPlayer, 512); + } + + if (distanceToPlayer < 2500.0f) o->oAction = 2; + if (mario_is_far_below_object(1200.0f)) { o->oAction = 0; stop_background_music(SEQUENCE_ARGS(4, SEQ_EVENT_BOSS)); @@ -162,15 +201,20 @@ void king_bobomb_act_6(void) { } } else { cur_obj_init_animation_with_sound(11); - if (cur_obj_rotate_yaw_toward(o->oAngleToMario, 0x800) == 1) - o->oAction = 2; + struct MarioState* marioState = king_bobomb_nearest_mario_state(); + if (marioState != NULL) { + int angleToPlayer = obj_angle_to_object(o, marioState->marioObj); + if (cur_obj_rotate_yaw_toward(angleToPlayer, 0x800) == 1) { + o->oAction = 2; + } + } } } } void king_bobomb_act_7(void) { cur_obj_init_animation_with_sound(2); - if (cur_obj_update_dialog_with_cutscene(2, 2, CUTSCENE_DIALOG, DIALOG_116)) { + if (cur_obj_update_dialog_with_cutscene_hack(2, 2, CUTSCENE_DIALOG, DIALOG_116)) { create_sound_spawner(SOUND_OBJ_KING_WHOMP_DEATH); cur_obj_hide(); cur_obj_become_intangible(); @@ -258,11 +302,11 @@ void king_bobomb_act_5(void) { // bobomb returns home o->oAction = 0; stop_background_music(SEQUENCE_ARGS(4, SEQ_EVENT_BOSS)); } - if (cur_obj_can_mario_activate_textbox_2(500.0f, 100.0f)) + if (nearest_mario_state_to_object(o) == &gMarioStates[0] && cur_obj_can_mario_activate_textbox_2(&gMarioStates[0], 500.0f, 100.0f)) o->oSubAction++; break; case 4: - if (cur_obj_update_dialog_with_cutscene(2, 1, CUTSCENE_DIALOG, DIALOG_128)) + if (cur_obj_update_dialog_with_cutscene_hack(2, 1, CUTSCENE_DIALOG, DIALOG_128)) o->oAction = 2; break; } @@ -296,7 +340,9 @@ void king_bobomb_move(void) { cur_obj_call_action_function(sKingBobombActions); exec_anim_sound_state(sKingBobombSoundStates); #ifndef NODRAWINGDISTANCE - if (o->oDistanceToMario < 5000.0f) + struct Object* player = nearest_player_to_object(o); + int distanceToPlayer = dist_between_objects(o, player); + if (distanceToPlayer < 5000.0f) #endif cur_obj_enable_rendering(); #ifndef NODRAWINGDISTANCE @@ -306,6 +352,15 @@ void king_bobomb_move(void) { } void bhv_king_bobomb_loop(void) { + if (o->oSyncID == 0) { + network_init_object(o, 4000.0f); + network_init_object_field(o, &o->oKingBobombUnk88); + network_init_object_field(o, &o->oFlags); + network_init_object_field(o, &o->oHealth); + network_init_object_field(o, &o->oDialogState); + network_init_object_field(o, &o->oDialogResponse); + } + f32 sp34 = 20.0f; f32 sp30 = 50.0f; UNUSED u8 pad[8]; diff --git a/src/game/behaviors/koopa.inc.c b/src/game/behaviors/koopa.inc.c index 3dd6a6be4..2639db706 100644 --- a/src/game/behaviors/koopa.inc.c +++ b/src/game/behaviors/koopa.inc.c @@ -514,7 +514,7 @@ s32 obj_begin_race(s32 noTimer) { } // Unfreeze mario and disable time stop to begin the race - set_mario_npc_dialog(0); + set_mario_npc_dialog(&gMarioState[0], 0); disable_time_stop_including_mario(); } else if (o->oTimer > 50) { return TRUE; @@ -531,7 +531,7 @@ static void koopa_the_quick_act_wait_before_race(void) { if (o->oKoopaTheQuickInitTextboxCooldown != 0) { o->oKoopaTheQuickInitTextboxCooldown -= 1; - } else if (cur_obj_can_mario_activate_textbox_2(400.0f, 400.0f)) { + } else if (cur_obj_can_mario_activate_textbox_2(&gMarioState[0], 400.0f, 400.0f)) { //! The next action doesn't execute until next frame, giving mario one // frame where he can jump, and thus no longer be ready to speak. // (On J, he has two frames and doing this enables time stop - see @@ -548,7 +548,7 @@ static void koopa_the_quick_act_wait_before_race(void) { */ static void koopa_the_quick_act_show_init_text(void) { s32 response = obj_update_race_proposition_dialog( - sKoopaTheQuickProperties[o->oKoopaTheQuickRaceIndex].initText); + &gMarioStates[0], sKoopaTheQuickProperties[o->oKoopaTheQuickRaceIndex].initText); UNUSED s32 unused; if (response == 1) { @@ -744,7 +744,7 @@ static void koopa_the_quick_act_after_race(void) { cur_obj_init_animation_with_sound(7); if (o->parentObj->oKoopaRaceEndpointUnk100 == 0) { - if (cur_obj_can_mario_activate_textbox_2(400.0f, 400.0f)) { + if (cur_obj_can_mario_activate_textbox_2(&gMarioState[0], 400.0f, 400.0f)) { stop_background_music(SEQUENCE_ARGS(4, SEQ_LEVEL_SLIDE)); // Determine which text to display @@ -767,7 +767,7 @@ static void koopa_the_quick_act_after_race(void) { o->oFlags &= ~OBJ_FLAG_ACTIVE_FROM_AFAR; } } else if (o->parentObj->oKoopaRaceEndpointUnk100 > 0) { - s32 dialogResponse = cur_obj_update_dialog_with_cutscene(2, 1, CUTSCENE_DIALOG, o->parentObj->oKoopaRaceEndpointUnk100); + s32 dialogResponse = cur_obj_update_dialog_with_cutscene(&gMarioState[0], 2, 1, CUTSCENE_DIALOG, o->parentObj->oKoopaRaceEndpointUnk100); if (dialogResponse != 0) { o->parentObj->oKoopaRaceEndpointUnk100 = -1; o->oTimer = 0; diff --git a/src/game/behaviors/mips.inc.c b/src/game/behaviors/mips.inc.c index 7d21df780..e478924b9 100644 --- a/src/game/behaviors/mips.inc.c +++ b/src/game/behaviors/mips.inc.c @@ -239,13 +239,13 @@ void bhv_mips_held(void) { else dialogID = DIALOG_162; - if (set_mario_npc_dialog(1) == 2) { + if (set_mario_npc_dialog(&gMarioState[0], 1) == 2) { o->activeFlags |= ACTIVE_FLAG_INITIATED_TIME_STOP; if (cutscene_object_with_dialog(CUTSCENE_DIALOG, o, dialogID)) { o->oInteractionSubtype |= INT_SUBTYPE_DROP_IMMEDIATELY; o->activeFlags &= ~ACTIVE_FLAG_INITIATED_TIME_STOP; o->oMipsStarStatus = MIPS_STAR_STATUS_SHOULD_SPAWN_STAR; - set_mario_npc_dialog(0); + set_mario_npc_dialog(&gMarioState[0], 0); } } } diff --git a/src/game/behaviors/racing_penguin.inc.c b/src/game/behaviors/racing_penguin.inc.c index f318e053e..e8375dd0a 100644 --- a/src/game/behaviors/racing_penguin.inc.c +++ b/src/game/behaviors/racing_penguin.inc.c @@ -19,7 +19,7 @@ void bhv_racing_penguin_init(void) { static void racing_penguin_act_wait_for_mario(void) { if (o->oTimer > o->oRacingPenguinInitTextCooldown && o->oPosY - gMarioObject->oPosY <= 0.0f - && cur_obj_can_mario_activate_textbox_2(400.0f, 400.0f)) { + && cur_obj_can_mario_activate_textbox_2(&gMarioState[0], 400.0f, 400.0f)) { o->oAction = RACING_PENGUIN_ACT_SHOW_INIT_TEXT; } } @@ -28,7 +28,7 @@ static void racing_penguin_act_show_init_text(void) { s32 response; struct Object *child; - response = obj_update_race_proposition_dialog(sRacingPenguinData[o->oBehParams2ndByte].text); + response = obj_update_race_proposition_dialog(&gMarioStates[0], sRacingPenguinData[o->oBehParams2ndByte].text); if (response == 1) { child = cur_obj_nearest_object_with_behavior(bhvPenguinRaceFinishLine); child->parentObj = o; @@ -122,7 +122,7 @@ static void racing_penguin_act_show_final_text(void) { cur_obj_init_animation_with_sound(3); o->oForwardVel = 0.0f; - if (cur_obj_can_mario_activate_textbox_2(400.0f, 400.0f)) { + if (cur_obj_can_mario_activate_textbox_2(&gMarioState[0], 400.0f, 400.0f)) { if (o->oRacingPenguinMarioWon) { if (o->oRacingPenguinMarioCheated) { o->oRacingPenguinFinalTextbox = DIALOG_132; @@ -144,7 +144,7 @@ static void racing_penguin_act_show_final_text(void) { o->oForwardVel = 4.0f; } } else if (o->oRacingPenguinFinalTextbox > 0) { - if ((textResult = cur_obj_update_dialog_with_cutscene(2, 1, CUTSCENE_DIALOG, o->oRacingPenguinFinalTextbox)) != 0) { + if ((textResult = cur_obj_update_dialog_with_cutscene(&gMarioState[0], 2, 1, CUTSCENE_DIALOG, o->oRacingPenguinFinalTextbox)) != 0) { o->oRacingPenguinFinalTextbox = -1; o->oTimer = 0; } diff --git a/src/game/behaviors/sl_snowman_wind.inc.c b/src/game/behaviors/sl_snowman_wind.inc.c index 7d84258bd..db9fbf305 100644 --- a/src/game/behaviors/sl_snowman_wind.inc.c +++ b/src/game/behaviors/sl_snowman_wind.inc.c @@ -15,13 +15,13 @@ void bhv_sl_snowman_wind_loop(void) { // Check if Mario is within 1000 units of the center of the bridge, and ready to speak. vec3f_copy_2(tempPos, &o->oPosX); obj_set_pos(o, 1100, 3328, 1164); // Position is in the middle of the ice bridge - if (cur_obj_can_mario_activate_textbox(1000.0f, 30.0f, 0x7FFF)) + if (cur_obj_can_mario_activate_textbox(&gMarioState[0], 1000.0f, 30.0f, 0x7FFF)) o->oSubAction++; vec3f_copy_2(&o->oPosX, tempPos); // Mario has come close, begin dialog. } else if (o->oSubAction == SL_SNOWMAN_WIND_ACT_TALKING) { - if (cur_obj_update_dialog(2, 2, DIALOG_153, 0)) + if (cur_obj_update_dialog(&gMarioState[0], 2, 2, DIALOG_153, 0)) o->oSubAction++; // Blowing, spawn wind particles (SL_SNOWMAN_WIND_ACT_BLOWING) diff --git a/src/game/behaviors/snowman.inc.c b/src/game/behaviors/snowman.inc.c index 640438520..49c7203e0 100644 --- a/src/game/behaviors/snowman.inc.c +++ b/src/game/behaviors/snowman.inc.c @@ -124,12 +124,12 @@ void bhv_snowmans_bottom_loop(void) { switch (o->oAction) { case 0: if (is_point_within_radius_of_mario(o->oPosX, o->oPosY, o->oPosZ, 400) == 1 - && set_mario_npc_dialog(1) == 2) { + && set_mario_npc_dialog(&gMarioState[0], 1) == 2) { sp1E = cutscene_object_with_dialog(CUTSCENE_DIALOG, o, DIALOG_110); if (sp1E) { o->oForwardVel = 10.0f; o->oAction = 1; - set_mario_npc_dialog(0); + set_mario_npc_dialog(&gMarioState[0], 0); } } break; @@ -191,7 +191,7 @@ void bhv_snowmans_head_loop(void) { switch (o->oAction) { case 0: - if (trigger_obj_dialog_when_facing(&o->oSnowmansHeadUnkF4, DIALOG_109, 400.0f, 1)) + if (trigger_obj_dialog_when_facing(&gMarioState[0], &o->oSnowmansHeadUnkF4, DIALOG_109, 400.0f, 1)) o->oAction = 1; break; @@ -215,7 +215,7 @@ void bhv_snowmans_head_loop(void) { break; case 4: - if (trigger_obj_dialog_when_facing(&o->oSnowmansHeadUnkF4, DIALOG_111, 700.0f, 2)) { + if (trigger_obj_dialog_when_facing(&gMarioState[0], &o->oSnowmansHeadUnkF4, DIALOG_111, 700.0f, 2)) { spawn_mist_particles(); spawn_default_star(-4700.0f, -1024.0f, 1890.0f); o->oAction = 1; diff --git a/src/game/behaviors/tuxie.inc.c b/src/game/behaviors/tuxie.inc.c index 1dae58501..554d1cf4e 100644 --- a/src/game/behaviors/tuxie.inc.c +++ b/src/game/behaviors/tuxie.inc.c @@ -54,7 +54,7 @@ void tuxies_mother_act_1(void) { dialogID = DIALOG_058; else dialogID = DIALOG_059; - if (cur_obj_update_dialog_with_cutscene(2, 1, CUTSCENE_DIALOG, dialogID)) { + if (cur_obj_update_dialog_with_cutscene(&gMarioState[0], 2, 1, CUTSCENE_DIALOG, dialogID)) { if (dialogID == DIALOG_058) o->oSubAction = 1; else @@ -112,12 +112,12 @@ void tuxies_mother_act_0(void) { } else { switch (o->oSubAction) { case 0: - if (cur_obj_can_mario_activate_textbox_2(300.0f, 100.0f)) + if (cur_obj_can_mario_activate_textbox_2(&gMarioState[0], 300.0f, 100.0f)) if (sp2C == 0) o->oSubAction++; break; case 1: - if (cur_obj_update_dialog_with_cutscene(2, 1, CUTSCENE_DIALOG, DIALOG_057)) + if (cur_obj_update_dialog_with_cutscene(&gMarioState[0], 2, 1, CUTSCENE_DIALOG, DIALOG_057)) o->oSubAction++; break; case 2: diff --git a/src/game/behaviors/ukiki.inc.c b/src/game/behaviors/ukiki.inc.c index e7598253b..a8b8a0361 100644 --- a/src/game/behaviors/ukiki.inc.c +++ b/src/game/behaviors/ukiki.inc.c @@ -374,7 +374,7 @@ void ukiki_act_go_to_cage(void) { cur_obj_init_animation_with_sound(UKIKI_ANIM_JUMP_CLAP); cur_obj_rotate_yaw_toward(o->oAngleToMario, 0x400); - if (cur_obj_can_mario_activate_textbox(200.0f, 30.0f, 0x7FFF)) { + if (cur_obj_can_mario_activate_textbox(&gMarioState[0], 200.0f, 30.0f, 0x7FFF)) { o->oSubAction++; // fallthrough } else { break; @@ -383,7 +383,7 @@ void ukiki_act_go_to_cage(void) { case UKIKI_SUB_ACT_CAGE_TALK_TO_MARIO: cur_obj_init_animation_with_sound(UKIKI_ANIM_HANDSTAND); - if (cur_obj_update_dialog_with_cutscene(3, 1, CUTSCENE_DIALOG, DIALOG_080)) { + if (cur_obj_update_dialog_with_cutscene(&gMarioState[0], 3, 1, CUTSCENE_DIALOG, DIALOG_080)) { o->oSubAction++; } break; @@ -516,7 +516,7 @@ void cage_ukiki_held_loop(void) { if (o->oPosY - o->oHomeY > -100.0f) { switch(o->oUkikiTextState) { case UKIKI_TEXT_DEFAULT: - if (set_mario_npc_dialog(2) == 2) { + if (set_mario_npc_dialog(&gMarioState[0], 2) == 2) { create_dialog_box_with_response(DIALOG_079); o->oUkikiTextState = UKIKI_TEXT_CAGE_TEXTBOX; } @@ -524,7 +524,7 @@ void cage_ukiki_held_loop(void) { case UKIKI_TEXT_CAGE_TEXTBOX: if (gDialogResponse != 0) { - set_mario_npc_dialog(0); + set_mario_npc_dialog(&gMarioState[0], 0); if (gDialogResponse == 1) { o->oInteractionSubtype |= INT_SUBTYPE_DROP_IMMEDIATELY; o->oUkikiTextState = UKIKI_TEXT_GO_TO_CAGE; @@ -567,7 +567,7 @@ void hat_ukiki_held_loop(void) { break; case UKIKI_TEXT_STEAL_HAT: - if (cur_obj_update_dialog(2, 2, DIALOG_100, 0)) { + if (cur_obj_update_dialog(&gMarioState[0], 2, 2, DIALOG_100, 0)) { o->oInteractionSubtype |= INT_SUBTYPE_DROP_IMMEDIATELY; o->oUkikiTextState = UKIKI_TEXT_STOLE_HAT; } @@ -577,9 +577,9 @@ void hat_ukiki_held_loop(void) { break; case UKIKI_TEXT_HAS_HAT: - if (cur_obj_update_dialog(2, 18, DIALOG_101, 0)) { + if (cur_obj_update_dialog(&gMarioState[0], 2, 18, DIALOG_101, 0)) { mario_retrieve_cap(); - set_mario_npc_dialog(0); + set_mario_npc_dialog(&gMarioState[0], 0); o->oUkikiHasHat &= ~UKIKI_HAT_ON; o->oUkikiTextState = UKIKI_TEXT_GAVE_HAT_BACK; } diff --git a/src/game/behaviors/whomp.inc.c b/src/game/behaviors/whomp.inc.c index 1f3bcb7f0..0e0119d62 100644 --- a/src/game/behaviors/whomp.inc.c +++ b/src/game/behaviors/whomp.inc.c @@ -28,7 +28,7 @@ void whomp_act_0(void) { cur_obj_set_pos_to_home(); o->oHealth = 3; } - } else if (cur_obj_update_dialog_with_cutscene(2, 1, CUTSCENE_DIALOG, DIALOG_114)) + } else if (cur_obj_update_dialog_with_cutscene(&gMarioState[0], 2, 1, CUTSCENE_DIALOG, DIALOG_114)) o->oAction = 2; } else if (o->oDistanceToMario < 500.0f) o->oAction = 1; @@ -209,7 +209,7 @@ void whomp_act_6(void) { void whomp_act_8(void) { if (o->oBehParams2ndByte != 0) { - if (cur_obj_update_dialog_with_cutscene(2, 2, CUTSCENE_DIALOG, DIALOG_115)) { + if (cur_obj_update_dialog_with_cutscene(&gMarioState[0], 2, 2, CUTSCENE_DIALOG, DIALOG_115)) { obj_set_angle(o, 0, 0, 0); cur_obj_hide(); cur_obj_become_intangible(); diff --git a/src/game/behaviors/wiggler.inc.c b/src/game/behaviors/wiggler.inc.c index 4c465f809..e24a51144 100644 --- a/src/game/behaviors/wiggler.inc.c +++ b/src/game/behaviors/wiggler.inc.c @@ -228,7 +228,7 @@ static void wiggler_act_walk(void) { // If Mario is positioned below the wiggler, assume he entered through the // lower cave entrance, so don't display text. - if (gMarioObject->oPosY < o->oPosY || cur_obj_update_dialog_with_cutscene(2, 0, CUTSCENE_DIALOG, DIALOG_150) != 0) { + if (gMarioObject->oPosY < o->oPosY || cur_obj_update_dialog_with_cutscene(&gMarioState[0], 2, 0, CUTSCENE_DIALOG, DIALOG_150) != 0) { o->oWigglerTextStatus = WIGGLER_TEXT_STATUS_COMPLETED_DIALOG; } } else { @@ -304,7 +304,7 @@ static void wiggler_act_jumped_on(void) { // defeated) or go back to walking if (o->header.gfx.scale[1] >= 4.0f) { if (o->oTimer > 30) { - if (cur_obj_update_dialog_with_cutscene(2, 0, CUTSCENE_DIALOG, attackText[o->oHealth - 2]) != 0) { + if (cur_obj_update_dialog_with_cutscene(&gMarioState[0], 2, 0, CUTSCENE_DIALOG, attackText[o->oHealth - 2]) != 0) { // Because we don't want the wiggler to disappear after being // defeated, we leave its health at 1 if (--o->oHealth == 1) { diff --git a/src/game/behaviors/yoshi.inc.c b/src/game/behaviors/yoshi.inc.c index b60d2df9a..b2c495717 100644 --- a/src/game/behaviors/yoshi.inc.c +++ b/src/game/behaviors/yoshi.inc.c @@ -75,7 +75,7 @@ void yoshi_idle_loop(void) { void yoshi_talk_loop(void) { if ((s16) o->oMoveAngleYaw == (s16) o->oAngleToMario) { cur_obj_init_animation(0); - if (set_mario_npc_dialog(1) == 2) { + if (set_mario_npc_dialog(&gMarioState[0], 1) == 2) { o->activeFlags |= ACTIVE_FLAG_INITIATED_TIME_STOP; if (cutscene_object_with_dialog(CUTSCENE_DIALOG, o, DIALOG_161)) { o->activeFlags &= ~ACTIVE_FLAG_INITIATED_TIME_STOP; @@ -122,7 +122,7 @@ void yoshi_finish_jumping_and_despawn_loop(void) { obj_move_xyz_using_fvel_and_yaw(o); o->oVelY -= 2.0; if (o->oPosY < 2100.0f) { - set_mario_npc_dialog(0); + set_mario_npc_dialog(&gMarioState[0], 0); gObjCutsceneDone = TRUE; sYoshiDead = 1; o->activeFlags = ACTIVE_FLAG_DEACTIVATED; diff --git a/src/game/camera.c b/src/game/camera.c index 23c40a7b4..d2862da08 100644 --- a/src/game/camera.c +++ b/src/game/camera.c @@ -7062,7 +7062,7 @@ void copy_spline_segment(struct CutsceneSplinePoint dst[], struct CutsceneSpline s16 cutscene_common_set_dialog_state(s32 state) { s16 timer = gCutsceneTimer; // If the dialog ended, return CUTSCENE_LOOP, which would end the cutscene shot - if (set_mario_npc_dialog(state) == 2) { + if (set_mario_npc_dialog(&gMarioState[0], state) == 2) { timer = CUTSCENE_LOOP; } return timer; diff --git a/src/game/mario.c b/src/game/mario.c index 59ed5585a..a1530eb72 100644 --- a/src/game/mario.c +++ b/src/game/mario.c @@ -726,6 +726,9 @@ s16 find_floor_slope(struct MarioState *m, s16 yawOffset) { * Adjusts Mario's camera and sound based on his action status. */ void update_mario_sound_and_camera(struct MarioState *m) { + // only update for local player + if (m != &gMarioStates[0]) { return; } + u32 action = m->action; s32 camPreset = m->area->camera->mode; @@ -1678,7 +1681,7 @@ void mario_update_hitbox_and_cap_model(struct MarioState *m) { // this can be paused through to give continual invisibility. This leads to // no interaction with objects. if (gGlobalTimer & 1) { - gMarioState->marioObj->header.gfx.node.flags |= GRAPH_RENDER_INVISIBLE; + m->marioObj->header.gfx.node.flags |= GRAPH_RENDER_INVISIBLE; } } diff --git a/src/game/mario_actions_automatic.c b/src/game/mario_actions_automatic.c index a74f4a186..c8639cd90 100644 --- a/src/game/mario_actions_automatic.c +++ b/src/game/mario_actions_automatic.c @@ -652,14 +652,18 @@ s32 act_grabbed(struct MarioState *m) { if (m->marioObj->oInteractStatus & INT_STATUS_MARIO_UNK2) { s32 thrown = (m->marioObj->oInteractStatus & INT_STATUS_MARIO_UNK6) == 0; - m->faceAngle[1] = m->usedObj->oMoveAngleYaw; + if (m->usedObj != NULL) { + m->faceAngle[1] = m->usedObj->oMoveAngleYaw; + } + vec3f_copy(m->pos, m->marioObj->header.gfx.pos); queue_rumble_data(5, 60); + m->heldByObj = NULL; return set_mario_action(m, (m->forwardVel >= 0.0f) ? ACT_THROWN_FORWARD : ACT_THROWN_BACKWARD, thrown); } - + if (m->usedObj != NULL) { m->heldByObj = m->usedObj; } set_mario_animation(m, MARIO_ANIM_BEING_GRABBED); return FALSE; } diff --git a/src/game/mario_actions_cutscene.c b/src/game/mario_actions_cutscene.c index 787d74e95..93a49793e 100644 --- a/src/game/mario_actions_cutscene.c +++ b/src/game/mario_actions_cutscene.c @@ -331,14 +331,14 @@ void cutscene_put_cap_on(struct MarioState *m) { * 2: Mario mat not be riding a shell or be invulnerable. * 3: Mario must not be in first person mode. */ -s32 mario_ready_to_speak(void) { - u32 actionGroup = gMarioState->action & ACT_GROUP_MASK; +s32 mario_ready_to_speak(struct MarioState* m) { + u32 actionGroup = m->action & ACT_GROUP_MASK; s32 isReadyToSpeak = FALSE; - if ((gMarioState->action == ACT_WAITING_FOR_DIALOG || actionGroup == ACT_GROUP_STATIONARY + if ((m->action == ACT_WAITING_FOR_DIALOG || actionGroup == ACT_GROUP_STATIONARY || actionGroup == ACT_GROUP_MOVING) - && (!(gMarioState->action & (ACT_FLAG_RIDING_SHELL | ACT_FLAG_INVULNERABLE)) - && gMarioState->action != ACT_FIRST_PERSON)) { + && (!(m->action & (ACT_FLAG_RIDING_SHELL | ACT_FLAG_INVULNERABLE)) + && m->action != ACT_FIRST_PERSON)) { isReadyToSpeak = TRUE; } @@ -351,24 +351,24 @@ s32 mario_ready_to_speak(void) { // 0 = not in dialog // 1 = starting dialog // 2 = speaking -s32 set_mario_npc_dialog(s32 actionArg) { +s32 set_mario_npc_dialog(struct MarioState* m, s32 actionArg) { s32 dialogState = 0; // in dialog - if (gMarioState->action == ACT_READING_NPC_DIALOG) { - if (gMarioState->actionState < 8) { + if (m->action == ACT_READING_NPC_DIALOG) { + if (m->actionState < 8) { dialogState = 1; // starting dialog } - if (gMarioState->actionState == 8) { + if (m->actionState == 8) { if (actionArg == 0) { - gMarioState->actionState++; // exit dialog + m->actionState++; // exit dialog } else { dialogState = 2; } } - } else if (actionArg != 0 && mario_ready_to_speak()) { - gMarioState->usedObj = gCurrentObject; - set_mario_action(gMarioState, ACT_READING_NPC_DIALOG, actionArg); + } else if (actionArg != 0 && mario_ready_to_speak(m)) { + m->usedObj = gCurrentObject; + set_mario_action(m, ACT_READING_NPC_DIALOG, actionArg); dialogState = 1; // starting dialog } diff --git a/src/game/mario_actions_cutscene.h b/src/game/mario_actions_cutscene.h index 276826cf5..5a2f22e2c 100644 --- a/src/game/mario_actions_cutscene.h +++ b/src/game/mario_actions_cutscene.h @@ -10,8 +10,8 @@ void print_displaying_credits_entry(void); void bhv_end_peach_loop(void); void bhv_end_toad_loop(void); s32 geo_switch_peach_eyes(s32 run, struct GraphNode *node, UNUSED s32 a2); -s32 mario_ready_to_speak(void); -s32 set_mario_npc_dialog(s32 actionArg); +s32 mario_ready_to_speak(struct MarioState* m); +s32 set_mario_npc_dialog(struct MarioState* m, s32 actionArg); s32 mario_execute_cutscene_action(struct MarioState *m); #endif // MARIO_ACTIONS_CUTSCENE_H diff --git a/src/game/mario_misc.c b/src/game/mario_misc.c index 95d879c71..511875b21 100644 --- a/src/game/mario_misc.c +++ b/src/game/mario_misc.c @@ -124,7 +124,7 @@ static void toad_message_opaque(void) { } static void toad_message_talking(void) { - if (cur_obj_update_dialog_with_cutscene(3, 1, CUTSCENE_DIALOG, gCurrentObject->oToadMessageDialogId) + if (cur_obj_update_dialog_with_cutscene(&gMarioState[0], 3, 1, CUTSCENE_DIALOG, gCurrentObject->oToadMessageDialogId) != 0) { gCurrentObject->oToadMessageRecentlyTalked = 1; gCurrentObject->oToadMessageState = TOAD_MESSAGE_FADING; diff --git a/src/game/obj_behaviors.c b/src/game/obj_behaviors.c index ab0e4c03a..d2b40e58a 100644 --- a/src/game/obj_behaviors.c +++ b/src/game/obj_behaviors.c @@ -519,42 +519,25 @@ s32 is_point_within_radius_of_mario(f32 x, f32 y, f32 z, s32 dist) { * Returns either gMarioObject or gLuigiObject depending on what is closer */ struct MarioState* nearest_mario_state_to_object(struct Object *obj) { - f32 mx = gMarioState[0].marioObj->header.gfx.pos[0] - obj->oPosX; - f32 my = gMarioState[0].marioObj->header.gfx.pos[1] - obj->oPosY; - f32 mz = gMarioState[0].marioObj->header.gfx.pos[2] - obj->oPosZ; - mx *= mx; - my *= my; - mz *= mz; + struct MarioState* nearest = NULL; + f32 nearestDist = 0; + for (int i = 0; i < MAX_PLAYERS; i++) { + float dist = dist_between_objects(obj, gMarioState[i].marioObj); + if (nearest == NULL || dist < nearestDist) { + nearest = &gMarioState[i]; + nearestDist = dist; + } + } - f32 lx = gMarioState[1].marioObj->header.gfx.pos[0] - obj->oPosX; - f32 ly = gMarioState[1].marioObj->header.gfx.pos[1] - obj->oPosY; - f32 lz = gMarioState[1].marioObj->header.gfx.pos[2] - obj->oPosZ; - lx *= lx; - ly *= ly; - lz *= lz; - - return (mx + my + mz <= lx + ly + lz) ? &gMarioState[0] : &gMarioState[1]; + return nearest; } /** * Returns either gMarioObject or gLuigiObject depending on what is closer */ struct Object* nearest_player_to_object(struct Object *obj) { - f32 mx = gMarioObject->header.gfx.pos[0] - obj->oPosX; - f32 my = gMarioObject->header.gfx.pos[1] - obj->oPosY; - f32 mz = gMarioObject->header.gfx.pos[2] - obj->oPosZ; - mx *= mx; - my *= my; - mz *= mz; - - f32 lx = gLuigiObject->header.gfx.pos[0] - obj->oPosX; - f32 ly = gLuigiObject->header.gfx.pos[1] - obj->oPosY; - f32 lz = gLuigiObject->header.gfx.pos[2] - obj->oPosZ; - lx *= lx; - ly *= ly; - lz *= lz; - - return (mx + my + mz <= lx + ly + lz) ? gMarioObject : gLuigiObject; + struct MarioState* nearest = nearest_mario_state_to_object(obj); + return nearest->marioObj; } /** @@ -734,19 +717,21 @@ s8 current_mario_room_check(s16 room) { /** * Triggers dialog when Mario is facing an object and controls it while in the dialog. */ -s16 trigger_obj_dialog_when_facing(s32 *inDialog, s16 dialogID, f32 dist, s32 actionArg) { +s16 trigger_obj_dialog_when_facing(struct MarioState* m, s32 *inDialog, s16 dialogID, f32 dist, s32 actionArg) { s16 dialogueResponse; + int angleToPlayer = obj_angle_to_object(o, m->marioObj); + if ((is_point_within_radius_of_mario(o->oPosX, o->oPosY, o->oPosZ, (s32) dist) == 1 - && obj_check_if_facing_toward_angle(o->oFaceAngleYaw, gMarioObject->header.gfx.angle[1] + 0x8000, 0x1000) == 1 - && obj_check_if_facing_toward_angle(o->oMoveAngleYaw, o->oAngleToMario, 0x1000) == 1) + && obj_check_if_facing_toward_angle(o->oFaceAngleYaw, m->marioObj->header.gfx.angle[1] + 0x8000, 0x1000) == 1 + && obj_check_if_facing_toward_angle(o->oMoveAngleYaw, angleToPlayer, 0x1000) == 1) || (*inDialog == 1)) { *inDialog = 1; - if (set_mario_npc_dialog(actionArg) == 2) { //If Mario is speaking. + if (set_mario_npc_dialog(m, actionArg) == 2) { //If Mario is speaking. dialogueResponse = cutscene_object_with_dialog(CUTSCENE_DIALOG, o, dialogID); if (dialogueResponse != 0) { - set_mario_npc_dialog(0); + set_mario_npc_dialog(m, 0); *inDialog = 0; return dialogueResponse; } diff --git a/src/game/obj_behaviors_2.c b/src/game/obj_behaviors_2.c index a7c7db73e..6b9296b4e 100644 --- a/src/game/obj_behaviors_2.c +++ b/src/game/obj_behaviors_2.c @@ -97,12 +97,12 @@ static s16 obj_get_pitch_from_vel(void) { * If the player declines the race, then disable time stop and allow Mario to * move again. */ -static s32 obj_update_race_proposition_dialog(s16 dialogID) { +static s32 obj_update_race_proposition_dialog(struct MarioState* m, s16 dialogID) { s32 dialogResponse = - cur_obj_update_dialog_with_cutscene(2, DIALOG_UNK2_FLAG_0 | DIALOG_UNK2_LEAVE_TIME_STOP_ENABLED, CUTSCENE_RACE_DIALOG, dialogID); + cur_obj_update_dialog_with_cutscene(m, 2, DIALOG_UNK2_FLAG_0 | DIALOG_UNK2_LEAVE_TIME_STOP_ENABLED, CUTSCENE_RACE_DIALOG, dialogID); if (dialogResponse == 2) { - set_mario_npc_dialog(0); + set_mario_npc_dialog(m, 0); disable_time_stop_including_mario(); } diff --git a/src/game/object_helpers.c b/src/game/object_helpers.c index b13d3d9bd..d09b997c8 100644 --- a/src/game/object_helpers.c +++ b/src/game/object_helpers.c @@ -2600,17 +2600,17 @@ void clear_time_stop_flags(s32 flags) { gTimeStopState = gTimeStopState & (flags ^ 0xFFFFFFFF); } -s32 cur_obj_can_mario_activate_textbox(f32 radius, f32 height, UNUSED s32 unused) { +s32 cur_obj_can_mario_activate_textbox(struct MarioState* m, f32 radius, f32 height, UNUSED s32 unused) { f32 latDistToMario; UNUSED s16 angleFromMario; if (o->oDistanceToMario < 1500.0f) { - latDistToMario = lateral_dist_between_objects(o, gMarioObject); - angleFromMario = obj_angle_to_object(gMarioObject, o); + latDistToMario = lateral_dist_between_objects(o, m->marioObj); + angleFromMario = obj_angle_to_object(m->marioObj, o); - if (latDistToMario < radius && o->oPosY < gMarioObject->oPosY + 160.0f - && gMarioObject->oPosY < o->oPosY + height && !(gMarioStates[0].action & ACT_FLAG_AIR) - && mario_ready_to_speak()) { + if (latDistToMario < radius && o->oPosY < m->marioObj->oPosY + 160.0f + && m->marioObj->oPosY < o->oPosY + height && !(m->action & ACT_FLAG_AIR) + && mario_ready_to_speak(m)) { return TRUE; } } @@ -2618,21 +2618,21 @@ s32 cur_obj_can_mario_activate_textbox(f32 radius, f32 height, UNUSED s32 unused return FALSE; } -s32 cur_obj_can_mario_activate_textbox_2(f32 radius, f32 height) { +s32 cur_obj_can_mario_activate_textbox_2(struct MarioState* m, f32 radius, f32 height) { // The last argument here is unused. When this function is called directly the argument is always set to 0x7FFF. - return cur_obj_can_mario_activate_textbox(radius, height, 0x1000); + return cur_obj_can_mario_activate_textbox(m, radius, height, 0x1000); } -static void cur_obj_end_dialog(s32 dialogFlags, s32 dialogResult) { +static void cur_obj_end_dialog(struct MarioState* m, s32 dialogFlags, s32 dialogResult) { o->oDialogResponse = dialogResult; o->oDialogState++; if (!(dialogFlags & DIALOG_UNK1_FLAG_4)) { - set_mario_npc_dialog(0); + set_mario_npc_dialog(m, 0); } } -s32 cur_obj_update_dialog(s32 actionArg, s32 dialogFlags, s32 dialogID, UNUSED s32 unused) { +s32 cur_obj_update_dialog(struct MarioState* m, s32 actionArg, s32 dialogFlags, s32 dialogID, UNUSED s32 unused) { s32 dialogResponse = 0; UNUSED s32 doneTurning = TRUE; @@ -2642,7 +2642,7 @@ s32 cur_obj_update_dialog(s32 actionArg, s32 dialogFlags, s32 dialogID, UNUSED s //! We enable time stop even if Mario is not ready to speak. This // allows us to move during time stop as long as Mario never enters // an action that can be interrupted with text. - if (gMarioState->health >= 0x100) { + if (m->health >= 0x100) { gTimeStopState |= TIME_STOP_ENABLED; o->activeFlags |= ACTIVE_FLAG_INITIATED_TIME_STOP; o->oDialogState++; @@ -2652,7 +2652,7 @@ s32 cur_obj_update_dialog(s32 actionArg, s32 dialogFlags, s32 dialogID, UNUSED s case DIALOG_UNK1_ENABLE_TIME_STOP: // Patched :( // Wait for Mario to be ready to speak, and then enable time stop - if (mario_ready_to_speak() || gMarioState->action == ACT_READING_NPC_DIALOG) { + if (mario_ready_to_speak(m) || m->action == ACT_READING_NPC_DIALOG) { //gTimeStopState |= TIME_STOP_ENABLED; o->activeFlags |= ACTIVE_FLAG_INITIATED_TIME_STOP; o->oDialogState++; @@ -2664,7 +2664,7 @@ s32 cur_obj_update_dialog(s32 actionArg, s32 dialogFlags, s32 dialogID, UNUSED s #endif case DIALOG_UNK1_INTERRUPT_MARIO_ACTION: - if (set_mario_npc_dialog(actionArg) == 2) { + if (set_mario_npc_dialog(m, actionArg) == 2) { o->oDialogState++; } break; @@ -2681,19 +2681,19 @@ s32 cur_obj_update_dialog(s32 actionArg, s32 dialogFlags, s32 dialogID, UNUSED s case DIALOG_UNK1_AWAIT_DIALOG: if (dialogFlags & DIALOG_UNK1_FLAG_RESPONSE) { if (gDialogResponse != 0) { - cur_obj_end_dialog(dialogFlags, gDialogResponse); + cur_obj_end_dialog(m, dialogFlags, gDialogResponse); } } else if (dialogFlags & DIALOG_UNK1_FLAG_DEFAULT) { if (get_dialog_id() == -1) { - cur_obj_end_dialog(dialogFlags, 3); + cur_obj_end_dialog(m, dialogFlags, 3); } } else { - cur_obj_end_dialog(dialogFlags, 3); + cur_obj_end_dialog(m, dialogFlags, 3); } break; case DIALOG_UNK1_DISABLE_TIME_STOP: - if (gMarioState->action != ACT_READING_NPC_DIALOG || (dialogFlags & DIALOG_UNK1_FLAG_4)) { + if (m->action != ACT_READING_NPC_DIALOG || (dialogFlags & DIALOG_UNK1_FLAG_4)) { gTimeStopState &= ~TIME_STOP_ENABLED; o->activeFlags &= ~ACTIVE_FLAG_INITIATED_TIME_STOP; dialogResponse = o->oDialogResponse; @@ -2709,7 +2709,7 @@ s32 cur_obj_update_dialog(s32 actionArg, s32 dialogFlags, s32 dialogID, UNUSED s return dialogResponse; } -s32 cur_obj_update_dialog_with_cutscene(s32 actionArg, s32 dialogFlags, s32 cutsceneTable, s32 dialogID) { +s32 cur_obj_update_dialog_with_cutscene(struct MarioState* m, s32 actionArg, s32 dialogFlags, s32 cutsceneTable, s32 dialogID) { s32 dialogResponse = 0; s32 doneTurning = TRUE; @@ -2719,7 +2719,7 @@ s32 cur_obj_update_dialog_with_cutscene(s32 actionArg, s32 dialogFlags, s32 cuts //! We enable time stop even if Mario is not ready to speak. This // allows us to move during time stop as long as Mario never enters // an action that can be interrupted with text. - if (gMarioState->health >= 0x0100) { + if (m->health >= 0x0100) { gTimeStopState |= TIME_STOP_ENABLED; o->activeFlags |= ACTIVE_FLAG_INITIATED_TIME_STOP; o->oDialogState++; @@ -2729,7 +2729,7 @@ s32 cur_obj_update_dialog_with_cutscene(s32 actionArg, s32 dialogFlags, s32 cuts #else case DIALOG_UNK2_ENABLE_TIME_STOP: // Wait for Mario to be ready to speak, and then enable time stop - if (mario_ready_to_speak() || gMarioState->action == ACT_READING_NPC_DIALOG) { + if (mario_ready_to_speak(m) || m->action == ACT_READING_NPC_DIALOG) { //gTimeStopState |= TIME_STOP_ENABLED; o->activeFlags |= ACTIVE_FLAG_INITIATED_TIME_STOP; o->oDialogState++; @@ -2743,13 +2743,13 @@ s32 cur_obj_update_dialog_with_cutscene(s32 actionArg, s32 dialogFlags, s32 cuts case DIALOG_UNK2_TURN_AND_INTERRUPT_MARIO_ACTION: if (dialogFlags & DIALOG_UNK2_FLAG_0) { - doneTurning = cur_obj_rotate_yaw_toward(obj_angle_to_object(o, gMarioObject), 0x800); + doneTurning = cur_obj_rotate_yaw_toward(obj_angle_to_object(o, m->marioObj), 0x800); if (o->oDialogResponse >= 0x21) { doneTurning = TRUE; } } - if (set_mario_npc_dialog(actionArg) == 2 && doneTurning) { + if (set_mario_npc_dialog(m, actionArg) == 2 && doneTurning) { o->oDialogResponse = 0; o->oDialogState++; } else { @@ -2773,13 +2773,13 @@ s32 cur_obj_update_dialog_with_cutscene(s32 actionArg, s32 dialogFlags, s32 cuts if (dialogFlags & DIALOG_UNK2_LEAVE_TIME_STOP_ENABLED) { dialogResponse = o->oDialogResponse; o->oDialogState = DIALOG_UNK2_ENABLE_TIME_STOP; - } else if (gMarioState->action != ACT_READING_NPC_DIALOG) { + } else if (m->action != ACT_READING_NPC_DIALOG) { gTimeStopState &= ~TIME_STOP_ENABLED; o->activeFlags &= ~ACTIVE_FLAG_INITIATED_TIME_STOP; dialogResponse = o->oDialogResponse; o->oDialogState = DIALOG_UNK2_ENABLE_TIME_STOP; } else { - set_mario_npc_dialog(0); + set_mario_npc_dialog(m, 0); } break; } diff --git a/src/game/object_helpers.h b/src/game/object_helpers.h index b959d362d..66f28aaaa 100644 --- a/src/game/object_helpers.h +++ b/src/game/object_helpers.h @@ -276,10 +276,10 @@ void enable_time_stop(void); void disable_time_stop(void); void set_time_stop_flags(s32 flags); void clear_time_stop_flags(s32 flags); -s32 cur_obj_can_mario_activate_textbox(f32 radius, f32 height, UNUSED s32 unused); -s32 cur_obj_can_mario_activate_textbox_2(f32 radius, f32 height); -s32 cur_obj_update_dialog(s32 actionArg, s32 dialogFlags, s32 dialogID, UNUSED s32 unused); -s32 cur_obj_update_dialog_with_cutscene(s32 actionArg, s32 dialogFlags, s32 cutsceneTable, s32 dialogID); +s32 cur_obj_can_mario_activate_textbox(struct MarioState* m, f32 radius, f32 height, UNUSED s32 unused); +s32 cur_obj_can_mario_activate_textbox_2(struct MarioState* m, f32 radius, f32 height); +s32 cur_obj_update_dialog(struct MarioState* m, s32 actionArg, s32 dialogFlags, s32 dialogID, UNUSED s32 unused); +s32 cur_obj_update_dialog_with_cutscene(struct MarioState* m, s32 actionArg, s32 dialogFlags, s32 cutsceneTable, s32 dialogID); s32 cur_obj_has_model(u16 modelID); void cur_obj_align_gfx_with_floor(void); s32 mario_is_within_rectangle(s16 minX, s16 maxX, s16 minZ, s16 maxZ); diff --git a/src/pc/network/packets/packet_object.c b/src/pc/network/packets/packet_object.c index 469e709e0..db31e3abe 100644 --- a/src/pc/network/packets/packet_object.c +++ b/src/pc/network/packets/packet_object.c @@ -63,25 +63,26 @@ void network_send_object(struct Object* o) { struct Packet p; packet_init(&p, PACKET_OBJECT, reliable); packet_write(&p, &o->oSyncID, 4); - packet_write(&p, &so->onEventId, 2); + packet_write(&p, &so->onEventId, sizeof(u16)); packet_write(&p, &so->behavior, sizeof(void*)); - packet_write(&p, &o->activeFlags, 2); + packet_write(&p, &o->activeFlags, sizeof(s16)); + packet_write(&p, &o->header.gfx.node.flags, sizeof(s16)); if (so->fullObjectSync) { - packet_write(&p, o->rawData.asU32, 320); + packet_write(&p, o->rawData.asU32, sizeof(u32) * 80); } else { - packet_write(&p, &o->oPosX, 28); - packet_write(&p, &o->oAction, 4); - packet_write(&p, &o->oSubAction, 4); - packet_write(&p, &o->oInteractStatus, 4); - packet_write(&p, &o->oHeldState, 4); - packet_write(&p, &o->oMoveAngleYaw, 4); - packet_write(&p, &o->oTimer, 4); + packet_write(&p, &o->oPosX, sizeof(u32) * 7); + packet_write(&p, &o->oAction, sizeof(u32)); + packet_write(&p, &o->oSubAction, sizeof(u32)); + packet_write(&p, &o->oInteractStatus, sizeof(u32)); + packet_write(&p, &o->oHeldState, sizeof(u32)); + packet_write(&p, &o->oMoveAngleYaw, sizeof(u32)); + packet_write(&p, &o->oTimer, sizeof(u32)); - packet_write(&p, &so->extraFieldCount, 1); + packet_write(&p, &so->extraFieldCount, sizeof(u8)); for (int i = 0; i < so->extraFieldCount; i++) { assert(so->extraFields[i] != NULL); - packet_write(&p, so->extraFields[i], 4); + packet_write(&p, so->extraFields[i], sizeof(u32)); } } @@ -101,7 +102,7 @@ void network_send_object(struct Object* o) { void network_receive_object(struct Packet* p) { // get sync ID u32 syncId; - packet_read(p, &syncId, 4); + packet_read(p, &syncId, sizeof(u32)); assert(syncId < MAX_SYNC_OBJECTS); // retrieve SyncObject @@ -119,7 +120,7 @@ void network_receive_object(struct Packet* p) { // make sure this is the newest event possible volatile u16 eventId = 0; - packet_read(p, &eventId, 2); + packet_read(p, &eventId, sizeof(u16)); if (so->onEventId > eventId && (u16)abs(eventId - so->onEventId) < USHRT_MAX / 2) { return; } so->onEventId = eventId; @@ -134,7 +135,7 @@ void network_receive_object(struct Packet* p) { // sync only death if (so->maxSyncDistance == SYNC_DISTANCE_ONLY_DEATH) { s16 activeFlags; - packet_read(p, &activeFlags, 2); + packet_read(p, &activeFlags, sizeof(u16)); if (activeFlags == ACTIVE_FLAG_DEACTIVATED) { so->o->oSyncDeath = 1; forget_sync_object(so); @@ -142,28 +143,33 @@ void network_receive_object(struct Packet* p) { return; } + if (gMarioStates[0].heldObj == o) { + return; + } + // write object flags - packet_read(p, &o->activeFlags, 2); + packet_read(p, &o->activeFlags, sizeof(u16)); + packet_read(p, &o->header.gfx.node.flags, sizeof(s16)); if (so->fullObjectSync) { - packet_read(p, o->rawData.asU32, 320); + packet_read(p, o->rawData.asU32, sizeof(u32) * 80); } else { - packet_read(p, &o->oPosX, 28); - packet_read(p, &o->oAction, 4); - packet_read(p, &o->oSubAction, 4); - packet_read(p, &o->oInteractStatus, 4); - packet_read(p, &o->oHeldState, 4); - packet_read(p, &o->oMoveAngleYaw, 4); - packet_read(p, &o->oTimer, 4); + packet_read(p, &o->oPosX, sizeof(u32) * 7); + packet_read(p, &o->oAction, sizeof(u32)); + packet_read(p, &o->oSubAction, sizeof(u32)); + packet_read(p, &o->oInteractStatus, sizeof(u32)); + packet_read(p, &o->oHeldState, sizeof(u32)); + packet_read(p, &o->oMoveAngleYaw, sizeof(u32)); + packet_read(p, &o->oTimer, sizeof(u32)); } // write extra fields u8 extraFields = 0; - packet_read(p, &extraFields, 1); + packet_read(p, &extraFields, sizeof(u8)); assert(extraFields == so->extraFieldCount); for (int i = 0; i < extraFields; i++) { assert(so->extraFields[i] != NULL); - packet_read(p, so->extraFields[i], 4); + packet_read(p, so->extraFields[i], sizeof(u32)); } // deactivated @@ -232,4 +238,4 @@ void network_update_objects(void) { network_send_object(syncObjects[i].o); } -} \ No newline at end of file +} diff --git a/src/pc/network/packets/packet_player.c b/src/pc/network/packets/packet_player.c index ed81817b3..990627554 100644 --- a/src/pc/network/packets/packet_player.c +++ b/src/pc/network/packets/packet_player.c @@ -8,15 +8,19 @@ void network_send_player(void) { u32 heldSyncID = (gMarioStates[0].heldObj != NULL) ? gMarioStates[0].heldObj->oSyncID : NULL; + u32 heldBySyncID = (gMarioStates[0].heldByObj != NULL) + ? gMarioStates[0].heldByObj->oSyncID + : NULL; struct Packet p; packet_init(&p, PACKET_PLAYER, false); - packet_write(&p, &gMarioStates[0], 96); + packet_write(&p, &gMarioStates[0], sizeof(u32) * 24); packet_write(&p, gMarioStates[0].controller, 20); - packet_write(&p, gMarioStates[0].marioObj->rawData.asU32, 320); - packet_write(&p, &gMarioStates[0].health, 2); - - packet_write(&p, &heldSyncID, 4); + packet_write(&p, gMarioStates[0].marioObj->rawData.asU32, sizeof(u32) * 80); + packet_write(&p, &gMarioStates[0].health, sizeof(s16)); + packet_write(&p, &gMarioStates[0].marioObj->header.gfx.node.flags, sizeof(s16)); + packet_write(&p, &heldSyncID, sizeof(u32)); + packet_write(&p, &heldBySyncID, sizeof(u32)); network_send(&p); } @@ -24,21 +28,31 @@ void network_receive_player(struct Packet* p) { if (gMarioStates[1].marioObj == NULL) { return; } int oldActionState = gMarioStates[1].actionState; u32 heldSyncID = NULL; + u32 heldBySyncID = NULL; - packet_read(p, &gMarioStates[1], 96); + packet_read(p, &gMarioStates[1], sizeof(u32) * 24); packet_read(p, gMarioStates[1].controller, 20); - packet_read(p, &gMarioStates[1].marioObj->rawData.asU32, 320); - packet_read(p, &gMarioStates[1].health, 2); - packet_read(p, &heldSyncID, 4); + packet_read(p, &gMarioStates[1].marioObj->rawData.asU32, sizeof(u32) * 80); + packet_read(p, &gMarioStates[1].health, sizeof(s16)); + packet_read(p, &gMarioStates[1].marioObj->header.gfx.node.flags, sizeof(s16)); + packet_read(p, &heldSyncID, sizeof(u32)); + packet_read(p, &heldBySyncID, sizeof(u32)); - if (heldSyncID != NULL) { - assert(syncObjects[heldSyncID].o != NULL); + if (heldSyncID != NULL && syncObjects[heldSyncID].o != NULL) { + // TODO: do we have to move graphics nodes around to make this visible? gMarioStates[1].heldObj = syncObjects[heldSyncID].o; gMarioStates[1].heldObj->heldByPlayerIndex = 1; } else { gMarioStates[1].heldObj = NULL; } + if (heldBySyncID != NULL && syncObjects[heldBySyncID].o != NULL) { + // TODO: do we have to move graphics nodes around to make this visible? + gMarioStates[1].heldByObj = syncObjects[heldBySyncID].o; + } else { + gMarioStates[1].heldByObj = NULL; + } + // restore action state, needed for jump kicking gMarioStates[1].actionState = oldActionState; }