From 95b9167287534dde3d37d72795aa4fa2e85c2a1f Mon Sep 17 00:00:00 2001 From: MysterD Date: Wed, 23 Sep 2020 23:18:45 -0700 Subject: [PATCH] Synchronized Klepto --- src/game/behaviors/klepto.inc.c | 108 +++++++++++++++++++++++++------- src/game/behaviors/ukiki.inc.c | 2 +- src/game/interaction.c | 12 +++- src/game/interaction.h | 2 +- src/game/level_update.c | 6 ++ 5 files changed, 101 insertions(+), 29 deletions(-) diff --git a/src/game/behaviors/klepto.inc.c b/src/game/behaviors/klepto.inc.c index a04af2c29..b2dad85d4 100644 --- a/src/game/behaviors/klepto.inc.c +++ b/src/game/behaviors/klepto.inc.c @@ -19,9 +19,12 @@ static Vec3f sKleptoTargetPositions[] = { static u8 sKleptoAttackHandlers[] = { 2, 2, 5, 5, 2, 2 }; static void klepto_target_mario(void) { - o->oKleptoDistanceToTarget = lateral_dist_between_objects(gMarioObject, o); - o->oKleptoUnk1B0 = obj_turn_pitch_toward_mario(&gMarioStates[0], 250.0f, 0); - o->oKleptoYawToTarget = o->oAngleToMario; + struct MarioState* marioState = nearest_mario_state_to_object(o); + struct Object* player = marioState->marioObj; + int angleToPlayer = obj_angle_to_object(o, player); + o->oKleptoDistanceToTarget = lateral_dist_between_objects(player, o); + o->oKleptoUnk1B0 = obj_turn_pitch_toward_mario(marioState, 250.0f, 0); + o->oKleptoYawToTarget = angleToPlayer; o->oKleptoUnk1AE = -60; } @@ -73,6 +76,18 @@ static void klepto_anim_dive(void) { obj_face_pitch_approach(0, 1000); } +static s32 kleptoCachedAnimState = 0; + +static void bhv_klepto_on_received_pre(u8 localIndex) { + kleptoCachedAnimState = o->oAnimState; +} + +static void bhv_klepto_on_received_post(u8 localIndex) { + if (kleptoCachedAnimState == KLEPTO_ANIM_STATE_HOLDING_NOTHING && o->oAnimState == KLEPTO_ANIM_STATE_HOLDING_STAR) { + o->oAnimState = KLEPTO_ANIM_STATE_HOLDING_NOTHING; + } +} + void bhv_klepto_init(void) { if (o->oBehParams2ndByte != 0) { o->oAnimState = KLEPTO_ANIM_STATE_HOLDING_STAR; @@ -87,6 +102,25 @@ void bhv_klepto_init(void) { o->oAction = KLEPTO_ACT_WAIT_FOR_MARIO; } } + + struct SyncObject* so = network_init_object(o, 4000.0f); + so->on_received_pre = bhv_klepto_on_received_pre; + so->on_received_post = bhv_klepto_on_received_post; + network_init_object_field(o, &o->oAnimState); + network_init_object_field(o, &o->oFlags); + network_init_object_field(o, &o->oKleptoDistanceToTarget); + network_init_object_field(o, &o->oKleptoUnkF8); + network_init_object_field(o, &o->oKleptoUnkFC); + network_init_object_field(o, &o->oKleptoSpeed); + network_init_object_field(o, &o->oKleptoTimeUntilTargetChange); + network_init_object_field(o, &o->oKleptoTargetNumber); + network_init_object_field(o, &o->oKleptoUnk1B0); + network_init_object_field(o, &o->oSoundStateID); + network_init_object_field(o, &o->oHomeX); + network_init_object_field(o, &o->oHomeY); + network_init_object_field(o, &o->oHomeZ); + network_init_object_field(o, &o->oMoveAnglePitch); + network_init_object_field(o, &o->oGravity); } static void klepto_change_target(void) { @@ -97,12 +131,15 @@ static void klepto_change_target(void) { f32 targetDist; f32 minTargetDist; - if (o->oDistanceToMario > 2000.0f) { + struct Object* player = nearest_player_to_object(o); + int distanceToPlayer = dist_between_objects(o, player); + + if (distanceToPlayer > 2000.0f) { minTargetDist = 99999.0f; for (i = 0; i < 3; i++) { - dx = gMarioObject->oPosX - sKleptoTargetPositions[i][0]; - dz = gMarioObject->oPosZ - sKleptoTargetPositions[i][2]; + dx = player->oPosX - sKleptoTargetPositions[i][0]; + dz = player->oPosZ - sKleptoTargetPositions[i][2]; targetDist = sqrtf(dx * dx + dz * dz); if (targetDist < minTargetDist) { @@ -128,8 +165,11 @@ static void klepto_circle_target(f32 radius, f32 targetSpeed) { s16 turnAmount; f32 accel; + struct Object* player = nearest_player_to_object(o); + int distanceToPlayer = dist_between_objects(o, player); + if (o->oAnimState != KLEPTO_ANIM_STATE_HOLDING_NOTHING - && ((o->oTimer > 60 && o->oDistanceToMario > 2000.0f) + && ((o->oTimer > 60 && distanceToPlayer > 2000.0f) || o->oTimer >= o->oKleptoTimeUntilTargetChange)) { klepto_change_target(); o->oKleptoTimeUntilTargetChange = random_linear_offset(300, 300); @@ -190,8 +230,11 @@ static void klepto_act_wait_for_mario(void) { static void klepto_act_turn_toward_mario(void) { klepto_target_mario(); + struct Object* player = nearest_player_to_object(o); + int angleToPlayer = obj_angle_to_object(o, player); + if (klepto_set_and_check_if_anim_at_end() && cur_obj_check_if_at_animation_end() && o->oKleptoDistanceToTarget > 800.0f - && abs_angle_diff(o->oAngleToMario, o->oFaceAngleYaw) < 0x800 && o->oKleptoUnk1B0 < 0x400) { + && abs_angle_diff(angleToPlayer, o->oFaceAngleYaw) < 0x800 && o->oKleptoUnk1B0 < 0x400) { cur_obj_play_sound_2(SOUND_OBJ_KLEPTO1); o->oAction = KLEPTO_ACT_DIVE_AT_MARIO; o->oMoveAngleYaw = o->oFaceAngleYaw; @@ -201,10 +244,15 @@ static void klepto_act_turn_toward_mario(void) { } klepto_circle_target(1000.0f, 40.0f); - obj_face_yaw_approach(o->oAngleToMario, 1000); + obj_face_yaw_approach(angleToPlayer, 1000); } static void klepto_act_dive_at_mario(void) { + struct MarioState* marioState = nearest_mario_state_to_object(o); + struct Object* player = marioState->marioObj; + int distanceToPlayer = dist_between_objects(o, player); + int angleToPlayer = obj_angle_to_object(o, player); + approach_f32_ptr(&o->oKleptoSpeed, 60.0f, 10.0f); if (o->oSoundStateID == 2) { if (cur_obj_check_anim_frame(11)) { @@ -220,7 +268,7 @@ static void klepto_act_dive_at_mario(void) { } } } else { - f32 dy = o->oPosY - gMarioObject->oPosY; + f32 dy = o->oPosY - player->oPosY; if (o->oSoundStateID == 3) { cur_obj_set_anim_if_at_end(4); } else if (o->oVelY > 0.0f && dy > 200.0f) { @@ -230,19 +278,20 @@ static void klepto_act_dive_at_mario(void) { o->oKleptoUnk1B0 = -0x3000; if (o->oAnimState == KLEPTO_ANIM_STATE_HOLDING_NOTHING) { if (o->oSubAction == 0) { - o->oKleptoUnk1B0 = obj_turn_pitch_toward_mario(&gMarioStates[0], 0.0f, 0); - o->oKleptoYawToTarget = o->oAngleToMario; + o->oKleptoUnk1B0 = obj_turn_pitch_toward_mario(marioState, 0.0f, 0); + o->oKleptoYawToTarget = angleToPlayer; if (dy < 160.0f) { o->oSubAction += 1; } } - if (gMarioStates[0].action != ACT_SLEEPING - && !(gMarioStates[0].action & (ACT_FLAG_SHORT_HITBOX | ACT_FLAG_BUTT_OR_STOMACH_SLIDE)) - && o->oDistanceToMario < 200.0f && dy > 50.0f && dy < 90.0f) { - if (mario_lose_cap_to_enemy(1)) { + if (marioState->action != ACT_SLEEPING + && !(marioState->action & (ACT_FLAG_SHORT_HITBOX | ACT_FLAG_BUTT_OR_STOMACH_SLIDE)) + && distanceToPlayer < 200.0f && dy > 50.0f && dy < 90.0f) { + if (network_owns_object(o) && mario_lose_cap_to_enemy(marioState, 1)) { o->oAnimState = KLEPTO_ANIM_STATE_HOLDING_CAP; + network_send_object(o); } } } @@ -319,6 +368,11 @@ void obj_set_speed_to_zero(void) { } void bhv_klepto_update(void) { + struct MarioState* marioState = nearest_mario_state_to_object(o); + struct Object* player = marioState->marioObj; + int distanceToPlayer = dist_between_objects(o, player); + int angleToPlayer = obj_angle_to_object(o, player); + UNUSED s32 unused; cur_obj_update_floor_and_walls(); @@ -359,23 +413,29 @@ void bhv_klepto_update(void) { if (obj_handle_attacks(&sKleptoHitbox, o->oAction, sKleptoAttackHandlers)) { cur_obj_play_sound_2(SOUND_OBJ_KLEPTO2); - if (o->oAnimState == KLEPTO_ANIM_STATE_HOLDING_CAP) { + if (network_owns_object(o) && o->oAnimState == KLEPTO_ANIM_STATE_HOLDING_CAP) { save_file_clear_flags(SAVE_FLAG_CAP_ON_KLEPTO); - spawn_object(o, MODEL_MARIOS_CAP, bhvNormalCap); + struct Object* cap = spawn_object(o, MODEL_MARIOS_CAP, bhvNormalCap); + + struct Object* spawn_objects[] = { cap }; + u32 models[] = { MODEL_MARIOS_CAP }; + network_send_spawn_objects(spawn_objects, models, 1); + } else if (o->oAnimState == KLEPTO_ANIM_STATE_HOLDING_STAR) { spawn_default_star(-5550.0f, 300.0f, -930.0f); } - o->oAnimState = KLEPTO_ANIM_STATE_HOLDING_NOTHING; - o->oAction = KLEPTO_ACT_STRUCK_BY_MARIO; + if (network_owns_object(o)) { + o->oAnimState = KLEPTO_ANIM_STATE_HOLDING_NOTHING; + o->oAction = KLEPTO_ACT_STRUCK_BY_MARIO; + network_send_object(o); + } o->oGravity = -2.0f; - o->oMoveAngleYaw = o->oAngleToMario + 0x8000; + o->oMoveAngleYaw = angleToPlayer + 0x8000; o->oFlags &= ~0x00000008; cur_obj_become_intangible(); - } else if (gMarioStates[0].action == ACT_SLEEPING - || (gMarioStates[0].action - & (ACT_FLAG_SHORT_HITBOX | ACT_FLAG_BUTT_OR_STOMACH_SLIDE))) { + } else if (marioState->action == ACT_SLEEPING || (marioState->action & (ACT_FLAG_SHORT_HITBOX | ACT_FLAG_BUTT_OR_STOMACH_SLIDE))) { cur_obj_become_intangible(); } else { cur_obj_become_tangible(); diff --git a/src/game/behaviors/ukiki.inc.c b/src/game/behaviors/ukiki.inc.c index b16a8c3e8..c4c8da171 100644 --- a/src/game/behaviors/ukiki.inc.c +++ b/src/game/behaviors/ukiki.inc.c @@ -569,7 +569,7 @@ u8 hat_ukiki_held_loop_2(void) { return o->oHeldState == HELD_HELD && o->oUkikiT void hat_ukiki_held_loop(void) { switch(o->oUkikiTextState) { case UKIKI_TEXT_DEFAULT: - if (mario_lose_cap_to_enemy(2)) { + if (mario_lose_cap_to_enemy(&gMarioStates[0], 2)) { o->oUkikiTextState = UKIKI_TEXT_STEAL_HAT; o->oUkikiHasHat |= UKIKI_HAT_ON; } else {} diff --git a/src/game/interaction.c b/src/game/interaction.c index 6e4920e57..c3710c920 100644 --- a/src/game/interaction.c +++ b/src/game/interaction.c @@ -382,12 +382,13 @@ void mario_blow_off_cap(struct MarioState *m, f32 capSpeed) { } } -u32 mario_lose_cap_to_enemy(u32 arg) { +u32 mario_lose_cap_to_enemy(struct MarioState* m, u32 arg) { + if (m->playerIndex != 0) { return FALSE; } u32 wasWearingCap = FALSE; - if (does_mario_have_hat(gMarioState)) { + if (does_mario_have_hat(m)) { save_file_set_flags(arg == 1 ? SAVE_FLAG_CAP_ON_KLEPTO : SAVE_FLAG_CAP_ON_UKIKI); - gMarioState->flags &= ~(MARIO_NORMAL_CAP | MARIO_CAP_ON_HEAD); + m->flags &= ~(MARIO_NORMAL_CAP | MARIO_CAP_ON_HEAD); wasWearingCap = TRUE; } @@ -1787,6 +1788,11 @@ u32 interact_cap(struct MarioState *m, UNUSED u32 interactType, struct Object *o u16 capMusic = 0; u16 capTime = 0; + if (capFlag == MARIO_NORMAL_CAP) { + // refuse normal cap when already on head + if (m->flags & (MARIO_NORMAL_CAP | MARIO_CAP_ON_HEAD)) { return FALSE; } + } + if (m->action != ACT_GETTING_BLOWN && capFlag != 0) { m->interactObj = o; o->oInteractStatus = INT_STATUS_INTERACTED; diff --git a/src/game/interaction.h b/src/game/interaction.h index 12e479642..08712e421 100644 --- a/src/game/interaction.h +++ b/src/game/interaction.h @@ -106,7 +106,7 @@ void mario_throw_held_object(struct MarioState *m); void mario_stop_riding_and_holding(struct MarioState *m); u32 does_mario_have_hat(struct MarioState *m); void mario_blow_off_cap(struct MarioState *m, f32 capSpeed); -u32 mario_lose_cap_to_enemy(u32 arg); +u32 mario_lose_cap_to_enemy(struct MarioState* m, u32 arg); void mario_retrieve_cap(void); struct Object *mario_get_collided_object(struct MarioState *m, u32 interactType); u32 mario_check_object_grab(struct MarioState *m); diff --git a/src/game/level_update.c b/src/game/level_update.c index 4a44d47fc..ab18a3dc9 100644 --- a/src/game/level_update.c +++ b/src/game/level_update.c @@ -1246,6 +1246,12 @@ s32 update_level(void) { } s32 init_level(void) { + // reset cap flags + save_file_clear_flags(SAVE_FLAG_CAP_ON_GROUND); + save_file_clear_flags(SAVE_FLAG_CAP_ON_KLEPTO); + save_file_clear_flags(SAVE_FLAG_CAP_ON_UKIKI); + save_file_clear_flags(SAVE_FLAG_CAP_ON_MR_BLIZZARD); + reset_dialog_render_state(); s32 val4 = 0;