Skip to content

Commit 6a20c0f

Browse files
authored
Merge pull request scp-fs2open#7117 from Goober5000/anchor_refactor
refactor ship anchors
2 parents 2690cb0 + 35ed88c commit 6a20c0f

22 files changed

Lines changed: 365 additions & 300 deletions

code/ai/aicode.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14060,7 +14060,7 @@ void ai_bay_depart()
1406014060

1406114061
// check if parent ship valid; if not, abort depart
1406214062
if (gameseq_get_state() != GS_STATE_LAB) {
14063-
auto anchor_ship_entry = ship_registry_get(Parse_names[Ships[Pl_objp->instance].departure_anchor]);
14063+
auto anchor_ship_entry = ship_registry_get(Ships[Pl_objp->instance].departure_anchor);
1406414064
if (!anchor_ship_entry ||
1406514065
!ship_useful_for_departure(anchor_ship_entry->shipnum, Ships[Pl_objp->instance].departure_path_mask)) {
1406614066
mprintf(("Aborting bay departure!\n"));

code/mission/missionparse.cpp

Lines changed: 142 additions & 119 deletions
Large diffs are not rendered by default.

code/mission/missionparse.h

Lines changed: 21 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "sound/sound.h"
2626
#include "mission/mission_flags.h"
2727
#include "nebula/volumetrics.h"
28+
#include "ship/anchor_t.h"
2829
#include "stats/scoring.h"
2930

3031
//WMC - This should be here
@@ -40,16 +41,11 @@ enum class DepartureLocation;
4041

4142
#define DEFAULT_AMBIENT_LIGHT_LEVEL 0x00787878
4243

43-
// arrival anchor types
44-
// mask should be high enough to avoid conflicting with ship anchors
45-
#define SPECIAL_ARRIVAL_ANCHOR_FLAG 0x1000
46-
#define SPECIAL_ARRIVAL_ANCHOR_PLAYER_FLAG 0x0100
47-
4844
#define MIN_TARGET_ARRIVAL_DISTANCE 500.0f // float because that's how FRED does the math
4945
#define MIN_TARGET_ARRIVAL_MULTIPLIER 2.0f // minimum distance is 2 * target radius, but at least 500
5046

51-
int get_special_anchor(const char *name);
52-
void check_anchor_for_hangar_bay(SCP_string &message, SCP_set<int> &anchor_shipnums_checked, int anchor_shipnum, const char *other_name, bool other_is_ship, bool is_arrival);
47+
anchor_t get_special_anchor(const char *name);
48+
void check_anchor_for_hangar_bay(SCP_string &message, SCP_set<anchor_t> &anchors_checked, anchor_t anchor, const char *other_name, bool other_is_ship, bool is_arrival);
5349

5450
// MISSION_VERSION should be the earliest version of FSO that can load the current mission format without
5551
// requiring version-specific comments. It should be updated whenever the format changes, but it should
@@ -102,19 +98,22 @@ inline const std::vector<std::pair<SCP_string, int>> Mission_event_teams_tvt = [
10298
}();
10399

104100
// Goober5000
105-
typedef struct support_ship_info {
106-
ArrivalLocation arrival_location; // arrival location
107-
int arrival_anchor; // arrival anchor
108-
DepartureLocation departure_location; // departure location
109-
int departure_anchor; // departure anchor
110-
float max_hull_repair_val; // % of a ship's hull that can be repaired -C
111-
float max_subsys_repair_val; // same thing, except for subsystems -C
112-
int max_support_ships; // max number of consecutive support ships
113-
int max_concurrent_ships; // max number of concurrent support ships in mission per team
114-
int ship_class; // ship class of support ship
115-
int tally; // number of support ships so far
116-
int support_available_for_species; // whether support is available for a given species (this is a bitfield)
117-
} support_ship_info;
101+
struct support_ship_info
102+
{
103+
ArrivalLocation arrival_location; // arrival location
104+
anchor_t arrival_anchor; // arrival anchor
105+
DepartureLocation departure_location; // departure location
106+
anchor_t departure_anchor; // departure anchor
107+
float max_hull_repair_val; // % of a ship's hull that can be repaired -C
108+
float max_subsys_repair_val; // same thing, except for subsystems -C
109+
int max_support_ships; // max number of consecutive support ships
110+
int max_concurrent_ships; // max number of concurrent support ships in mission per team
111+
int ship_class; // ship class of support ship
112+
int tally; // number of support ships so far
113+
int support_available_for_species; // whether support is available for a given species (this is a bitfield)
114+
115+
void reset();
116+
};
118117

119118
// movie type defines
120119
// If you add one here, you must also add a description to missioncutscenedlg.cpp for FRED
@@ -446,13 +445,13 @@ class p_object
446445

447446
ArrivalLocation arrival_location = ArrivalLocation::AT_LOCATION;
448447
int arrival_distance = 0; // used when arrival location is near or in front of some ship
449-
int arrival_anchor = -1; // ship used for anchoring an arrival point
448+
anchor_t arrival_anchor = anchor_t::invalid(); // ship registry entry used for anchoring an arrival point
450449
int arrival_path_mask = 0; // Goober5000
451450
int arrival_cue = -1; // Index in Sexp_nodes of this sexp.
452451
int arrival_delay = 0;
453452

454453
DepartureLocation departure_location = DepartureLocation::AT_LOCATION;
455-
int departure_anchor = -1;
454+
anchor_t departure_anchor = anchor_t::invalid();
456455
int departure_path_mask = 0; // Goober5000
457456
int departure_cue = -1; // Index in Sexp_nodes of this sexp.
458457
int departure_delay = 0;

code/missioneditor/common.cpp

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,16 +50,36 @@ void stuff_special_arrival_anchor_name(char* buf, int anchor_num, bool retail_fo
5050
{
5151
// filter out iff
5252
int iff_index = anchor_num;
53-
iff_index &= ~SPECIAL_ARRIVAL_ANCHOR_FLAG;
54-
iff_index &= ~SPECIAL_ARRIVAL_ANCHOR_PLAYER_FLAG;
53+
iff_index &= ~ANCHOR_SPECIAL_ARRIVAL;
54+
iff_index &= ~ANCHOR_SPECIAL_ARRIVAL_PLAYER;
5555

5656
// filter players
57-
int restrict_to_players = (anchor_num & SPECIAL_ARRIVAL_ANCHOR_PLAYER_FLAG);
57+
int restrict_to_players = (anchor_num & ANCHOR_SPECIAL_ARRIVAL_PLAYER);
5858

5959
// get name
6060
stuff_special_arrival_anchor_name(buf, iff_index, restrict_to_players, retail_format);
6161
}
6262

63+
// Ship and wing arrival and departure anchors should always be ship registry entry indexes, except for a very brief window during mission parsing.
64+
// But FRED and QtFRED dialogs use ship indexes instead. So, rather than refactor all the dialogs, this converts between the two. If an anchor
65+
// is a valid ship registry index, the equivalent ship index is returned; otherwise the special value (-1 or a flag) is returned instead.
66+
int anchor_to_target(anchor_t anchor)
67+
{
68+
auto anchor_entry = ship_registry_get(anchor);
69+
return anchor_entry ? anchor_entry->shipnum : anchor.value();
70+
}
71+
72+
// Ship and wing arrival and departure anchors should always be ship registry entry indexes, except for a very brief window during mission parsing.
73+
// But FRED and QtFRED dialogs use ship indexes instead. So, rather than refactor all the dialogs, this converts between the two. If a target
74+
// is a valid ship index, the equivalent ship registry index is returned; otherwise the special value (-1 or a flag) is returned instead.
75+
anchor_t target_to_anchor(int target)
76+
{
77+
if (target >= 0 && target < MAX_SHIPS)
78+
return anchor_t(ship_registry_get_index(Ships[target].ship_name));
79+
else
80+
return anchor_t(target);
81+
}
82+
6383
void generate_weaponry_usage_list_team(int team, int* arr)
6484
{
6585
int i;
@@ -112,4 +132,4 @@ void generate_weaponry_usage_list_wing(int wing_num, int* arr)
112132
}
113133
}
114134
}
115-
}
135+
}

code/missioneditor/common.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#pragma once
22
#include "globalincs/globals.h"
33
#include "mission/missionmessage.h"
4+
#include "ship/anchor_t.h"
45

56
// Voice acting manager
67
#define INVALID_MESSAGE ((MMessage*)SIZE_MAX) // was originally SIZE_T_MAX but that wasn't available outside fred. May need more research.
@@ -31,6 +32,10 @@ void stuff_special_arrival_anchor_name(char* buf, int iff_index, int restrict_to
3132

3233
void stuff_special_arrival_anchor_name(char* buf, int anchor_num, bool retail_format);
3334

35+
int anchor_to_target(anchor_t anchor);
36+
37+
anchor_t target_to_anchor(int target);
38+
3439
void generate_weaponry_usage_list_team(int team, int* arr);
3540

36-
void generate_weaponry_usage_list_wing(int wing_num, int* arr);
41+
void generate_weaponry_usage_list_wing(int wing_num, int* arr);

code/missioneditor/missionsave.cpp

Lines changed: 24 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -3555,33 +3555,31 @@ int Fred_mission_save::save_objects()
35553555
fout("\n$Arrival Anchor:");
35563556
}
35573557

3558-
z = shipp->arrival_anchor;
3558+
z = shipp->arrival_anchor.value();
35593559
if (z < 0) {
35603560
fout(" <error>");
3561-
} else if (z & SPECIAL_ARRIVAL_ANCHOR_FLAG) {
3561+
} else if (z & ANCHOR_SPECIAL_ARRIVAL) {
35623562
// get name
35633563
char tmp[NAME_LENGTH + 15];
35643564
stuff_special_arrival_anchor_name(tmp, z, save_config.save_format == MissionFormat::RETAIL);
35653565

35663566
// save it
35673567
fout(" %s", tmp);
35683568
} else {
3569-
fout(" %s", Ships[z].ship_name);
3569+
auto anchor_entry = ship_registry_get(z);
3570+
fout(" %s", anchor_entry ? anchor_entry->name : "<error>");
35703571
}
35713572
}
35723573

35733574
// Goober5000
35743575
if (save_config.save_format != MissionFormat::RETAIL) {
35753576
if ((shipp->arrival_location == ArrivalLocation::FROM_DOCK_BAY) && (shipp->arrival_path_mask > 0)) {
3576-
int anchor_shipnum;
3577-
polymodel* pm;
3578-
3579-
anchor_shipnum = shipp->arrival_anchor;
3580-
Assert(anchor_shipnum >= 0 && anchor_shipnum < MAX_SHIPS);
3577+
auto anchor_entry = ship_registry_get(shipp->arrival_anchor);
3578+
Assertion(anchor_entry, "Could not find arrival anchor for ship %s!", shipp->ship_name);
3579+
auto pm = model_get(anchor_entry->sip()->model_num);
35813580

35823581
fout("\n+Arrival Paths: ( ");
35833582

3584-
pm = model_get(Ship_info[Ships[anchor_shipnum].ship_info_index].model_num);
35853583
for (auto n = 0; n < pm->ship_bay->num_paths; n++) {
35863584
if (shipp->arrival_path_mask & (1 << n)) {
35873585
fout("\"%s\" ", pm->paths[pm->ship_bay->path_indexes[n]].name);
@@ -3618,24 +3616,19 @@ int Fred_mission_save::save_objects()
36183616
required_string_fred("$Departure Anchor:");
36193617
parse_comments();
36203618

3621-
if (shipp->departure_anchor >= 0)
3622-
fout(" %s", Ships[shipp->departure_anchor].ship_name);
3623-
else
3624-
fout(" <error>");
3619+
auto anchor_entry = ship_registry_get(shipp->departure_anchor);
3620+
fout(" %s", anchor_entry ? anchor_entry->name : "<error>");
36253621
}
36263622

36273623
// Goober5000
36283624
if (save_config.save_format != MissionFormat::RETAIL) {
36293625
if ((shipp->departure_location == DepartureLocation::TO_DOCK_BAY) && (shipp->departure_path_mask > 0)) {
3630-
int anchor_shipnum;
3631-
polymodel* pm;
3632-
3633-
anchor_shipnum = shipp->departure_anchor;
3634-
Assert(anchor_shipnum >= 0 && anchor_shipnum < MAX_SHIPS);
3626+
auto anchor_entry = ship_registry_get(shipp->departure_anchor);
3627+
Assertion(anchor_entry, "Could not find departure anchor for ship %s!", shipp->ship_name);
3628+
auto pm = model_get(anchor_entry->sip()->model_num);
36353629

36363630
fout("\n+Departure Paths: ( ");
36373631

3638-
pm = model_get(Ship_info[Ships[anchor_shipnum].ship_info_index].model_num);
36393632
for (auto n = 0; n < pm->ship_bay->num_paths; n++) {
36403633
if (shipp->departure_path_mask & (1 << n)) {
36413634
fout("\"%s\" ", pm->paths[pm->ship_bay->path_indexes[n]].name);
@@ -4932,33 +4925,31 @@ int Fred_mission_save::save_wings()
49324925
else
49334926
fout("\n$Arrival Anchor:");
49344927

4935-
int z = w.arrival_anchor;
4928+
int z = w.arrival_anchor.value();
49364929
if (z < 0) {
49374930
fout(" <error>");
4938-
} else if (z & SPECIAL_ARRIVAL_ANCHOR_FLAG) {
4931+
} else if (z & ANCHOR_SPECIAL_ARRIVAL) {
49394932
// get name
49404933
char tmp[NAME_LENGTH + 15];
49414934
stuff_special_arrival_anchor_name(tmp, z, save_config.save_format == MissionFormat::RETAIL);
49424935

49434936
// save it
49444937
fout(" %s", tmp);
49454938
} else {
4946-
fout(" %s", Ships[z].ship_name);
4939+
auto anchor_entry = ship_registry_get(z);
4940+
fout(" %s", anchor_entry ? anchor_entry->name : "<error>");
49474941
}
49484942
}
49494943

49504944
// Goober5000
49514945
if (save_config.save_format != MissionFormat::RETAIL) {
49524946
if ((w.arrival_location == ArrivalLocation::FROM_DOCK_BAY) && (w.arrival_path_mask > 0)) {
4953-
int anchor_shipnum;
4954-
polymodel* pm;
4955-
4956-
anchor_shipnum = w.arrival_anchor;
4957-
Assert(anchor_shipnum >= 0 && anchor_shipnum < MAX_SHIPS);
4947+
auto anchor_entry = ship_registry_get(w.arrival_anchor);
4948+
Assertion(anchor_entry, "Could not find arrival anchor for wing %s!", w.name);
4949+
auto pm = model_get(anchor_entry->sip()->model_num);
49584950

49594951
fout("\n+Arrival Paths: ( ");
49604952

4961-
pm = model_get(Ship_info[Ships[anchor_shipnum].ship_info_index].model_num);
49624953
for (auto n = 0; n < pm->ship_bay->num_paths; n++) {
49634954
if (w.arrival_path_mask & (1 << n)) {
49644955
fout("\"%s\" ", pm->paths[pm->ship_bay->path_indexes[n]].name);
@@ -4991,24 +4982,19 @@ int Fred_mission_save::save_wings()
49914982
required_string_fred("$Departure Anchor:");
49924983
parse_comments();
49934984

4994-
if (w.departure_anchor >= 0)
4995-
fout(" %s", Ships[w.departure_anchor].ship_name);
4996-
else
4997-
fout(" <error>");
4985+
auto anchor_entry = ship_registry_get(w.departure_anchor);
4986+
fout(" %s", anchor_entry ? anchor_entry->name : "<error>");
49984987
}
49994988

50004989
// Goober5000
50014990
if (save_config.save_format != MissionFormat::RETAIL) {
50024991
if ((w.departure_location == DepartureLocation::TO_DOCK_BAY) && (w.departure_path_mask > 0)) {
5003-
int anchor_shipnum;
5004-
polymodel* pm;
5005-
5006-
anchor_shipnum = w.departure_anchor;
5007-
Assert(anchor_shipnum >= 0 && anchor_shipnum < MAX_SHIPS);
4992+
auto anchor_entry = ship_registry_get(w.departure_anchor);
4993+
Assertion(anchor_entry, "Could not find departure anchor for wing %s!", w.name);
4994+
auto pm = model_get(anchor_entry->sip()->model_num);
50084995

50094996
fout("\n+Departure Paths: ( ");
50104997

5011-
pm = model_get(Ship_info[Ships[anchor_shipnum].ship_info_index].model_num);
50124998
for (auto n = 0; n < pm->ship_bay->num_paths; n++) {
50134999
if (w.departure_path_mask & (1 << n)) {
50145000
fout("\"%s\" ", pm->paths[pm->ship_bay->path_indexes[n]].name);

code/parse/sexp.cpp

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2981,7 +2981,7 @@ int check_sexp_syntax(int node, int return_type, int recursive, int *bad_node, s
29812981
int valid = 0;
29822982

29832983
// <any friendly>, etc.
2984-
if (get_special_anchor(CTEXT(node)) >= 0)
2984+
if (get_special_anchor(CTEXT(node)).isValid())
29852985
{
29862986
valid = 1;
29872987
}
@@ -23594,8 +23594,8 @@ void sexp_set_support_ship(int n)
2359423594
}
2359523595
else
2359623596
{
23597-
// find or create the anchor
23598-
The_mission.support_ships.arrival_anchor = get_parse_name_index(CTEXT(n));
23597+
// find the anchor
23598+
The_mission.support_ships.arrival_anchor = anchor_t(ship_registry_get_index(CTEXT(n)));
2359923599
}
2360023600

2360123601
// get departure location
@@ -23620,8 +23620,8 @@ void sexp_set_support_ship(int n)
2362023620
}
2362123621
else
2362223622
{
23623-
// find or create the anchor
23624-
The_mission.support_ships.departure_anchor = get_parse_name_index(CTEXT(n));
23623+
// find the anchor
23624+
The_mission.support_ships.departure_anchor = anchor_t(ship_registry_get_index(CTEXT(n)));
2362523625
}
2362623626

2362723627
// get ship class
@@ -23662,7 +23662,7 @@ void sexp_set_support_ship(int n)
2366223662
// Goober5000 - set stuff for arriving ships or wings
2366323663
void sexp_set_arrival_info(int node)
2366423664
{
23665-
int arrival_anchor, arrival_mask, arrival_distance, arrival_delay, n = node;
23665+
int arrival_mask, arrival_distance, arrival_delay, n = node;
2366623666
bool show_warp, adjust_warp_when_docked, is_nan, is_nan_forever;
2366723667
object_ship_wing_point_team oswpt;
2366823668

@@ -23683,16 +23683,16 @@ void sexp_set_arrival_info(int node)
2368323683
n = CDR(n);
2368423684

2368523685
// get arrival anchor
23686-
arrival_anchor = -1;
23686+
anchor_t arrival_anchor;
2368723687
if ((n < 0) || !stricmp(CTEXT(n), "<no anchor>"))
2368823688
{
2368923689
// if no anchor, set arrival location to hyperspace
2369023690
arrival_location = ArrivalLocation::AT_LOCATION;
2369123691
}
2369223692
else
2369323693
{
23694-
// find or create the anchor
23695-
arrival_anchor = get_parse_name_index(CTEXT(n));
23694+
// find the anchor
23695+
arrival_anchor = anchor_t(ship_registry_get_index(CTEXT(n)));
2369623696
}
2369723697
n = CDR(n);
2369823698

@@ -23762,7 +23762,7 @@ void sexp_set_arrival_info(int node)
2376223762
// Goober5000 - set stuff for departing ships or wings
2376323763
void sexp_set_departure_info(int node)
2376423764
{
23765-
int departure_anchor, departure_mask, departure_delay, n = node;
23765+
int departure_mask, departure_delay, n = node;
2376623766
bool show_warp, adjust_warp_when_docked, is_nan, is_nan_forever;
2376723767
object_ship_wing_point_team oswpt;
2376823768

@@ -23783,16 +23783,16 @@ void sexp_set_departure_info(int node)
2378323783
n = CDR(n);
2378423784

2378523785
// get departure anchor
23786-
departure_anchor = -1;
23786+
anchor_t departure_anchor;
2378723787
if ((n < 0) || !stricmp(CTEXT(n), "<no anchor>"))
2378823788
{
2378923789
// if no anchor, set departure location to hyperspace
2379023790
departure_location = DepartureLocation::AT_LOCATION;
2379123791
}
2379223792
else
2379323793
{
23794-
// find or create the anchor
23795-
departure_anchor = get_parse_name_index(CTEXT(n));
23794+
// find the anchor
23795+
departure_anchor = anchor_t(ship_registry_get_index(CTEXT(n)));
2379623796
}
2379723797
n = CDR(n);
2379823798

0 commit comments

Comments
 (0)