diff --git a/common/main/fwd-object.h b/common/main/fwd-object.h index ce2d929df..d0cd9833f 100644 --- a/common/main/fwd-object.h +++ b/common/main/fwd-object.h @@ -267,12 +267,6 @@ void clear_transient_objects(int clear_all); [[nodiscard]] imobjptridx_t obj_allocate(d_level_unique_object_state &); -// after calling init_object(), the network code has grabbed specific -// object slots without allocating them. Go though the objects & -// build the free list, then set the apporpriate globals Don't call -// this function if you don't know what you're doing. -void special_reset_objects(d_level_unique_object_state &); - // attaches an object, such as a fireball, to another object, such as // a robot void obj_attach(object_array &Objects, vmobjptridx_t parent, vmobjptridx_t sub); diff --git a/common/main/object.h b/common/main/object.h index 9e613a0e1..636fcd6c9 100644 --- a/common/main/object.h +++ b/common/main/object.h @@ -727,6 +727,12 @@ struct d_level_unique_boss_state : ::dcx::d_level_unique_boss_state const player &get_player_controlling_guidebot(const d_unique_buddy_state & /* reserved for future use */, const valptridx::array_managed_type &Players); #endif +// after calling init_object(), the network code has grabbed specific +// object slots without allocating them. Go though the objects & +// build the free list, then set the appropriate globals. +// Don't call this function unless you know what you're doing. +void special_reset_objects(d_level_unique_object_state &, const d_robot_info_array &Robot_info); + unsigned laser_parent_is_player(fvcobjptr &, const laser_parent &, const object_base &); unsigned laser_parent_is_object(fvcobjptr &, const laser_parent &, const object_base &); unsigned laser_parent_is_object(const laser_parent &, vcobjptridx_t); diff --git a/similar/main/net_udp.cpp b/similar/main/net_udp.cpp index 2af6aa3e0..59f06f560 100644 --- a/similar/main/net_udp.cpp +++ b/similar/main/net_udp.cpp @@ -2479,9 +2479,10 @@ static int net_udp_verify_objects(int remote, int local) return(1); } -static void net_udp_read_object_packet(const uint8_t *const data) +static void net_udp_read_object_packet(const d_level_shared_robot_info_state &LevelSharedRobotInfoState, const uint8_t *const data) { auto &Objects = LevelUniqueObjectState.Objects; + auto &Robot_info = LevelSharedRobotInfoState.Robot_info; auto &vmobjptridx = Objects.vmptridx; // Object from another net player we need to sync with sbyte obj_owner; @@ -2512,7 +2513,7 @@ static void net_udp_read_object_packet(const uint8_t *const data) // Special debug checksum marker for entire send if (mode == 1) { - special_reset_objects(LevelUniqueObjectState); + special_reset_objects(LevelUniqueObjectState, Robot_info); mode = 0; } if (remote_objnum != object_count) { @@ -2538,7 +2539,7 @@ static void net_udp_read_object_packet(const uint8_t *const data) else { if (mode == 1) { - special_reset_objects(LevelUniqueObjectState); + special_reset_objects(LevelUniqueObjectState, Robot_info); mode = 0; } objnum = obj_allocate(LevelUniqueObjectState); @@ -3476,7 +3477,7 @@ static void net_udp_process_packet(const d_level_shared_robot_info_state &LevelS case upid::object_data: if (multi_i_am_master() || length > UPID_MAX_SIZE || Network_status != network_state::waiting) break; - net_udp_read_object_packet(data); + net_udp_read_object_packet(LevelSharedRobotInfoState, data); break; case upid::ping: if (multi_i_am_master()) diff --git a/similar/main/object.cpp b/similar/main/object.cpp index b9138a91b..1510846b7 100644 --- a/similar/main/object.cpp +++ b/similar/main/object.cpp @@ -914,8 +914,8 @@ void init_objects() //after calling init_object(), the network code has grabbed specific //object slots without allocating them. Go though the objects & build -//the free list, then set the apporpriate globals -void special_reset_objects(d_level_unique_object_state &LevelUniqueObjectState) +//the free list, then set the appropriate globals +void special_reset_objects(d_level_unique_object_state &LevelUniqueObjectState, const d_robot_info_array &Robot_info) { unsigned num_objects = MAX_OBJECTS; @@ -924,12 +924,34 @@ void special_reset_objects(d_level_unique_object_state &LevelUniqueObjectState) assert(Objects.front().type != OBJ_NONE); //0 should be used DXX_POISON_VAR(LevelUniqueObjectState.free_obj_list, 0xfd); +#if defined(DXX_BUILD_DESCENT_I) + /* Descent 1 does not have a guidebot, so there is nothing to fix up. For + * simplicity, both games pass the parameter. + */ + (void)Robot_info; +#elif defined(DXX_BUILD_DESCENT_II) + icobjidx_t Buddy_objnum = object_none; +#endif for (objnum_t i = MAX_OBJECTS; i--;) - if (Objects.vcptr(i)->type == OBJ_NONE) + { + const auto &obj = *Objects.vcptr(i); +#if defined(DXX_BUILD_DESCENT_II) + if (obj.type == OBJ_ROBOT) + { + auto &robptr = Robot_info[get_robot_id(obj)]; + if (robot_is_companion(robptr)) + Buddy_objnum = i; + } +#endif + if (obj.type == OBJ_NONE) LevelUniqueObjectState.free_obj_list[--num_objects] = i; else if (i > Highest_object_index) Objects.set_count(i + 1); + } +#if defined(DXX_BUILD_DESCENT_II) + LevelUniqueObjectState.BuddyState.Buddy_objnum = Buddy_objnum; +#endif LevelUniqueObjectState.num_objects = num_objects; } @@ -2180,6 +2202,10 @@ void reset_objects(d_level_unique_object_state &LevelUniqueObjectState, const un auto &Objects = LevelUniqueObjectState.get_objects(); assert(LevelUniqueObjectState.num_objects < Objects.size()); Objects.set_count(n_objs); +#if defined(DXX_BUILD_DESCENT_II) + if (LevelUniqueObjectState.BuddyState.Buddy_objnum.get_unchecked_index() >= n_objs) + LevelUniqueObjectState.BuddyState.Buddy_objnum = object_none; +#endif for (objnum_t i = n_objs; i < MAX_OBJECTS; ++i) { diff --git a/similar/main/state.cpp b/similar/main/state.cpp index 19a08f3be..b4e6e2281 100644 --- a/similar/main/state.cpp +++ b/similar/main/state.cpp @@ -2128,7 +2128,7 @@ int state_restore_all_sub(const d_level_shared_destructible_light_state &LevelSh } #endif } - special_reset_objects(LevelUniqueObjectState); + special_reset_objects(LevelUniqueObjectState, LevelSharedRobotInfoState.Robot_info); /* Reload plrobj reference. The player's object number may have * been changed by the state_object_rw_to_object call. */ @@ -2541,7 +2541,7 @@ int state_restore_all_sub(const d_level_shared_destructible_light_state &LevelSh if (!coop_player_got[i] && vcplayerptr(i)->connected == player_connection_status::playing) multi_disconnect_player(i); Viewer = ConsoleObject = &get_local_plrobj(); // make sure Viewer and ConsoleObject are set up (which we skipped by not using InitPlayerObject but we need since objects changed while loading) - special_reset_objects(LevelUniqueObjectState); // since we juggled around with objects to remap coop players rebuild the index of free objects + special_reset_objects(LevelUniqueObjectState, LevelSharedRobotInfoState.Robot_info); // since we juggled around with objects to remap coop players rebuild the index of free objects state_set_next_autosave(GameUniqueState, Netgame.MPGameplayOptions.AutosaveInterval); } else