Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions code/mission/mission_flags.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ namespace Mission {
Neb2_fog_color_override, // Whether to use explicit fog colors instead of checking the palette - Goober5000
Fullneb_background_bitmaps, // Show background bitmaps despite fullneb
Preload_subspace, // Preload the subspace tunnel for both the sexp and specs checkbox (for scripts) - MjnMixael
Large_ships_no_collide_by_default, // Automatically puts all large ships in a shared collision group

NUM_VALUES
};
Expand Down
27 changes: 26 additions & 1 deletion code/mission/missionparse.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,8 @@ SCP_unordered_set<int> Fred_migrated_immobile_ships;
int Num_path_restrictions;
path_restriction_t Path_restrictions[MAX_PATH_RESTRICTIONS];

constexpr int DEFAULT_LARGE_SHIP_NO_COLLIDE_COLLISION_GROUP = 0;

extern int debrief_find_persona_index();

static bool mission_has_layer_name(const mission* pm, const SCP_string& layerName) {
Expand Down Expand Up @@ -397,7 +399,8 @@ flag_def_list_new<Mission::Mission_Flags> Parse_mission_flags[] = {
{"Toggle Starting in Chase View", Mission::Mission_Flags::Toggle_start_chase_view, true, false},
{"Nebula Fog Color Override", Mission::Mission_Flags::Neb2_fog_color_override, true, true},
{"Full Nebula Background Bitmaps", Mission::Mission_Flags::Fullneb_background_bitmaps, true, true},
{"Preload Subspace Tunnel", Mission::Mission_Flags::Preload_subspace, true, false}
{"Preload Subspace Tunnel", Mission::Mission_Flags::Preload_subspace, true, false},
{"Large Ships Do Not Collide By Default", Mission::Mission_Flags::Large_ships_no_collide_by_default, true, false}
};

parse_object_flag_description<Mission::Mission_Flags> Parse_mission_flag_descriptions[] = {
Expand Down Expand Up @@ -431,6 +434,7 @@ parse_object_flag_description<Mission::Mission_Flags> Parse_mission_flag_descrip
{Mission::Mission_Flags::Neb2_fog_color_override, "Whether to use explicit fog colors instead of checking the palette"},
{Mission::Mission_Flags::Fullneb_background_bitmaps, "Show background bitmaps despite full nebula"},
{Mission::Mission_Flags::Preload_subspace, "Preload the subspace tunnel for both the sexp and specs checkbox"},
{Mission::Mission_Flags::Large_ships_no_collide_by_default, "Automatically places all large ships in the configured collision group, preventing large ships from colliding with each other"},
};

const size_t Num_parse_mission_flags = sizeof(Parse_mission_flags) / sizeof(flag_def_list_new<Mission::Mission_Flags>);
Expand Down Expand Up @@ -844,6 +848,18 @@ void parse_mission_info(mission *pm, bool basic = false)
stuff_int(&pm->contrail_threshold);
}

if (optional_string("+Large Ship Collision Group:")) {
stuff_int(&pm->large_ship_no_collide_collision_group);

if (pm->large_ship_no_collide_collision_group < 0 || pm->large_ship_no_collide_collision_group > 31) {
WarningEx(LOCATION,
"Invalid large ship collision group id %d specified. Valid IDs range from 0 to 31. Using group %d instead.\n",
pm->large_ship_no_collide_collision_group,
DEFAULT_LARGE_SHIP_NO_COLLIDE_COLLISION_GROUP);
pm->large_ship_no_collide_collision_group = DEFAULT_LARGE_SHIP_NO_COLLIDE_COLLISION_GROUP;
}
}

if (optional_string("+Volumetric Nebula:")) {
pm->volumetrics.emplace().parse_volumetric_nebula();
}
Expand Down Expand Up @@ -2238,6 +2254,11 @@ int parse_create_object_sub(p_object *p_objp, bool standalone_ship)
// Goober5000 - set the collision group if one was provided
Objects[objnum].collision_group_id = p_objp->collision_group_id;

// Mission-level performance helper: large ships may be grouped so they skip mutual collision checks.
if (The_mission.flags[Mission::Mission_Flags::Large_ships_no_collide_by_default] && sip->is_big_or_huge()) {
Objects[objnum].collision_group_id |= (1 << The_mission.large_ship_no_collide_collision_group);
}

// Goober5000 - set some fields that the mission log might need (if logged via parse_bring_in_docked_wing just below)
shipp->display_name = p_objp->display_name;
shipp->alt_type_index = p_objp->alt_type_index;
Expand Down Expand Up @@ -7178,6 +7199,7 @@ void mission::Reset()

envmap_name[ 0 ] = '\0';
contrail_threshold = CONTRAIL_THRESHOLD_DEFAULT;
large_ship_no_collide_collision_group = DEFAULT_LARGE_SHIP_NO_COLLIDE_COLLISION_GROUP;
ambient_light_level = DEFAULT_AMBIENT_LIGHT_LEVEL;
sound_environment.id = -1;

Expand Down Expand Up @@ -9557,6 +9579,9 @@ bool check_for_24_3_data()

bool check_for_25_1_data()
{
if (The_mission.flags[Mission::Mission_Flags::Large_ships_no_collide_by_default])
return true;

if (count_items_with_value(Props) > 0)
return true;

Expand Down
1 change: 1 addition & 0 deletions code/mission/missionparse.h
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,7 @@ typedef struct mission {
char envmap_name[MAX_FILENAME_LEN];
int skybox_flags;
int contrail_threshold;
int large_ship_no_collide_collision_group;
int ambient_light_level;
std::optional<volumetric_nebula> volumetrics;
sound_env sound_environment;
Expand Down
4 changes: 4 additions & 0 deletions code/missioneditor/missionsave.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2568,6 +2568,10 @@ int Fred_mission_save::save_mission_info()
if (The_mission.contrail_threshold != CONTRAIL_THRESHOLD_DEFAULT) {
fout("\n$Contrail Speed Threshold: %d\n", The_mission.contrail_threshold);
}

if (The_mission.flags[Mission::Mission_Flags::Large_ships_no_collide_by_default]) {
fout("\n+Large Ship Collision Group: %d\n", The_mission.large_ship_no_collide_collision_group);
}
}

{
Expand Down
10 changes: 10 additions & 0 deletions qtfred/help-src/doc/dialogs/MissionSpecsDialog.html
Original file line number Diff line number Diff line change
Expand Up @@ -140,5 +140,15 @@ <h2>Flags</h2>
box to find a specific flag by name, or use <strong>Select All</strong> /
<strong>Select None</strong> to bulk-toggle. Hover over any flag label for a tooltip
description.</p>
<p>Some flags reveal an additional control when enabled:</p>
<table>
<tr><th>Flag</th><th>Control</th><th>Description</th></tr>
<tr><td>Large Ships Do Not Collide By Default</td>
<td>Large Ship Collision Group</td>
<td>Collision group ID (0–31) that large and huge ships are automatically
placed into when the mission loads. Ships sharing the same group skip
collision checks against each other, reducing physics overhead in
missions with many capital ships. Default is 0.</td></tr>
</table>
</body>
</html>
18 changes: 18 additions & 0 deletions qtfred/src/mission/dialogs/MissionSpecDialogModel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ void MissionSpecDialogModel::initializeData() {

_m_contrail_threshold = The_mission.contrail_threshold;
_m_contrail_threshold_flag = (_m_contrail_threshold != CONTRAIL_THRESHOLD_DEFAULT);
_m_large_ship_no_collide_collision_group = The_mission.large_ship_no_collide_collision_group;

_m_custom_data = The_mission.custom_data;
_m_custom_strings = The_mission.custom_strings;
Expand Down Expand Up @@ -125,6 +126,7 @@ bool MissionSpecDialogModel::apply() {
The_mission.support_ships.max_support_ships = (_m_disallow_support) ? 0 : -1;
The_mission.support_ships.max_hull_repair_val = _m_max_hull_repair_val;
The_mission.support_ships.max_subsys_repair_val = _m_max_subsys_repair_val;
The_mission.large_ship_no_collide_collision_group = _m_large_ship_no_collide_collision_group;

// Copy mission flags
The_mission.flags = _m_flags;
Expand Down Expand Up @@ -418,6 +420,22 @@ void MissionSpecDialogModel::setMissionFlagDirect(Mission::Mission_Flags flag, b
}
}

void MissionSpecDialogModel::setLargeShipNoCollideCollisionGroup(int group)
{
if (group < 0) {
group = 0;
} else if (group > 31) {
group = 31;
}

modify(_m_large_ship_no_collide_collision_group, group);
}

int MissionSpecDialogModel::getLargeShipNoCollideCollisionGroup() const
{
return _m_large_ship_no_collide_collision_group;
}

bool MissionSpecDialogModel::getMissionFlag(Mission::Mission_Flags flag) const {
return _m_flags[flag];
}
Expand Down
3 changes: 3 additions & 0 deletions qtfred/src/mission/dialogs/MissionSpecDialogModel.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ class MissionSpecDialogModel : public AbstractDialogModel {
float _m_max_subsys_repair_val;
bool _m_contrail_threshold_flag;
int _m_contrail_threshold;
int _m_large_ship_no_collide_collision_group;
SCP_map<SCP_string, SCP_string> _m_custom_data;
SCP_vector<custom_string> _m_custom_strings;
sound_env _m_sound_env;
Expand Down Expand Up @@ -119,6 +120,8 @@ class MissionSpecDialogModel : public AbstractDialogModel {

void setMissionFlag(const SCP_string& flag_name, bool enabled);
void setMissionFlagDirect(Mission::Mission_Flags flag, bool enabled);
void setLargeShipNoCollideCollisionGroup(int group);
int getLargeShipNoCollideCollisionGroup() const;
bool getMissionFlag(Mission::Mission_Flags flag) const;
const SCP_vector<std::pair<SCP_string, bool>>& getMissionFlagsList();
static SCP_vector<std::pair<SCP_string, SCP_string>> getMissionFlagDescriptions();
Expand Down
15 changes: 15 additions & 0 deletions qtfred/src/ui/dialogs/MissionSpecDialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ void MissionSpecDialog::initFlagList()
// per flag immediate apply to the model
connect(ui->flagList, &fso::fred::FlagListWidget::flagToggled, this, [this](const QString& name, bool checked) {
_model->setMissionFlag(name.toUtf8().constData(), checked);
updateLargeShipCollisionGroup();
});
}

Expand All @@ -149,6 +150,15 @@ void MissionSpecDialog::updateFlags()
}

ui->flagList->setFlags(toWidget);
updateLargeShipCollisionGroup();
}

void MissionSpecDialog::updateLargeShipCollisionGroup()
{
const auto enabled = _model->getMissionFlag(Mission::Mission_Flags::Large_ships_no_collide_by_default);
ui->largeShipCollisionGroupLabel->setVisible(enabled);
ui->largeShipCollisionGroup->setVisible(enabled);
ui->largeShipCollisionGroup->setValue(_model->getLargeShipNoCollideCollisionGroup());
}

void MissionSpecDialog::updateMissionType() {
Expand Down Expand Up @@ -433,6 +443,11 @@ void MissionSpecDialog::on_musicPackCombo_currentIndexChanged(int index) {
_model->setSubEventMusic(subMusic);
}

void MissionSpecDialog::on_largeShipCollisionGroup_valueChanged(int value)
{
_model->setLargeShipNoCollideCollisionGroup(value);
}

void MissionSpecDialog::on_aiProfileCombo_currentIndexChanged(int index)
{
auto aipIndex = ui->aiProfileCombo->itemData(index).value<int>();
Expand Down
2 changes: 2 additions & 0 deletions qtfred/src/ui/dialogs/MissionSpecDialog.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ private slots:

// Right column
// flags are dynamically generated and connected
void on_largeShipCollisionGroup_valueChanged(int value);
void on_aiProfileCombo_currentIndexChanged(int index);

// General
Expand All @@ -84,6 +85,7 @@ private slots:

void initFlagList();
void updateFlags();
void updateLargeShipCollisionGroup();

void updateMissionType();
void updateCmdMessage();
Expand Down
33 changes: 33 additions & 0 deletions qtfred/ui/MissionSpecDialog.ui
Original file line number Diff line number Diff line change
Expand Up @@ -822,6 +822,39 @@
</property>
</widget>
</item>
<item>
<layout class="QFormLayout" name="largeShipCollisionGroupLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item row="0" column="0">
<widget class="QLabel" name="largeShipCollisionGroupLabel">
<property name="text">
<string>Large Ship Collision Group</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="largeShipCollisionGroup">
<property name="minimum">
<number>0</number>
</property>
<property name="maximum">
<number>31</number>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
Expand Down
Loading