Skip to content

Commit 36c134f

Browse files
authored
Merge pull request #1154 from z64555/cleanup/dock_swabber
Fixes two crashes in red-alert missions, cleans up and refactors some of the docking code
2 parents d648091 + f30f955 commit 36c134f

File tree

8 files changed

+244
-53
lines changed

8 files changed

+244
-53
lines changed

code/missionui/redalert.cpp

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929
#include "missionui/redalert.h"
3030
#include "mod_table/mod_table.h"
3131
#include "model/model.h"
32+
#include "object/deadobjectdock.h"
33+
#include "object/objectdock.h"
3234
#include "ship/ship.h"
3335
#include "sound/audiostr.h"
3436
#include "sound/fsspeech.h"
@@ -776,23 +778,26 @@ void red_alert_store_wingman_status()
776778
}
777779

778780
// Delete a ship in a red alert mission (since it must have died/departed in the previous mission)
779-
void red_alert_delete_ship(ship *shipp, int ship_state)
781+
void red_alert_delete_ship(int shipnum, int ship_state)
780782
{
781-
if ( (shipp->wing_status_wing_index >= 0) && (shipp->wing_status_wing_pos >= 0) ) {
782-
if (ship_state == RED_ALERT_DESTROYED_SHIP_CLASS) {
783-
hud_set_wingman_status_dead(shipp->wing_status_wing_index, shipp->wing_status_wing_pos);
784-
} else if (ship_state == RED_ALERT_PLAYER_DEL_SHIP_CLASS) {
785-
hud_set_wingman_status_none(shipp->wing_status_wing_index, shipp->wing_status_wing_pos);
786-
} else {
787-
Error(LOCATION, "Red Alert: asked to delete ship (%s) with invalid ship state (%d)", shipp->ship_name, ship_state);
788-
}
789-
}
783+
ship* shipp = &Ships[shipnum];
784+
int cleanup_mode; // See ship.h for cleanup mode defines. SHIP_VANISHED etc.
790785

791-
ship_add_exited_ship( shipp, Ship::Exit_Flags::Player_deleted );
792-
obj_delete(shipp->objnum);
793-
if ( shipp->wingnum >= 0 ) {
794-
ship_wing_cleanup( SHIP_INDEX(shipp), &Wings[shipp->wingnum] );
786+
switch (ship_state) {
787+
case RED_ALERT_DESTROYED_SHIP_CLASS:
788+
cleanup_mode = SHIP_DESTROYED_REDALERT;
789+
break;
790+
case RED_ALERT_PLAYER_DEL_SHIP_CLASS:
791+
cleanup_mode = SHIP_DEPARTED_REDALERT;
792+
break;
793+
default:
794+
Assertion(false, "Red-alert: Unknown delete state '%i'\n", ship_state);
795+
cleanup_mode = SHIP_VANISHED;
796+
break;
795797
}
798+
799+
Objects[shipp->objnum].flags.set(Object::Object_Flags::Should_be_dead);
800+
ship_cleanup(shipnum, cleanup_mode);
796801
}
797802

798803
// just mark the parse object as never going to arrive
@@ -896,7 +901,7 @@ void red_alert_bash_wingman_status()
896901
if ( !ship_data_restored ) {
897902
// we need to be a little tricky here because deletion invalidates the ship_obj
898903
ship_obj *next_so = GET_NEXT(so);
899-
red_alert_delete_ship(shipp, ship_state);
904+
red_alert_delete_ship(ship_objp->instance, ship_state);
900905
so = next_so;
901906
} else {
902907
so = GET_NEXT(so);

code/object/deadobjectdock.cpp

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ dock_instance *dead_dock_find_instance(object *objp, int dockpoint);
2323

2424
object *dock_get_first_dead_docked_object(object *objp)
2525
{
26+
Assert(objp != NULL);
27+
2628
// are we docked?
2729
if (!object_is_dead_docked(objp))
2830
return NULL;
@@ -32,6 +34,9 @@ object *dock_get_first_dead_docked_object(object *objp)
3234

3335
int dock_find_dead_dockpoint_used_by_object(object *objp, object *other_objp)
3436
{
37+
Assert(objp != NULL);
38+
Assert(other_objp != NULL);
39+
3540
dock_instance *result = dead_dock_find_instance(objp, other_objp);
3641

3742
if (result == NULL)
@@ -43,6 +48,9 @@ int dock_find_dead_dockpoint_used_by_object(object *objp, object *other_objp)
4348
// dock management functions -------------------------------------------------------------------------------------
4449
void dock_dead_dock_objects(object *objp1, int dockpoint1, object *objp2, int dockpoint2)
4550
{
51+
Assert(objp1 != NULL);
52+
Assert(objp2 != NULL);
53+
4654
#ifndef NDEBUG
4755
if ((dead_dock_find_instance(objp1, objp2) != NULL) || (dead_dock_find_instance(objp2, objp1) != NULL))
4856
{
@@ -62,18 +70,26 @@ void dock_dead_dock_objects(object *objp1, int dockpoint1, object *objp2, int do
6270

6371
void dock_dead_undock_objects(object *objp1, object *objp2)
6472
{
65-
#ifndef NDEBUG
66-
if ((dead_dock_find_instance(objp1, objp2) == NULL) || (dead_dock_find_instance(objp2, objp1) == NULL))
67-
{
68-
Error(LOCATION, "Trying to undock an object that isn't docked!\n");
69-
}
70-
#endif
73+
Assert(objp1 != NULL);
74+
Assert(objp2 != NULL);
7175

7276
// remove objects from each others' dock lists
7377
dead_dock_remove_instance(objp1, objp2);
7478
dead_dock_remove_instance(objp2, objp1);
7579
}
7680

81+
void dock_dead_undock_all(object *objp)
82+
{
83+
Assert(objp != NULL);
84+
85+
while (object_is_dead_docked(objp))
86+
{
87+
object* dockee = dock_get_first_dead_docked_object(objp);
88+
89+
dock_dead_undock_objects(objp, dockee);
90+
}
91+
}
92+
7793
void dead_dock_add_instance(object *objp, int dockpoint, object *other_objp)
7894
{
7995
dock_instance *item;
@@ -128,11 +144,18 @@ void dead_dock_remove_instance(object *objp, object *other_objp)
128144
// delete it
129145
vm_free(ptr);
130146
}
147+
else
148+
{
149+
// Trigger assertion. We can recover from this, thankfully
150+
Assertion(false, "Tried to undock an object that isn't dead docked!\n");
151+
}
131152
}
132153

133154
// just free the list without worrying about undocking anything
134155
void dock_free_dead_dock_list(object *objp)
135156
{
157+
Assert(objp != NULL);
158+
136159
while (objp->dead_dock_list != NULL)
137160
{
138161
dock_instance *ptr = objp->dead_dock_list;

code/object/deadobjectdock.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,12 @@ void dock_dead_dock_objects(object *objp1, int dockpoint1, object *objp2, int do
2525
// remove objp1 and objp2 from each others' dock lists; currently called by do_dying_undock_physics and ship_cleanup
2626
void dock_dead_undock_objects(object *objp1, object *objp2);
2727

28+
/**
29+
* @brief Undocks all dead docks.
30+
* @note This is a slow method. Use dock_free_dead_dock_list() when doing object cleanup
31+
*/
32+
void dock_dead_undock_all(object *objp);
33+
2834
// free the entire dock list without undocking anything; should only be used on object cleanup
2935
void dock_free_dead_dock_list(object *objp);
3036

code/object/object.h

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -304,9 +304,37 @@ void obj_client_post_interpolate();
304304
// move an observer object in multiplayer
305305
void obj_observer_move(float frame_time);
306306

307-
// Goober5000
307+
/**
308+
* @brief Checks if the given object is docked with anyone.
309+
*
310+
* @returns Nonzero if docked, or
311+
* @returns 0 if not docked
312+
*
313+
* @author Goober5000
314+
*/
308315
int object_is_docked(object *objp);
316+
317+
/**
318+
* @brief Checks if the given object is dead-docked with anyone.
319+
*
320+
* @returns Nonzero if docked, or
321+
* @returns 0 if not docked
322+
*
323+
* @details An object is "dead-docked" when it is dying and still has objects docked to it. The dead_dock list is
324+
* populated when the object dies, and is used later on to jettison and maybe damage the docked objects.
325+
*
326+
* @author Goober5000
327+
*/
309328
int object_is_dead_docked(object *objp);
329+
330+
/**
331+
* @brief Moves a docked object to keep up with the parent object as it moves
332+
*
333+
* @param[in,out] objp The docked object
334+
* @param[in] parent_objp The object that it's docked to
335+
*
336+
* @author Goober5000
337+
*/
310338
void obj_move_one_docked_object(object *objp, object *parent_objp);
311339

312340
//WMC

code/object/objectdock.cpp

Lines changed: 60 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ int dock_count_instances(object *objp);
4646

4747
object *dock_get_first_docked_object(object *objp)
4848
{
49+
Assert(objp != NULL);
50+
4951
// are we docked?
5052
if (!object_is_docked(objp))
5153
return NULL;
@@ -55,6 +57,8 @@ object *dock_get_first_docked_object(object *objp)
5557

5658
bool dock_check_docked_one_on_one(object *objp)
5759
{
60+
Assert(objp != NULL);
61+
5862
// we must be docked
5963
if (!object_is_docked(objp))
6064
return false;
@@ -76,11 +80,14 @@ bool dock_check_docked_one_on_one(object *objp)
7680

7781
int dock_count_direct_docked_objects(object *objp)
7882
{
83+
Assert(objp != NULL);
7984
return dock_count_instances(objp);
8085
}
8186

8287
int dock_count_total_docked_objects(object *objp)
8388
{
89+
Assert(objp != NULL);
90+
8491
dock_function_info dfi;
8592

8693
dock_evaluate_all_docked_objects(objp, &dfi, dock_count_total_docked_objects_helper);
@@ -90,11 +97,17 @@ int dock_count_total_docked_objects(object *objp)
9097

9198
bool dock_check_find_direct_docked_object(object *objp, object *other_objp)
9299
{
100+
Assert(objp != NULL);
101+
Assert(other_objp != NULL);
102+
93103
return (dock_find_instance(objp, other_objp) != NULL);
94104
}
95105

96106
bool dock_check_find_docked_object(object *objp, object *other_objp)
97107
{
108+
Assert(objp != NULL);
109+
Assert(other_objp != NULL);
110+
98111
dock_function_info dfi;
99112
dfi.parameter_variables.objp_value = other_objp;
100113

@@ -105,6 +118,8 @@ bool dock_check_find_docked_object(object *objp, object *other_objp)
105118

106119
object *dock_find_object_at_dockpoint(object *objp, int dockpoint)
107120
{
121+
Assert(objp != NULL);
122+
108123
dock_instance *result = dock_find_instance(objp, dockpoint);
109124

110125
if (result == NULL)
@@ -115,6 +130,9 @@ object *dock_find_object_at_dockpoint(object *objp, int dockpoint)
115130

116131
int dock_find_dockpoint_used_by_object(object *objp, object *other_objp)
117132
{
133+
Assert(objp != NULL);
134+
Assert(other_objp != NULL);
135+
118136
dock_instance *result = dock_find_instance(objp, other_objp);
119137

120138
if (result == NULL)
@@ -125,6 +143,9 @@ int dock_find_dockpoint_used_by_object(object *objp, object *other_objp)
125143

126144
void dock_calc_docked_center(vec3d *dest, object *objp)
127145
{
146+
Assert(dest != NULL);
147+
Assert(objp != NULL);
148+
128149
vm_vec_zero(dest);
129150

130151
dock_function_info dfi;
@@ -138,6 +159,9 @@ void dock_calc_docked_center(vec3d *dest, object *objp)
138159

139160
void dock_calc_docked_center_of_mass(vec3d *dest, object *objp)
140161
{
162+
Assert(dest != NULL);
163+
Assert(objp != NULL);
164+
141165
vm_vec_zero(dest);
142166

143167
dock_function_info dfi;
@@ -151,6 +175,8 @@ void dock_calc_docked_center_of_mass(vec3d *dest, object *objp)
151175

152176
float dock_calc_total_docked_mass(object *objp)
153177
{
178+
Assert(objp != NULL);
179+
154180
dock_function_info dfi;
155181

156182
dock_evaluate_all_docked_objects(objp, &dfi, dock_calc_total_docked_mass_helper);
@@ -160,6 +186,8 @@ float dock_calc_total_docked_mass(object *objp)
160186

161187
float dock_calc_max_cross_sectional_radius_perpendicular_to_axis(object *objp, axis_type axis)
162188
{
189+
Assert(objp != NULL);
190+
163191
vec3d local_line_end;
164192
vec3d *world_line_start, world_line_end;
165193
dock_function_info dfi;
@@ -210,6 +238,8 @@ float dock_calc_max_cross_sectional_radius_perpendicular_to_axis(object *objp, a
210238

211239
float dock_calc_max_semilatus_rectum_parallel_to_axis(object *objp, axis_type axis)
212240
{
241+
Assert(objp != NULL);
242+
213243
vec3d local_line_end;
214244
vec3d *world_line_start, world_line_end;
215245
dock_function_info dfi;
@@ -260,6 +290,8 @@ float dock_calc_max_semilatus_rectum_parallel_to_axis(object *objp, axis_type ax
260290

261291
float dock_calc_docked_fspeed(object *objp)
262292
{
293+
Assert(objp != NULL);
294+
263295
// *sigh*... the docked fspeed is simply the max fspeed of all docked objects
264296
dock_function_info dfi;
265297
dock_evaluate_all_docked_objects(objp, &dfi, dock_find_max_fspeed_helper);
@@ -268,6 +300,8 @@ float dock_calc_docked_fspeed(object *objp)
268300

269301
float dock_calc_docked_speed(object *objp)
270302
{
303+
Assert(objp != NULL);
304+
271305
// ditto with speed
272306
dock_function_info dfi;
273307
dock_evaluate_all_docked_objects(objp, &dfi, dock_find_max_speed_helper);
@@ -370,6 +404,8 @@ void dock_evaluate_tree(object *objp, dock_function_info *infop, void (*function
370404

371405
void dock_move_docked_objects(object *objp)
372406
{
407+
Assert(objp != NULL);
408+
373409
if ((objp->type != OBJ_SHIP) && (objp->type != OBJ_START))
374410
return;
375411

@@ -601,6 +637,9 @@ void dock_find_max_speed_helper(object *objp, dock_function_info *infop)
601637
// dock management functions -------------------------------------------------------------------------------------
602638
void dock_dock_objects(object *objp1, int dockpoint1, object *objp2, int dockpoint2)
603639
{
640+
Assert(objp1 != NULL);
641+
Assert(objp2 != NULL);
642+
604643
#ifndef NDEBUG
605644
if ((dock_find_instance(objp1, objp2) != NULL) || (dock_find_instance(objp2, objp1) != NULL))
606645
{
@@ -620,18 +659,26 @@ void dock_dock_objects(object *objp1, int dockpoint1, object *objp2, int dockpoi
620659

621660
void dock_undock_objects(object *objp1, object *objp2)
622661
{
623-
#ifndef NDEBUG
624-
if ((dock_find_instance(objp1, objp2) == NULL) || (dock_find_instance(objp2, objp1) == NULL))
625-
{
626-
Error(LOCATION, "Trying to undock an object that isn't docked!\n");
627-
}
628-
#endif
662+
Assert(objp1 != NULL);
663+
Assert(objp2 != NULL);
629664

630665
// remove objects from each others' dock lists
631666
dock_remove_instance(objp1, objp2);
632667
dock_remove_instance(objp2, objp1);
633668
}
634669

670+
void dock_undock_all(object *objp)
671+
{
672+
Assert(objp != NULL);
673+
674+
while (object_is_docked(objp))
675+
{
676+
object* dockee = dock_get_first_docked_object(objp);
677+
678+
dock_undock_objects(objp, dockee);
679+
}
680+
}
681+
635682
// dock list functions -------------------------------------------------------------------------------------------
636683
bool dock_check_assume_hub()
637684
{
@@ -719,11 +766,18 @@ void dock_remove_instance(object *objp, object *other_objp)
719766
// delete it
720767
vm_free(ptr);
721768
}
769+
else
770+
{
771+
// Trigger an assertion, we can recover from this one, thankfully.
772+
Assertion(false, "Tried to undock an object that isn't docked!\n");
773+
}
722774
}
723775

724776
// just free the list without worrying about undocking anything
725777
void dock_free_dock_list(object *objp)
726778
{
779+
Assert(objp != NULL);
780+
727781
while (objp->dock_list != NULL)
728782
{
729783
dock_instance *ptr = objp->dock_list;

0 commit comments

Comments
 (0)