diff --git a/qtfred/src/mission/dialogs/ShipEditor/ShipEditorDialogModel.cpp b/qtfred/src/mission/dialogs/ShipEditor/ShipEditorDialogModel.cpp index e276d9542a6..de71a59ee77 100644 --- a/qtfred/src/mission/dialogs/ShipEditor/ShipEditorDialogModel.cpp +++ b/qtfred/src/mission/dialogs/ShipEditor/ShipEditorDialogModel.cpp @@ -21,9 +21,7 @@ #include -namespace fso { -namespace fred { -namespace dialogs { +namespace fso::fred::dialogs { ShipEditorDialogModel::ShipEditorDialogModel(QObject* parent, EditorViewport* viewport) : AbstractDialogModel(parent, viewport) { @@ -124,17 +122,68 @@ std::vector> ShipEditorDialogModel::getAcceptedOrder void ShipEditorDialogModel::setAcceptedOrders(const std::vector>& newOrders) { orders = newOrders; + // Write directly to all marked ships + for (auto* ptr = GET_FIRST(&obj_used_list); ptr != END_OF_LIST(&obj_used_list); ptr = GET_NEXT(ptr)) { + if (((ptr->type == OBJ_SHIP) || (ptr->type == OBJ_START)) && (ptr->flags[Object::Object_Flags::Marked])) { + auto i = ptr->instance; + SCP_set default_orders = ship_get_default_orders_accepted(&Ship_info[Ships[i].ship_info_index]); + SCP_set new_orders_set; + for (size_t order_id : default_orders) { + for (const auto& order : orders) { + if (order.first == Player_orders[order_id].localized_name) { + if (order.second) { + new_orders_set.insert(order_id); + } + } + } + } + Ships[i].orders_accepted = new_orders_set; + } + } set_modified(); + _editor->missionChanged(); } -void ShipEditorDialogModel::setArrivalPaths(const std::vector>& newOrders) + +void ShipEditorDialogModel::setArrivalPaths(const std::vector>& newPaths) { - arrivalPaths = newOrders; - set_modified(); + arrivalPaths = newPaths; + if (!newPaths.empty() && !multi_edit && single_ship >= 0) { + int num_allowed = 0; + int m_path_mask = 0; + for (int i = 0; i < static_cast(newPaths.size()); i++) { + if (newPaths[i].second) { + m_path_mask |= (1 << i); + num_allowed++; + } + } + if (num_allowed == static_cast(newPaths.size())) { + m_path_mask = 0; + } + Ships[single_ship].arrival_path_mask = m_path_mask; + set_modified(); + _editor->missionChanged(); + } } -void ShipEditorDialogModel::setDeparturePaths(const std::vector>& newOrders) + +void ShipEditorDialogModel::setDeparturePaths(const std::vector>& newPaths) { - departurePaths = newOrders; - set_modified(); + departurePaths = newPaths; + if (!newPaths.empty() && !multi_edit && single_ship >= 0) { + int num_allowed = 0; + int m_path_mask = 0; + for (int i = 0; i < static_cast(newPaths.size()); i++) { + if (newPaths[i].second) { + m_path_mask |= (1 << i); + num_allowed++; + } + } + if (num_allowed == static_cast(newPaths.size())) { + m_path_mask = 0; + } + Ships[single_ship].departure_path_mask = m_path_mask; + set_modified(); + _editor->missionChanged(); + } } void ShipEditorDialogModel::initializeData() { @@ -154,6 +203,8 @@ void ShipEditorDialogModel::initializeData() ship_orders.clear(); arrivalPaths.clear(); departurePaths.clear(); + _m_alt_name = ""; + _m_callsign = ""; object* objp; if (The_mission.game_type & MISSION_TYPE_MULTI) { mission_type = 0; // multi player mission @@ -429,6 +480,8 @@ void ShipEditorDialogModel::initializeData() _m_ship_class = Ships[player_ship].ship_info_index; _m_team = Ships[player_ship].team; _m_player_ship = true; + _m_alt_name = Fred_alt_names[player_ship]; + _m_callsign = Fred_callsigns[player_ship]; } else { // no ships or players selected.. _m_ship_name = ""; @@ -464,11 +517,13 @@ void ShipEditorDialogModel::initializeData() std::vector> ShipEditorDialogModel::getArrivalPaths() const { std::vector> m_path_list; + if (_m_arrival_target < 0 || _m_arrival_target >= MAX_SHIPS) + return m_path_list; int target_class = Ships[_m_arrival_target].ship_info_index; auto m_model = model_get(Ship_info[target_class].model_num); - Assert(m_model->ship_bay); + if (!m_model || !m_model->ship_bay || m_model->ship_bay->num_paths <= 0) + return m_path_list; auto m_num_paths = m_model->ship_bay->num_paths; - Assert(m_num_paths > 0); auto m_path_mask = Ships[single_ship].arrival_path_mask; for (int i = 0; i < m_num_paths; i++) { @@ -487,11 +542,13 @@ std::vector> ShipEditorDialogModel::getArrivalPaths( std::vector> ShipEditorDialogModel::getDeparturePaths() const { std::vector> m_path_list; - int target_class = Ships[_m_arrival_target].ship_info_index; + if (_m_departure_target < 0 || _m_departure_target >= MAX_SHIPS) + return m_path_list; + int target_class = Ships[_m_departure_target].ship_info_index; auto m_model = model_get(Ship_info[target_class].model_num); - Assert(m_model->ship_bay); + if (!m_model || !m_model->ship_bay || m_model->ship_bay->num_paths <= 0) + return m_path_list; auto m_num_paths = m_model->ship_bay->num_paths; - Assert(m_num_paths > 0); auto m_path_mask = Ships[single_ship].departure_path_mask; for (int i = 0; i < m_num_paths; i++) { @@ -507,440 +564,12 @@ std::vector> ShipEditorDialogModel::getDeparturePath } return m_path_list; } -bool ShipEditorDialogModel::update_data() -{ - char *str, old_name[255]; - object* ptr; - size_t i; - int z, wing; - if (multi_edit) { - ptr = GET_FIRST(&obj_used_list); - while (ptr != END_OF_LIST(&obj_used_list)) { - if (((ptr->type == OBJ_START) || (ptr->type == OBJ_SHIP)) && (ptr->flags[Object::Object_Flags::Marked])) - update_ship(get_ship_from_obj(ptr)); - - ptr = GET_NEXT(ptr); - } - } else if (player_ship >= 0) { // editing a single player - update_ship(player_ship); - } else if (single_ship >= 0) { // editing a single ship - drop_white_space(_m_ship_name); - if (_m_ship_name.empty()) { - auto button = _viewport->dialogProvider->showButtonDialog(DialogType::Error, - "Ship Name Error", - "A ship name cannot be empty.\n Press OK to restore old name", - {DialogButton::Ok, DialogButton::Cancel}); - if (button == DialogButton::Cancel) { - return false; - } else { - _m_ship_name = Ships[single_ship].ship_name; - modelChanged(); - } - } - - ptr = GET_FIRST(&obj_used_list); - while (ptr != END_OF_LIST(&obj_used_list)) { - if (((ptr->type == OBJ_SHIP) || (ptr->type == OBJ_START)) && (single_ship != ptr->instance)) { - str = Ships[ptr->instance].ship_name; - if (!stricmp(_m_ship_name.c_str(), str)) { - auto button = _viewport->dialogProvider->showButtonDialog(DialogType::Error, - "Ship Name Error", - "This ship name is already being used by another ship.\n Press OK to restore old name", - {DialogButton::Ok, DialogButton::Cancel}); - if (button == DialogButton::Cancel) { - return false; - } else { - _m_ship_name = Ships[single_ship].ship_name; - modelChanged(); - } - } - } - - ptr = GET_NEXT(ptr); - } - - for (i = 0; i < MAX_WINGS; i++) { - if (Wings[i].wave_count && !stricmp(Wings[i].name, _m_ship_name.c_str())) { - auto button = _viewport->dialogProvider->showButtonDialog(DialogType::Error, - "Ship Name Error", - "This ship name is already being used by a wing.\n Press OK to restore old name", - {DialogButton::Ok, DialogButton::Cancel}); - if (button == DialogButton::Cancel) { - return false; - } else { - _m_ship_name = Ships[single_ship].ship_name; - modelChanged(); - } - } - } - - // We don't need to check teams. "Unknown" is a valid name and also an IFF. - - for (i = 0; i < Ai_tp_list.size(); i++) { - if (!stricmp(_m_ship_name.c_str(), Ai_tp_list[i].name)) { - - auto button = _viewport->dialogProvider->showButtonDialog(DialogType::Error, - "Ship Name Error", - "This ship name is already being used by a target priority group.\n Press OK to restore old " - "name", - {DialogButton::Ok, DialogButton::Cancel}); - if (button == DialogButton::Cancel) { - return false; - } else { - _m_ship_name = Ships[single_ship].ship_name; - modelChanged(); - } - } - } - - if (find_matching_waypoint_list(_m_ship_name.c_str()) != nullptr) { - - auto button = _viewport->dialogProvider->showButtonDialog(DialogType::Error, - "Ship Name Error", - "This ship name is already being used by a a waypoint path.\n Press OK to restore old " - "name", - {DialogButton::Ok, DialogButton::Cancel}); - if (button == DialogButton::Cancel) { - return false; - } else { - _m_ship_name = Ships[single_ship].ship_name; - modelChanged(); - } - } - - if (jumpnode_get_by_name(_m_ship_name.c_str()) != nullptr) { - - auto button = _viewport->dialogProvider->showButtonDialog(DialogType::Error, - "Ship Name Error", - "This ship name is already being used by a a jump node.\n Press OK to restore old " - "name", - {DialogButton::Ok, DialogButton::Cancel}); - if (button == DialogButton::Cancel) { - return false; - } else { - _m_ship_name = Ships[single_ship].ship_name; - modelChanged(); - } - } - - if (_m_ship_name[0] == '<') { - - auto button = _viewport->dialogProvider->showButtonDialog(DialogType::Error, - "Ship Name Error", - "Ship names not allowed to begin with <.\n Press OK to restore old " - "name", - {DialogButton::Ok, DialogButton::Cancel}); - if (button == DialogButton::Cancel) { - return false; - } else { - _m_ship_name = Ships[single_ship].ship_name; - modelChanged(); - } - } - - wing = Ships[single_ship].wingnum; - if (wing >= 0) { - Assert((wing < MAX_WINGS) && Wings[wing].wave_count); // NOLINT - int j; - for (j = 0; j < Wings[wing].wave_count; j++) - if (_editor->wing_objects[wing][j] == Ships[single_ship].objnum) - break; - - Assert(j < Wings[wing].wave_count); - wing_bash_ship_name(old_name, Wings[wing].name, static_cast(j + 1)); - if (strcmp(old_name, _m_ship_name.c_str())) { - - auto button = _viewport->dialogProvider->showButtonDialog(DialogType::Error, - "Ship Name Error", - "This ship is part of a wing, and its name cannot be changed", - {DialogButton::Ok, DialogButton::Cancel}); - if (button == DialogButton::Cancel) { - return false; - } else { - _m_ship_name = old_name; - modelChanged(); - } - } - } - - z = update_ship(single_ship); - if (z) - return z; - - strcpy_s(old_name, Ships[single_ship].ship_name); - strcpy_s(Ships[single_ship].ship_name, _m_ship_name.c_str()); - str = Ships[single_ship].ship_name; - if (strcmp(old_name, str)) { - update_sexp_references(old_name, str); - _editor->ai_update_goal_references(sexp_ref_type::SHIP, old_name, str); - _editor->update_texture_replacements(old_name, str); - int j; - for (j = 0; j < Num_reinforcements; j++) { - if (!strcmp(old_name, Reinforcements[j].name)) { - Assert(strlen(str) < NAME_LENGTH); - strcpy_s(Reinforcements[j].name, str); - } - } - - _editor->missionChanged(); - } - } - - if (Player_start_shipnum < 0 || - Objects[Ships[Player_start_shipnum].objnum].type != OBJ_START) { // need a new single player start. - ptr = GET_FIRST(&obj_used_list); - while (ptr != END_OF_LIST(&obj_used_list)) { - if (ptr->type == OBJ_START) { - Player_start_shipnum = ptr->instance; - break; - } - - ptr = GET_NEXT(ptr); - } - } - _editor->missionChanged(); - return true; -} - bool ShipEditorDialogModel::apply() { - if (_modified) { - update_data(); - _editor->missionChanged(); - _modified = false; - } return true; } void ShipEditorDialogModel::reject() {} - -bool ShipEditorDialogModel::update_ship(int ship) -{ - int z, d; - SCP_string str; - - lcl_fred_replace_stuff(_m_ship_display_name); - - // the display name was precalculated, so now just assign it - if (_m_ship_display_name == _m_ship_name || stricmp(_m_ship_display_name.c_str(), "") == 0) { - if (Ships[ship].has_display_name()) - set_modified(); - Ships[ship].display_name = ""; - Ships[ship].flags.remove(Ship::Ship_Flags::Has_display_name); - } else { - if (!Ships[ship].has_display_name()) - set_modified(); - Ships[ship].display_name = _m_ship_display_name; - Ships[ship].flags.set(Ship::Ship_Flags::Has_display_name); - } - - ship_alt_name_close(ship); - ship_callsign_close(ship); - Ships[ship].respawn_priority = 0; - if (The_mission.game_type & MISSION_TYPE_MULTI) { - Ships[ship].respawn_priority = respawn_priority; - } - if ((Ships[ship].ship_info_index != _m_ship_class) && (_m_ship_class != -1)) { - change_ship_type(ship, _m_ship_class); - } - if (_m_team != -1) - Ships[ship].team = _m_team; - - if (Objects[Ships[ship].objnum].type != OBJ_SHIP) { - if (mission_type || (Objects[Ships[ship].objnum].type != OBJ_START)) { - return false; - } - } - - if (_m_ai_class != -1) { - Ships[ship].weapons.ai_class = _m_ai_class; - } - if (!_m_cargo1.empty()) { - lcl_fred_replace_stuff(_m_cargo1); - z = string_lookup(_m_cargo1.c_str(), Cargo_names, Num_cargo); - if (z == -1) { - if (Num_cargo < MAX_CARGO) { - z = Num_cargo++; - strcpy(Cargo_names[z], _m_cargo1.c_str()); - } else { - sprintf(str, "Maximum number of cargo names %d reached.\nIgnoring new name.\n", MAX_CARGO); - _viewport->dialogProvider->showButtonDialog(DialogType::Warning, - "Cargo Error", - str, - {DialogButton::Ok}); - z = 0; - _m_cargo1 = Cargo_names[z]; - } - } - Ships[ship].cargo1 = (char)z; - } - - Ships[ship].score = _m_score; - if (_m_assist_score == -1) { - Ships[ship].assist_score_pct = ((float)_m_assist_score) / 100; - if (Ships[ship].assist_score_pct < 0) { - Ships[ship].assist_score_pct = 0; - _viewport->dialogProvider->showButtonDialog(DialogType::Warning, - "Ship Error", - "Assist Percentage too low. Set to 0. No score will be granted for an assist", - {DialogButton::Ok}); - } else if (Ships[ship].assist_score_pct > 1) { - Ships[ship].assist_score_pct = 1; - _viewport->dialogProvider->showButtonDialog(DialogType::Warning, - "Ship Error", - "Assist Percentage too high. Set to 1. Assists will score as many points as a kill", - {DialogButton::Ok}); - } - } - - Ships[ship].persona_index = _m_persona; - - if (Ships[ship].wingnum < 0) { - - if (_m_arrival_location != -1) - Ships[ship].arrival_location = static_cast(_m_arrival_location); - if (_m_departure_location != -1) - Ships[ship].departure_location = static_cast(_m_departure_location); - - if (!multi_edit || _m_update_arrival) { // should we update the arrival cue? - if (Ships[ship].arrival_cue >= 0) - free_sexp2(Ships[ship].arrival_cue); - - Ships[ship].arrival_cue = _m_arrival_tree_formula; - } - - if (!multi_edit || _m_update_departure) { - if (Ships[ship].departure_cue >= 0) - free_sexp2(Ships[ship].departure_cue); - - Ships[ship].departure_cue = _m_departure_tree_formula; - } - Ships[ship].arrival_distance = _m_arrival_dist; - Ships[ship].arrival_delay = _m_arrival_delay; - Ships[ship].departure_delay = _m_departure_delay; - if (_m_arrival_target >= 0) { - Ships[ship].arrival_anchor = target_to_anchor(_m_arrival_target); - - // if the arrival is not hyperspace or docking bay -- force arrival distance to be - // greater than 2*radius of target. - if (((_m_arrival_location != static_cast(ArrivalLocation::FROM_DOCK_BAY)) && - (_m_arrival_location != static_cast(ArrivalLocation::AT_LOCATION))) && - (_m_arrival_target >= 0) && !(_m_arrival_target & ANCHOR_SPECIAL_ARRIVAL)) { - d = int(std::min(500.0f, 2.0f * Objects[Ships[ship].objnum].radius)); - if ((Ships[ship].arrival_distance < d) && (Ships[ship].arrival_distance > -d)) { - sprintf(str, - "Ship must arrive at least %d meters away from target.\n" - "Value has been reset to this. Use with caution!\r\n" - "Recommended distance is %d meters.\r\n", - d, - static_cast(2.0f * Objects[Ships[ship].objnum].radius)); - - _viewport->dialogProvider->showButtonDialog(DialogType::Error, "Error", str, {DialogButton::Ok}); - if (Ships[ship].arrival_distance < 0) - Ships[ship].arrival_distance = -d; - else - Ships[ship].arrival_distance = d; - - _m_arrival_dist = Ships[ship].arrival_distance; - modelChanged(); - } - } - } - if (_m_departure_target >= 0) { - - Ships[ship].departure_anchor = target_to_anchor(_m_departure_target); - } - } - - if (_m_hotkey != -1) - Ships[ship].hotkey = _m_hotkey - 1; - - if (!_m_no_arrival_warp) { - - if (Ships[ship].flags[Ship::Ship_Flags::No_arrival_warp]) - - Ships[ship].flags.remove(Ship::Ship_Flags::No_arrival_warp); - } - - else { - if (!(Ships[ship].flags[Ship::Ship_Flags::No_arrival_warp])) - - Ships[ship].flags.set(Ship::Ship_Flags::No_arrival_warp); - } - - if (!_m_no_departure_warp) { - - if (Ships[ship].flags[Ship::Ship_Flags::No_departure_warp]) - - Ships[ship].flags.remove(Ship::Ship_Flags::No_departure_warp); - } - - else { - if (!(Ships[ship].flags[Ship::Ship_Flags::No_departure_warp])) - - Ships[ship].flags.set(Ship::Ship_Flags::No_departure_warp); - } - - if (_m_player_ship) { - if (Objects[Ships[ship].objnum].type != OBJ_START) { - Player_starts++; - } - - Objects[Ships[ship].objnum].type = OBJ_START; - } else { - if (Objects[Ships[ship].objnum].type == OBJ_START) { - Player_starts--; - } - - Objects[Ships[ship].objnum].type = OBJ_SHIP; - } - if (!orders.empty()) { - SCP_set default_orders; - SCP_set new_orders; - default_orders = ship_get_default_orders_accepted(&Ship_info[Ships[ship].ship_info_index]); - for (size_t order_id : default_orders) { - for (auto& order : orders) { - if (order.first == Player_orders[order_id].localized_name) { - if (order.second) { - new_orders.insert(order_id); - } - continue; - } - } - } - Ships[ship].orders_accepted = new_orders; - } - if (!arrivalPaths.empty()) { - int num_allowed = 0; - auto m_path_mask = 0; - for (auto i = 0; i < static_cast(arrivalPaths.size()); i++) { - if (arrivalPaths[i].second) { - m_path_mask |= (1 << i); - num_allowed++; - } - } - if (num_allowed == static_cast(arrivalPaths.size())) { - m_path_mask = 0; - } - Ships[ship].arrival_path_mask = m_path_mask; - } - if (!departurePaths.empty()) { - int num_allowed = 0; - auto m_path_mask = 0; - for (auto i = 0; i < static_cast(departurePaths.size()); i++) { - if (departurePaths[i].second) { - m_path_mask |= (1 << i); - num_allowed++; - } - } - if (num_allowed == static_cast(departurePaths.size())) { - m_path_mask = 0; - } - Ships[ship].departure_path_mask = m_path_mask; - } - _editor->missionChanged(); - return false; -} void ShipEditorDialogModel::ship_alt_name_close(int ship) { @@ -992,7 +621,7 @@ void ShipEditorDialogModel::ship_callsign_close(int ship) return; } drop_white_space(_m_callsign); - if (_m_alt_name.empty()) { + if (_m_callsign.empty()) { return; } @@ -1031,7 +660,142 @@ void ShipEditorDialogModel::ship_callsign_close(int ship) void ShipEditorDialogModel::setShipName(const SCP_string& m_ship_name) { - modify(_m_ship_name, m_ship_name); + if (_m_ship_name == m_ship_name) + return; + + // Name changes only apply to single-ship editing + if (multi_edit || single_ship < 0) + return; + + SCP_string new_name = m_ship_name; + drop_white_space(new_name); + + if (new_name.empty()) { + _viewport->dialogProvider->showButtonDialog(DialogType::Error, + "Ship Name Error", + "A ship name cannot be empty.", + {DialogButton::Ok}); + _m_ship_name = Ships[single_ship].ship_name; + modelChanged(); + return; + } + + if (new_name[0] == '<') { + _viewport->dialogProvider->showButtonDialog(DialogType::Error, + "Ship Name Error", + "Ship names not allowed to begin with <.", + {DialogButton::Ok}); + _m_ship_name = Ships[single_ship].ship_name; + modelChanged(); + return; + } + + // Check for duplicate ship names + for (auto* ptr = GET_FIRST(&obj_used_list); ptr != END_OF_LIST(&obj_used_list); ptr = GET_NEXT(ptr)) { + if (((ptr->type == OBJ_SHIP) || (ptr->type == OBJ_START)) && (ptr->instance != single_ship)) { + if (!stricmp(new_name.c_str(), Ships[ptr->instance].ship_name)) { + _viewport->dialogProvider->showButtonDialog(DialogType::Error, + "Ship Name Error", + "This ship name is already being used by another ship.", + {DialogButton::Ok}); + _m_ship_name = Ships[single_ship].ship_name; + modelChanged(); + return; + } + } + } + + // Check for conflict with wing names + for (auto& w : Wings) { + if (w.wave_count && !stricmp(w.name, new_name.c_str())) { + _viewport->dialogProvider->showButtonDialog(DialogType::Error, + "Ship Name Error", + "This ship name is already being used by a wing.", + {DialogButton::Ok}); + _m_ship_name = Ships[single_ship].ship_name; + modelChanged(); + return; + } + } + + // Check for conflict with AI target priority group names + for (auto& tp : Ai_tp_list) { + if (!stricmp(new_name.c_str(), tp.name)) { + _viewport->dialogProvider->showButtonDialog(DialogType::Error, + "Ship Name Error", + "This ship name is already being used by a target priority group.", + {DialogButton::Ok}); + _m_ship_name = Ships[single_ship].ship_name; + modelChanged(); + return; + } + } + + // Check for conflict with waypoint paths + if (find_matching_waypoint_list(new_name.c_str()) != nullptr) { + _viewport->dialogProvider->showButtonDialog(DialogType::Error, + "Ship Name Error", + "This ship name is already being used by a waypoint path.", + {DialogButton::Ok}); + _m_ship_name = Ships[single_ship].ship_name; + modelChanged(); + return; + } + + // Check for conflict with jump nodes + if (jumpnode_get_by_name(new_name.c_str()) != nullptr) { + _viewport->dialogProvider->showButtonDialog(DialogType::Error, + "Ship Name Error", + "This ship name is already being used by a jump node.", + {DialogButton::Ok}); + _m_ship_name = Ships[single_ship].ship_name; + modelChanged(); + return; + } + + // Wing member ships cannot be renamed independently + int wing = Ships[single_ship].wingnum; + if (wing >= 0) { + Assert((wing < MAX_WINGS) && Wings[wing].wave_count); // NOLINT + char expected_name[255]; + int j; + for (j = 0; j < Wings[wing].wave_count; j++) + if (_editor->wing_objects[wing][j] == Ships[single_ship].objnum) + break; + Assert(j < Wings[wing].wave_count); + wing_bash_ship_name(expected_name, Wings[wing].name, static_cast(j + 1)); + if (strcmp(expected_name, new_name.c_str())) { + _viewport->dialogProvider->showButtonDialog(DialogType::Error, + "Ship Name Error", + "This ship is part of a wing, and its name cannot be changed", + {DialogButton::Ok}); + _m_ship_name = Ships[single_ship].ship_name; + modelChanged(); + return; + } + } + + // All validation passed — write the new name + char old_name[NAME_LENGTH]; + strcpy_s(old_name, Ships[single_ship].ship_name); + strcpy_s(Ships[single_ship].ship_name, new_name.c_str()); + _m_ship_name = new_name; + + if (strcmp(old_name, Ships[single_ship].ship_name)) { + update_sexp_references(old_name, Ships[single_ship].ship_name); + _editor->ai_update_goal_references(sexp_ref_type::SHIP, old_name, Ships[single_ship].ship_name); + _editor->update_texture_replacements(old_name, Ships[single_ship].ship_name); + for (int j = 0; j < Num_reinforcements; j++) { + if (!strcmp(old_name, Reinforcements[j].name)) { + Assert(strlen(Ships[single_ship].ship_name) < NAME_LENGTH); + strcpy_s(Reinforcements[j].name, Ships[single_ship].ship_name); + } + } + } + + set_modified(); + _editor->missionChanged(); + modelChanged(); } SCP_string ShipEditorDialogModel::getShipName() const { @@ -1040,7 +804,25 @@ SCP_string ShipEditorDialogModel::getShipName() const void ShipEditorDialogModel::setShipDisplayName(const SCP_string& m_ship_display_name) { - modify(_m_ship_display_name, m_ship_display_name); + if (_m_ship_display_name == m_ship_display_name) + return; + _m_ship_display_name = m_ship_display_name; + + // Display name only applies to single-ship editing + if (!multi_edit && single_ship >= 0) { + SCP_string display = m_ship_display_name; + lcl_fred_replace_stuff(display); + if (display == _m_ship_name || stricmp(display.c_str(), "") == 0) { + Ships[single_ship].display_name = ""; + Ships[single_ship].flags.remove(Ship::Ship_Flags::Has_display_name); + } else { + Ships[single_ship].display_name = display; + Ships[single_ship].flags.set(Ship::Ship_Flags::Has_display_name); + } + set_modified(); + _editor->missionChanged(); + } + modelChanged(); } SCP_string ShipEditorDialogModel::getShipDisplayName() const { @@ -1049,19 +831,19 @@ SCP_string ShipEditorDialogModel::getShipDisplayName() const void ShipEditorDialogModel::setShipClass(int m_ship_class) { - object* ptr; - ptr = GET_FIRST(&obj_used_list); - while (ptr != END_OF_LIST(&obj_used_list)) { + if (_m_ship_class == m_ship_class) + return; + _m_ship_class = m_ship_class; + for (auto* ptr = GET_FIRST(&obj_used_list); ptr != END_OF_LIST(&obj_used_list); ptr = GET_NEXT(ptr)) { if (((ptr->type == OBJ_SHIP) || (ptr->type == OBJ_START)) && (ptr->flags[Object::Object_Flags::Marked])) { if (Ships[ptr->instance].ship_info_index != m_ship_class) { change_ship_type(ptr->instance, m_ship_class); - set_modified(); } } - ptr = GET_NEXT(ptr); } - modify(_m_ship_class, m_ship_class); + set_modified(); _editor->missionChanged(); + modelChanged(); } int ShipEditorDialogModel::getShipClass() const @@ -1071,7 +853,16 @@ int ShipEditorDialogModel::getShipClass() const void ShipEditorDialogModel::setAIClass(const int m_ai_class) { - modify(_m_ai_class, m_ai_class); + if (_m_ai_class == m_ai_class) + return; + _m_ai_class = m_ai_class; + for (auto* ptr = GET_FIRST(&obj_used_list); ptr != END_OF_LIST(&obj_used_list); ptr = GET_NEXT(ptr)) { + if (((ptr->type == OBJ_SHIP) || (ptr->type == OBJ_START)) && (ptr->flags[Object::Object_Flags::Marked])) { + Ships[ptr->instance].weapons.ai_class = m_ai_class; + } + } + set_modified(); + _editor->missionChanged(); modelChanged(); } @@ -1082,7 +873,16 @@ int ShipEditorDialogModel::getAIClass() const void ShipEditorDialogModel::setTeam(const int m_team) { - modify(_m_team, m_team); + if (_m_team == m_team) + return; + _m_team = m_team; + for (auto* ptr = GET_FIRST(&obj_used_list); ptr != END_OF_LIST(&obj_used_list); ptr = GET_NEXT(ptr)) { + if (((ptr->type == OBJ_SHIP) || (ptr->type == OBJ_START)) && (ptr->flags[Object::Object_Flags::Marked])) { + Ships[ptr->instance].team = m_team; + } + } + set_modified(); + _editor->missionChanged(); modelChanged(); } @@ -1093,7 +893,33 @@ int ShipEditorDialogModel::getTeam() const void ShipEditorDialogModel::setCargo(const SCP_string& m_cargo) { - modify(_m_cargo1, m_cargo); + if (_m_cargo1 == m_cargo) + return; + _m_cargo1 = m_cargo; + + SCP_string cargo_name = m_cargo; + lcl_fred_replace_stuff(cargo_name); + int z = string_lookup(cargo_name.c_str(), Cargo_names, Num_cargo); + if (z == -1) { + if (Num_cargo < MAX_CARGO) { + z = Num_cargo++; + strcpy(Cargo_names[z], cargo_name.c_str()); + } else { + SCP_string str; + sprintf(str, "Maximum number of cargo names %d reached.\nIgnoring new name.\n", MAX_CARGO); + _viewport->dialogProvider->showButtonDialog(DialogType::Warning, "Cargo Error", str, {DialogButton::Ok}); + z = 0; + _m_cargo1 = Cargo_names[z]; + } + } + for (auto* ptr = GET_FIRST(&obj_used_list); ptr != END_OF_LIST(&obj_used_list); ptr = GET_NEXT(ptr)) { + if (((ptr->type == OBJ_SHIP) || (ptr->type == OBJ_START)) && (ptr->flags[Object::Object_Flags::Marked])) { + Ships[ptr->instance].cargo1 = (char)z; + } + } + set_modified(); + _editor->missionChanged(); + modelChanged(); } SCP_string ShipEditorDialogModel::getCargo() const @@ -1103,7 +929,15 @@ SCP_string ShipEditorDialogModel::getCargo() const void ShipEditorDialogModel::setAltName(const SCP_string& m_altName) { - modify(_m_alt_name, m_altName); + if (_m_alt_name == m_altName) + return; + _m_alt_name = m_altName; + if (!multi_edit && single_ship >= 0) { + ship_alt_name_close(single_ship); + set_modified(); + _editor->missionChanged(); + } + modelChanged(); } SCP_string ShipEditorDialogModel::getAltName() const @@ -1113,7 +947,15 @@ SCP_string ShipEditorDialogModel::getAltName() const void ShipEditorDialogModel::setCallsign(const SCP_string& m_callsign) { - modify(_m_callsign, m_callsign); + if (_m_callsign == m_callsign) + return; + _m_callsign = m_callsign; + if (!multi_edit && single_ship >= 0) { + ship_callsign_close(single_ship); + set_modified(); + _editor->missionChanged(); + } + modelChanged(); } SCP_string ShipEditorDialogModel::getCallsign() const @@ -1128,7 +970,18 @@ SCP_string ShipEditorDialogModel::getWing() const void ShipEditorDialogModel::setHotkey(const int m_hotkey) { - modify(_m_hotkey, m_hotkey); + if (_m_hotkey == m_hotkey) + return; + _m_hotkey = m_hotkey; + // hotkey stored as 1-indexed in model (0 = none), Ships[] uses 0-indexed (-1 = none, hotkey-1 otherwise) + for (auto* ptr = GET_FIRST(&obj_used_list); ptr != END_OF_LIST(&obj_used_list); ptr = GET_NEXT(ptr)) { + if (((ptr->type == OBJ_SHIP) || (ptr->type == OBJ_START)) && (ptr->flags[Object::Object_Flags::Marked])) { + Ships[ptr->instance].hotkey = m_hotkey - 1; + } + } + set_modified(); + _editor->missionChanged(); + modelChanged(); } int ShipEditorDialogModel::getHotkey() const @@ -1138,7 +991,17 @@ int ShipEditorDialogModel::getHotkey() const void ShipEditorDialogModel::setPersona(const int m_persona) { - modify(_m_persona, m_persona); + if (_m_persona == m_persona) + return; + _m_persona = m_persona; + for (auto* ptr = GET_FIRST(&obj_used_list); ptr != END_OF_LIST(&obj_used_list); ptr = GET_NEXT(ptr)) { + if (((ptr->type == OBJ_SHIP) || (ptr->type == OBJ_START)) && (ptr->flags[Object::Object_Flags::Marked])) { + Ships[ptr->instance].persona_index = m_persona; + } + } + set_modified(); + _editor->missionChanged(); + modelChanged(); } int ShipEditorDialogModel::getPersona() const @@ -1148,7 +1011,17 @@ int ShipEditorDialogModel::getPersona() const void ShipEditorDialogModel::setScore(const int m_score) { - modify(_m_score, m_score); + if (_m_score == m_score) + return; + _m_score = m_score; + for (auto* ptr = GET_FIRST(&obj_used_list); ptr != END_OF_LIST(&obj_used_list); ptr = GET_NEXT(ptr)) { + if (((ptr->type == OBJ_SHIP) || (ptr->type == OBJ_START)) && (ptr->flags[Object::Object_Flags::Marked])) { + Ships[ptr->instance].score = m_score; + } + } + set_modified(); + _editor->missionChanged(); + modelChanged(); } int ShipEditorDialogModel::getScore() const @@ -1158,7 +1031,19 @@ int ShipEditorDialogModel::getScore() const void ShipEditorDialogModel::setAssist(const int m_assist_score) { - modify(_m_assist_score, m_assist_score); + if (_m_assist_score == m_assist_score) + return; + _m_assist_score = m_assist_score; + float pct = static_cast(m_assist_score) / 100.0f; + pct = std::clamp(pct, 0.0f, 1.0f); + for (auto* ptr = GET_FIRST(&obj_used_list); ptr != END_OF_LIST(&obj_used_list); ptr = GET_NEXT(ptr)) { + if (((ptr->type == OBJ_SHIP) || (ptr->type == OBJ_START)) && (ptr->flags[Object::Object_Flags::Marked])) { + Ships[ptr->instance].assist_score_pct = pct; + } + } + set_modified(); + _editor->missionChanged(); + modelChanged(); } int ShipEditorDialogModel::getAssist() const @@ -1168,7 +1053,36 @@ int ShipEditorDialogModel::getAssist() const void ShipEditorDialogModel::setPlayer(const bool m_player) { - modify(_m_player_ship, m_player); + if (_m_player_ship == m_player) + return; + _m_player_ship = m_player; + for (auto* ptr = GET_FIRST(&obj_used_list); ptr != END_OF_LIST(&obj_used_list); ptr = GET_NEXT(ptr)) { + if (((ptr->type == OBJ_SHIP) || (ptr->type == OBJ_START)) && (ptr->flags[Object::Object_Flags::Marked])) { + if (m_player) { + if (Objects[Ships[ptr->instance].objnum].type != OBJ_START) { + Player_starts++; + } + Objects[Ships[ptr->instance].objnum].type = OBJ_START; + } else { + if (Objects[Ships[ptr->instance].objnum].type == OBJ_START) { + Player_starts--; + } + Objects[Ships[ptr->instance].objnum].type = OBJ_SHIP; + } + } + } + // Fix up Player_start_shipnum if it became invalid + if (Player_start_shipnum < 0 || Objects[Ships[Player_start_shipnum].objnum].type != OBJ_START) { + for (auto* p = GET_FIRST(&obj_used_list); p != END_OF_LIST(&obj_used_list); p = GET_NEXT(p)) { + if (p->type == OBJ_START) { + Player_start_shipnum = p->instance; + break; + } + } + } + set_modified(); + _editor->missionChanged(); + modelChanged(); } bool ShipEditorDialogModel::getPlayer() const @@ -1178,7 +1092,19 @@ bool ShipEditorDialogModel::getPlayer() const void ShipEditorDialogModel::setRespawn(const int value) { - modify(respawn_priority, value); + if (respawn_priority == value) + return; + respawn_priority = value; + if (The_mission.game_type & MISSION_TYPE_MULTI) { + for (auto* ptr = GET_FIRST(&obj_used_list); ptr != END_OF_LIST(&obj_used_list); ptr = GET_NEXT(ptr)) { + if (((ptr->type == OBJ_SHIP) || (ptr->type == OBJ_START)) && (ptr->flags[Object::Object_Flags::Marked])) { + Ships[ptr->instance].respawn_priority = value; + } + } + } + set_modified(); + _editor->missionChanged(); + modelChanged(); } int ShipEditorDialogModel::getRespawn() const @@ -1188,7 +1114,19 @@ int ShipEditorDialogModel::getRespawn() const void ShipEditorDialogModel::setArrivalLocationIndex(const int value) { - modify(_m_arrival_location, value); + if (_m_arrival_location == value) + return; + _m_arrival_location = value; + for (auto* ptr = GET_FIRST(&obj_used_list); ptr != END_OF_LIST(&obj_used_list); ptr = GET_NEXT(ptr)) { + if (((ptr->type == OBJ_SHIP) || (ptr->type == OBJ_START)) && (ptr->flags[Object::Object_Flags::Marked])) { + if (Ships[ptr->instance].wingnum < 0) { + Ships[ptr->instance].arrival_location = static_cast(value); + } + } + } + set_modified(); + _editor->missionChanged(); + modelChanged(); } int ShipEditorDialogModel::getArrivalLocationIndex() const @@ -1198,7 +1136,7 @@ int ShipEditorDialogModel::getArrivalLocationIndex() const void ShipEditorDialogModel::setArrivalLocation(const ArrivalLocation value) { - modify(_m_arrival_location, static_cast(value)); + setArrivalLocationIndex(static_cast(value)); } ArrivalLocation ShipEditorDialogModel::getArrivalLocation() const @@ -1208,7 +1146,19 @@ ArrivalLocation ShipEditorDialogModel::getArrivalLocation() const void ShipEditorDialogModel::setArrivalTarget(const int value) { - modify(_m_arrival_target, value); + if (_m_arrival_target == value) + return; + _m_arrival_target = value; + for (auto* ptr = GET_FIRST(&obj_used_list); ptr != END_OF_LIST(&obj_used_list); ptr = GET_NEXT(ptr)) { + if (((ptr->type == OBJ_SHIP) || (ptr->type == OBJ_START)) && (ptr->flags[Object::Object_Flags::Marked])) { + if (Ships[ptr->instance].wingnum < 0 && value >= 0) { + Ships[ptr->instance].arrival_anchor = target_to_anchor(value); + } + } + } + set_modified(); + _editor->missionChanged(); + modelChanged(); } int ShipEditorDialogModel::getArrivalTarget() const @@ -1218,7 +1168,19 @@ int ShipEditorDialogModel::getArrivalTarget() const void ShipEditorDialogModel::setArrivalDistance(const int value) { - modify(_m_arrival_dist, value); + if (_m_arrival_dist == value) + return; + _m_arrival_dist = value; + for (auto* ptr = GET_FIRST(&obj_used_list); ptr != END_OF_LIST(&obj_used_list); ptr = GET_NEXT(ptr)) { + if (((ptr->type == OBJ_SHIP) || (ptr->type == OBJ_START)) && (ptr->flags[Object::Object_Flags::Marked])) { + if (Ships[ptr->instance].wingnum < 0) { + Ships[ptr->instance].arrival_distance = value; + } + } + } + set_modified(); + _editor->missionChanged(); + modelChanged(); } int ShipEditorDialogModel::getArrivalDistance() const @@ -1228,7 +1190,19 @@ int ShipEditorDialogModel::getArrivalDistance() const void ShipEditorDialogModel::setArrivalDelay(const int value) { - modify(_m_arrival_delay, value); + if (_m_arrival_delay == value) + return; + _m_arrival_delay = value; + for (auto* ptr = GET_FIRST(&obj_used_list); ptr != END_OF_LIST(&obj_used_list); ptr = GET_NEXT(ptr)) { + if (((ptr->type == OBJ_SHIP) || (ptr->type == OBJ_START)) && (ptr->flags[Object::Object_Flags::Marked])) { + if (Ships[ptr->instance].wingnum < 0) { + Ships[ptr->instance].arrival_delay = value; + } + } + } + set_modified(); + _editor->missionChanged(); + modelChanged(); } int ShipEditorDialogModel::getArrivalDelay() const @@ -1259,7 +1233,21 @@ int ShipEditorDialogModel::getArrivalFormula() const void ShipEditorDialogModel::setNoArrivalWarp(const int value) { - modify(_m_no_arrival_warp, value); + if (_m_no_arrival_warp == value) + return; + _m_no_arrival_warp = value; + for (auto* ptr = GET_FIRST(&obj_used_list); ptr != END_OF_LIST(&obj_used_list); ptr = GET_NEXT(ptr)) { + if (((ptr->type == OBJ_SHIP) || (ptr->type == OBJ_START)) && (ptr->flags[Object::Object_Flags::Marked])) { + if (value) { + Ships[ptr->instance].flags.set(Ship::Ship_Flags::No_arrival_warp); + } else { + Ships[ptr->instance].flags.remove(Ship::Ship_Flags::No_arrival_warp); + } + } + } + set_modified(); + _editor->missionChanged(); + modelChanged(); } int ShipEditorDialogModel::getNoArrivalWarp() const @@ -1269,7 +1257,19 @@ int ShipEditorDialogModel::getNoArrivalWarp() const void ShipEditorDialogModel::setDepartureLocationIndex(const int value) { - modify(_m_departure_location, value); + if (_m_departure_location == value) + return; + _m_departure_location = value; + for (auto* ptr = GET_FIRST(&obj_used_list); ptr != END_OF_LIST(&obj_used_list); ptr = GET_NEXT(ptr)) { + if (((ptr->type == OBJ_SHIP) || (ptr->type == OBJ_START)) && (ptr->flags[Object::Object_Flags::Marked])) { + if (Ships[ptr->instance].wingnum < 0) { + Ships[ptr->instance].departure_location = static_cast(value); + } + } + } + set_modified(); + _editor->missionChanged(); + modelChanged(); } int ShipEditorDialogModel::getDepartureLocationIndex() const @@ -1279,7 +1279,7 @@ int ShipEditorDialogModel::getDepartureLocationIndex() const void ShipEditorDialogModel::setDepartureLocation(const DepartureLocation value) { - modify(_m_departure_location, static_cast(value)); + setDepartureLocationIndex(static_cast(value)); } DepartureLocation ShipEditorDialogModel::getDepartureLocation() const @@ -1289,7 +1289,19 @@ DepartureLocation ShipEditorDialogModel::getDepartureLocation() const void ShipEditorDialogModel::setDepartureTarget(const int value) { - modify(_m_departure_target, value); + if (_m_departure_target == value) + return; + _m_departure_target = value; + for (auto* ptr = GET_FIRST(&obj_used_list); ptr != END_OF_LIST(&obj_used_list); ptr = GET_NEXT(ptr)) { + if (((ptr->type == OBJ_SHIP) || (ptr->type == OBJ_START)) && (ptr->flags[Object::Object_Flags::Marked])) { + if (Ships[ptr->instance].wingnum < 0 && value >= 0) { + Ships[ptr->instance].departure_anchor = target_to_anchor(value); + } + } + } + set_modified(); + _editor->missionChanged(); + modelChanged(); } int ShipEditorDialogModel::getDepartureTarget() const @@ -1299,7 +1311,19 @@ int ShipEditorDialogModel::getDepartureTarget() const void ShipEditorDialogModel::setDepartureDelay(const int value) { - modify(_m_departure_delay, value); + if (_m_departure_delay == value) + return; + _m_departure_delay = value; + for (auto* ptr = GET_FIRST(&obj_used_list); ptr != END_OF_LIST(&obj_used_list); ptr = GET_NEXT(ptr)) { + if (((ptr->type == OBJ_SHIP) || (ptr->type == OBJ_START)) && (ptr->flags[Object::Object_Flags::Marked])) { + if (Ships[ptr->instance].wingnum < 0) { + Ships[ptr->instance].departure_delay = value; + } + } + } + set_modified(); + _editor->missionChanged(); + modelChanged(); } int ShipEditorDialogModel::getDepartureDelay() const @@ -1330,7 +1354,21 @@ int ShipEditorDialogModel::getDepartureFormula() const void ShipEditorDialogModel::setNoDepartureWarp(const int value) { - modify(_m_no_departure_warp, value); + if (_m_no_departure_warp == value) + return; + _m_no_departure_warp = value; + for (auto* ptr = GET_FIRST(&obj_used_list); ptr != END_OF_LIST(&obj_used_list); ptr = GET_NEXT(ptr)) { + if (((ptr->type == OBJ_SHIP) || (ptr->type == OBJ_START)) && (ptr->flags[Object::Object_Flags::Marked])) { + if (value) { + Ships[ptr->instance].flags.set(Ship::Ship_Flags::No_departure_warp); + } else { + Ships[ptr->instance].flags.remove(Ship::Ship_Flags::No_departure_warp); + } + } + } + set_modified(); + _editor->missionChanged(); + modelChanged(); } int ShipEditorDialogModel::getNoDepartureWarp() const @@ -1341,62 +1379,52 @@ int ShipEditorDialogModel::getNoDepartureWarp() const void ShipEditorDialogModel::OnPrevious() { int i, n, arr[MAX_SHIPS]; - if (!update_data()) { - n = make_ship_list(arr); - if (!n) { - return; - } - if (_editor->cur_ship < 0) { - i = n - 1; - } - - else { - for (i = 0; i < n; i++) { - if (Ships[_editor->cur_ship].objnum == arr[i]) { - break; - } - } - - Assert(i < n); - i--; - if (i < 0) { - i = n - 1; + n = make_ship_list(arr); + if (!n) { + return; + } + if (_editor->cur_ship < 0) { + i = n - 1; + } else { + for (i = 0; i < n; i++) { + if (Ships[_editor->cur_ship].objnum == arr[i]) { + break; } } - _editor->unmark_all(); - _editor->selectObject(arr[i]); - initializeData(); + Assert(i < n); + i--; + if (i < 0) { + i = n - 1; + } } + + _editor->unmark_all(); + _editor->selectObject(arr[i]); } void ShipEditorDialogModel::OnNext() { int i, n, arr[MAX_SHIPS]; + n = make_ship_list(arr); + if (!n) + return; - if (!update_data()) { - n = make_ship_list(arr); - if (!n) - return; + if (_editor->cur_ship < 0) + i = 0; + else { + for (i = 0; i < n; i++) + if (Ships[_editor->cur_ship].objnum == arr[i]) + break; - if (_editor->cur_ship < 0) + Assert(i < n); + i++; + if (i == n) i = 0; - - else { - for (i = 0; i < n; i++) - if (Ships[_editor->cur_ship].objnum == arr[i]) - break; - - Assert(i < n); - i++; - if (i == n) - i = 0; - } - - _editor->unmark_all(); - _editor->selectObject(arr[i]); - initializeData(); } + + _editor->unmark_all(); + _editor->selectObject(arr[i]); } void ShipEditorDialogModel::OnDeleteShip() @@ -1414,10 +1442,10 @@ void ShipEditorDialogModel::OnShipReset() ship_weapon* wp; model_subsystem* sp; - _m_cargo1 = "Nothing"; - _m_ai_class = AI_DEFAULT_CLASS; - if (_m_ship_class) { - _m_team = Species_info[Ship_info[_m_ship_class].species].default_iff; + setCargo("Nothing"); + setAIClass(AI_DEFAULT_CLASS); + if (_m_ship_class >= 0) { + setTeam(Species_info[Ship_info[_m_ship_class].species].default_iff); } objp = GET_FIRST(&obj_used_list); @@ -1536,6 +1564,4 @@ void ShipEditorDialogModel::set_modified() _modified = true; } } -} // namespace dialogs -} // namespace fred -} // namespace fso \ No newline at end of file +} // namespace fso::fred::dialogs \ No newline at end of file diff --git a/qtfred/src/mission/dialogs/ShipEditor/ShipEditorDialogModel.h b/qtfred/src/mission/dialogs/ShipEditor/ShipEditorDialogModel.h index be1a4fbcbfc..5b596242758 100644 --- a/qtfred/src/mission/dialogs/ShipEditor/ShipEditorDialogModel.h +++ b/qtfred/src/mission/dialogs/ShipEditor/ShipEditorDialogModel.h @@ -44,9 +44,6 @@ class ShipEditorDialogModel : public AbstractDialogModel { void set_modified(); - bool update_ship(int ship); - bool update_data(); - void ship_alt_name_close(int base_ship); void ship_callsign_close(int base_ship); diff --git a/qtfred/src/ui/dialogs/FictionViewerDialog.cpp b/qtfred/src/ui/dialogs/FictionViewerDialog.cpp index f69944f18e1..9f7c692956f 100644 --- a/qtfred/src/ui/dialogs/FictionViewerDialog.cpp +++ b/qtfred/src/ui/dialogs/FictionViewerDialog.cpp @@ -39,7 +39,7 @@ void FictionViewerDialog::accept() if (_model->apply()) { QDialog::accept(); } - // else: validation failed, don’t close + // else: validation failed, don't close } void FictionViewerDialog::reject() diff --git a/qtfred/src/ui/dialogs/MissionSpecs/CustomDataDialog.cpp b/qtfred/src/ui/dialogs/MissionSpecs/CustomDataDialog.cpp index 54795666750..b8583424f7c 100644 --- a/qtfred/src/ui/dialogs/MissionSpecs/CustomDataDialog.cpp +++ b/qtfred/src/ui/dialogs/MissionSpecs/CustomDataDialog.cpp @@ -42,7 +42,7 @@ void CustomDataDialog::accept() if (_model->apply()) { QDialog::accept(); } - // else: validation failed, don’t close + // else: validation failed, don't close } void CustomDataDialog::reject() diff --git a/qtfred/src/ui/dialogs/MissionSpecs/CustomStringsDialog.cpp b/qtfred/src/ui/dialogs/MissionSpecs/CustomStringsDialog.cpp index 91c19f87d43..6b8c6b74fc9 100644 --- a/qtfred/src/ui/dialogs/MissionSpecs/CustomStringsDialog.cpp +++ b/qtfred/src/ui/dialogs/MissionSpecs/CustomStringsDialog.cpp @@ -42,7 +42,7 @@ void CustomStringsDialog::accept() if (_model->apply()) { QDialog::accept(); } - // else: validation failed, don’t close + // else: validation failed, don't close } void CustomStringsDialog::reject() diff --git a/qtfred/src/ui/dialogs/ReinforcementsEditorDialog.cpp b/qtfred/src/ui/dialogs/ReinforcementsEditorDialog.cpp index a9e4c3936a7..8c6bd538003 100644 --- a/qtfred/src/ui/dialogs/ReinforcementsEditorDialog.cpp +++ b/qtfred/src/ui/dialogs/ReinforcementsEditorDialog.cpp @@ -27,7 +27,7 @@ void ReinforcementsDialog::accept() if (_model->apply()) { QDialog::accept(); } - // else: validation failed, don’t close + // else: validation failed, don't close } void ReinforcementsDialog::reject() diff --git a/qtfred/src/ui/dialogs/ShieldSystemDialog.cpp b/qtfred/src/ui/dialogs/ShieldSystemDialog.cpp index 27975d0fdfc..aa54e3e1d59 100644 --- a/qtfred/src/ui/dialogs/ShieldSystemDialog.cpp +++ b/qtfred/src/ui/dialogs/ShieldSystemDialog.cpp @@ -29,7 +29,7 @@ void ShieldSystemDialog::accept() if (_model->apply()) { QDialog::accept(); } - // else: validation failed, don’t close + // else: validation failed, don't close } void ShieldSystemDialog::reject() diff --git a/qtfred/src/ui/dialogs/ShipEditor/ShipAltShipClass.cpp b/qtfred/src/ui/dialogs/ShipEditor/ShipAltShipClass.cpp index 2aad1084859..240b3d77090 100644 --- a/qtfred/src/ui/dialogs/ShipEditor/ShipAltShipClass.cpp +++ b/qtfred/src/ui/dialogs/ShipEditor/ShipAltShipClass.cpp @@ -25,7 +25,7 @@ void ShipAltShipClass::accept() if (_model->apply()) { QDialog::accept(); } - // else: validation failed, don’t close + // else: validation failed, don't close } void ShipAltShipClass::reject() @@ -210,7 +210,6 @@ void ShipAltShipClass::initUI() void ShipAltShipClass::updateUI() { util::SignalBlockers blockers(this); // block signals while we set up the UI - QModelIndexList* list; auto current = ui->classList->currentIndex(); auto ship_class = -1; auto variable = -1; @@ -223,32 +222,36 @@ void ShipAltShipClass::updateUI() if (ui->variableCombo->model()->rowCount() <= 1) { dynamic_cast(ui->shipCombo->model())->setFilterFixedString("Set From Variable"); } - list = new QModelIndexList( - ui->shipCombo->model()->match(ui->shipCombo->model()->index(0, 0), Qt::UserRole, ship_class)); - if (!list->empty()) { - ui->shipCombo->setCurrentIndex(list->first().row()); - } else { - if (ui->classList->model()->rowCount() != 0 && ship_class != -1) { - _viewport->dialogProvider->showButtonDialog(DialogType::Error, - "Error", - "Illegal ship class.\n Resetting to -1", - {DialogButton::Ok}); + { + QModelIndexList shipMatches = + ui->shipCombo->model()->match(ui->shipCombo->model()->index(0, 0), Qt::UserRole, ship_class); + if (!shipMatches.empty()) { + ui->shipCombo->setCurrentIndex(shipMatches.first().row()); + } else { + if (ui->classList->model()->rowCount() != 0 && ship_class != -1) { + _viewport->dialogProvider->showButtonDialog(DialogType::Error, + "Error", + "Illegal ship class.\n Resetting to -1", + {DialogButton::Ok}); + } + ui->shipCombo->setCurrentIndex(0); } - ui->shipCombo->setCurrentIndex(0); } - auto varlist = new QModelIndexList( - ui->variableCombo->model()->match(ui->variableCombo->model()->index(0, 0), Qt::UserRole, variable)); - if (!varlist->empty()) { - ui->variableCombo->setCurrentIndex(varlist->first().row()); - } else { - if (ui->classList->model()->rowCount() != 0) { - _viewport->dialogProvider->showButtonDialog(DialogType::Error, - "Error", - "Illegal variable index.\n Resetting to -1", - {DialogButton::Ok}); + { + QModelIndexList varMatches = + ui->variableCombo->model()->match(ui->variableCombo->model()->index(0, 0), Qt::UserRole, variable); + if (!varMatches.empty()) { + ui->variableCombo->setCurrentIndex(varMatches.first().row()); + } else { + if (ui->classList->model()->rowCount() != 0) { + _viewport->dialogProvider->showButtonDialog(DialogType::Error, + "Error", + "Illegal variable index.\n Resetting to -1", + {DialogButton::Ok}); + } + ui->variableCombo->setCurrentIndex(0); } - ui->variableCombo->setCurrentIndex(0); } if (ui->variableCombo->model()->rowCount() <= 1) { diff --git a/qtfred/src/ui/dialogs/ShipEditor/ShipCustomWarpDialog.cpp b/qtfred/src/ui/dialogs/ShipEditor/ShipCustomWarpDialog.cpp index 14c663021bf..756d3a8a9e2 100644 --- a/qtfred/src/ui/dialogs/ShipEditor/ShipCustomWarpDialog.cpp +++ b/qtfred/src/ui/dialogs/ShipEditor/ShipCustomWarpDialog.cpp @@ -80,24 +80,14 @@ void ShipCustomWarpDialog::on_comboBoxType_currentIndexChanged(int index) _model->setType(index); } void ShipCustomWarpDialog::on_lineEditStartSound_editingFinished() -{ // String wrangling reqired in order to avoid crashes when directly converting from Qstring to std::string on some - // enviroments - QString temp(ui->lineEditStartSound->text()); - if (!temp.isEmpty()) { - _model->setStartSound(temp.toLatin1().constData()); - } else { - _model->setStartSound(""); - } +{ + SCP_string startSound = ui->lineEditStartSound->text().toUtf8().constData(); + _model->setStartSound(startSound); } void ShipCustomWarpDialog::on_lineEditEndSound_editingFinished() -{ // String wrangling reqired in order to avoid crashes when directly converting from Qstring to std::string on some - // enviroments - QString temp(ui->lineEditEndSound->text()); - if (!temp.isEmpty()) { - _model->setEndSound(temp.toLatin1().constData()); - } else { - _model->setEndSound(""); - } +{ + SCP_string endSound = ui->lineEditEndSound->text().toUtf8().constData(); + _model->setEndSound(endSound); } void ShipCustomWarpDialog::on_doubleSpinBoxEngage_valueChanged(double value) { @@ -120,14 +110,9 @@ void ShipCustomWarpDialog::on_doubleSpinBoxRadius_valueChanged(double value) _model->setRadius(value); } void ShipCustomWarpDialog::on_lineEditAnim_editingFinished() -{ // String wrangling reqired in order to avoid crashes when directly converting from Qstring to std::string on some - // enviroments - QString temp(ui->lineEditAnim->text()); - if (!temp.isEmpty()) { - _model->setAnim(temp.toLatin1().constData()); - } else { - _model->setAnim(""); - } +{ + SCP_string anim = ui->lineEditAnim->text().toUtf8().constData(); + _model->setAnim(anim); } void ShipCustomWarpDialog::on_checkBoxSupercap_toggled(bool state) { diff --git a/qtfred/src/ui/dialogs/ShipEditor/ShipEditorDialog.cpp b/qtfred/src/ui/dialogs/ShipEditor/ShipEditorDialog.cpp index 79c80db9b34..f14d2e68e13 100644 --- a/qtfred/src/ui/dialogs/ShipEditor/ShipEditorDialog.cpp +++ b/qtfred/src/ui/dialogs/ShipEditor/ShipEditorDialog.cpp @@ -32,7 +32,6 @@ ShipEditorDialog::ShipEditorDialog(FredView* parent, EditorViewport* viewport) ui->callsignCombo->lineEdit()->setMaxLength(CALLSIGN_LEN); connect(_model.get(), &AbstractDialogModel::modelChanged, this, [this] { updateUI(false); }); - connect(this, &QDialog::accepted, _model.get(), &ShipEditorDialogModel::apply); connect(viewport->editor, &Editor::currentObjectChanged, this, &ShipEditorDialog::update); connect(viewport->editor, &Editor::objectMarkingChanged, this, &ShipEditorDialog::update); @@ -69,8 +68,6 @@ bool ShipEditorDialog::getIfMultipleShips() const void ShipEditorDialog::closeEvent(QCloseEvent* e) { - util::SignalBlockers blockers(this); - _model->apply(); _viewport->editor->autosave("ship editor"); QDialog::closeEvent(e); } @@ -118,9 +115,6 @@ void ShipEditorDialog::on_tblInfoButton_clicked() void ShipEditorDialog::update() { if (this->isVisible()) { - if (_model->getNumSelectedObjects() && _model->query_modified()) { - _model->apply(); - } _model->initializeData(); updateUI(true); } @@ -206,10 +200,11 @@ void ShipEditorDialog::updateColumnOne(bool overwrite) for (auto j = 0; j < Mission_alt_type_count; j++) { ui->altNameCombo->addItem(Mission_alt_types[j]); } - if (ui->altNameCombo->findText(QString(altname.c_str()))) { - ui->altNameCombo->setCurrentIndex(ui->altNameCombo->findText(QString(altname.c_str()))); + int altNameIdx = ui->altNameCombo->findText(QString(altname.c_str())); + if (altNameIdx >= 0) { + ui->altNameCombo->setCurrentIndex(altNameIdx); } else { - ui->altNameCombo->setCurrentIndex(ui->altNameCombo->findText("")); + ui->altNameCombo->setEditText(""); } } } @@ -218,19 +213,19 @@ void ShipEditorDialog::updateColumnOne(bool overwrite) if (_model->getIfMultipleShips()) { ui->callsignCombo->setEnabled(false); } else { - ui->callsignCombo->clear(); auto callsign = _model->getCallsign(); ui->callsignCombo->setEnabled(true); if (overwrite) { + ui->callsignCombo->clear(); ui->callsignCombo->addItem(""); for (auto j = 0; j < Mission_callsign_count; j++) { ui->callsignCombo->addItem(Mission_callsigns[j], QVariant(Mission_callsigns[j])); } - - if (ui->callsignCombo->findText(QString(callsign.c_str()))) { - ui->callsignCombo->setCurrentIndex(ui->callsignCombo->findText(QString(callsign.c_str()))); + int callsignIdx = ui->callsignCombo->findText(QString(callsign.c_str())); + if (callsignIdx >= 0) { + ui->callsignCombo->setCurrentIndex(callsignIdx); } else { - ui->altNameCombo->setCurrentIndex(ui->callsignCombo->findText("")); + ui->callsignCombo->setEditText(""); } } } @@ -863,32 +858,32 @@ void ShipEditorDialog::on_departureLocationCombo_currentIndexChanged(int index) auto depLocationIdx = ui->departureLocationCombo->itemData(index).toInt(); _model->setDepartureLocationIndex(depLocationIdx); } -void fred::dialogs::ShipEditorDialog::on_departureTargetCombo_currentIndexChanged(int index) +void ShipEditorDialog::on_departureTargetCombo_currentIndexChanged(int index) { auto depLocationIdx = ui->departureTargetCombo->itemData(index).toInt(); _model->setDepartureTarget(depLocationIdx); } -void fred::dialogs::ShipEditorDialog::on_departureDelaySpinBox_valueChanged(int value) +void ShipEditorDialog::on_departureDelaySpinBox_valueChanged(int value) { _model->setDepartureDelay(value); } -void fred::dialogs::ShipEditorDialog::on_updateDepartureCueCheckBox_toggled(bool value) +void ShipEditorDialog::on_updateDepartureCueCheckBox_toggled(bool value) { _model->setDepartureCue(value); } -void fred::dialogs::ShipEditorDialog::on_departureTree_rootNodeFormulaChanged(int old, int node) +void ShipEditorDialog::on_departureTree_rootNodeFormulaChanged(int old, int node) { _model->setDepartureFormula(old, node); } -void fred::dialogs::ShipEditorDialog::on_departureTree_helpChanged(const QString& help) +void ShipEditorDialog::on_departureTree_helpChanged(const QString& help) { ui->helpText->setPlainText(help); } -void fred::dialogs::ShipEditorDialog::on_departureTree_miniHelpChanged(const QString& help) +void ShipEditorDialog::on_departureTree_miniHelpChanged(const QString& help) { ui->HelpTitle->setText(help); } -void fred::dialogs::ShipEditorDialog::on_noDepartureWarpCheckBox_toggled(bool value) +void ShipEditorDialog::on_noDepartureWarpCheckBox_toggled(bool value) { _model->setNoDepartureWarp(value); } diff --git a/qtfred/src/ui/dialogs/ShipEditor/ShipFlagsDialog.cpp b/qtfred/src/ui/dialogs/ShipEditor/ShipFlagsDialog.cpp index d70fcfdfb56..ad66ce1762b 100644 --- a/qtfred/src/ui/dialogs/ShipEditor/ShipFlagsDialog.cpp +++ b/qtfred/src/ui/dialogs/ShipEditor/ShipFlagsDialog.cpp @@ -45,7 +45,7 @@ void ShipFlagsDialog::accept() { if (_model->apply()) { QDialog::accept(); } - // else: validation failed, don’t close + // else: validation failed, don't close } void ShipFlagsDialog::reject() { diff --git a/qtfred/src/ui/dialogs/ShipEditor/ShipGoalsDialog.cpp b/qtfred/src/ui/dialogs/ShipEditor/ShipGoalsDialog.cpp index 17fcee617b6..e195fe47d3b 100644 --- a/qtfred/src/ui/dialogs/ShipEditor/ShipGoalsDialog.cpp +++ b/qtfred/src/ui/dialogs/ShipEditor/ShipGoalsDialog.cpp @@ -108,7 +108,7 @@ void ShipGoalsDialog::accept() if (_model->apply()) { QDialog::accept(); } - // else: validation failed, don’t close + // else: validation failed, don't close } void ShipGoalsDialog::reject() @@ -316,11 +316,14 @@ void ShipGoalsDialog::updateUI() _model->setDock(i, -1); ship_subsys* cur_subsys; auto subsysvalue = _model->getSubsys(i); - cur_subsys = GET_FIRST(&Ships[i].subsys_list); - while (cur_subsys != END_OF_LIST(&Ships[i].subsys_list)) { - subsys[i]->addItem(cur_subsys->system_info->subobj_name, - QVariant(QString(cur_subsys->system_info->subobj_name))); - cur_subsys = GET_NEXT(cur_subsys); + int target_ship_idx = _model->getObject(i) & DATA_MASK; + if (target_ship_idx >= 0 && target_ship_idx < MAX_SHIPS) { + cur_subsys = GET_FIRST(&Ships[target_ship_idx].subsys_list); + while (cur_subsys != END_OF_LIST(&Ships[target_ship_idx].subsys_list)) { + subsys[i]->addItem(cur_subsys->system_info->subobj_name, + QVariant(QString(cur_subsys->system_info->subobj_name))); + cur_subsys = GET_NEXT(cur_subsys); + } } if (subsysvalue.empty()) { subsys[i]->setCurrentIndex(0); diff --git a/qtfred/src/ui/dialogs/ShipEditor/ShipInitialStatusDialog.cpp b/qtfred/src/ui/dialogs/ShipEditor/ShipInitialStatusDialog.cpp index d1fcff8d810..889f9f90295 100644 --- a/qtfred/src/ui/dialogs/ShipEditor/ShipInitialStatusDialog.cpp +++ b/qtfred/src/ui/dialogs/ShipEditor/ShipInitialStatusDialog.cpp @@ -127,15 +127,13 @@ void ShipInitialStatusDialog::on_subIntegritySpinBox_valueChanged(int value) } void ShipInitialStatusDialog::on_cargoEdit_editingFinished() { - auto cargo = ui->cargoEdit->text(); - auto cargofixed = cargo.toUtf8(); - _model->setCargo(cargofixed.toStdString()); + SCP_string cargo = ui->cargoEdit->text().toUtf8().constData(); + _model->setCargo(cargo); } void ShipInitialStatusDialog::on_colourComboBox_currentIndexChanged(int index) { - auto string = ui->colourComboBox->itemText(index); - auto stringfixed = string.toUtf8(); - _model->setColour(stringfixed.toStdString()); + SCP_string colour = ui->colourComboBox->itemText(index).toUtf8().constData(); + _model->setColour(colour); } void ShipInitialStatusDialog::on_okPushButton_clicked() { @@ -327,9 +325,6 @@ void ShipInitialStatusDialog::list_dockees(int dock_types) } void ShipInitialStatusDialog::list_dockee_points(int shipnum) { - ship* shipp = &Ships[_model->getShip()]; - ship* other_shipp = &Ships[shipnum]; - // enable/disable dropdown ui->dockeePointComboBox->setEnabled((shipnum >= 0)); @@ -341,6 +336,9 @@ void ShipInitialStatusDialog::list_dockee_points(int shipnum) return; } + ship* shipp = &Ships[_model->getShip()]; + ship* other_shipp = &Ships[shipnum]; + // get the required dock type(s) int dock_type = model_get_dock_index_type(Ship_info[shipp->ship_info_index].model_num, cur_docker_point); diff --git a/qtfred/src/ui/dialogs/ShipEditor/ShipSpecialStatsDialog.cpp b/qtfred/src/ui/dialogs/ShipEditor/ShipSpecialStatsDialog.cpp index f61a92af20b..9367795c23d 100644 --- a/qtfred/src/ui/dialogs/ShipEditor/ShipSpecialStatsDialog.cpp +++ b/qtfred/src/ui/dialogs/ShipEditor/ShipSpecialStatsDialog.cpp @@ -30,7 +30,7 @@ void ShipSpecialStatsDialog::accept() if (_model->apply()) { QDialog::accept(); } - // else: validation failed, don’t close + // else: validation failed, don't close } void ShipSpecialStatsDialog::reject() diff --git a/qtfred/src/ui/dialogs/VariableDialog.cpp b/qtfred/src/ui/dialogs/VariableDialog.cpp index c3821c2161c..83dbe6fb301 100644 --- a/qtfred/src/ui/dialogs/VariableDialog.cpp +++ b/qtfred/src/ui/dialogs/VariableDialog.cpp @@ -44,7 +44,7 @@ void VariableDialog::accept() if (_model->apply()) { QDialog::accept(); } - // else: validation failed, don’t close + // else: validation failed, don't close } void VariableDialog::reject() diff --git a/qtfred/ui/ShipEditorDialog.ui b/qtfred/ui/ShipEditorDialog.ui index f9eef784f4c..7b282cc45ea 100644 --- a/qtfred/ui/ShipEditorDialog.ui +++ b/qtfred/ui/ShipEditorDialog.ui @@ -36,32 +36,25 @@ 0 - - - - - Display Name - - - - - + + + - Alt Name + Ship Name - - + + - <html><head/><body><p>Sets the Ship's AI</p></body></html> + <html><head/><body><p>Sets the ship's name</p></body></html> - - + + - Ship Name + Display Name @@ -72,89 +65,96 @@ - - - - <html><head/><body><p>Sets the ship's team</p></body></html> - - - - - + + - Cargo + Ship Class - - - - AI Class + + + + <html><head/><body><p>Sets the ship's class</p></body></html> - - + + - Team + Callsign - - + + - <html><head/><body><p>Type to add Ship's Cargo or select previous</p></body></html> + <html><head/><body><p>Sets ship's callsign (Replaces name in messages)</p></body></html> true - - + + - Callsign - - - - - - - <html><head/><body><p>Sets the ship's name</p></body></html> + Alt Name - - + + - <html><head/><body><p>Sets ship's callsign (Replaces name in messages)</p></body></html> + <html><head/><body><p>Change ship's class name (i.e. GTF Ulysses -&gt; NTF Ulysses)</p></body></html> true + + + + AI Class + + + - + - <html><head/><body><p>Change ship's class name (i.e. GTF Ulysses -&gt; NTF Ulysses)</p></body></html> + <html><head/><body><p>Sets the Ship's AI</p></body></html> - - true + + + + + + Team - - + + - <html><head/><body><p>Sets the ship's class</p></body></html> + <html><head/><body><p>Sets the ship's team</p></body></html> - - + + - Ship Class + Cargo + + + + + + + <html><head/><body><p>Type to add Ship's Cargo or select previous</p></body></html> + + + true @@ -175,73 +175,32 @@ - - - - - <html><head/><body><p>Wing the current ship is in</p></body></html> - - - Static - - - - - - - <html><head/><body><p>How many points the player gets for an assist</p></body></html> - - - QAbstractSpinBox::NoButtons - - - - - + + + - Kill Score + Wing: - - + + - <html><head/><body><p>How many points the player gets for the kill</p></body></html> - - - QAbstractSpinBox::NoButtons + <html><head/><body><p>Wing the current ship is in</p></body></html> - - - - - Persona - - - - - - - <html><head/><body><p>Sets the head ani &amp; voice for automated messages</p></body></html> + Static - + Hotkey - - - - Assist % - - - - + <html><head/><body><p>Adds the ship to the specified targeting hotkey</p></body></html> @@ -298,21 +257,62 @@ - - + + - Wing: + Persona - + + + + <html><head/><body><p>Sets the head ani &amp; voice for automated messages</p></body></html> + + + + + + + Kill Score + + + + + + + <html><head/><body><p>How many points the player gets for the kill</p></body></html> + + + QAbstractSpinBox::NoButtons + + + + + + + Assist % + + + + + + + <html><head/><body><p>How many points the player gets for an assist</p></body></html> + + + QAbstractSpinBox::NoButtons + + + + Respawn Priority - + @@ -364,24 +364,11 @@ - + QLayout::SetDefaultConstraint - - 0 - - - - - <html><head/><body><p>Change ship's max health or explosion damage (Combines olf FRED's Special hits and special exp dialogs)</p></body></html> - - - Special Stats - - - - + 6 @@ -396,7 +383,7 @@ - 35 + 16777215 16777215 @@ -415,7 +402,7 @@ - 35 + 16777215 16777215 @@ -426,7 +413,21 @@ - + + + + Delete + + + + + + + Reset + + + + <html><head/><body><p>Change the ships weapons</p></body></html> @@ -436,7 +437,7 @@ - + <html><head/><body><p>Sets what orders the player can give the ship</p></body></html> @@ -446,17 +447,13 @@ - - - - Reset + + + + <html><head/><body><p>Change ship's max health or explosion damage (Combines olf FRED's Special hits and special exp dialogs)</p></body></html> - - - - - Delete + Special Stats @@ -533,14 +530,7 @@ - - - - - Distance - - - + @@ -548,10 +538,10 @@ - - + + - <html><head/><body><p>Target Ship</p></body></html> + <html><head/><body><p>Sets ship's arrival location</p><p>Hyperspace - Ship appears where it is on the map,</p><p>Near Ship - Ship appears at a random location the specified distance of the target,</p><p>In front of ship - Ship appears ate the specified distance somewhere in a cone in front of the target,</p><p>Docking Bay - Ship arrives in the targets fighter bay</p></body></html> @@ -562,38 +552,20 @@ - - - - Delay + + + + <html><head/><body><p>Target Ship</p></body></html> - - - - <html><head/><body><p>Sets ship's arrival location</p><p>Hyperspace - Ship appears where it is on the map,</p><p>Near Ship - Ship appears at a random location the specified distance of the target,</p><p>In front of ship - Ship appears ate the specified distance somewhere in a cone in front of the target,</p><p>Docking Bay - Ship arrives in the targets fighter bay</p></body></html> + + + + Distance - - - - - - <html><head/><body><p>Time to wait after cue conditions met</p></body></html> - - - - - - - Seconds - - - - - @@ -624,6 +596,31 @@ + + + + Delay + + + + + + + + + <html><head/><body><p>Time to wait after cue conditions met</p></body></html> + + + + + + + Seconds + + + + + @@ -703,7 +700,21 @@ - + + + + + Location + + + + + + + <html><head/><body><p>Sets ship's departure location</p><p>Hyperspace - Ship leaves from where it is,</p><p>Docking Bay - Ship departs into the targets fighter bay</p></body></html> + + + @@ -718,13 +729,6 @@ - - - - Delay - - - @@ -741,10 +745,10 @@ - - - - <html><head/><body><p>Sets ship's departure location</p><p>Hyperspace - Ship leaves from where it is,</p><p>Docking Bay - Ship departs into the targets fighter bay</p></body></html> + + + + Delay @@ -779,13 +783,6 @@ - - - - Location - - -