Recompute guidebot index on game load
The index of the guidebot is set by loading the level data, and this is usually sufficient. However, if the user kills the guidebot, then uses cheats to create a new one, the new guidebot will often have a different index than the original guidebot. If such a game is saved and then reloaded, then after the reload, the computed guidebot index will be reverted to the index of the original dead guidebot. This causes various problems, including potentially a crash. Recompute the guidebot index after loading the objects from the save file, so that it matches the live guidebot. Reported-by: GitInMotion <https://github.com/dxx-rebirth/dxx-rebirth/issues/713>
This commit is contained in:
parent
c21c317441
commit
b4e3d67725
|
@ -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);
|
||||
|
|
|
@ -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<player>::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);
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue