/* * Copyright (C) Volition, Inc. 1999. All rights reserved. * * All source code herein is the property of Volition, Inc. You may not sell * or otherwise commercially exploit the source or things you created based on the * source. * */ #include "stdafx.h" #include "MainFrm.h" #include "FRED.h" #include "FREDDoc.h" #include "Management.h" #include "wing.h" #include "ai/aigoals.h" #include "FREDView.h" #include "missioneditor/common.h" #include "cfile/cfile.h" #include "restrictpaths.h" #include "warpparamsdlg.h" #include "ship/ship.h" #define ID_WING_MENU 9000 #ifdef _DEBUG #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif constexpr auto INPUT_THRESHOLD = 0.001f; // smallest increment of input box constexpr auto INPUT_FORMAT = "%#.3f"; ///////////////////////////////////////////////////////////////////////////// // wing_editor dialog wing_editor::wing_editor(CWnd* pParent /*=NULL*/) : CDialog(wing_editor::IDD, pParent) { //{{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; m_threshold = 0; m_formation = 0; // retail formation (no formation) is -1, but it's the 0-offset in the combo box m_formation_scale = _T("1.0"); m_arrival_location = -1; m_departure_location = -1; m_arrival_delay = 0; m_departure_delay = 0; m_reinforcement = FALSE; m_hotkey = -1; m_ignore_count = FALSE; m_arrival_delay_max = 0; m_arrival_delay_min = 0; m_arrival_dist = 0; m_arrival_target = -1; m_no_arrival_music = FALSE; m_departure_target = -1; m_no_arrival_message = FALSE; m_no_first_wave_message = FALSE; m_no_arrival_warp = FALSE; m_no_departure_warp = FALSE; m_same_arrival_warp_when_docked = FALSE; m_same_departure_warp_when_docked = FALSE; m_no_dynamic = FALSE; //}}AFX_DATA_INIT modified = 0; select_sexp_node = -1; bypass_errors = 0; } void wing_editor::DoDataExchange(CDataExchange* pDX) { CString str; CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(wing_editor) DDX_Control(pDX, IDC_DEPARTURE_DELAY_SPIN, m_departure_delay_spin); DDX_Control(pDX, IDC_ARRIVAL_DELAY_SPIN, m_arrival_delay_spin); DDX_Control(pDX, IDC_DEPARTURE_TREE, m_departure_tree); DDX_Control(pDX, IDC_ARRIVAL_TREE, m_arrival_tree); 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); DDX_Text(pDX, IDC_WING_FORMATION_SCALE, m_formation_scale); DDX_CBIndex(pDX, IDC_ARRIVAL_LOCATION, m_arrival_location); DDX_CBIndex(pDX, IDC_DEPARTURE_LOCATION, m_departure_location); DDX_Check(pDX, IDC_REINFORCEMENT, m_reinforcement); DDX_CBIndex(pDX, IDC_HOTKEY, m_hotkey); DDX_Check(pDX, IDC_IGNORE_COUNT, m_ignore_count); DDX_Text(pDX, IDC_ARRIVAL_DISTANCE, m_arrival_dist); DDX_CBIndex(pDX, IDC_ARRIVAL_TARGET, m_arrival_target); DDX_Check(pDX, IDC_NO_ARRIVAL_MUSIC, m_no_arrival_music); DDX_CBIndex(pDX, IDC_DEPARTURE_TARGET, m_departure_target); DDX_Check(pDX, IDC_NO_ARRIVAL_MESSAGE, m_no_arrival_message); DDX_Check(pDX, IDC_NO_FIRST_WAVE_MESSAGE, m_no_first_wave_message); DDX_Check(pDX, IDC_NO_ARRIVAL_WARP, m_no_arrival_warp); DDX_Check(pDX, IDC_NO_DEPARTURE_WARP, m_no_departure_warp); DDX_Check(pDX, IDC_SAME_ARRIVAL_WARP_WHEN_DOCKED, m_same_arrival_warp_when_docked); DDX_Check(pDX, IDC_SAME_DEPARTURE_WARP_WHEN_DOCKED, m_same_departure_warp_when_docked); DDX_Check(pDX, IDC_NO_DYNAMIC, m_no_dynamic); //}}AFX_DATA_MAP if (pDX->m_bSaveAndValidate) { // get dialog control values GetDlgItem(IDC_ARRIVAL_DELAY)->GetWindowText(str); m_arrival_delay = atoi(str); if (m_arrival_delay < 0) m_arrival_delay = 0; GetDlgItem(IDC_DEPARTURE_DELAY)->GetWindowText(str); m_departure_delay = atoi(str); if (m_departure_delay < 0) m_departure_delay = 0; GetDlgItem(IDC_WING_WAVES)->GetWindowText(str); m_waves = atoi(str); if (m_waves < 0) m_waves = 0; GetDlgItem(IDC_WING_WAVE_THRESHOLD)->GetWindowText(str); m_threshold = atoi(str); if (m_threshold < 0) m_threshold = 0; GetDlgItem(IDC_ARRIVAL_DELAY_MIN)->GetWindowText(str); m_arrival_delay_min = atoi(str); if (m_arrival_delay_min < 0) m_arrival_delay_min = 0; GetDlgItem(IDC_ARRIVAL_DELAY_MAX)->GetWindowText(str); m_arrival_delay_max = atoi(str); if (m_arrival_delay_max < 0) m_arrival_delay_max = 0; } else { DDX_Text(pDX, IDC_ARRIVAL_DELAY, m_arrival_delay); DDX_Text(pDX, IDC_DEPARTURE_DELAY, m_departure_delay); DDX_Text(pDX, IDC_WING_WAVES, m_waves); DDX_Text(pDX, IDC_WING_WAVE_THRESHOLD, m_threshold); DDX_Text(pDX, IDC_ARRIVAL_DELAY_MIN, m_arrival_delay_min); DDX_Text(pDX, IDC_ARRIVAL_DELAY_MAX, m_arrival_delay_max); } } BEGIN_MESSAGE_MAP(wing_editor, CDialog) //{{AFX_MSG_MAP(wing_editor) ON_WM_INITMENU() ON_NOTIFY(UDN_DELTAPOS, IDC_SPIN_WAVES, OnDeltaposSpinWaves) ON_NOTIFY(NM_RCLICK, IDC_ARRIVAL_TREE, OnRclickArrivalTree) ON_NOTIFY(NM_RCLICK, IDC_DEPARTURE_TREE, OnRclickDepartureTree) ON_NOTIFY(TVN_BEGINLABELEDIT, IDC_ARRIVAL_TREE, OnBeginlabeleditArrivalTree) ON_NOTIFY(TVN_BEGINLABELEDIT, IDC_DEPARTURE_TREE, OnBeginlabeleditDepartureTree) ON_NOTIFY(TVN_ENDLABELEDIT, IDC_ARRIVAL_TREE, OnEndlabeleditArrivalTree) ON_NOTIFY(TVN_ENDLABELEDIT, IDC_DEPARTURE_TREE, OnEndlabeleditDepartureTree) ON_BN_CLICKED(IDC_DELETE_WING, OnDeleteWing) ON_BN_CLICKED(IDC_DISBAND_WING, OnDisbandWing) ON_WM_CLOSE() ON_BN_CLICKED(IDC_GOALS2, OnGoals2) ON_BN_CLICKED(IDC_REINFORCEMENT, OnReinforcement) ON_BN_CLICKED(IDC_NEXT, OnNext) ON_NOTIFY(TVN_SELCHANGED, IDC_ARRIVAL_TREE, OnSelchangedArrivalTree) ON_NOTIFY(TVN_SELCHANGED, IDC_DEPARTURE_TREE, OnSelchangedDepartureTree) ON_BN_CLICKED(IDC_HIDE_CUES, OnHideCues) ON_BN_CLICKED(IDC_PREV, OnPrev) ON_CBN_SELCHANGE(IDC_ARRIVAL_LOCATION, OnSelchangeArrivalLocation) ON_CBN_SELCHANGE(IDC_DEPARTURE_LOCATION, OnSelchangeDepartureLocation) ON_CBN_SELCHANGE(IDC_HOTKEY, OnSelchangeHotkey) ON_BN_CLICKED(IDC_WING_SQUAD_LOGO_BUTTON, OnSquadLogo) ON_BN_CLICKED(IDC_RESTRICT_ARRIVAL, OnRestrictArrival) ON_BN_CLICKED(IDC_RESTRICT_DEPARTURE, OnRestrictDeparture) ON_BN_CLICKED(IDC_CUSTOM_WARPIN_PARAMS, OnBnClickedCustomWarpinParams) ON_BN_CLICKED(IDC_CUSTOM_WARPOUT_PARAMS, OnBnClickedCustomWarpoutParams) ON_BN_CLICKED(IDC_WING_FORMATION_ALIGN, OnWingFormationAlign) ON_EN_CHANGE(IDC_WING_NAME, OnChangeWingName) ON_EN_CHANGE(IDC_WING_WAVES, OnChangeWingWaves) //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // wing_editor message handlers BOOL wing_editor::Create() { BOOL r; int i; CComboBox *box; r = CDialog::Create(IDD, Fred_main_wnd); box = (CComboBox *)GetDlgItem(IDC_WING_FORMATION); box->ResetContent(); box->AddString("Default"); for (auto &f : Wing_formations) box->AddString(f.name); box = (CComboBox *) GetDlgItem(IDC_ARRIVAL_LOCATION); box->ResetContent(); for (i=0; iAddString(Arrival_location_names[i]); box = (CComboBox *) GetDlgItem(IDC_DEPARTURE_LOCATION); box->ResetContent(); for (i=0; iAddString(Departure_location_names[i]); m_hotkey = 0; m_waves_spin.SetRange(1, 99); m_arrival_tree._model.modified = &modified; // provide way to indicate trees are modified in dialog m_arrival_tree.setup((CEdit *) GetDlgItem(IDC_HELP_BOX)); m_departure_tree._model.modified = &modified; m_departure_tree.setup(); m_arrival_delay_spin.SetRange(0, 999); m_departure_delay_spin.SetRange(0, 999); initialize_data(1); return r; } void wing_editor::OnInitMenu(CMenu* pMenu) { CMenu *m; m = pMenu->GetSubMenu(0); clear_menu(m); generate_wing_popup_menu(m, ID_WING_MENU, MF_ENABLED); if (cur_wing != -1) m->CheckMenuItem(ID_WING_MENU + cur_wing, MF_BYCOMMAND | MF_CHECKED); CDialog::OnInitMenu(pMenu); } void wing_editor::OnOK() { HWND h; CWnd *w; w = GetFocus(); if (w) { h = w->m_hWnd; GetDlgItem(IDC_ARRIVAL_TREE)->SetFocus(); ::SetFocus(h); } } void wing_editor::OnClose() { if (verify() && (!bypass_errors)) { SetWindowPos(&wndTop, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE); bypass_errors = 0; return; } if (update_data()) { SetWindowPos(&wndTop, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE); bypass_errors = 0; return; } SetWindowPos(Fred_main_wnd, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_HIDEWINDOW); Fred_main_wnd->SetWindowPos(&wndTop, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); FREDDoc_ptr->autosave("wing editor"); } // initialize everything that update_data_safe() saves. void wing_editor::initialize_data_safe(int full_update) { int i, enable = TRUE, player_wing = 0, player_enabled = 1, waves_enabled = 1; CComboBox *arrival_box, *departure_box; nprintf(("Fred routing", "Wing dialog load safe\n")); if (!GetSafeHwnd()) return; arrival_box = (CComboBox *) GetDlgItem(IDC_ARRIVAL_TARGET); departure_box = (CComboBox *)GetDlgItem(IDC_DEPARTURE_TARGET); m_ignore_count = 0; if (cur_wing < 0) { m_wing_squad_filename = _T(""); m_wing_display_name = _T(""); m_special_ship = -1; m_formation = 0; m_formation_scale = _T("1.0"); m_arrival_location = -1; m_departure_location = -1; m_arrival_delay = 0; m_arrival_delay_min = 0; m_arrival_delay_max = 0; m_arrival_dist = 0; m_arrival_target = -1; m_departure_target = -1; m_departure_delay = 0; m_arrival_tree.clear_tree(); m_departure_tree.clear_tree(); m_arrival_tree.DeleteAllItems(); m_departure_tree.DeleteAllItems(); m_reinforcement = FALSE; m_hotkey = 0; m_ignore_count = 0; m_no_arrival_music = FALSE; m_no_arrival_message = FALSE; m_no_first_wave_message = FALSE; m_no_arrival_warp = FALSE; m_no_departure_warp = FALSE; m_same_arrival_warp_when_docked = FALSE; m_same_departure_warp_when_docked = FALSE; m_no_dynamic = 0; waves_enabled = player_enabled = enable = FALSE; } else { CComboBox *ptr; if ((Player_start_shipnum >= 0) && (Player_start_shipnum < MAX_SHIPS) && (Ships[Player_start_shipnum].objnum >= 0)) if (Ships[Player_start_shipnum].wingnum == cur_wing) player_wing = 1; if (The_mission.game_type & MISSION_TYPE_MULTI) { if (The_mission.game_type & MISSION_TYPE_MULTI_TEAMS) { for (i=0; i"; m_special_ship = Wings[cur_wing].special_ship; m_waves = Wings[cur_wing].num_waves; m_threshold = Wings[cur_wing].threshold; m_formation = Wings[cur_wing].formation + 1; // there doesn't seem to be an easier way to do this m_formation_scale.Format(INPUT_FORMAT, Wings[cur_wing].formation_scale); m_formation_scale.TrimRight('0'); if (m_formation_scale.Right(1) == CString(".")) m_formation_scale.Append("0"); m_arrival_location = static_cast(Wings[cur_wing].arrival_location); m_departure_location = static_cast(Wings[cur_wing].departure_location); m_arrival_delay = Wings[cur_wing].arrival_delay; m_arrival_delay_min = Wings[cur_wing].wave_delay_min; m_arrival_delay_max = Wings[cur_wing].wave_delay_max; m_arrival_dist = Wings[cur_wing].arrival_distance; m_arrival_target = anchor_to_target(Wings[cur_wing].arrival_anchor); m_departure_target = anchor_to_target(Wings[cur_wing].departure_anchor); m_no_dynamic = (Wings[cur_wing].flags[Ship::Wing_Flags::No_dynamic])?1:0; // Add the ships/special items to the combo box here before data is updated if ( m_arrival_location == static_cast(ArrivalLocation::FROM_DOCK_BAY) ) { management_add_ships_to_combo( arrival_box, SHIPS_2_COMBO_DOCKING_BAY_ONLY ); } else { management_add_ships_to_combo( arrival_box, SHIPS_2_COMBO_SPECIAL | SHIPS_2_COMBO_ALL_SHIPS ); } // Goober5000 - gah, this is ridiculous! Prior to this point in the function (and only in this function), // m_arrival_target seems to refer to the arrival anchor. The rest of the time, it refers to the index // of the drop-down list. if (m_arrival_target >= 0) { if (m_arrival_target & ANCHOR_SPECIAL_ARRIVAL) { // figure out what the box represents this as char tmp[NAME_LENGTH + 15]; stuff_special_arrival_anchor_name(tmp, m_arrival_target, false); // find it in the box m_arrival_target = arrival_box->FindStringExact(-1, tmp); } else { // find it in the box m_arrival_target = arrival_box->FindStringExact(-1, Ships[m_arrival_target].ship_name); } } // add the ships to the departure target combo box if ( m_departure_location == static_cast(DepartureLocation::TO_DOCK_BAY) ) { management_add_ships_to_combo( departure_box, SHIPS_2_COMBO_DOCKING_BAY_ONLY ); } else { departure_box->ResetContent(); } if ( m_departure_target >= 0 ) m_departure_target = departure_box->FindStringExact(-1, Ships[m_departure_target].ship_name); m_departure_delay = Wings[cur_wing].departure_delay; m_arrival_tree.load_tree(Wings[cur_wing].arrival_cue); m_departure_tree.load_tree(Wings[cur_wing].departure_cue, "false"); m_hotkey = Wings[cur_wing].hotkey+1; if (Wings[cur_wing].flags[Ship::Wing_Flags::Ignore_count]) m_ignore_count = 1; else m_ignore_count = 0; m_no_arrival_music = Wings[cur_wing].flags[Ship::Wing_Flags::No_arrival_music] ? TRUE : FALSE; m_no_arrival_message = Wings[cur_wing].flags[Ship::Wing_Flags::No_arrival_message] ? TRUE : FALSE; m_no_first_wave_message = Wings[cur_wing].flags[Ship::Wing_Flags::No_first_wave_message] ? TRUE : FALSE; m_no_arrival_warp = Wings[cur_wing].flags[Ship::Wing_Flags::No_arrival_warp] ? TRUE : FALSE; m_no_departure_warp = Wings[cur_wing].flags[Ship::Wing_Flags::No_departure_warp] ? TRUE : FALSE; m_same_arrival_warp_when_docked = Wings[cur_wing].flags[Ship::Wing_Flags::Same_arrival_warp_when_docked] ? TRUE : FALSE; m_same_departure_warp_when_docked = Wings[cur_wing].flags[Ship::Wing_Flags::Same_departure_warp_when_docked] ? TRUE : FALSE; ptr = (CComboBox *) GetDlgItem(IDC_WING_SPECIAL_SHIP); ptr->ResetContent(); for (i=0; iAddString(Ships[Wings[cur_wing].ship_index[i]].ship_name); m_threshold_spin.SetRange(0, static_cast(calc_max_wave_treshold())); i = find_item_with_string(Reinforcements, &reinforcements::name, Wings[cur_wing].name); if (i >= 0) m_reinforcement = TRUE; else m_reinforcement = FALSE; } if (full_update) UpdateData(FALSE); GetDlgItem(IDC_WING_NAME)->EnableWindow(enable); GetDlgItem(IDC_WING_SQUAD_LOGO_BUTTON)->EnableWindow(enable); GetDlgItem(IDC_WING_SPECIAL_SHIP)->EnableWindow(enable); GetDlgItem(IDC_WING_WAVES)->EnableWindow(waves_enabled); GetDlgItem(IDC_WING_WAVE_THRESHOLD)->EnableWindow(waves_enabled); GetDlgItem(IDC_DISBAND_WING)->EnableWindow(enable); GetDlgItem(IDC_SPIN_WAVES)->EnableWindow(waves_enabled); GetDlgItem(IDC_SPIN_WAVE_THRESHOLD)->EnableWindow(waves_enabled); GetDlgItem(IDC_WING_FORMATION)->EnableWindow(enable); GetDlgItem(IDC_WING_FORMATION_ALIGN)->EnableWindow(enable); GetDlgItem(IDC_WING_FORMATION_SCALE)->EnableWindow(enable); GetDlgItem(IDC_ARRIVAL_LOCATION)->EnableWindow(enable); GetDlgItem(IDC_ARRIVAL_DELAY)->EnableWindow(player_enabled); GetDlgItem(IDC_ARRIVAL_DELAY_MIN)->EnableWindow(player_enabled); GetDlgItem(IDC_ARRIVAL_DELAY_MAX)->EnableWindow(player_enabled); GetDlgItem(IDC_ARRIVAL_DELAY_SPIN)->EnableWindow(player_enabled); if (m_arrival_location) { GetDlgItem(IDC_ARRIVAL_DISTANCE)->EnableWindow(enable); GetDlgItem(IDC_ARRIVAL_TARGET)->EnableWindow(enable); } else { GetDlgItem(IDC_ARRIVAL_DISTANCE)->EnableWindow(FALSE); GetDlgItem(IDC_ARRIVAL_TARGET)->EnableWindow(FALSE); } if (m_arrival_location == static_cast(ArrivalLocation::FROM_DOCK_BAY)) { GetDlgItem(IDC_RESTRICT_ARRIVAL)->EnableWindow(enable); GetDlgItem(IDC_CUSTOM_WARPIN_PARAMS)->EnableWindow(FALSE); } else { GetDlgItem(IDC_RESTRICT_ARRIVAL)->EnableWindow(FALSE); GetDlgItem(IDC_CUSTOM_WARPIN_PARAMS)->EnableWindow(enable); } GetDlgItem(IDC_NO_DYNAMIC)->EnableWindow(enable); if (m_departure_location) { GetDlgItem(IDC_DEPARTURE_TARGET)->EnableWindow(enable); } else { GetDlgItem(IDC_DEPARTURE_TARGET)->EnableWindow(FALSE); } if (m_departure_location == static_cast(DepartureLocation::TO_DOCK_BAY)) { GetDlgItem(IDC_RESTRICT_DEPARTURE)->EnableWindow(enable); GetDlgItem(IDC_CUSTOM_WARPOUT_PARAMS)->EnableWindow(FALSE); } else { GetDlgItem(IDC_RESTRICT_DEPARTURE)->EnableWindow(FALSE); GetDlgItem(IDC_CUSTOM_WARPOUT_PARAMS)->EnableWindow(enable); } // the player wing must be present at mission start, so its arrival cue is only editable // if it has multiple waves (where the cue governs the arrival of subsequent waves) if (player_wing) GetDlgItem(IDC_ARRIVAL_TREE)->EnableWindow(m_waves > 1); else GetDlgItem(IDC_ARRIVAL_TREE)->EnableWindow(enable); GetDlgItem(IDC_DEPARTURE_LOCATION)->EnableWindow(enable); GetDlgItem(IDC_DEPARTURE_DELAY)->EnableWindow(enable); GetDlgItem(IDC_DEPARTURE_DELAY_SPIN)->EnableWindow(enable); GetDlgItem(IDC_DEPARTURE_TREE)->EnableWindow(enable); GetDlgItem(IDC_GOALS2)->EnableWindow(enable); GetDlgItem(IDC_DELETE_WING)->EnableWindow(enable); GetDlgItem(IDC_REINFORCEMENT)->EnableWindow(enable); GetDlgItem(IDC_HOTKEY)->EnableWindow(enable); GetDlgItem(IDC_IGNORE_COUNT)->EnableWindow(enable); GetDlgItem(IDC_NO_ARRIVAL_MUSIC)->EnableWindow(enable); GetDlgItem(IDC_NO_ARRIVAL_MESSAGE)->EnableWindow(enable); GetDlgItem(IDC_NO_FIRST_WAVE_MESSAGE)->EnableWindow(enable); GetDlgItem(IDC_NO_ARRIVAL_WARP)->EnableWindow(enable); GetDlgItem(IDC_NO_DEPARTURE_WARP)->EnableWindow(enable); GetDlgItem(IDC_SAME_ARRIVAL_WARP_WHEN_DOCKED)->EnableWindow(enable); GetDlgItem(IDC_SAME_DEPARTURE_WARP_WHEN_DOCKED)->EnableWindow(enable); if (cur_wing >= 0) { enable = TRUE; // check to see if the wing has a ship which is not a fighter/bomber type. If so, then disable // the wing_waves and wing_threshold stuff for (i = 0; i < Wings[cur_wing].wave_count; i++ ) { if ( !(Ship_info[Ships[Wings[cur_wing].ship_index[i]].ship_info_index].is_fighter_bomber() )) enable = FALSE; } } else enable = FALSE; } void wing_editor::initialize_data(int full_update) { int i; CWnd *w = NULL; nprintf(("Fred routing", "Wing dialog load\n")); if (!GetSafeHwnd()) return; m_arrival_tree.select_sexp_node = m_departure_tree.select_sexp_node = select_sexp_node; select_sexp_node = -1; if (cur_wing == -1) m_wing_name = _T(""); else m_wing_name = _T(Wings[cur_wing].name); initialize_data_safe(full_update); modified = 0; if (w) w -> SetFocus(); i = m_arrival_tree.select_sexp_node; if (i != -1) { w = GetDlgItem(IDC_ARRIVAL_TREE); m_arrival_tree.hilite_item(i); } else { i = m_departure_tree.select_sexp_node; if (i != -1) { w = GetDlgItem(IDC_DEPARTURE_TREE); m_departure_tree.hilite_item(i); } } } // update wing structure(s) with dialog data. The data is first checked for errors. If // no errors occur, returns 0. If an error occurs, returns -1. If the update is bypassed, // returns 1. Bypass is necessary to avoid an infinite loop, and it doesn't actually // update the data. Bypass only occurs if bypass mode is active and we still get an error. // Once the error no longer occurs, bypass mode is cleared and data is updated. int wing_editor::update_data(int redraw) { char *str, old_name[255], buf[512]; int i, z; nprintf(("Fred routing", "Wing dialog save\n")); if (!GetSafeHwnd()) return 0; UpdateData(TRUE); UpdateData(TRUE); m_wing_name.TrimLeft(); m_wing_name.TrimRight(); if (cur_wing >= 0) { SCP_string conflict = check_name_conflict("wing", m_wing_name, -1, cur_wing); if (!conflict.empty()) { if (bypass_errors) return 1; bypass_errors = 1; CString msg; msg.Format("%s\nPress OK to restore old name", conflict.c_str()); z = MessageBox(msg, "Error", MB_ICONEXCLAMATION | MB_OKCANCEL); if (z == IDCANCEL) return -1; m_wing_name = _T(Wings[cur_wing].name); UpdateData(FALSE); } strcpy_s(old_name, Wings[cur_wing].name); string_copy(Wings[cur_wing].name, m_wing_name, NAME_LENGTH, 1); lcl_fred_replace_stuff(m_wing_display_name); // the display name was precalculated, so now just assign it if (m_wing_display_name == m_wing_name || m_wing_display_name.CompareNoCase("") == 0) { if (Wings[cur_wing].has_display_name()) set_modified(); Wings[cur_wing].display_name = ""; Wings[cur_wing].flags.remove(Ship::Wing_Flags::Has_display_name); } else { if (!Wings[cur_wing].has_display_name() || Wings[cur_wing].display_name != (LPCSTR)m_wing_display_name) set_modified(); Wings[cur_wing].display_name = m_wing_display_name; Wings[cur_wing].flags.set(Ship::Wing_Flags::Has_display_name); } update_data_safe(); update_custom_wing_indexes(); bypass_errors = 0; modified = 0; str = Wings[cur_wing].name; if (strcmp(old_name, str)) { update_sexp_references(old_name, str); ai_update_goal_references(sexp_ref_type::WING, old_name, str); update_texture_replacements(old_name, str); i = find_item_with_string(Reinforcements, &reinforcements::name, old_name); if (i >= 0) strcpy_s(Reinforcements[i].name, str); for (i=0; i calc_max_wave_treshold()) { m_threshold = calc_max_wave_treshold(); if (!bypass_errors) { sprintf(buf, "Wave threshold is set too high. Value has been lowered to %d", (int) m_threshold); MessageBox(buf); } } if (m_waves < 1) { m_waves = 1; if (!bypass_errors) { sprintf(buf, "Number of waves illegal. Can not have %d waves. Number of waves has as been set to 1.", (int) m_waves); MessageBox(buf); } } MODIFY(Wings[cur_wing].special_ship, m_special_ship); MODIFY(Wings[cur_wing].num_waves, m_waves); 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].arrival_location, static_cast(m_arrival_location)); MODIFY(Wings[cur_wing].departure_location, static_cast(m_departure_location)); MODIFY(Wings[cur_wing].arrival_delay, m_arrival_delay); if (m_arrival_delay_min > m_arrival_delay_max) { if (!bypass_errors) { sprintf(buf, "Arrival delay minimum greater than maximum. Value lowered to %d", m_arrival_delay_max); MessageBox(buf); } m_arrival_delay_min = m_arrival_delay_max; } MODIFY(Wings[cur_wing].wave_delay_min, m_arrival_delay_min); MODIFY(Wings[cur_wing].wave_delay_max, m_arrival_delay_max); MODIFY(Wings[cur_wing].arrival_distance, m_arrival_dist); if (m_arrival_target >= 0) { i = (int)((CComboBox *) GetDlgItem(IDC_ARRIVAL_TARGET))->GetItemData(m_arrival_target); MODIFY(Wings[cur_wing].arrival_anchor, target_to_anchor(i)); // when arriving near or in front of a ship, be sure that we are far enough away from it!!! if (((m_arrival_location != static_cast(ArrivalLocation::AT_LOCATION)) && (m_arrival_location != static_cast(ArrivalLocation::FROM_DOCK_BAY))) && (i >= 0) && !(i & ANCHOR_SPECIAL_ARRIVAL)) { d = int(std::min(MIN_TARGET_ARRIVAL_DISTANCE, MIN_TARGET_ARRIVAL_MULTIPLIER * Objects[Ships[i].objnum].radius)); if ((Wings[cur_wing].arrival_distance < d) && (Wings[cur_wing].arrival_distance > -d)) { if (!bypass_errors) { sprintf(buf, "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, (int)(MIN_TARGET_ARRIVAL_MULTIPLIER * Objects[Ships[i].objnum].radius) ); MessageBox(buf); } if (Wings[cur_wing].arrival_distance < 0) Wings[cur_wing].arrival_distance = -d; else Wings[cur_wing].arrival_distance = d; m_arrival_dist = Wings[cur_wing].arrival_distance; } } } if (m_departure_target >= 0) { i = (int)((CComboBox *) GetDlgItem(IDC_DEPARTURE_TARGET))->GetItemData(m_departure_target); MODIFY(Wings[cur_wing].departure_anchor, target_to_anchor(i)); } MODIFY(Wings[cur_wing].departure_delay, m_departure_delay); hotkey = m_hotkey - 1; MODIFY(Wings[cur_wing].hotkey, hotkey); if (m_ignore_count) { if (!(Wings[cur_wing].flags[Ship::Wing_Flags::Ignore_count])) set_modified(); Wings[cur_wing].flags.set(Ship::Wing_Flags::Ignore_count); } else { if (Wings[cur_wing].flags[Ship::Wing_Flags::Ignore_count]) set_modified(); Wings[cur_wing].flags.remove(Ship::Wing_Flags::Ignore_count); } if (m_no_arrival_music) { if (!(Wings[cur_wing].flags[Ship::Wing_Flags::No_arrival_music])) set_modified(); Wings[cur_wing].flags.set(Ship::Wing_Flags::No_arrival_music); } else { if (Wings[cur_wing].flags[Ship::Wing_Flags::No_arrival_music]) set_modified(); Wings[cur_wing].flags.remove(Ship::Wing_Flags::No_arrival_music); } // check the no message flag if (m_no_arrival_message) { if (!(Wings[cur_wing].flags[Ship::Wing_Flags::No_arrival_message])) set_modified(); Wings[cur_wing].flags.set(Ship::Wing_Flags::No_arrival_message); } else { if (Wings[cur_wing].flags[Ship::Wing_Flags::No_arrival_message]) set_modified(); Wings[cur_wing].flags.remove(Ship::Wing_Flags::No_arrival_message); } if (m_no_first_wave_message) { if (!(Wings[cur_wing].flags[Ship::Wing_Flags::No_first_wave_message])) set_modified(); Wings[cur_wing].flags.set(Ship::Wing_Flags::No_first_wave_message); } else { if (Wings[cur_wing].flags[Ship::Wing_Flags::No_first_wave_message]) set_modified(); Wings[cur_wing].flags.remove(Ship::Wing_Flags::No_first_wave_message); } // set the no warp effect for wings flag if (m_no_arrival_warp) { if (!(Wings[cur_wing].flags[Ship::Wing_Flags::No_arrival_warp])) set_modified(); Wings[cur_wing].flags.set(Ship::Wing_Flags::No_arrival_warp); } else { if (Wings[cur_wing].flags[Ship::Wing_Flags::No_arrival_warp]) set_modified(); Wings[cur_wing].flags.remove(Ship::Wing_Flags::No_arrival_warp); } // set the no warp effect for wings flag if (m_no_departure_warp) { if (!(Wings[cur_wing].flags[Ship::Wing_Flags::No_departure_warp])) set_modified(); Wings[cur_wing].flags.set(Ship::Wing_Flags::No_departure_warp); } else { if (Wings[cur_wing].flags[Ship::Wing_Flags::No_departure_warp]) set_modified(); Wings[cur_wing].flags.remove(Ship::Wing_Flags::No_departure_warp); } // set the same warp effect for wings flag if (m_same_arrival_warp_when_docked) { if (!(Wings[cur_wing].flags[Ship::Wing_Flags::Same_arrival_warp_when_docked])) set_modified(); Wings[cur_wing].flags.set(Ship::Wing_Flags::Same_arrival_warp_when_docked); } else { if (Wings[cur_wing].flags[Ship::Wing_Flags::Same_arrival_warp_when_docked]) set_modified(); Wings[cur_wing].flags.remove(Ship::Wing_Flags::Same_arrival_warp_when_docked); } // set the same warp effect for wings flag if (m_same_departure_warp_when_docked) { if (!(Wings[cur_wing].flags[Ship::Wing_Flags::Same_departure_warp_when_docked])) set_modified(); Wings[cur_wing].flags.set(Ship::Wing_Flags::Same_departure_warp_when_docked); } else { if (Wings[cur_wing].flags[Ship::Wing_Flags::Same_departure_warp_when_docked]) set_modified(); Wings[cur_wing].flags.remove(Ship::Wing_Flags::Same_departure_warp_when_docked); } if (m_no_dynamic) { if (!(Wings[cur_wing].flags[Ship::Wing_Flags::No_dynamic])) set_modified(); Wings[cur_wing].flags.set(Ship::Wing_Flags::No_dynamic); } else { if (Wings[cur_wing].flags[Ship::Wing_Flags::No_dynamic]) set_modified(); Wings[cur_wing].flags.remove(Ship::Wing_Flags::No_dynamic); } if (Wings[cur_wing].arrival_cue >= 0) free_sexp2(Wings[cur_wing].arrival_cue); Wings[cur_wing].arrival_cue = m_arrival_tree._model.save_tree(); if (Wings[cur_wing].departure_cue >= 0) free_sexp2(Wings[cur_wing].departure_cue); Wings[cur_wing].departure_cue = m_departure_tree._model.save_tree(); // copy squad stuff if(stricmp(m_wing_squad_filename, Wings[cur_wing].wing_squad_filename)) { string_copy(Wings[cur_wing].wing_squad_filename, m_wing_squad_filename, MAX_FILENAME_LEN - 1); set_modified(); } if (modified) set_modified(); } BOOL wing_editor::OnCommand(WPARAM wParam, LPARAM lParam) { int id, wing; id = LOWORD(wParam); if (id >= ID_WING_MENU && id < ID_WING_MENU + MAX_WINGS) { if (!update_data()) { wing = id - ID_WING_MENU; mark_wing(wing); return 1; } } return CDialog::OnCommand(wParam, lParam); } void wing_editor::OnDeltaposSpinWaves(NMHDR* pNMHDR, LRESULT* pResult) { int new_pos; NM_UPDOWN* pNMUpDown = (NM_UPDOWN*)pNMHDR; new_pos = pNMUpDown->iPos + pNMUpDown->iDelta; if (new_pos > 0 && new_pos < 100) { *pResult = 0; modified = 1; } else *pResult = 1; } void wing_editor::OnRclickArrivalTree(NMHDR* pNMHDR, LRESULT* pResult) { m_arrival_tree.right_clicked(); *pResult = 0; } void wing_editor::OnRclickDepartureTree(NMHDR* pNMHDR, LRESULT* pResult) { m_departure_tree.right_clicked(); *pResult = 0; } void wing_editor::OnBeginlabeleditArrivalTree(NMHDR* pNMHDR, LRESULT* pResult) { TV_DISPINFO* pTVDispInfo = (TV_DISPINFO*)pNMHDR; if (m_arrival_tree.edit_label(pTVDispInfo->item.hItem) == 1) { *pResult = 0; modified = 1; } else *pResult = 1; } void wing_editor::OnBeginlabeleditDepartureTree(NMHDR* pNMHDR, LRESULT* pResult) { TV_DISPINFO* pTVDispInfo = (TV_DISPINFO*)pNMHDR; if (m_departure_tree.edit_label(pTVDispInfo->item.hItem) == 1) { *pResult = 0; modified = 1; } else *pResult = 1; } void wing_editor::OnEndlabeleditArrivalTree(NMHDR* pNMHDR, LRESULT* pResult) { TV_DISPINFO* pTVDispInfo = (TV_DISPINFO*)pNMHDR; *pResult = m_arrival_tree.end_label_edit(pTVDispInfo->item); } void wing_editor::OnEndlabeleditDepartureTree(NMHDR* pNMHDR, LRESULT* pResult) { TV_DISPINFO* pTVDispInfo = (TV_DISPINFO*)pNMHDR; *pResult = m_departure_tree.end_label_edit(pTVDispInfo->item); } int wing_editor::verify() { nprintf(("Fred routing", "Wing dialog verify\n")); if (!GetSafeHwnd() || !modified) return 0; if (bypass_errors) return 1; return 0; } // delete wing and all ships that are part of the wing void wing_editor::OnDeleteWing() { modified = 0; // no need to run update checks, since wing will be gone shortly anyway. delete_wing(cur_wing); } // delete wing, but leave ships intact and wingless void wing_editor::OnDisbandWing() { modified = 0; // no need to run update checks, since wing will be gone shortly anyway. disband_wing(cur_wing); } void wing_editor::OnGoals2() { ShipGoalsDlg dlg_goals; Assert(cur_wing != -1); dlg_goals.self_wing = cur_wing; dlg_goals.DoModal(); if (query_initial_orders_conflict(cur_wing)) MessageBox("One or more ships of this wing also has initial orders", "Possible conflict"); } void wing_editor::OnReinforcement() { UpdateData(TRUE); UpdateData(TRUE); //if (m_reinforcement) // m_arrival_tree.clear_tree("false"); } void wing_editor::OnPrev() { int wing, count = 0; if (!update_data() && Num_wings) { wing = cur_wing - 1; if (wing < 0) wing = MAX_WINGS - 1; while (!Wings[wing].wave_count) { wing--; if (count++ > MAX_WINGS) return; if (wing < 0) wing = MAX_WINGS - 1; } mark_wing(wing); Wing_editor_dialog.initialize_data(1); Update_wing = 0; } return; } void wing_editor::OnNext() { int wing, count = 0; if (!update_data() && Num_wings) { wing = cur_wing + 1; if (wing >= MAX_WINGS) wing = 0; while (!Wings[wing].wave_count) { wing++; if (count++ > MAX_WINGS) return; if (wing >= MAX_WINGS) wing = 0; } mark_wing(wing); Wing_editor_dialog.initialize_data(1); Update_wing = 0; } return; } void wing_editor::OnSelchangedArrivalTree(NMHDR* pNMHDR, LRESULT* pResult) { HTREEITEM h; NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR; h = pNMTreeView->itemNew.hItem; if (h) m_arrival_tree.update_help(h); *pResult = 0; } void wing_editor::OnSelchangedDepartureTree(NMHDR* pNMHDR, LRESULT* pResult) { HTREEITEM h; NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR; h = pNMTreeView->itemNew.hItem; if (h) m_departure_tree.update_help(h); *pResult = 0; } void wing_editor::calc_help_height() { CRect minihelp, help; GetDlgItem(IDC_MINI_HELP_BOX)->GetWindowRect(minihelp); GetDlgItem(IDC_HELP_BOX)->GetWindowRect(help); help_height = (help.bottom - minihelp.top) + 10; } void wing_editor::calc_cue_height() { CRect cue; GetDlgItem(IDC_CUE_FRAME)->GetWindowRect(cue); cue_height = (cue.bottom - cue.top) + 1; } void wing_editor::show_hide_sexp_help() { CRect rect; if (((CButton *) GetDlgItem(IDC_HIDE_CUES)) -> GetCheck()) return; GetWindowRect(rect); if (Show_sexp_help) rect.bottom += help_height; else rect.bottom -= help_height; MoveWindow(rect); } void wing_editor::show_hide_cues() { ((CButton*)GetDlgItem(IDC_HIDE_CUES))->SetCheck(Hide_wing_cues ? TRUE : FALSE); OnHideCues(); } void wing_editor::OnHideCues() { CRect rect; GetWindowRect(rect); if (((CButton *) GetDlgItem(IDC_HIDE_CUES)) -> GetCheck()) { rect.bottom -= cue_height; if (Show_sexp_help) rect.bottom -= help_height; Hide_wing_cues = 1; } else { rect.bottom += cue_height; if (Show_sexp_help) rect.bottom += help_height; Hide_wing_cues = 0; } MoveWindow(rect); } void wing_editor::OnSelchangeArrivalLocation() { CComboBox *box; box = (CComboBox *)GetDlgItem(IDC_ARRIVAL_TARGET); UpdateData(); if (m_arrival_location) { GetDlgItem(IDC_ARRIVAL_DISTANCE)->EnableWindow(TRUE); GetDlgItem(IDC_ARRIVAL_TARGET)->EnableWindow(TRUE); if (m_arrival_target < 0) { m_arrival_target = 0; } // determine which items we should put into the arrival target combo box if ( m_arrival_location == static_cast(ArrivalLocation::FROM_DOCK_BAY) ) { management_add_ships_to_combo( box, SHIPS_2_COMBO_DOCKING_BAY_ONLY ); } else { management_add_ships_to_combo( box, SHIPS_2_COMBO_SPECIAL | SHIPS_2_COMBO_ALL_SHIPS ); } } else { m_arrival_target = -1; GetDlgItem(IDC_ARRIVAL_DISTANCE)->EnableWindow(FALSE); GetDlgItem(IDC_ARRIVAL_TARGET)->EnableWindow(FALSE); } if (m_arrival_location == static_cast(ArrivalLocation::FROM_DOCK_BAY)) { GetDlgItem(IDC_RESTRICT_ARRIVAL)->EnableWindow(TRUE); GetDlgItem(IDC_CUSTOM_WARPIN_PARAMS)->EnableWindow(FALSE); } else { GetDlgItem(IDC_RESTRICT_ARRIVAL)->EnableWindow(FALSE); GetDlgItem(IDC_CUSTOM_WARPIN_PARAMS)->EnableWindow(TRUE); } UpdateData(FALSE); } void wing_editor::OnSelchangeDepartureLocation() { CComboBox *box; box = (CComboBox *)GetDlgItem(IDC_DEPARTURE_TARGET); UpdateData(); if (m_departure_location) { GetDlgItem(IDC_DEPARTURE_TARGET)->EnableWindow(TRUE); if (m_departure_target < 0) { m_departure_target = 0; } // we need to build up the list box content based on the departure type. When // from a docking bay, only show ships in the list which have them. Show all ships otherwise if ( m_departure_location == static_cast(DepartureLocation::TO_DOCK_BAY) ) { management_add_ships_to_combo( box, SHIPS_2_COMBO_DOCKING_BAY_ONLY ); } else { // I think that this section is currently illegal Int3(); } } else { m_departure_target = -1; GetDlgItem(IDC_DEPARTURE_TARGET)->EnableWindow(FALSE); } if (m_departure_location == static_cast(DepartureLocation::TO_DOCK_BAY)) { GetDlgItem(IDC_RESTRICT_DEPARTURE)->EnableWindow(TRUE); GetDlgItem(IDC_CUSTOM_WARPOUT_PARAMS)->EnableWindow(FALSE); } else { GetDlgItem(IDC_RESTRICT_DEPARTURE)->EnableWindow(FALSE); GetDlgItem(IDC_CUSTOM_WARPOUT_PARAMS)->EnableWindow(TRUE); } UpdateData(FALSE); } // see if hotkey should possibly be reserved for player starting wing void wing_editor::OnSelchangeHotkey() { char buf[256]; int set_num, i; UpdateData(TRUE); set_num = m_hotkey - 1; // hotkey sets are 1 index based // first, determine if we are currently working with a starting wing for ( i = 0; i < MAX_STARTING_WINGS; i++ ) { if ( !stricmp( Wings[cur_wing].name, Starting_wing_names[i]) ) break; } if ( i == MAX_STARTING_WINGS ) return; // we have a player starting wing. See if we assigned a non-standard hotkey if ( (set_num >= MAX_STARTING_WINGS) || (set_num != i) ) { sprintf(buf, "Assigning nonstandard hotkey to wing %s (default is F%d)", Wings[cur_wing].name, 5+i); MessageBox(buf, NULL, MB_OK | MB_ICONEXCLAMATION ); } } void wing_editor::OnSquadLogo() { int z; char *Logo_ext = "Image Files (*.dds, *.pcx)|*.dds;*.pcx|" "DDS Files (*.dds)|*.dds|" "PCX Files (*.pcx)|*.pcx|" "All Files (*.*)|*.*|" "|"; //phreak 05/05/2003 //this needs to be here or else the data in the wing editor dialog will revert //to what it was before it was opened. UpdateData(TRUE); // get list of squad images z = cfile_push_chdir(CF_TYPE_SQUAD_IMAGES); CFileDialog dlg(TRUE, NULL, NULL, OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR, Logo_ext); // if we have a result if (dlg.DoModal() == IDOK) { m_wing_squad_filename = dlg.GetFileName(); } else { m_wing_squad_filename = _T(""); } UpdateData(FALSE); // restore directory if (!z){ cfile_pop_dir(); } } // Goober5000 void wing_editor::OnRestrictArrival() { int arrive_from_ship; CComboBox *box; restrict_paths dlg; // grab stuff from GUI UpdateData(TRUE); if (m_arrival_location != static_cast(ArrivalLocation::FROM_DOCK_BAY)) { Int3(); return; } box = (CComboBox *) GetDlgItem(IDC_ARRIVAL_TARGET); if (box->GetCount() == 0) return; arrive_from_ship = (int)box->GetItemData(m_arrival_target); if (!ship_has_hangar_bay(arrive_from_ship)) { Int3(); return; } dlg.m_arrival = true; dlg.m_ship_class = Ships[arrive_from_ship].ship_info_index; dlg.m_path_mask = &Wings[cur_wing].arrival_path_mask; dlg.DoModal(); } // Goober5000 void wing_editor::OnRestrictDeparture() { int depart_to_ship; CComboBox *box; restrict_paths dlg; // grab stuff from GUI UpdateData(TRUE); if (m_departure_location != static_cast(DepartureLocation::TO_DOCK_BAY)) { Int3(); return; } box = (CComboBox *) GetDlgItem(IDC_DEPARTURE_TARGET); if (box->GetCount() == 0) return; depart_to_ship = (int)box->GetItemData(m_departure_target); if (!ship_has_hangar_bay(depart_to_ship)) { Int3(); return; } dlg.m_arrival = false; dlg.m_ship_class = Ships[depart_to_ship].ship_info_index; dlg.m_path_mask = &Wings[cur_wing].departure_path_mask; dlg.DoModal(); } int wing_editor::calc_max_wave_treshold() { // Maximum MAX_SHIPS_PER_WING ships can be alive at any given time return std::max(0, MAX_SHIPS_PER_WING - Wings[cur_wing].wave_count); } void wing_editor::OnBnClickedCustomWarpinParams() { warp_params_dlg dlg; dlg.m_warp_in = true; dlg.DoModal(); } void wing_editor::OnBnClickedCustomWarpoutParams() { warp_params_dlg dlg; dlg.m_warp_in = false; dlg.DoModal(); } void wing_editor::OnWingFormationAlign() { auto wingp = &Wings[cur_wing]; auto leader_objp = &Objects[Ships[wingp->ship_index[0]].objnum]; // temporarily set formation in case it isn't set yet (since changes don't take effect until dialog is closed) auto old_formation = wingp->formation; auto old_formation_scale = wingp->formation_scale; UpdateData(TRUE); // read controls wingp->formation = m_formation - 1; wingp->formation_scale = (float)atof(m_formation_scale); for (int i = 1; i < wingp->wave_count; i++) { auto objp = &Objects[Ships[wingp->ship_index[i]].objnum]; get_absolute_wing_pos(&objp->pos, leader_objp, cur_wing, i, false); objp->orient = leader_objp->orient; // drag any docked partners along (no-op for undocked ships) object_moved(objp); } // roll back temporary formation wingp->formation = old_formation; wingp->formation_scale = old_formation_scale; } void wing_editor::OnChangeWingName() { // sync the edit box to the variable UpdateData(TRUE); // automatically determine or reset the display name m_wing_display_name = get_display_name_for_text_box(m_wing_name); // sync the variable to the edit box UpdateData(FALSE); } void wing_editor::OnChangeWingWaves() { if (!GetSafeHwnd() || cur_wing < 0) return; // only the player wing's arrival cue is gated on the number of waves if ((Player_start_shipnum < 0) || (Player_start_shipnum >= MAX_SHIPS) || (Ships[Player_start_shipnum].objnum < 0)) return; if (Ships[Player_start_shipnum].wingnum != cur_wing) return; // read the control directly; this notification can arrive in the middle of a DDX update, // so calling UpdateData() here would not be safe CString str; GetDlgItem(IDC_WING_WAVES)->GetWindowText(str); GetDlgItem(IDC_ARRIVAL_TREE)->EnableWindow(atoi(str) > 1); }