Skip to content

Commit b6c0e8b

Browse files
committed
fix ShipStatus states to correctly account for exploding ships
Adds a `DEATH_ROLL` status to specifically cover the state after ships have been destroyed but before they exit. I've also audited all code that interacts with the ship registry to use the correct state with this new state taken into consideration. This fixes access to exploding ships that was broken when the ship registry framework was introduced. In particular, the `when destroyed X beam-lock-all X` QoL feature now works again.
1 parent 5634454 commit b6c0e8b

File tree

8 files changed

+58
-48
lines changed

8 files changed

+58
-48
lines changed

code/ai/aicode.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -386,7 +386,7 @@ int is_preferred_weapon(int weapon_num, object *firer_objp, object *target_objp)
386386
continue;
387387

388388
auto ship_entry = &Ship_registry[hfi->ship_registry_index];
389-
if (ship_entry->status != ShipStatus::PRESENT)
389+
if (!ship_entry->objp)
390390
continue;
391391

392392
int signature = ship_entry->objp->signature;

code/ai/aigoals.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -976,7 +976,7 @@ void ai_add_goal_sub_sexp( int sexp, int type, ai_info *aip, ai_goal *aigp, char
976976
// this goal needs some extra setup
977977
// if this doesn't work, the goal will be immediately removed
978978
auto ship_entry = ship_registry_get(aigp->target_name);
979-
if (ship_entry->status == ShipStatus::PRESENT)
979+
if (ship_entry->shipp)
980980
{
981981
auto target_aip = &Ai_info[ship_entry->shipp->ai_index];
982982
target_aip->ai_flags.set(AI::AI_Flags::Awaiting_repair);
@@ -1797,7 +1797,7 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
17971797
status = SHIP_STATUS_UNKNOWN;
17981798
}
17991799
// goal ship is currently in mission
1800-
else if (ship_entry->status == ShipStatus::PRESENT)
1800+
else if (ship_entry->status == ShipStatus::PRESENT || ship_entry->status == ShipStatus::DEATH_ROLL)
18011801
{
18021802
status = SHIP_STATUS_ARRIVED;
18031803
}

code/mission/missiontraining.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -922,7 +922,7 @@ void message_training_queue_check()
922922
auto ship_entry = ship_registry_get(NOX("instructor"));
923923
if (ship_entry != nullptr)
924924
{
925-
if (ship_entry->status == ShipStatus::PRESENT)
925+
if (ship_entry->shipp != nullptr)
926926
{
927927
// if the instructor is dying or departing, do nothing
928928
if (ship_entry->shipp->is_dying_or_departing())

code/parse/sexp.cpp

Lines changed: 40 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -6585,6 +6585,7 @@ void eval_object_ship_wing_point_team(object_ship_wing_point_team *oswpt, int no
65856585
break;
65866586

65876587
case ShipStatus::PRESENT:
6588+
case ShipStatus::DEATH_ROLL:
65886589
oswpt->type = OSWPT_TYPE_SHIP;
65896590
break;
65906591

@@ -6853,7 +6854,7 @@ int sexp_is_destroyed(int n, fix *latest_time)
68536854
if (ship_entry->status == ShipStatus::NOT_YET_PRESENT)
68546855
return SEXP_CANT_EVAL;
68556856

6856-
if (ship_entry->status == ShipStatus::EXITED)
6857+
if (ship_entry->status == ShipStatus::DEATH_ROLL || ship_entry->status == ShipStatus::EXITED)
68576858
{
68586859
// check the mission log
68596860
if (mission_log_get_time(LOG_SHIP_DESTROYED, ship_entry->name, nullptr, &time) || mission_log_get_time(LOG_SELF_DESTRUCTED, ship_entry->name, nullptr, &time))
@@ -7301,7 +7302,7 @@ int sexp_was_destroyed_by(int n, fix *latest_time)
73017302
*latest_time = time;
73027303
}
73037304
// if the ship has exited, no way to destroy it
7304-
else if (ship_entry->status == ShipStatus::EXITED)
7305+
else if (destroyed_ship_entry->status == ShipStatus::EXITED)
73057306
return SEXP_KNOWN_FALSE;
73067307
}
73077308

@@ -7526,7 +7527,14 @@ int sexp_time_exited(int n, int op_num)
75267527
if (ship)
75277528
{
75287529
auto ship_entry = eval_ship(n);
7529-
if (!ship_entry || ship_entry->status != ShipStatus::EXITED)
7530+
if (!ship_entry)
7531+
return SEXP_NAN;
7532+
if (ship_entry->status == ShipStatus::DEATH_ROLL)
7533+
{
7534+
if (!destroyed)
7535+
return SEXP_NAN;
7536+
}
7537+
else if (ship_entry->status != ShipStatus::EXITED)
75307538
return SEXP_NAN;
75317539

75327540
if (destroyed)
@@ -8784,7 +8792,8 @@ int sexp_angle_vectors(int node) {
87848792
return fl2ir(angle);
87858793
}
87868794

8787-
int sexp_angle_fvec_target(int node) {
8795+
int sexp_angle_fvec_target(int node)
8796+
{
87888797
auto* ship = eval_ship(node);
87898798

87908799
if (ship->status == ShipStatus::EXITED)
@@ -9412,7 +9421,7 @@ int sexp_last_order_time(int n)
94129421

94139422
auto ship_entry = eval_ship(n);
94149423
if (ship_entry) {
9415-
if (ship_entry->status == ShipStatus::PRESENT) {
9424+
if (ship_entry->shipp) {
94169425
aigp = Ai_info[ship_entry->shipp->ai_index].goals;
94179426
}
94189427
} else {
@@ -9785,7 +9794,7 @@ int sexp_destroyed_departed_delay(int n)
97859794
return SEXP_CANT_EVAL;
97869795
}
97879796

9788-
if (ship_entry->status == ShipStatus::EXITED) {
9797+
if (ship_entry->status == ShipStatus::DEATH_ROLL || ship_entry->status == ShipStatus::EXITED) {
97899798
if (mission_log_get_time(LOG_SHIP_DEPARTED, ship_entry->name, nullptr, &time_gone)) {
97909799
count++;
97919800
} else if (mission_log_get_time(LOG_SHIP_DESTROYED, ship_entry->name, nullptr, &time_gone)) {
@@ -11847,6 +11856,8 @@ int sexp_is_iff(int n)
1184711856
// ship is in the EXITED state but probably in the process of exploding
1184811857
else if (oswpt.ship_entry->shipp)
1184911858
{
11859+
UNREACHABLE("With the addition of the ShipStatus::DEATH_ROLL state, this shouldn't happen");
11860+
1185011861
// if the team doesn't match the team specified, return false immediately
1185111862
if (oswpt.ship_entry->shipp->team != team)
1185211863
return SEXP_KNOWN_FALSE;
@@ -12335,7 +12346,7 @@ void sexp_add_goal(int n)
1233512346
auto ship_entry = eval_ship(n);
1233612347
if (ship_entry)
1233712348
{
12338-
if (ship_entry->status != ShipStatus::PRESENT)
12349+
if (!ship_entry->shipp)
1233912350
return; // ship not around anymore???? then forget it!
1234012351

1234112352
ai_add_ship_goal_sexp(goal_node, AIG_TYPE_EVENT_SHIP, &(Ai_info[ship_entry->shipp->ai_index]));
@@ -12362,7 +12373,7 @@ void sexp_remove_goal(int n)
1236212373
auto ship_entry = eval_ship(n);
1236312374
if (ship_entry)
1236412375
{
12365-
if (ship_entry->status != ShipStatus::PRESENT)
12376+
if (!ship_entry->shipp)
1236612377
return; // ship not around anymore???? then forget it!
1236712378

1236812379
int goalindex = ai_remove_goal_sexp_sub(goal_node, Ai_info[ship_entry->shipp->ai_index].goals);
@@ -12394,7 +12405,7 @@ void sexp_clear_goals(int n)
1239412405
auto ship_entry = eval_ship(n);
1239512406
if (ship_entry)
1239612407
{
12397-
if (ship_entry->status != ShipStatus::PRESENT)
12408+
if (!ship_entry->shipp)
1239812409
continue; // ship not around anymore???? then forget it!
1239912410

1240012411
ai_clear_ship_goals(&(Ai_info[ship_entry->shipp->ai_index]));
@@ -16225,7 +16236,7 @@ void sexp_deal_with_ship_flag(int node, bool process_subsequent_nodes, Object::O
1622516236
continue;
1622616237

1622716238
// if ship is in-mission
16228-
if (ship_entry->status == ShipStatus::PRESENT)
16239+
if (ship_entry->shipp)
1622916240
{
1623016241
// save flags for state change comparisons
1623116242
auto object_flag_orig = ship_entry->objp->flags;
@@ -20181,23 +20192,20 @@ void sexp_set_alphamult(int n)
2018120192
case OSWPT_TYPE_SHIP:
2018220193
{
2018320194
auto ship_entry = oswpt.ship_entry;
20195+
ship* shipp = ship_entry->shipp;
2018420196

20185-
if (ship_entry->status == ShipStatus::PRESENT)
20186-
{
20187-
ship* shipp = ship_entry->shipp;
20188-
shipp->flags.remove(Ship::Ship_Flags::Cloaked);
20189-
if (newAlpha >= 100) {
20190-
shipp->alpha_mult = 1.0f;
20191-
shipp->flags.remove(Ship::Ship_Flags::Render_with_alpha_mult);
20192-
}
20193-
else if (newAlpha <= 0) {
20194-
shipp->alpha_mult = 0.0f;
20195-
shipp->flags.set(Ship::Ship_Flags::Cloaked);
20196-
}
20197-
else {
20198-
shipp->alpha_mult = ((float)newAlpha) / 100.f;
20199-
shipp->flags.set(Ship::Ship_Flags::Render_with_alpha_mult);
20200-
}
20197+
shipp->flags.remove(Ship::Ship_Flags::Cloaked);
20198+
if (newAlpha >= 100) {
20199+
shipp->alpha_mult = 1.0f;
20200+
shipp->flags.remove(Ship::Ship_Flags::Render_with_alpha_mult);
20201+
}
20202+
else if (newAlpha <= 0) {
20203+
shipp->alpha_mult = 0.0f;
20204+
shipp->flags.set(Ship::Ship_Flags::Cloaked);
20205+
}
20206+
else {
20207+
shipp->alpha_mult = ((float)newAlpha) / 100.f;
20208+
shipp->flags.set(Ship::Ship_Flags::Render_with_alpha_mult);
2020120209
}
2020220210
break;
2020320211
}
@@ -20307,7 +20315,7 @@ void sexp_ship_copy_damage(int node)
2030720315
continue;
2030820316

2030920317
// maybe it's present in-mission
20310-
if (target->status == ShipStatus::PRESENT)
20318+
if (target->shipp)
2031120319
{
2031220320
ship_copy_damage(target->shipp, source->shipp);
2031320321
continue;
@@ -25709,7 +25717,7 @@ int sexp_is_in_mission(int node)
2570925717
{
2571025718
// For this sexp, we do not short-circuit known-true or known-false.
2571125719
auto ship_entry = eval_ship(n);
25712-
if (!ship_entry || ship_entry->status != ShipStatus::PRESENT)
25720+
if (!ship_entry || !ship_entry->shipp)
2571325721
return SEXP_FALSE;
2571425722
}
2571525723

@@ -25718,7 +25726,6 @@ int sexp_is_in_mission(int node)
2571825726

2571925727
int sexp_has_armor_type(int node)
2572025728
{
25721-
2572225729
// get ship from sexp
2572325730
auto ship_entry = eval_ship(node);
2572425731
if (!ship_entry || ship_entry->status == ShipStatus::NOT_YET_PRESENT)
@@ -25808,7 +25815,7 @@ void sexp_manipulate_colgroup(int node, bool add_to_group)
2580825815
return;
2580925816
node = CDR(node);
2581025817

25811-
int colgroup_id = (ship_entry->status == ShipStatus::PRESENT)
25818+
int colgroup_id = (ship_entry->objp)
2581225819
? ship_entry->objp->collision_group_id
2581325820
: ship_entry->p_objp->collision_group_id;
2581425821

@@ -25830,7 +25837,7 @@ void sexp_manipulate_colgroup(int node, bool add_to_group)
2583025837
}
2583125838
}
2583225839

25833-
if (ship_entry->status == ShipStatus::PRESENT)
25840+
if (ship_entry->objp)
2583425841
ship_entry->objp->collision_group_id = colgroup_id;
2583525842
else
2583625843
ship_entry->p_objp->collision_group_id = colgroup_id;
@@ -25856,7 +25863,7 @@ void sexp_manipulate_colgroup_new(int node, bool add_to_group)
2585625863
if (!ship_entry || ship_entry->status == ShipStatus::EXITED)
2585725864
continue;
2585825865

25859-
if (ship_entry->status == ShipStatus::PRESENT)
25866+
if (ship_entry->objp)
2586025867
{
2586125868
if (add_to_group)
2586225869
ship_entry->objp->collision_group_id |= (1 << group);
@@ -25881,7 +25888,7 @@ int sexp_get_colgroup(int node)
2588125888
if (ship_entry->status == ShipStatus::EXITED)
2588225889
return SEXP_NAN_FOREVER;
2588325890

25884-
if (ship_entry->status == ShipStatus::PRESENT)
25891+
if (ship_entry->objp)
2588525892
return ship_entry->objp->collision_group_id;
2588625893
else
2588725894
return ship_entry->p_objp->collision_group_id;

code/parse/sexp/LuaSEXP.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ luacpp::LuaValue LuaSEXP::sexpToLua(int node, int argnum, int parent_node) const
176176
return LuaValue::createValue(_action.getLuaState(), ship_entry ? ship_entry->name : "");
177177
}
178178

179-
if (!ship_entry || ship_entry->status != ShipStatus::PRESENT) {
179+
if (!ship_entry || !ship_entry->objp) {
180180
// Name is invalid
181181
return LuaValue::createValue(_action.getLuaState(), l_Ship.Set(object_h()));
182182
}
@@ -256,7 +256,7 @@ luacpp::LuaValue LuaSEXP::sexpToLua(int node, int argnum, int parent_node) const
256256

257257
auto ship_entry = eval_ship(this_node);
258258

259-
if (!ship_entry || ship_entry->status != ShipStatus::PRESENT) {
259+
if (!ship_entry || !ship_entry->shipp) {
260260
// Name is invalid
261261
return LuaValue::createValue(_action.getLuaState(), l_Ship.Set(object_h()));
262262
}
@@ -284,7 +284,7 @@ luacpp::LuaValue LuaSEXP::sexpToLua(int node, int argnum, int parent_node) const
284284
}
285285

286286
auto ship_entry = eval_ship(this_node);
287-
if (!ship_entry || ship_entry->status != ShipStatus::PRESENT) {
287+
if (!ship_entry || !ship_entry->shipp) {
288288
// Name is invalid
289289
return LuaValue::createValue(_action.getLuaState(), l_Ship.Set(object_h()));
290290
}

code/playerman/playercontrol.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1768,7 +1768,7 @@ void player_generate_death_message(player *player_p)
17681768

17691769
// killer_parent_name is always a ship name or a callsign (or blank). If it's a ship name, get the ship and use the ship's display name
17701770
auto ship_entry = ship_registry_get(player_p->killer_parent_name);
1771-
auto killer_display_name = (ship_entry != nullptr && ship_entry->status == ShipStatus::PRESENT) ? ship_entry->shipp->get_display_name() : player_p->killer_parent_name;
1771+
auto killer_display_name = (ship_entry && ship_entry->shipp) ? ship_entry->shipp->get_display_name() : player_p->killer_parent_name;
17721772

17731773
switch (player_p->killer_objtype)
17741774
{
@@ -1785,7 +1785,7 @@ void player_generate_death_message(player *player_p)
17851785

17861786
case OBJ_WEAPON:
17871787
// is this from a friendly ship?
1788-
if ((ship_entry != nullptr) && (ship_entry->status == ShipStatus::PRESENT) && (Player_ship != nullptr) && (Player_ship->team == ship_entry->shipp->team))
1788+
if (ship_entry && ship_entry->shipp && Player_ship && (Player_ship->team == ship_entry->shipp->team))
17891789
{
17901790
sprintf(msg, XSTR( "%s was killed by friendly fire from %s", 1338), player_p->callsign, killer_display_name);
17911791
}
@@ -1827,7 +1827,7 @@ void player_generate_death_message(player *player_p)
18271827
else
18281828
{
18291829
// is this from a friendly ship?
1830-
if ((ship_entry != nullptr) && (ship_entry->status == ShipStatus::PRESENT) && (Player_ship != nullptr) && (Player_ship->team == ship_entry->shipp->team))
1830+
if (ship_entry && ship_entry->shipp && Player_ship && (Player_ship->team == ship_entry->shipp->team))
18311831
{
18321832
sprintf(msg, XSTR( "%s was destroyed by friendly beam fire from %s", 1339), player_p->callsign, killer_display_name);
18331833
}

code/ship/ship.h

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -906,10 +906,13 @@ enum class ShipStatus
906906
// A ship is currently in-mission, and its objp and shipp pointers are valid
907907
PRESENT,
908908

909-
// A ship is destroyed, departed, or vanished. Note however that for destroyed ships,
910-
// ship_cleanup is not called until the death roll is complete, which means there is a
911-
// period of time where the ship is "exited", but objp and shipp are still valid and
912-
// exited_index is not yet assigned.
909+
// A ship has been destroyed but is still doing its death roll (not yet "exited");
910+
// the objp and shipp pointers are still valid
911+
DEATH_ROLL,
912+
913+
// A ship is destroyed, departed, or vanished; the objp and shipp pointers are nullptr.
914+
// Note that for destroyed ships, ship_cleanup is not called until the death roll is complete,
915+
// so the ship will spend a period of time in DEATH_ROLL before moving to EXITED.
913916
EXITED
914917
};
915918

code/ship/shiphit.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1979,7 +1979,7 @@ void ship_hit_kill(object *ship_objp, object *other_obj, vec3d *hitpos, float pe
19791979

19801980
// Goober5000 - since we added a mission log entry above, immediately set the status. For destruction, ship_cleanup isn't called until a little bit later
19811981
auto entry = &Ship_registry[Ship_registry_map[sp->ship_name]];
1982-
entry->status = ShipStatus::EXITED;
1982+
entry->status = ShipStatus::DEATH_ROLL;
19831983

19841984
ship_generic_kill_stuff( ship_objp, percent_killed );
19851985

0 commit comments

Comments
 (0)