diff --git a/code/mission/missionparse.cpp b/code/mission/missionparse.cpp index 057a62afe4f..300113f7916 100644 --- a/code/mission/missionparse.cpp +++ b/code/mission/missionparse.cpp @@ -4641,10 +4641,11 @@ int parse_wing_create_ships( wing *wingp, int num_to_create, bool force_create, // bash the ship name to be the name of the wing + some number if there is > 1 wave in this wing wingp->total_arrived_count++; + auto wing_ship_index = wingp->total_arrived_count + wingp->red_alert_skipped_ships; if (wingp->num_waves > 1) { bool needs_display_name; - wing_bash_ship_name(p_objp->name, wingp->name, wingp->total_arrived_count + wingp->red_alert_skipped_ships, &needs_display_name); + wing_bash_ship_name(p_objp->name, wingp->name, wing_ship_index, &needs_display_name); // set up display name if we need to // (In the unlikely edge case where the ship already has a display name for some reason, it will be overwritten. @@ -4668,6 +4669,19 @@ int parse_wing_create_ships( wing *wingp, int num_to_create, bool force_create, } } + // Wing display names take priority over all display names because they are newer and cooler + if (!wingp->display_name.empty()) + { + char ship_display_name[NAME_LENGTH]; + bool wing_display_name_has_hash; + wing_bash_ship_name(ship_display_name, wingp->display_name.c_str(), wing_ship_index, &wing_display_name_has_hash); + + p_objp->display_name = ship_display_name; + if (wing_display_name_has_hash) + end_string_at_first_hash_symbol(p_objp->display_name); + p_objp->flags.set(Mission::Parse_Object_Flags::SF_Has_display_name); + } + // also, if multiplayer, set the parse object's net signature to be wing's net signature // base + total_arrived_count (before adding 1) // Cyborg -- The original ships in the wave have their net_signature set at mission parse @@ -4838,6 +4852,10 @@ void parse_wing(mission *pm) error_display(0, NOX("Redundant wing name: %s\n"), wingp->name); wingnum = Num_wings; + if (optional_string("+Display Name:")) { + stuff_string(wingp->display_name, F_NAME); + } + // squad logo - Goober5000 if (optional_string("+Squad Logo:")) { @@ -9560,6 +9578,12 @@ bool check_for_25_1_data() if (count_items_with_value(Props) > 0) return true; + for (int i = 0; i < Num_wings; i++) { + if (!Wings[i].display_name.empty()) { + return true; + } + } + constexpr auto defaultLayer = "Default"; for (const auto& so : list_range(&Ship_obj_list)) diff --git a/code/missioneditor/missionsave.cpp b/code/missioneditor/missionsave.cpp index e46fb6b590c..139e21fbdc8 100644 --- a/code/missioneditor/missionsave.cpp +++ b/code/missioneditor/missionsave.cpp @@ -4955,6 +4955,15 @@ int Fred_mission_save::save_wings() parse_comments(count ? 2 : 1); fout(" %s", w.name); + if (!w.display_name.empty()) { + if (optional_string_fred("+Display Name:", "$Name:")) + parse_comments(); + else + fout("\n+Display Name:"); + + fout_ext(" ", "%s", w.display_name.c_str()); + } + count++; // squad logo - Goober5000 diff --git a/code/ship/ship.cpp b/code/ship/ship.cpp index 32454b762b0..060f1b3e591 100644 --- a/code/ship/ship.cpp +++ b/code/ship/ship.cpp @@ -7547,6 +7547,7 @@ ship_weapon::ship_weapon() { void wing::clear() { name[0] = '\0'; + display_name.clear(); wing_squad_filename[0] = '\0'; reinforcement_index = -1; hotkey = -1; diff --git a/code/ship/ship.h b/code/ship/ship.h index fc25427a6bc..0f30d1da8c8 100644 --- a/code/ship/ship.h +++ b/code/ship/ship.h @@ -1571,6 +1571,7 @@ extern SCP_vector Engine_wash_info; // Defines a wing of ships. typedef struct wing { char name[NAME_LENGTH]; + SCP_string display_name; char wing_squad_filename[MAX_FILENAME_LEN]; // Goober5000 int reinforcement_index; // index in reinforcement struct or -1 int hotkey; diff --git a/fred2/fred.rc b/fred2/fred.rc index bbfefe7442b..f57659dee75 100644 --- a/fred2/fred.rc +++ b/fred2/fred.rc @@ -1241,14 +1241,15 @@ BEGIN PUSHBUTTON "Prev",IDC_PREV,240,7,24,14,0,WS_EX_STATICEDGE PUSHBUTTON "Next",IDC_NEXT,267,7,24,14,0,WS_EX_STATICEDGE EDITTEXT IDC_WING_NAME,65,7,73,14,ES_AUTOHSCROLL - COMBOBOX IDC_WING_SPECIAL_SHIP,65,23,73,161,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - EDITTEXT IDC_WING_WAVES,65,37,61,14,ES_AUTOHSCROLL | ES_NUMBER - CONTROL "Spin2",IDC_SPIN_WAVES,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,127,37,11,15 - EDITTEXT IDC_WING_WAVE_THRESHOLD,65,53,61,15,ES_AUTOHSCROLL | ES_NUMBER - CONTROL "Spin2",IDC_SPIN_WAVE_THRESHOLD,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,127,53,11,15 - COMBOBOX IDC_HOTKEY,65,70,73,115,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "Squad Logo",IDC_WING_SQUAD_LOGO_BUTTON,7,89,55,14 - EDITTEXT IDC_WING_SQUAD_LOGO,65,90,80,14,ES_AUTOHSCROLL | ES_READONLY + EDITTEXT IDC_WING_DISPLAY_NAME,65,22,73,14,ES_AUTOHSCROLL + COMBOBOX IDC_WING_SPECIAL_SHIP,65,38,73,161,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + EDITTEXT IDC_WING_WAVES,65,52,61,14,ES_AUTOHSCROLL | ES_NUMBER + CONTROL "Spin2",IDC_SPIN_WAVES,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,127,52,11,15 + EDITTEXT IDC_WING_WAVE_THRESHOLD,65,68,61,15,ES_AUTOHSCROLL | ES_NUMBER + CONTROL "Spin2",IDC_SPIN_WAVE_THRESHOLD,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,127,68,11,15 + COMBOBOX IDC_HOTKEY,65,84,73,115,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Squad Logo",IDC_WING_SQUAD_LOGO_BUTTON,7,98,55,14 + EDITTEXT IDC_WING_SQUAD_LOGO,65,99,80,14,ES_AUTOHSCROLL | ES_READONLY CONTROL "Reinforcement Unit",IDC_REINFORCEMENT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,143,10,77,10 CONTROL "Ignore for Counting Goals",IDC_IGNORE_COUNT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,143,21,96,10 CONTROL "No Arrival Music",IDC_NO_ARRIVAL_MUSIC,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,143,32,67,10 @@ -1282,9 +1283,10 @@ BEGIN CONTROL "Hide Cues",IDC_HIDE_CUES,"Button",BS_AUTOCHECKBOX | BS_PUSHLIKE | WS_TABSTOP,241,71,49,12 GROUPBOX "Departure",IDC_STATIC,153,110,138,270 RTEXT "Wing Name",IDC_STATIC,19,10,42,8 - RTEXT "Wave Threshold",IDC_STATIC,7,56,54,8 - RTEXT "# of Waves",IDC_STATIC,16,40,45,8 - RTEXT "Leader",IDC_STATIC,38,25,23,8,NOT WS_GROUP + RTEXT "Display Name",IDC_STATIC,10,25,51,8 + RTEXT "Wave Threshold",IDC_STATIC,7,71,54,8 + RTEXT "# of Waves",IDC_STATIC,16,55,45,8 + RTEXT "Leader",IDC_STATIC,38,40,23,8,NOT WS_GROUP LTEXT "Location",IDC_STATIC,15,124,28,8 LTEXT "Cue:",IDC_STATIC,15,259,16,8 GROUPBOX "Arrival",IDC_CUE_FRAME,7,110,138,270 @@ -1293,7 +1295,7 @@ BEGIN LTEXT "Delay",IDC_STATIC,160,140,19,8 LTEXT "Delay",IDC_STATIC,15,140,19,8 LTEXT "Seconds",IDC_STATIC,102,141,45,8 - RTEXT "Hotkey",IDC_STATIC,37,72,24,8 + RTEXT "Hotkey",IDC_STATIC,37,86,24,8 GROUPBOX "Delay Between Waves",IDC_STATIC,15,154,119,30 LTEXT "Min",IDC_STATIC,21,167,12,8 LTEXT "Max",IDC_STATIC,80,167,14,8 diff --git a/fred2/resource.h b/fred2/resource.h index 0ba948f0bd9..998e7a7511d 100644 --- a/fred2/resource.h +++ b/fred2/resource.h @@ -1271,6 +1271,7 @@ #define IDC_PROP_PREV 1710 #define IDC_PROP_NEXT 1711 #define IDC_PROP_FLAGS 1712 +#define IDC_WING_DISPLAY_NAME 1713 #define IDC_SEXP_POPUP_LIST 32770 #define ID_FILE_MISSIONNOTES 32771 #define ID_DUPLICATE 32774 @@ -1581,7 +1582,7 @@ #define _APS_3D_CONTROLS 1 #define _APS_NEXT_RESOURCE_VALUE 335 #define _APS_NEXT_COMMAND_VALUE 33104 -#define _APS_NEXT_CONTROL_VALUE 1705 +#define _APS_NEXT_CONTROL_VALUE 1714 #define _APS_NEXT_SYMED_VALUE 105 #endif #endif diff --git a/fred2/wing_editor.cpp b/fred2/wing_editor.cpp index e9df5847710..6bff0092390 100644 --- a/fred2/wing_editor.cpp +++ b/fred2/wing_editor.cpp @@ -45,6 +45,7 @@ wing_editor::wing_editor(CWnd* pParent /*=NULL*/) { //{{AFX_DATA_INIT(wing_editor) m_wing_name = _T(""); + m_wing_display_name = _T(""); m_wing_squad_filename = _T(""); m_special_ship = -1; m_waves = 0; @@ -90,6 +91,7 @@ void wing_editor::DoDataExchange(CDataExchange* pDX) DDX_Control(pDX, IDC_SPIN_WAVE_THRESHOLD, m_threshold_spin); DDX_Control(pDX, IDC_SPIN_WAVES, m_waves_spin); DDX_Text(pDX, IDC_WING_NAME, m_wing_name); + DDX_Text(pDX, IDC_WING_DISPLAY_NAME, m_wing_display_name); DDX_Text(pDX, IDC_WING_SQUAD_LOGO, m_wing_squad_filename); DDX_CBIndex(pDX, IDC_WING_SPECIAL_SHIP, m_special_ship); DDX_CBIndex(pDX, IDC_WING_FORMATION, m_formation); @@ -221,6 +223,8 @@ BOOL wing_editor::Create() m_arrival_delay_spin.SetRange(0, 999); m_departure_delay_spin.SetRange(0, 999); + ((CEdit *)GetDlgItem(IDC_WING_DISPLAY_NAME))->SetLimitText(NAME_LENGTH - 1); + initialize_data(1); return r; } @@ -286,6 +290,7 @@ void wing_editor::initialize_data_safe(int full_update) m_ignore_count = 0; if (cur_wing < 0) { + m_wing_display_name = _T(""); m_wing_squad_filename = _T(""); m_special_ship = -1; m_formation = 0; @@ -348,6 +353,7 @@ void wing_editor::initialize_data_safe(int full_update) if (Ships[Player_start_shipnum].wingnum == cur_wing) player_wing = 1; + m_wing_display_name = _T(Wings[cur_wing].display_name.c_str()); m_wing_squad_filename = _T(Wings[cur_wing].wing_squad_filename); m_special_ship = Wings[cur_wing].special_ship; m_waves = Wings[cur_wing].num_waves; @@ -451,6 +457,7 @@ void wing_editor::initialize_data_safe(int full_update) UpdateData(FALSE); GetDlgItem(IDC_WING_NAME)->EnableWindow(enable); + GetDlgItem(IDC_WING_DISPLAY_NAME)->EnableWindow(enable); GetDlgItem(IDC_WING_SQUAD_LOGO_BUTTON)->EnableWindow(enable); GetDlgItem(IDC_WING_SPECIAL_SHIP)->EnableWindow(enable); GetDlgItem(IDC_WING_WAVES)->EnableWindow(player_enabled); @@ -544,10 +551,13 @@ void wing_editor::initialize_data(int full_update) m_arrival_tree.select_sexp_node = m_departure_tree.select_sexp_node = select_sexp_node; select_sexp_node = -1; - if (cur_wing == -1) + if (cur_wing == -1) { m_wing_name = _T(""); - else + m_wing_display_name = _T(""); + } else { m_wing_name = _T(Wings[cur_wing].name); + m_wing_display_name = _T(Wings[cur_wing].display_name.c_str()); + } initialize_data_safe(full_update); modified = 0; @@ -800,6 +810,7 @@ void wing_editor::update_data_safe() MODIFY(Wings[cur_wing].threshold, m_threshold); MODIFY(Wings[cur_wing].formation, m_formation - 1); MODIFY(Wings[cur_wing].formation_scale, (float)atof(m_formation_scale)); + MODIFY(Wings[cur_wing].display_name, (LPCSTR)m_wing_display_name); MODIFY(Wings[cur_wing].arrival_location, static_cast(m_arrival_location)); MODIFY(Wings[cur_wing].departure_location, static_cast(m_departure_location)); diff --git a/fred2/wing_editor.h b/fred2/wing_editor.h index 71a231abdc2..f7bab81b055 100644 --- a/fred2/wing_editor.h +++ b/fred2/wing_editor.h @@ -47,6 +47,7 @@ class wing_editor : public CDialog CSpinButtonCtrl m_threshold_spin; CSpinButtonCtrl m_waves_spin; CString m_wing_name; + CString m_wing_display_name; int m_special_ship; int m_waves; int m_threshold; diff --git a/qtfred/help-src/doc/dialogs/WingEditorDialog.html b/qtfred/help-src/doc/dialogs/WingEditorDialog.html index 29108ca0336..56ff20ad73c 100644 --- a/qtfred/help-src/doc/dialogs/WingEditorDialog.html +++ b/qtfred/help-src/doc/dialogs/WingEditorDialog.html @@ -18,6 +18,10 @@

General fields

FieldDescription NameWing name shown on the HUD and used in SEXPs (e.g. Alpha, Gamma). + Display NameOptional name shown to the player in place of the + internal name. Useful for localisation — the display name can be translated + while the internal name stays stable for SEXPs and scripting. Leave blank to + use the internal name. Wing leaderWhich ship in the wing acts as leader. Other members form up on the leader. Number of wavesHow many waves of this wing will arrive over the diff --git a/qtfred/src/mission/dialogs/WingEditorDialogModel.cpp b/qtfred/src/mission/dialogs/WingEditorDialogModel.cpp index 459c9d46134..5558ed627b6 100644 --- a/qtfred/src/mission/dialogs/WingEditorDialogModel.cpp +++ b/qtfred/src/mission/dialogs/WingEditorDialogModel.cpp @@ -425,6 +425,24 @@ void WingEditorDialogModel::setWingName(const SCP_string& name) } } +SCP_string WingEditorDialogModel::getWingDisplayName() const +{ + if (!wingIsValid()) + return ""; + + const auto w = getCurrentWing(); + return w->display_name; +} + +void WingEditorDialogModel::setWingDisplayName(const SCP_string& name) +{ + if (!wingIsValid()) + return; + + auto* w = getCurrentWing(); + modify(w->display_name, name); +} + int WingEditorDialogModel::getWingLeaderIndex() const { if (!wingIsValid()) diff --git a/qtfred/src/mission/dialogs/WingEditorDialogModel.h b/qtfred/src/mission/dialogs/WingEditorDialogModel.h index b25195be769..a45767229ff 100644 --- a/qtfred/src/mission/dialogs/WingEditorDialogModel.h +++ b/qtfred/src/mission/dialogs/WingEditorDialogModel.h @@ -58,6 +58,8 @@ class WingEditorDialogModel : public AbstractDialogModel { // Top section, first column SCP_string getWingName() const; void setWingName(const SCP_string& name); + SCP_string getWingDisplayName() const; + void setWingDisplayName(const SCP_string& name); int getWingLeaderIndex() const; void setWingLeaderIndex(int newLeaderIndex); int getNumberOfWaves() const; diff --git a/qtfred/src/ui/dialogs/WingEditorDialog.cpp b/qtfred/src/ui/dialogs/WingEditorDialog.cpp index 060bd86def1..8ec1b80e496 100644 --- a/qtfred/src/ui/dialogs/WingEditorDialog.cpp +++ b/qtfred/src/ui/dialogs/WingEditorDialog.cpp @@ -25,6 +25,8 @@ WingEditorDialog::WingEditorDialog(FredView* parent, EditorViewport* viewport) ui->wingNameEdit->setMaxLength(NAME_LENGTH - 1); + ui->wingDisplayNameEdit->setMaxLength(NAME_LENGTH - 1); + setWindowTitle(tr("Wing Editor")); // Whenever the model reports changes, refresh the UI @@ -58,6 +60,7 @@ void WingEditorDialog::updateUi() // Top section, first column ui->wingNameEdit->setText(_model->getWingName().c_str()); + ui->wingDisplayNameEdit->setText(_model->getWingDisplayName().c_str()); ui->wingLeaderCombo->setCurrentIndex(_model->getWingLeaderIndex()); ui->numWavesSpinBox->setValue(_model->getNumberOfWaves()); ui->waveThresholdSpinBox->setValue(_model->getWaveThreshold()); diff --git a/qtfred/ui/WingEditorDialog.ui b/qtfred/ui/WingEditorDialog.ui index a73c7f3ae9e..f61b479f585 100644 --- a/qtfred/ui/WingEditorDialog.ui +++ b/qtfred/ui/WingEditorDialog.ui @@ -43,7 +43,7 @@ - + Hotkey @@ -53,7 +53,7 @@ - + # of Waves @@ -70,7 +70,7 @@ - + Wave Threshold @@ -80,7 +80,7 @@ - + 1 @@ -90,10 +90,10 @@ - + - + @@ -107,6 +107,23 @@ + + + Display Name + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Optional display name for ships in this wing. + + + + Wing Leader @@ -116,7 +133,7 @@ - + true