mirror of
https://github.com/scp-fs2open/fs2open.github.com.git
synced 2026-11-11 04:31:35 -10:00
To enforce type safety for arrival and departure locations, this converts them to enum classes. Various casts are added when appropriate to convert between the indexed and enum values.
1483 lines
43 KiB
C++
1483 lines
43 KiB
C++
/*
|
|
* 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 "globalincs/linklist.h"
|
|
#include "ai/aigoals.h"
|
|
#include "FREDView.h"
|
|
#include "starfield/starfield.h"
|
|
#include "jumpnode/jumpnode.h"
|
|
#include "cfile/cfile.h"
|
|
#include "restrictpaths.h"
|
|
#include "iff_defs/iff_defs.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_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_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)
|
|
//}}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; i<MAX_ARRIVAL_NAMES; i++)
|
|
box->AddString(Arrival_location_names[i]);
|
|
|
|
box = (CComboBox *) GetDlgItem(IDC_DEPARTURE_LOCATION);
|
|
box->ResetContent();
|
|
for (i=0; i<MAX_DEPARTURE_NAMES; i++)
|
|
box->AddString(Departure_location_names[i]);
|
|
|
|
m_hotkey = 0;
|
|
m_waves_spin.SetRange(1, 99);
|
|
m_arrival_tree.link_modified(&modified); // provide way to indicate trees are modified in dialog
|
|
m_arrival_tree.setup((CEdit *) GetDlgItem(IDC_HELP_BOX));
|
|
m_departure_tree.link_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;
|
|
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_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;
|
|
player_enabled = enable = FALSE;
|
|
|
|
} else {
|
|
CComboBox *ptr;
|
|
|
|
if (The_mission.game_type & MISSION_TYPE_MULTI)
|
|
{
|
|
if (The_mission.game_type & MISSION_TYPE_MULTI_TEAMS)
|
|
{
|
|
for (i=0; i<MAX_TVT_WINGS; i++)
|
|
{
|
|
if (cur_wing == TVT_wings[i])
|
|
player_enabled = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (i=0; i<MAX_STARTING_WINGS; i++)
|
|
{
|
|
if (cur_wing == Starting_wings[i])
|
|
player_enabled = 0;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (cur_wing == Ships[Player_start_shipnum].wingnum)
|
|
player_enabled = 0;
|
|
}
|
|
|
|
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;
|
|
|
|
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;
|
|
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<int>(Wings[cur_wing].arrival_location);
|
|
m_departure_location = static_cast<int>(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 = Wings[cur_wing].arrival_anchor;
|
|
m_departure_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<int>(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 & SPECIAL_ARRIVAL_ANCHOR_FLAG)
|
|
{
|
|
// figure out what the box represents this as
|
|
char tmp[NAME_LENGTH + 15];
|
|
stuff_special_arrival_anchor_name(tmp, m_arrival_target, 0);
|
|
|
|
// 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<int>(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;
|
|
if (player_wing)
|
|
m_arrival_tree.load_tree(Locked_sexp_true);
|
|
else
|
|
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; i<Wings[cur_wing].wave_count; i++)
|
|
ptr->AddString(Ships[Wings[cur_wing].ship_index[i]].ship_name);
|
|
|
|
m_threshold_spin.SetRange(0, static_cast<short>(calc_max_wave_treshold()));
|
|
for (i=0; i<Num_reinforcements; i++)
|
|
if (!stricmp(Reinforcements[i].name, Wings[cur_wing].name))
|
|
break;
|
|
|
|
if (i < Num_reinforcements)
|
|
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(player_enabled);
|
|
GetDlgItem(IDC_WING_WAVE_THRESHOLD)->EnableWindow(player_enabled);
|
|
GetDlgItem(IDC_DISBAND_WING)->EnableWindow(enable);
|
|
GetDlgItem(IDC_SPIN_WAVES)->EnableWindow(player_enabled);
|
|
GetDlgItem(IDC_SPIN_WAVE_THRESHOLD)->EnableWindow(player_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<int>(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<int>(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);
|
|
}
|
|
|
|
if (player_wing)
|
|
GetDlgItem(IDC_ARRIVAL_TREE)->EnableWindow(0);
|
|
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;
|
|
object *ptr;
|
|
|
|
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) {
|
|
for (i=0; i<MAX_WINGS; i++)
|
|
if (Wings[i].wave_count && !stricmp(Wings[i].name, m_wing_name) && (i != cur_wing)) {
|
|
if (bypass_errors)
|
|
return 1;
|
|
|
|
bypass_errors = 1;
|
|
z = MessageBox("This wing name is already being used by another wing\n"
|
|
"Press OK to restore old name", "Error", MB_ICONEXCLAMATION | MB_OKCANCEL);
|
|
|
|
if (z == IDCANCEL)
|
|
return -1;
|
|
|
|
m_wing_name = _T(Wings[cur_wing].name);
|
|
UpdateData(FALSE);
|
|
}
|
|
|
|
ptr = GET_FIRST(&obj_used_list);
|
|
while (ptr != END_OF_LIST(&obj_used_list)) {
|
|
if ((ptr->type == OBJ_SHIP) || (ptr->type == OBJ_START)) {
|
|
if (!stricmp(m_wing_name, Ships[ptr->instance].ship_name)) {
|
|
if (bypass_errors)
|
|
return 1;
|
|
|
|
bypass_errors = 1;
|
|
z = MessageBox("This wing name is already being used by a ship\n"
|
|
"Press OK to restore old name", "Error", MB_ICONEXCLAMATION | MB_OKCANCEL);
|
|
|
|
if (z == IDCANCEL)
|
|
return -1;
|
|
|
|
m_wing_name = _T(Wings[cur_wing].name);
|
|
UpdateData(FALSE);
|
|
}
|
|
}
|
|
|
|
ptr = GET_NEXT(ptr);
|
|
}
|
|
|
|
// We don't need to check teams. "Unknown" is a valid name and also an IFF.
|
|
|
|
for ( i=0; i < (int)Ai_tp_list.size(); i++) {
|
|
if (!stricmp(m_wing_name, Ai_tp_list[i].name))
|
|
{
|
|
if (bypass_errors)
|
|
return 1;
|
|
|
|
bypass_errors = 1;
|
|
z = MessageBox("This wing name is already being used by a target priority group.\n"
|
|
"Press OK to restore old name", "Error", MB_ICONEXCLAMATION | MB_OKCANCEL);
|
|
|
|
if (z == IDCANCEL)
|
|
return -1;
|
|
|
|
m_wing_name = _T(Wings[cur_wing].name);
|
|
UpdateData(FALSE);
|
|
}
|
|
}
|
|
|
|
if (find_matching_waypoint_list((LPCSTR) m_wing_name) != NULL)
|
|
{
|
|
if (bypass_errors)
|
|
return 1;
|
|
|
|
bypass_errors = 1;
|
|
z = MessageBox("This wing name is already being used by a waypoint path\n"
|
|
"Press OK to restore old name", "Error", MB_ICONEXCLAMATION | MB_OKCANCEL);
|
|
|
|
if (z == IDCANCEL)
|
|
return -1;
|
|
|
|
m_wing_name = _T(Wings[cur_wing].name);
|
|
UpdateData(FALSE);
|
|
}
|
|
|
|
if(jumpnode_get_by_name(m_wing_name) != NULL)
|
|
{
|
|
if (bypass_errors)
|
|
return 1;
|
|
|
|
bypass_errors = 1;
|
|
z = MessageBox("This wing name is already being used by a jump node\n"
|
|
"Press OK to restore old name", "Error", MB_ICONEXCLAMATION | MB_OKCANCEL);
|
|
|
|
if (z == IDCANCEL)
|
|
return -1;
|
|
|
|
m_wing_name = _T(Wings[cur_wing].name);
|
|
UpdateData(FALSE);
|
|
}
|
|
|
|
if (!stricmp(m_wing_name.Left(1), "<")) {
|
|
if (bypass_errors)
|
|
return 1;
|
|
|
|
bypass_errors = 1;
|
|
z = MessageBox("Wing names not allowed to begin with <\n"
|
|
"Press OK to restore old name", "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);
|
|
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);
|
|
for (i=0; i<Num_reinforcements; i++)
|
|
if (!strcmp(old_name, Reinforcements[i].name)) {
|
|
Assert(strlen(str) < NAME_LENGTH);
|
|
strcpy_s(Reinforcements[i].name, str);
|
|
}
|
|
|
|
for (i=0; i<Wings[cur_wing].wave_count; i++) {
|
|
if ((Objects[wing_objects[cur_wing][i]].type == OBJ_SHIP) || (Objects[wing_objects[cur_wing][i]].type == OBJ_START)) {
|
|
wing_bash_ship_name(buf, str, i + 1);
|
|
rename_ship(Wings[cur_wing].ship_index[i], buf);
|
|
// clear display name if we have one hanging around
|
|
Ships[Wings[cur_wing].ship_index[i]].flags.remove(Ship::Ship_Flags::Has_display_name);
|
|
}
|
|
}
|
|
|
|
Update_window = 1;
|
|
}
|
|
|
|
//Check if we're trying to add more and we've got too many.
|
|
if( (Num_reinforcements >= MAX_REINFORCEMENTS) && (m_reinforcement == 1))
|
|
{
|
|
if (bypass_errors)
|
|
return 1;
|
|
|
|
bypass_errors = 1;
|
|
|
|
char error_message[256];
|
|
sprintf(error_message, "Too many reinforcements; could not add wing '%s' to reinforcement list!", str);
|
|
MessageBox(error_message, "Error", MB_ICONEXCLAMATION | MB_OK);
|
|
|
|
//clear the flag
|
|
m_reinforcement = 0;
|
|
UpdateData(FALSE);
|
|
|
|
return -1;
|
|
|
|
}
|
|
//Otherwise, just update as normal.
|
|
else if (set_reinforcement(str, m_reinforcement) == 1)
|
|
{
|
|
free_sexp2(Wings[cur_wing].arrival_cue);
|
|
Wings[cur_wing].arrival_cue = Locked_sexp_false;
|
|
}
|
|
}
|
|
|
|
if (redraw)
|
|
update_map_window();
|
|
|
|
return 0;
|
|
}
|
|
|
|
// update parts of wing that can't fail. This is useful if for when you need to change
|
|
// something in a wing that this updates elsewhere in Fred. Normally when auto-update
|
|
// kicks in, the changes you make will be wiped out by the auto=update, so instead you
|
|
// would call this function to update the wing, make your changes, and then call the
|
|
// initialize_data_safe() function to show your changes in the dialog
|
|
void wing_editor::update_data_safe()
|
|
{
|
|
char buf[512];
|
|
int i, d, hotkey = -1;
|
|
|
|
nprintf(("Fred routing", "Wing dialog save safe\n"));
|
|
if (!GetSafeHwnd())
|
|
return;
|
|
|
|
UpdateData(TRUE);
|
|
UpdateData(TRUE);
|
|
|
|
if (cur_wing < 0)
|
|
return;
|
|
|
|
if (m_threshold > 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<ArrivalLocation>(m_arrival_location));
|
|
MODIFY(Wings[cur_wing].departure_location, static_cast<DepartureLocation>(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, 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<int>(ArrivalLocation::AT_LOCATION)) && (m_arrival_location != static_cast<int>(ArrivalLocation::FROM_DOCK_BAY))) && (i >= 0) && !(i & SPECIAL_ARRIVAL_ANCHOR_FLAG)) {
|
|
d = int(std::min(500.0f, 2.0f * 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)(2.0f * 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, 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.save_tree();
|
|
|
|
if (Wings[cur_wing].departure_cue >= 0)
|
|
free_sexp2(Wings[cur_wing].departure_cue);
|
|
Wings[cur_wing].departure_cue = m_departure_tree.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.
|
|
remove_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) + 10;
|
|
}
|
|
|
|
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<int>(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<int>(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<int>(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<int>(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<int>(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_dock_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<int>(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_dock_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()
|
|
{
|
|
const int treshold1 = Wings[cur_wing].wave_count - 1; // At least 1 ship must have died before allowing respawn
|
|
const int treshold2 = MAX_SHIPS_PER_WING - Wings[cur_wing].wave_count; // Maximum MAX_SHIPS_PER_WING ships can be alive at any given time
|
|
return std::min(treshold1, treshold2);
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
// roll back temporary formation
|
|
wingp->formation = old_formation;
|
|
wingp->formation_scale = old_formation_scale;
|
|
}
|