Skip to content

Commit e6da70a

Browse files
authored
Merge pull request #7053 from Goober5000/check_for_hangar_bay
check missions for missing hangar bays
2 parents ac03c1a + c144478 commit e6da70a

File tree

5 files changed

+114
-8
lines changed

5 files changed

+114
-8
lines changed

code/mission/missionparse.cpp

Lines changed: 46 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6622,6 +6622,15 @@ bool post_process_mission(mission *pm)
66226622

66236623
// convert all ship name indices to ship indices now that mission has been loaded
66246624
if (Fred_running) {
6625+
// lambda for seeing whether the anchors actually work for arrival/departure
6626+
SCP_string message;
6627+
SCP_set<int> anchors_checked;
6628+
auto check_anchor = [&message, &anchors_checked](int anchor_shipnum, const char *other_name, bool other_is_ship, bool is_arrival) {
6629+
check_anchor_for_hangar_bay(message, anchors_checked, anchor_shipnum, other_name, other_is_ship, is_arrival);
6630+
if (!message.empty())
6631+
Warning(LOCATION, "%s", message.c_str());
6632+
};
6633+
66256634
i = 0;
66266635
for (const auto &parse_name: Parse_names) {
66276636
auto ship_entry = ship_registry_get(parse_name);
@@ -6632,21 +6641,32 @@ bool post_process_mission(mission *pm)
66326641
}
66336642

66346643
for (i=0; i<MAX_SHIPS; i++) {
6635-
if ((Ships[i].objnum >= 0) && (Ships[i].arrival_anchor >= 0) && (Ships[i].arrival_anchor < SPECIAL_ARRIVAL_ANCHOR_FLAG))
6644+
if ((Ships[i].objnum >= 0) && (Ships[i].arrival_anchor >= 0) && (Ships[i].arrival_anchor < SPECIAL_ARRIVAL_ANCHOR_FLAG)) {
66366645
Ships[i].arrival_anchor = indices[Ships[i].arrival_anchor];
6646+
if (Ships[i].arrival_location == ArrivalLocation::FROM_DOCK_BAY)
6647+
check_anchor(Ships[i].arrival_anchor, Ships[i].ship_name, true, true);
6648+
}
66376649

6638-
if ( (Ships[i].objnum >= 0) && (Ships[i].departure_anchor >= 0) )
6650+
if ((Ships[i].objnum >= 0) && (Ships[i].departure_anchor >= 0)) {
66396651
Ships[i].departure_anchor = indices[Ships[i].departure_anchor];
6652+
if (Ships[i].departure_location == DepartureLocation::TO_DOCK_BAY)
6653+
check_anchor(Ships[i].departure_anchor, Ships[i].ship_name, true, false);
6654+
}
66406655
}
66416656

66426657
for (i=0; i<MAX_WINGS; i++) {
6643-
if (Wings[i].wave_count && (Wings[i].arrival_anchor >= 0) && (Wings[i].arrival_anchor < SPECIAL_ARRIVAL_ANCHOR_FLAG))
6658+
if (Wings[i].wave_count && (Wings[i].arrival_anchor >= 0) && (Wings[i].arrival_anchor < SPECIAL_ARRIVAL_ANCHOR_FLAG)) {
66446659
Wings[i].arrival_anchor = indices[Wings[i].arrival_anchor];
6660+
if (Wings[i].arrival_location == ArrivalLocation::FROM_DOCK_BAY)
6661+
check_anchor(Wings[i].arrival_anchor, Wings[i].name, false, true);
6662+
}
66456663

6646-
if (Wings[i].wave_count && (Wings[i].departure_anchor >= 0) )
6664+
if (Wings[i].wave_count && (Wings[i].departure_anchor >= 0)) {
66476665
Wings[i].departure_anchor = indices[Wings[i].departure_anchor];
6666+
if (Wings[i].departure_location == DepartureLocation::TO_DOCK_BAY)
6667+
check_anchor(Wings[i].departure_anchor, Wings[i].name, false, false);
6668+
}
66486669
}
6649-
66506670
}
66516671

66526672
// before doing anything else, we must validate all of the sexpressions that were loaded into the mission.
@@ -8673,6 +8693,27 @@ int get_anchor(const char *name)
86738693
return get_parse_name_index(name);
86748694
}
86758695

8696+
/**
8697+
* See if an arrival/departure anchor is missing a hangar bay. If it is, the message parameter will be populated with an appropriate error.
8698+
*/
8699+
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)
8700+
{
8701+
message.clear();
8702+
8703+
if (anchor_shipnum < 0)
8704+
return;
8705+
if (anchor_shipnums_checked.contains(anchor_shipnum))
8706+
return;
8707+
anchor_shipnums_checked.insert(anchor_shipnum);
8708+
8709+
if (!ship_has_dock_bay(anchor_shipnum))
8710+
{
8711+
auto shipp = &Ships[anchor_shipnum];
8712+
sprintf(message, "%s (%s) is used as a%s anchor by %s %s (and possibly elsewhere too), but it does not have a hangar bay!", shipp->ship_name,
8713+
Ship_info[shipp->ship_info_index].name, is_arrival ? "n arrival" : " departure", other_is_ship ? "ship" : "wing", other_name);
8714+
}
8715+
};
8716+
86768717
/**
86778718
* Fixup the goals/ai references for player objects in the mission
86788719
*/

code/mission/missionparse.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ enum class DepartureLocation;
4949
#define MIN_TARGET_ARRIVAL_MULTIPLIER 2.0f // minimum distance is 2 * target radius, but at least 500
5050

5151
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);
5253

5354
// MISSION_VERSION should be the earliest version of FSO that can load the current mission format without
5455
// requiring version-specific comments. It should be updated whenever the format changes, but it should

code/ship/ship.cpp

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19981,9 +19981,21 @@ bool ship_has_dock_bay(int shipnum)
1998119981
{
1998219982
Assert(shipnum >= 0 && shipnum < MAX_SHIPS);
1998319983

19984-
polymodel *pm;
19985-
19986-
pm = model_get( Ship_info[Ships[shipnum].ship_info_index].model_num );
19984+
auto sip = &Ship_info[Ships[shipnum].ship_info_index];
19985+
19986+
// the model might not be loaded yet, so load it explicitly here
19987+
if (sip->model_num < 0)
19988+
{
19989+
if (VALID_FNAME(sip->pof_file))
19990+
sip->model_num = model_load(sip->pof_file, sip);
19991+
}
19992+
if (sip->model_num < 0)
19993+
{
19994+
Warning(LOCATION, "%s does not have a valid model number!", sip->name);
19995+
return false;
19996+
}
19997+
19998+
auto pm = model_get(sip->model_num);
1998719999
Assert( pm );
1998820000

1998920001
return ( pm->ship_bay && (pm->ship_bay->num_paths > 0) );

fred2/fredview.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2440,6 +2440,8 @@ int CFREDView::global_error_check()
24402440
int bs, i, j, n, s, t, z, ai, count, ship, wing, obj, team, point, multi;
24412441
object *ptr;
24422442
brief_stage *sp;
2443+
SCP_string anchor_message;
2444+
SCP_set<int> anchor_shipnums_checked;
24432445

24442446
g_err = multi = 0;
24452447
if ( The_mission.game_type & MISSION_TYPE_MULTI )
@@ -2638,6 +2640,12 @@ int CFREDView::global_error_check()
26382640
return 1;
26392641
}
26402642
}
2643+
if (Ships[i].arrival_location == ArrivalLocation::FROM_DOCK_BAY) {
2644+
check_anchor_for_hangar_bay(anchor_message, anchor_shipnums_checked, Ships[i].arrival_anchor, Ships[i].ship_name, true, true);
2645+
if (!anchor_message.empty() && error("%s", anchor_message.c_str())) {
2646+
return 1;
2647+
}
2648+
}
26412649
}
26422650

26432651
if (Ships[i].departure_location != DepartureLocation::AT_LOCATION) {
@@ -2646,6 +2654,12 @@ int CFREDView::global_error_check()
26462654
return 1;
26472655
}
26482656
}
2657+
if (Ships[i].departure_location == DepartureLocation::TO_DOCK_BAY) {
2658+
check_anchor_for_hangar_bay(anchor_message, anchor_shipnums_checked, Ships[i].departure_anchor, Ships[i].ship_name, true, false);
2659+
if (!anchor_message.empty() && error("%s", anchor_message.c_str())) {
2660+
return 1;
2661+
}
2662+
}
26492663
}
26502664

26512665
ai = Ships[i].ai_index;
@@ -2841,12 +2855,24 @@ int CFREDView::global_error_check()
28412855
if (Wings[i].arrival_anchor < 0)
28422856
if (error("Wing \"%s\" requires a valid arrival target", Wings[i].name))
28432857
return 1;
2858+
if (Wings[i].arrival_location == ArrivalLocation::FROM_DOCK_BAY) {
2859+
check_anchor_for_hangar_bay(anchor_message, anchor_shipnums_checked, Wings[i].arrival_anchor, Wings[i].name, false, true);
2860+
if (!anchor_message.empty() && error("%s", anchor_message.c_str())) {
2861+
return 1;
2862+
}
2863+
}
28442864
}
28452865

28462866
if (Wings[i].departure_location != DepartureLocation::AT_LOCATION) {
28472867
if (Wings[i].departure_anchor < 0)
28482868
if (error("Wing \"%s\" requires a valid departure target", Wings[i].name))
28492869
return 1;
2870+
if (Wings[i].departure_location == DepartureLocation::TO_DOCK_BAY) {
2871+
check_anchor_for_hangar_bay(anchor_message, anchor_shipnums_checked, Wings[i].departure_anchor, Wings[i].name, false, false);
2872+
if (!anchor_message.empty() && error("%s", anchor_message.c_str())) {
2873+
return 1;
2874+
}
2875+
}
28502876
}
28512877

28522878
if ((str = error_check_initial_orders(Wings[i].ai_goals, -1, i))>0) {

qtfred/src/mission/Editor.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1964,6 +1964,8 @@ int Editor::global_error_check_impl() {
19641964
int bs, i, j, n, s, t, z, ai, count, ship, wing, obj, team, point, multi;
19651965
object* ptr;
19661966
brief_stage* sp;
1967+
SCP_string anchor_message;
1968+
SCP_set<int> anchor_shipnums_checked;
19671969

19681970
g_err = multi = 0;
19691971
if (The_mission.game_type & MISSION_TYPE_MULTI) {
@@ -2158,6 +2160,12 @@ int Editor::global_error_check_impl() {
21582160
return 1;
21592161
}
21602162
}
2163+
if (Ships[i].arrival_location == ArrivalLocation::FROM_DOCK_BAY) {
2164+
check_anchor_for_hangar_bay(anchor_message, anchor_shipnums_checked, Ships[i].arrival_anchor, Ships[i].ship_name, true, true);
2165+
if (!anchor_message.empty() && error("%s", anchor_message.c_str())) {
2166+
return 1;
2167+
}
2168+
}
21612169
}
21622170

21632171
if (Ships[i].departure_location != DepartureLocation::AT_LOCATION) {
@@ -2166,6 +2174,12 @@ int Editor::global_error_check_impl() {
21662174
return 1;
21672175
}
21682176
}
2177+
if (Ships[i].departure_location == DepartureLocation::TO_DOCK_BAY) {
2178+
check_anchor_for_hangar_bay(anchor_message, anchor_shipnums_checked, Ships[i].departure_anchor, Ships[i].ship_name, true, false);
2179+
if (!anchor_message.empty() && error("%s", anchor_message.c_str())) {
2180+
return 1;
2181+
}
2182+
}
21692183
}
21702184

21712185
ai = Ships[i].ai_index;
@@ -2374,6 +2388,12 @@ int Editor::global_error_check_impl() {
23742388
return 1;
23752389
}
23762390
}
2391+
if (Wings[i].arrival_location == ArrivalLocation::FROM_DOCK_BAY) {
2392+
check_anchor_for_hangar_bay(anchor_message, anchor_shipnums_checked, Wings[i].arrival_anchor, Wings[i].name, false, true);
2393+
if (!anchor_message.empty() && error("%s", anchor_message.c_str())) {
2394+
return 1;
2395+
}
2396+
}
23772397
}
23782398

23792399
if (Wings[i].departure_location != DepartureLocation::AT_LOCATION) {
@@ -2382,6 +2402,12 @@ int Editor::global_error_check_impl() {
23822402
return 1;
23832403
}
23842404
}
2405+
if (Wings[i].departure_location == DepartureLocation::TO_DOCK_BAY) {
2406+
check_anchor_for_hangar_bay(anchor_message, anchor_shipnums_checked, Wings[i].departure_anchor, Wings[i].name, false, false);
2407+
if (!anchor_message.empty() && error("%s", anchor_message.c_str())) {
2408+
return 1;
2409+
}
2410+
}
23852411
}
23862412

23872413
if ((str = error_check_initial_orders(Wings[i].ai_goals, -1, i)) != nullptr) {

0 commit comments

Comments
 (0)