Skip to content
13 changes: 12 additions & 1 deletion qtfred/src/mission/dialogs/ObjectOrientEditorDialogModel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
#include <globalincs/linklist.h>
#include <ship/ship.h>
#include <math/bitarray.h>
#include <jumpnode/jumpnode.h>
#include <prop/prop.h>

namespace fso::fred::dialogs {

Expand Down Expand Up @@ -44,8 +46,17 @@ void ObjectOrientEditorDialogModel::initializeData()
_pointToObjectList.emplace_back(ObjectEntry(text, OBJ_INDEX(ptr)));
break;
}
case OBJ_JUMP_NODE: {
CJumpNode* jnp = jumpnode_get_by_objnum(OBJ_INDEX(ptr));
if (jnp)
_pointToObjectList.emplace_back(ObjectEntry(jnp->GetName(), OBJ_INDEX(ptr)));
break;
}
case OBJ_PROP:
if (Props[ptr->instance].has_value())
_pointToObjectList.emplace_back(ObjectEntry(Props[ptr->instance]->prop_name, OBJ_INDEX(ptr)));
break;
case OBJ_POINT:
case OBJ_JUMP_NODE:
break;
default:
Assertion(false, "Unknown object type in Object Orient Dialog!"); // unknown object type
Expand Down
23 changes: 7 additions & 16 deletions qtfred/src/mission/dialogs/ShipEditor/ShipEditorDialogModel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,21 +31,12 @@ ShipEditorDialogModel::ShipEditorDialogModel(QObject* parent, EditorViewport* vi

int ShipEditorDialogModel::tristate_set(int val, int cur_state)
{
if (val) {
if (!cur_state) {
return Qt::PartiallyChecked;
}
} else {
if (cur_state) {
return Qt::PartiallyChecked;
}
}
if (cur_state == 1) {

return Qt::Checked;
} else {
return Qt::Unchecked;
}
if (cur_state == Qt::PartiallyChecked)
return Qt::PartiallyChecked;
bool cur_bool = (cur_state == Qt::Checked);
if (static_cast<bool>(val) != cur_bool)
return Qt::PartiallyChecked;
return cur_state;
}
int ShipEditorDialogModel::getSingleShip() const
{
Expand Down Expand Up @@ -290,7 +281,7 @@ void ShipEditorDialogModel::initializeData()
if (base_player >= 0) {
_m_ship_class = Ships[i].ship_info_index;
_m_team = Ships[i].team;
pship = (objp->type == OBJ_START) ? 1 : 0;
pship = (objp->type == OBJ_START) ? Qt::Checked : Qt::Unchecked;
base_player = -1;
} else {
if (Ships[i].ship_info_index != _m_ship_class) {
Expand Down
89 changes: 66 additions & 23 deletions qtfred/src/mission/dialogs/ShipEditor/ShipFlagsDialogModel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,22 @@
#include <object/object.h>

namespace fso::fred::dialogs {

// Flags that are not applicable to player start ships and should be hidden/skipped for them.
// Add entries here to extend the list.
static const Ship::Ship_Flags player_start_hidden_flags[] = {
Ship::Ship_Flags::Reinforcement,
Ship::Ship_Flags::Kill_before_mission,
};
int ShipFlagsDialogModel::tristate_set(int val, int cur_state)
{
if (val) {
if (!cur_state) {
return CheckState::PartiallyChecked;
}
} else {
if (cur_state) {
return CheckState::PartiallyChecked;
}
}
if (cur_state == 1) {

return CheckState::Checked;
} else {
return CheckState::Unchecked;
}
// cur_state uses Qt::CheckState encoding (0=Unchecked, 1=PartiallyChecked, 2=Checked)
if (cur_state == Qt::PartiallyChecked)
return Qt::PartiallyChecked;
bool cur_bool = (cur_state == Qt::Checked);
if (static_cast<bool>(val) != cur_bool)
return Qt::PartiallyChecked;
return cur_state;
}
std::pair<SCP_string, int>* ShipFlagsDialogModel::getFlag(const SCP_string& flag_name)
{
Expand Down Expand Up @@ -81,12 +80,26 @@ void ShipFlagsDialogModel::update_ship(const int shipnum)
ship* shipp = &Ships[shipnum];
object* objp = &Objects[shipp->objnum];
for (const auto& [name, checked] : flags) {
// PartiallyChecked means mixed selection — leave each ship's flag as-is
if (checked == Qt::PartiallyChecked)
continue;
const bool set = (checked == Qt::Checked);
for (size_t i = 0; i < Num_Parse_ship_flags; ++i) {
if (!stricmp(name.c_str(), Parse_ship_flags[i].name)) {

// Skip flags that aren't applicable to player start ships, even if they were shown and edited in multi edit mode
if (objp->type == OBJ_START) {
bool hidden = false;
for (const auto& hf : player_start_hidden_flags) {
if (Parse_ship_flags[i].def == hf) { hidden = true; break; }
}
if (hidden) continue;
}

if (Parse_ship_flags[i].def == Ship::Ship_Flags::Reinforcement) {
_editor->set_reinforcement(shipp->ship_name, checked);
_editor->set_reinforcement(shipp->ship_name, set);
} else {
if (checked) {
if (set) {
shipp->flags.set(Parse_ship_flags[i].def);
} else {
shipp->flags.remove(Parse_ship_flags[i].def);
Expand All @@ -97,7 +110,7 @@ void ShipFlagsDialogModel::update_ship(const int shipnum)
}
for (size_t i = 0; i < Num_Parse_ship_ai_flags; ++i) {
if (!stricmp(name.c_str(), Parse_ship_ai_flags[i].name)) {
if (checked) {
if (set) {
Ai_info[shipp->ai_index].ai_flags.set(Parse_ship_ai_flags[i].def);
} else {
Ai_info[shipp->ai_index].ai_flags.remove(Parse_ship_ai_flags[i].def);
Expand All @@ -108,13 +121,13 @@ void ShipFlagsDialogModel::update_ship(const int shipnum)
for (size_t i = 0; i < Num_Parse_ship_object_flags; ++i) {
if (!stricmp(name.c_str(), Parse_ship_object_flags[i].name)) {
if (Parse_ship_object_flags[i].def == Object::Object_Flags::Collides) {
if (checked) {
if (set) {
objp->flags.remove(Parse_ship_object_flags[i].def);
} else {
objp->flags.set(Parse_ship_object_flags[i].def);
}
} else {
if (checked) {
if (set) {
objp->flags.set(Parse_ship_object_flags[i].def);
} else {
objp->flags.remove(Parse_ship_object_flags[i].def);
Expand Down Expand Up @@ -220,6 +233,21 @@ void ShipFlagsDialogModel::initializeData()

first = 1;

bool all_player_ships = false;
bool any_marked = false;
for (objp = GET_FIRST(&obj_used_list); objp != END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp)) {
if (((objp->type == OBJ_START) || (objp->type == OBJ_SHIP)) && objp->flags[Object::Object_Flags::Marked]) {
if (!any_marked) {
all_player_ships = true;
any_marked = true;
}
if (objp->type != OBJ_START) {
all_player_ships = false;
break;
}
}
}

objp = GET_FIRST(&obj_used_list);
while (objp != END_OF_LIST(&obj_used_list)) {
if ((objp->type == OBJ_START) || (objp->type == OBJ_SHIP)) {
Expand All @@ -246,13 +274,20 @@ void ShipFlagsDialogModel::initializeData()
flagDef.def == Ship::Ship_Flags::Force_shields_on) {
continue;
}
if (all_player_ships) {
bool hidden = false;
for (const auto& hf : player_start_hidden_flags) {
if (flagDef.def == hf) { hidden = true; break; }
}
if (hidden) continue;
}
bool checked = shipp->flags[flagDef.def];
flags.emplace_back(flagDef.name, checked);
flags.emplace_back(flagDef.name, checked ? Qt::Checked : Qt::Unchecked);
}
for (size_t i = 0; i < Num_Parse_ship_ai_flags; i++) {
auto flagDef = Parse_ship_ai_flags[i];
bool checked = Ai_info[shipp->ai_index].ai_flags[flagDef.def];
flags.emplace_back(flagDef.name, checked);
flags.emplace_back(flagDef.name, checked ? Qt::Checked : Qt::Unchecked);
}
for (size_t i = 0; i < Num_Parse_ship_object_flags; i++) {
auto flagDef = Parse_ship_object_flags[i];
Expand All @@ -262,8 +297,9 @@ void ShipFlagsDialogModel::initializeData()
} else {
checked = objp->flags[flagDef.def];
}
flags.emplace_back(flagDef.name, checked);
flags.emplace_back(flagDef.name, checked ? Qt::Checked : Qt::Unchecked);
}
first = 0;
} else {
for (size_t i = 0; i < Num_Parse_ship_flags; i++) {
auto flagDef = Parse_ship_flags[i];
Expand All @@ -281,6 +317,13 @@ void ShipFlagsDialogModel::initializeData()
flagDef.def == Ship::Ship_Flags::Force_shields_on) {
continue;
}
if (all_player_ships) {
bool hidden = false;
for (const auto& hf : player_start_hidden_flags) {
if (flagDef.def == hf) { hidden = true; break; }
}
if (hidden) continue;
}
bool checked = shipp->flags[flagDef.def];
getFlag(flagDef.name)->second = tristate_set(checked, getFlag(flagDef.name)->second);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,8 @@ void ShipInitialStatusDialogModel::initializeData(bool multi)
Assert(m_ship >= 0);
}

m_move_ships_when_undocking = _viewport->Move_ships_when_undocking;

// initialize dockpoint stuff
if (!m_multi_edit) {
num_dock_points = model_get_num_dock_points(Ship_info[Ships[m_ship].ship_info_index].model_num);
Expand All @@ -142,48 +144,48 @@ void ShipInitialStatusDialogModel::initializeData(bool multi)
m_hull = static_cast<int>(Objects[_editor->currentObject].hull_strength);
guardian_threshold = Ships[m_ship].ship_guardian_threshold;
if (Objects[_editor->currentObject].flags[Object::Object_Flags::No_shields])
m_has_shields = 0;
m_has_shields = Qt::Unchecked;
else
m_has_shields = 1;
m_has_shields = Qt::Checked;

if (Ships[m_ship].flags[Ship::Ship_Flags::Force_shields_on])
m_force_shields = 1;
m_force_shields = Qt::Checked;
else
m_force_shields = 0;
m_force_shields = Qt::Unchecked;

if (Ships[m_ship].flags[Ship::Ship_Flags::Ship_locked])
m_ship_locked = 1;
m_ship_locked = Qt::Checked;
else
m_ship_locked = 0;
m_ship_locked = Qt::Unchecked;

if (Ships[m_ship].flags[Ship::Ship_Flags::Weapons_locked])
m_weapons_locked = 1;
m_weapons_locked = Qt::Checked;
else
m_weapons_locked = 0;
m_weapons_locked = Qt::Unchecked;
// Lock primaries
if (Ships[m_ship].flags[Ship::Ship_Flags::Primaries_locked]) {
m_primaries_locked = 1;
m_primaries_locked = Qt::Checked;
} else {
m_primaries_locked = 0;
m_primaries_locked = Qt::Unchecked;
}
// Lock secondaries
if (Ships[m_ship].flags[Ship::Ship_Flags::Secondaries_locked]) {
m_secondaries_locked = 1;
m_secondaries_locked = Qt::Checked;
} else {
m_secondaries_locked = 0;
m_secondaries_locked = Qt::Unchecked;
}

// Lock turrets
if (Ships[m_ship].flags[Ship::Ship_Flags::Lock_all_turrets_initially]) {
m_turrets_locked = 1;
m_turrets_locked = Qt::Checked;
} else {
m_turrets_locked = 0;
m_turrets_locked = Qt::Unchecked;
}

if (Ships[m_ship].flags[Ship::Ship_Flags::Afterburner_locked]) {
m_afterburner_locked = 1;
m_afterburner_locked = Qt::Checked;
} else {
m_afterburner_locked = 0;
m_afterburner_locked = Qt::Unchecked;
}

if (m_multi_edit) {
Expand All @@ -199,11 +201,11 @@ void ShipInitialStatusDialogModel::initializeData(bool multi)
hflag = 1;
if (objp->flags[Object::Object_Flags::No_shields]) {
if (m_has_shields)
m_has_shields = 1;
m_has_shields = Qt::PartiallyChecked;

} else {
if (!m_has_shields)
m_has_shields = 1;
m_has_shields = Qt::PartiallyChecked;
}

Assert((objp->type == OBJ_SHIP) || (objp->type == OBJ_START));
Expand Down Expand Up @@ -337,7 +339,7 @@ void ShipInitialStatusDialogModel::undock(object* objp1, object* objp2)
ship_num = get_ship_from_obj(OBJ_INDEX(objp1));
other_ship_num = get_ship_from_obj(OBJ_INDEX(objp2));

if (_viewport->Move_ships_when_undocking) {
if (m_move_ships_when_undocking) {
if (ship_class_compare(Ships[ship_num].ship_info_index, Ships[other_ship_num].ship_info_index) <= 0) {
vm_vec_scale_add2(&objp2->pos,
&v,
Expand Down Expand Up @@ -592,9 +594,9 @@ bool ShipInitialStatusDialogModel::apply()

modify(objp->hull_strength, (float)m_hull);

if (m_has_shields == 1) {
if (m_has_shields == Qt::Checked) {
objp->flags.remove(Object::Object_Flags::No_shields);
} else if (m_has_shields == 0) {
} else if (m_has_shields == Qt::Unchecked) {
objp->flags.set(Object::Object_Flags::No_shields);
}
auto shipp = &Ships[get_ship_from_obj(objp)];
Expand Down Expand Up @@ -637,6 +639,15 @@ bool ShipInitialStatusDialogModel::apply()

void ShipInitialStatusDialogModel::reject() {}

bool ShipInitialStatusDialogModel::getMoveShipsWhenUndocking() const
{
return m_move_ships_when_undocking;
}
void ShipInitialStatusDialogModel::setMoveShipsWhenUndocking(bool value)
{
modify(m_move_ships_when_undocking, value);
}

void ShipInitialStatusDialogModel::setVelocity(const int value)
{
modify(m_velocity, value);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ class ShipInitialStatusDialogModel : public AbstractDialogModel {
dock_evaluate_tree(object* objp, dock_function_info* infop, void (*function)(object*), ubyte* visited_bitstring);
bool m_multi_edit;
bool m_use_teams = false;
bool m_move_ships_when_undocking = true;

public:
ShipInitialStatusDialogModel(QObject* parent, EditorViewport* viewport, bool multi);
Expand Down Expand Up @@ -132,6 +133,9 @@ class ShipInitialStatusDialogModel : public AbstractDialogModel {

int getGuardian() const;
void setGuardian(int);

bool getMoveShipsWhenUndocking() const;
void setMoveShipsWhenUndocking(bool);
};

/**
Expand Down
Loading
Loading