]> icculus.org git repositories - taylor/freespace2.git/blob - src/fred2/wing_editor.cpp
Initial revision
[taylor/freespace2.git] / src / fred2 / wing_editor.cpp
1 /*
2  * $Logfile: /Freespace2/code/fred2/wing_editor.cpp $
3  * $Revision$
4  * $Date$
5  * $Author$
6  *
7  * Wing editor dialog box handler code
8  *
9  * $Log$
10  * Revision 1.1  2002/05/03 03:28:09  root
11  * Initial revision
12  *
13  * 
14  * 3     8/16/99 10:52p Andsager
15  * Allow closer ship positioning for NEAR_SHIP ship and wing arrivals.
16  * 
17  * 2     10/07/98 6:28p Dave
18  * Initial checkin. Renamed all relevant stuff to be Fred2 instead of
19  * Fred. Globalized mission and campaign file extensions. Removed Silent
20  * Threat specific code.
21  * 
22  * 1     10/07/98 3:02p Dave
23  * 
24  * 1     10/07/98 3:00p Dave
25  * 
26  * 83    9/14/98 3:31p Allender
27  * don't allow alpha, beta, and gamma to get > 1 wave when editing a
28  * multiplayer missions
29  * 
30  * 82    6/17/98 4:50p Hoffoss
31  * Added error checking for arrival delays used on wing player is in.
32  * 
33  * 81    5/22/98 10:10a Hoffoss
34  * Fixed bug with hide cue button not working correctly.
35  * 
36  * 80    3/24/98 12:30p Allender
37  * arrival/departure target boxes were getting initialized incorrectly
38  * 
39  * 79    3/21/98 7:36p Lawrance
40  * Move jump nodes to own lib.
41  * 
42  * 78    3/16/98 8:27p Allender
43  * Fred support for two new AI flags -- kamikaze and no dynamic goals.
44  * 
45  * 77    3/10/98 6:11p Hoffoss
46  * Added jump node renaming abilities to Fred.
47  * 
48  * 76    2/23/98 9:48p Allender
49  * added no arrival/departure warps to wings
50  * 
51  * 75    12/31/97 3:56p Hoffoss
52  * Forced alpha wing to always have a true arrival cue.
53  * 
54  * 74    12/29/97 4:55p Johnson
55  * Added some fixes.
56  * 
57  * 73    12/18/97 10:40a Hoffoss
58  * Fixed bug with a few of the checkboxes not initializing properly.
59  * 
60  * 72    11/25/97 10:03a Allender
61  * added no arrival message checkbox to wing editor
62  * 
63  * 71    11/25/97 9:42a Hoffoss
64  * Removed starting wing checkbox from wing editor.
65  * 
66  * 70    11/13/97 4:14p Allender
67  * automatic assignment of hotkeys for starting wings.  Appripriate
68  * warnings when they are incorrectly used.  hotkeys correctly assigned to
69  * ships/wing arriving after mission start
70  * 
71  * 69    11/11/97 2:13p Allender
72  * docking bay support for Fred and Freespace.  Added hook to ai code for
73  * arrival/departure from dock bays.  Fred support now sufficient.
74  * 
75  * 68    11/10/97 10:13p Allender
76  * added departure anchor to Fred and Freespace in preparation for using
77  * docking bays.  Functional in Fred, not in FreeSpace.
78  * 
79  * 67    10/28/97 3:33p Hoffoss
80  * Fixed bug where <1 num_waves was being allowed to be entered into Fred.
81  * 
82  * 66    10/14/97 5:33p Hoffoss
83  * Added Fred support (and fsm support) for the no_arrival_music flags in
84  * ships and wings.
85  * 
86  * 65    10/01/97 12:37p Hoffoss
87  * Changed Fred (and FreeSpace) to utilize alpha, beta and gamma as player
88  * starting wing names.
89  * 
90  * 64    9/04/97 5:35p Hoffoss
91  * Fixed arrival distance stuff.
92  * 
93  * 63    9/04/97 5:04p Johnson
94  * Fixed bug with arrival target distance checking.
95  * 
96  * 62    9/04/97 4:30p Hoffoss
97  * Removed sexp tree info from grayed trees.
98  * 
99  * 61    8/30/97 9:52p Hoffoss
100  * Implemented arrival location, distance, and anchor in Fred.
101  * 
102  * 60    8/22/97 4:16p Hoffoss
103  * added support for arrival and departure info in ship editor using
104  * wing's info if editing marked ships in a wing instead of using ship's.
105  * 
106  * 59    8/21/97 3:20p Duncan
107  * Fixed bug in wing renaming when a player is in the wing.
108  * 
109  * 58    8/19/97 1:44p Hoffoss
110  * Fixed bug with updating too quickly (i.e. via prev and next buttons).
111  * 
112  * 57    8/15/97 5:14p Hoffoss
113  * Completely changed around how initial orders dialog worked.  It's
114  * pretty awesome now.
115  * 
116  * 56    8/15/97 11:24a Hoffoss
117  * Changed order of events.
118  * 
119  * 55    8/13/97 11:31p Hoffoss
120  * Added bound checking on min/max wave delay.
121  * 
122  * 54    8/13/97 11:22p Hoffoss
123  * Implemented wave delay min and max in Fred.
124  * 
125  * 53    8/12/97 7:17p Hoffoss
126  * Added previous button to ship and wing editors.
127  * 
128  * 52    8/12/97 6:32p Hoffoss
129  * Added code to allow hiding of arrival and departure cues in editors.
130  * 
131  * 51    8/12/97 3:33p Hoffoss
132  * Fixed the "press cancel to go to reference" code to work properly.
133  * 
134  * 50    8/12/97 1:55a Hoffoss
135  * Made extensive changes to object reference checking and handling for
136  * object deletion call.
137  * 
138  * 49    8/10/97 4:22p Hoffoss
139  * Made main display update when ships or wings are renamed.
140  * 
141  * 48    8/08/97 10:00a Hoffoss
142  * Added protection from threshold being equal or higher than the number
143  * of ships in a wing.
144  * 
145  * 47    8/01/97 2:45p Hoffoss
146  * Fixed bug with no new item in MFC CTreeCtrl selection changed message.
147  * Throught it shouldn't happen, but Whiteside made it happen.
148  * 
149  * 46    7/30/97 5:23p Hoffoss
150  * Removed Sexp tree verification code, since it duplicates normal sexp
151  * verification, and is just another set of code to keep maintained.
152  * 
153  * 45    7/30/97 12:31p Hoffoss
154  * Made improvements to ship goals editor (initial orders) to disallow
155  * illegal orders.
156  * 
157  * 44    7/28/97 2:28p Hoffoss
158  * Added bypasses to MFC integer validation routines.
159  * 
160  * 43    7/25/97 2:40p Hoffoss
161  * Fixed bug in sexp tree selection updating handling.
162  * 
163  * 42    7/24/97 4:44p Hoffoss
164  * Added sexp help to more dialogs, and changed made some changes to make
165  * it work correctly for ship and wing editors.
166  * 
167  * 41    7/18/97 2:05p Hoffoss
168  * Fixed some bugs BoundsChecker turned up.
169  * 
170  * 40    7/16/97 6:30p Hoffoss
171  * Added icons to sexp trees, mainly because I think they will be required
172  * for drag n drop.
173  * 
174  * 39    7/09/97 2:38p Allender
175  * organized ship/wing editor dialogs.  Added protect ship and ignore
176  * count checkboxes to those dialogs.  Changed flag code for
177  * parse_objects.  Added unprotect sexpressions
178  * 
179  * 38    7/08/97 10:15a Allender
180  * making ships/wings reinforcements now do not set the arrival cue to
181  * false.  A reinforcement may only be available after it's arrival cue is
182  * true
183  * 
184  * 37    7/02/97 3:30p Hoffoss
185  * Put in code to validate and bash if necessary the wing wave threshold.
186  * 
187  * 36    6/18/97 3:07p Hoffoss
188  * Wing ship names are 1 indexes instead of 0 indexed now.
189  * 
190  * 35    6/05/97 6:10p Hoffoss
191  * Added features: Autosaving, object hiding.  Also fixed some minor bugs.
192  * 
193  * 34    5/30/97 11:33a Allender
194  * more hotkey combo box stuff
195  * 
196  * 33    5/23/97 1:53p Hoffoss
197  * Fixed problems with modeless dialog updating.  It won't get caught in
198  * an infinate loop anymore, but still gives an error warning 3 times when
199  * using cancel and trying to switch window focus to main window.  Don't
200  * know if I can fix that, but it's not too critical right now.
201  * 
202  * 32    5/01/97 4:15p Hoffoss
203  * Fixed bugs.
204  * 
205  * 31    4/28/97 2:37p Hoffoss
206  * Added hotkey editing to Fred for ships and wings.
207  * 
208  * 30    4/23/97 11:55a Hoffoss
209  * Fixed many bugs uncovered while trying to create Mission 6.
210  * 
211  * 29    4/07/97 1:53p Hoffoss
212  * Fixed a few bugs, and added sexp chain duplicating for object
213  * duplicating.
214  * 
215  * 28    4/03/97 11:35a Hoffoss
216  * Fixed bugs: viewpoint didn't reset, initial orders not updated when
217  * referenced ship is renamed or deleted.
218  * 
219  * 27    4/01/97 5:15p Hoffoss
220  * Fixed errors in max length checks, renaming a wing now renames the
221  * ships in the wing as well, as it should.
222  * 
223  * 26    3/20/97 3:55p Hoffoss
224  * Major changes to how dialog boxes initialize (load) and update (save)
225  * their internal data.  This should simplify things and create less
226  * problems.
227  * 
228  * 25    3/17/97 4:29p Hoffoss
229  * Automated player's wing flaging as a starting player wing.
230  * 
231  * 24    3/05/97 10:54a Hoffoss
232  * removed special arrival/departure cue token usage in wing editor.
233  * 
234  * 23    2/28/97 11:31a Hoffoss
235  * Implemented modeless dialog saving and restoring, and changed some
236  * variables names.
237  * 
238  * 22    2/27/97 3:16p Allender
239  * major wing structure enhancement.  simplified wing code.  All around
240  * better wing support
241  * 
242  * 21    2/24/97 5:38p Hoffoss
243  * Added dialog box to name a wing at creation, code to change ship names
244  * to match wing name, and code to maintain these ship names.
245  * 
246  * 20    2/21/97 5:34p Hoffoss
247  * Added extensive modification detection and fixed a bug in initial
248  * orders editor.
249  * 
250  * 19    2/20/97 4:03p Hoffoss
251  * Several ToDo items: new reinforcement clears arrival cue, reinforcement
252  * control from ship and wing dialogs, show grid toggle.
253  * 
254  * 18    2/17/97 5:28p Hoffoss
255  * Checked RCS headers, added them were missing, changing description to
256  * something better, etc where needed.
257  *
258  * $NoKeywords: $
259  */
260
261 #include "stdafx.h"
262 #include "mainfrm.h"
263 #include "fred.h"
264 #include "freddoc.h"
265 #include "management.h"
266 #include "wing.h"
267 #include "linklist.h"
268 #include "aigoals.h"
269 #include "fredview.h"
270 #include "starfield.h"
271 #include "jumpnode.h"
272
273 #define ID_WING_MENU 9000
274
275 #ifdef _DEBUG
276 #define new DEBUG_NEW
277 #undef THIS_FILE
278 static char THIS_FILE[] = __FILE__;
279 #endif
280
281 /////////////////////////////////////////////////////////////////////////////
282 // wing_editor dialog
283
284 wing_editor::wing_editor(CWnd* pParent /*=NULL*/)
285         : CDialog(wing_editor::IDD, pParent)
286 {
287         //{{AFX_DATA_INIT(wing_editor)
288         m_wing_name = _T("");
289         m_special_ship = -1;
290         m_waves = 0;
291         m_threshold = 0;
292         m_arrival_location = -1;
293         m_departure_location = -1;
294         m_arrival_delay = 0;
295         m_departure_delay = 0;
296         m_reinforcement = FALSE;
297         m_hotkey = -1;
298         m_ignore_count = FALSE;
299         m_arrival_delay_max = 0;
300         m_arrival_delay_min = 0;
301         m_arrival_dist = 0;
302         m_arrival_target = -1;
303         m_no_arrival_music = FALSE;
304         m_departure_target = -1;
305         m_no_arrival_message = FALSE;
306         m_no_arrival_warp = FALSE;
307         m_no_departure_warp = FALSE;
308         m_no_dynamic = FALSE;
309         //}}AFX_DATA_INIT
310         modified = 0;
311         select_sexp_node = -1;
312         bypass_errors = 0;
313 }
314
315 void wing_editor::DoDataExchange(CDataExchange* pDX)
316 {
317         CString str;
318
319         CDialog::DoDataExchange(pDX);
320         //{{AFX_DATA_MAP(wing_editor)
321         DDX_Control(pDX, IDC_DEPARTURE_DELAY_SPIN, m_departure_delay_spin);
322         DDX_Control(pDX, IDC_ARRIVAL_DELAY_SPIN, m_arrival_delay_spin);
323         DDX_Control(pDX, IDC_DEPARTURE_TREE, m_departure_tree);
324         DDX_Control(pDX, IDC_ARRIVAL_TREE, m_arrival_tree);
325         DDX_Control(pDX, IDC_SPIN_WAVE_THRESHOLD, m_threshold_spin);
326         DDX_Control(pDX, IDC_SPIN_WAVES, m_waves_spin);
327         DDX_Text(pDX, IDC_WING_NAME, m_wing_name);
328         DDX_CBIndex(pDX, IDC_WING_SPECIAL_SHIP, m_special_ship);
329         DDX_CBIndex(pDX, IDC_ARRIVAL_LOCATION, m_arrival_location);
330         DDX_CBIndex(pDX, IDC_DEPARTURE_LOCATION, m_departure_location);
331         DDX_Check(pDX, IDC_REINFORCEMENT, m_reinforcement);
332         DDX_CBIndex(pDX, IDC_HOTKEY, m_hotkey);
333         DDX_Check(pDX, IDC_IGNORE_COUNT, m_ignore_count);
334         DDX_Text(pDX, IDC_ARRIVAL_DISTANCE, m_arrival_dist);
335         DDX_CBIndex(pDX, IDC_ARRIVAL_TARGET, m_arrival_target);
336         DDX_Check(pDX, IDC_NO_ARRIVAL_MUSIC, m_no_arrival_music);
337         DDX_CBIndex(pDX, IDC_DEPARTURE_TARGET, m_departure_target);
338         DDX_Check(pDX, IDC_NO_ARRIVAL_MESSAGE, m_no_arrival_message);
339         DDX_Check(pDX, IDC_NO_ARRIVAL_WARP, m_no_arrival_warp);
340         DDX_Check(pDX, IDC_NO_DEPARTURE_WARP, m_no_departure_warp);
341         DDX_Check(pDX, IDC_NO_DYNAMIC, m_no_dynamic);
342         //}}AFX_DATA_MAP
343
344         if (pDX->m_bSaveAndValidate) {  // get dialog control values
345                 GetDlgItem(IDC_ARRIVAL_DELAY)->GetWindowText(str);
346                 m_arrival_delay = atoi(str);
347                 if (m_arrival_delay < 0)
348                         m_arrival_delay = 0;
349
350                 GetDlgItem(IDC_DEPARTURE_DELAY)->GetWindowText(str);
351                 m_departure_delay = atoi(str);
352                 if (m_departure_delay < 0)
353                         m_departure_delay = 0;
354
355                 GetDlgItem(IDC_WING_WAVES)->GetWindowText(str);
356                 m_waves = atoi(str);
357                 if (m_waves < 0)
358                         m_waves = 0;
359
360                 GetDlgItem(IDC_WING_WAVE_THRESHOLD)->GetWindowText(str);
361                 m_threshold = atoi(str);
362                 if (m_threshold < 0)
363                         m_threshold = 0;
364
365                 GetDlgItem(IDC_ARRIVAL_DELAY_MIN)->GetWindowText(str);
366                 m_arrival_delay_min = atoi(str);
367                 if (m_arrival_delay_min < 0)
368                         m_arrival_delay_min = 0;
369
370                 GetDlgItem(IDC_ARRIVAL_DELAY_MAX)->GetWindowText(str);
371                 m_arrival_delay_max = atoi(str);
372                 if (m_arrival_delay_max < 0)
373                         m_arrival_delay_max = 0;
374
375         } else {
376                 DDX_Text(pDX, IDC_ARRIVAL_DELAY, m_arrival_delay);
377                 DDX_Text(pDX, IDC_DEPARTURE_DELAY, m_departure_delay);
378                 DDX_Text(pDX, IDC_WING_WAVES, m_waves);
379                 DDX_Text(pDX, IDC_WING_WAVE_THRESHOLD, m_threshold);
380                 DDX_Text(pDX, IDC_ARRIVAL_DELAY_MIN, m_arrival_delay_min);
381                 DDX_Text(pDX, IDC_ARRIVAL_DELAY_MAX, m_arrival_delay_max);
382         }
383 }
384
385 BEGIN_MESSAGE_MAP(wing_editor, CDialog)
386         //{{AFX_MSG_MAP(wing_editor)
387         ON_WM_INITMENU()
388         ON_NOTIFY(UDN_DELTAPOS, IDC_SPIN_WAVES, OnDeltaposSpinWaves)
389         ON_NOTIFY(NM_RCLICK, IDC_ARRIVAL_TREE, OnRclickArrivalTree)
390         ON_NOTIFY(NM_RCLICK, IDC_DEPARTURE_TREE, OnRclickDepartureTree)
391         ON_NOTIFY(TVN_BEGINLABELEDIT, IDC_ARRIVAL_TREE, OnBeginlabeleditArrivalTree)
392         ON_NOTIFY(TVN_BEGINLABELEDIT, IDC_DEPARTURE_TREE, OnBeginlabeleditDepartureTree)
393         ON_NOTIFY(TVN_ENDLABELEDIT, IDC_ARRIVAL_TREE, OnEndlabeleditArrivalTree)
394         ON_NOTIFY(TVN_ENDLABELEDIT, IDC_DEPARTURE_TREE, OnEndlabeleditDepartureTree)
395         ON_BN_CLICKED(IDC_DELETE_WING, OnDeleteWing)
396         ON_BN_CLICKED(IDC_DISBAND_WING, OnDisbandWing)
397         ON_WM_CLOSE()
398         ON_BN_CLICKED(IDC_GOALS2, OnGoals2)
399         ON_BN_CLICKED(IDC_REINFORCEMENT, OnReinforcement)
400         ON_BN_CLICKED(IDC_NEXT, OnNext)
401         ON_NOTIFY(TVN_SELCHANGED, IDC_ARRIVAL_TREE, OnSelchangedArrivalTree)
402         ON_NOTIFY(TVN_SELCHANGED, IDC_DEPARTURE_TREE, OnSelchangedDepartureTree)
403         ON_BN_CLICKED(IDC_HIDE_CUES, OnHideCues)
404         ON_BN_CLICKED(IDC_PREV, OnPrev)
405         ON_CBN_SELCHANGE(IDC_ARRIVAL_LOCATION, OnSelchangeArrivalLocation)
406         ON_CBN_SELCHANGE(IDC_DEPARTURE_LOCATION, OnSelchangeDepartureLocation)
407         ON_CBN_SELCHANGE(IDC_HOTKEY, OnSelchangeHotkey)
408         //}}AFX_MSG_MAP
409 END_MESSAGE_MAP()
410
411 /////////////////////////////////////////////////////////////////////////////
412 // wing_editor message handlers
413
414 BOOL wing_editor::Create()
415 {
416         BOOL r;
417         int i;
418         CComboBox *box;
419
420         r = CDialog::Create(IDD, Fred_main_wnd);
421         box = (CComboBox *) GetDlgItem(IDC_ARRIVAL_LOCATION);
422         box->ResetContent();
423         for (i=0; i<MAX_ARRIVAL_NAMES; i++)
424                 box->AddString(Arrival_location_names[i]);
425
426         box = (CComboBox *) GetDlgItem(IDC_DEPARTURE_LOCATION);
427         box->ResetContent();
428         for (i=0; i<MAX_DEPARTURE_NAMES; i++)
429                 box->AddString(Departure_location_names[i]);
430
431         m_hotkey = 0;
432         m_waves_spin.SetRange(1, 99);
433         m_arrival_tree.link_modified(&modified);  // provide way to indicate trees are modified in dialog
434         m_arrival_tree.setup((CEdit *) GetDlgItem(IDC_HELP_BOX));
435         m_departure_tree.link_modified(&modified);
436         m_departure_tree.setup();
437         m_arrival_delay_spin.SetRange(0, 999);
438         m_departure_delay_spin.SetRange(0, 999);
439
440         initialize_data(1);
441         return r;
442 }
443
444 void wing_editor::OnInitMenu(CMenu* pMenu)
445 {
446         CMenu *m;
447
448         m = pMenu->GetSubMenu(0);
449         clear_menu(m);
450         generate_wing_popup_menu(m, ID_WING_MENU, MF_ENABLED);
451         if (cur_wing != -1)
452                 m->CheckMenuItem(ID_WING_MENU + cur_wing, MF_BYCOMMAND | MF_CHECKED);
453
454         CDialog::OnInitMenu(pMenu);
455 }
456
457 void wing_editor::OnOK()
458 {
459         HWND h;
460         CWnd *w;
461
462         w = GetFocus();
463         if (w) {
464                 h = w->m_hWnd;
465                 GetDlgItem(IDC_ARRIVAL_TREE)->SetFocus();
466                 ::SetFocus(h);
467         }
468 }
469
470 void wing_editor::OnClose() 
471 {
472         if (verify() && (!bypass_errors)) {
473                 SetWindowPos(&wndTop, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
474                 bypass_errors = 0;
475                 return;
476         }
477
478         if (update_data()) {
479                 SetWindowPos(&wndTop, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
480                 bypass_errors = 0;
481                 return;
482         }
483
484         SetWindowPos(Fred_main_wnd, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_HIDEWINDOW);
485         Fred_main_wnd->SetWindowPos(&wndTop, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
486 }
487
488 // initialize everything that update_data_safe() saves.
489 void wing_editor::initialize_data_safe(int full_update)
490 {
491         int i, enable = TRUE, player_wing = 0, player_enabled = 1;
492         CComboBox *arrival_box, *departure_box;
493
494         nprintf(("Fred routing", "Wing dialog load safe\n"));
495         if (!GetSafeHwnd())
496                 return;
497
498         arrival_box = (CComboBox *) GetDlgItem(IDC_ARRIVAL_TARGET);
499         departure_box = (CComboBox *)GetDlgItem(IDC_DEPARTURE_TARGET);
500
501         m_ignore_count = 0;
502         if (cur_wing < 0) {
503                 m_special_ship = -1;
504                 m_arrival_location = -1;
505                 m_departure_location = -1;
506                 m_arrival_delay = 0;
507                 m_arrival_delay_min = 0;
508                 m_arrival_delay_max = 0;
509                 m_arrival_dist = 0;
510                 m_arrival_target = -1;
511                 m_departure_target = -1;
512                 m_departure_delay = 0;
513                 m_arrival_tree.clear_tree();
514                 m_departure_tree.clear_tree();
515                 m_arrival_tree.DeleteAllItems();
516                 m_departure_tree.DeleteAllItems();
517                 m_reinforcement = FALSE;
518                 m_hotkey = 0;
519                 m_ignore_count = 0;
520                 m_no_arrival_music = 0;
521                 m_no_arrival_message = 0;
522                 m_no_arrival_warp = 0;
523                 m_no_departure_warp = 0;
524                 m_no_dynamic = 0;
525                 player_enabled = enable = FALSE;
526
527         } else {
528                 CComboBox *ptr;
529
530                 if (cur_wing == wing_name_lookup("alpha", 1))
531                         player_enabled = 0;
532
533                 if ((The_mission.game_type & MISSION_TYPE_MULTI_TEAMS) && (cur_wing == wing_name_lookup("zeta", 1)))
534                         player_enabled = 0;
535
536                 // in multiplayer coop missions, alpha, beta, and gamma are both off limits.
537                 if ( The_mission.game_type & MISSION_TYPE_MULTI_COOP ) {
538                         if ( (cur_wing == wing_name_lookup("alpha", 1)) || (cur_wing == wing_name_lookup("beta", 1)) || (cur_wing == wing_name_lookup("gamma", 1)) ) {
539                                 player_enabled = 0;
540                         }
541                 }
542
543                 if ((Player_start_shipnum >= 0) && (Player_start_shipnum < MAX_SHIPS) && (Ships[Player_start_shipnum].objnum >= 0))
544                         if (Ships[Player_start_shipnum].wingnum == cur_wing)
545                                 player_wing = 1;
546
547                 m_special_ship = Wings[cur_wing].special_ship;
548                 m_waves = Wings[cur_wing].num_waves;
549                 m_threshold = Wings[cur_wing].threshold;
550                 m_arrival_location = Wings[cur_wing].arrival_location;
551                 m_departure_location = Wings[cur_wing].departure_location;
552                 m_arrival_delay = Wings[cur_wing].arrival_delay;
553                 m_arrival_delay_min = Wings[cur_wing].wave_delay_min;
554                 m_arrival_delay_max = Wings[cur_wing].wave_delay_max;
555                 m_arrival_dist = Wings[cur_wing].arrival_distance;
556                 m_arrival_target = Wings[cur_wing].arrival_anchor;
557                 m_departure_target = Wings[cur_wing].departure_anchor;
558                 m_no_dynamic = (Wings[cur_wing].flags & WF_NO_DYNAMIC)?1:0;
559
560                 // Add the ships/special items to the combo box here before data is updated
561                 if ( m_arrival_location == ARRIVE_FROM_DOCK_BAY ) {
562                         management_add_ships_to_combo( arrival_box, SHIPS_2_COMBO_DOCKING_BAY_ONLY );
563                 } else {
564                         management_add_ships_to_combo( arrival_box, SHIPS_2_COMBO_SPECIAL | SHIPS_2_COMBO_ALL_SHIPS );
565                 }
566
567                 if (m_arrival_target >= SPECIAL_ARRIVAL_ANCHORS_OFFSET)
568                         m_arrival_target -= SPECIAL_ARRIVAL_ANCHORS_OFFSET;
569                 else if (m_arrival_target >= 0)
570                         m_arrival_target = arrival_box->FindStringExact(-1, Ships[m_arrival_target].ship_name);
571
572                 if ( m_departure_target >= 0 )
573                         m_departure_target = departure_box->FindStringExact(-1, Ships[m_departure_target].ship_name);
574
575                 // add the ships to the departure target combo box
576                 if ( m_departure_location == DEPART_AT_DOCK_BAY ) {
577                         management_add_ships_to_combo( departure_box, SHIPS_2_COMBO_DOCKING_BAY_ONLY );
578                 } else {
579                         departure_box->ResetContent();
580                 }
581
582                 m_departure_delay = Wings[cur_wing].departure_delay;
583                 if (player_wing)
584                         m_arrival_tree.load_tree(Locked_sexp_true);
585                 else
586                         m_arrival_tree.load_tree(Wings[cur_wing].arrival_cue);
587
588                 m_departure_tree.load_tree(Wings[cur_wing].departure_cue, "false");
589                 m_hotkey = Wings[cur_wing].hotkey+1;
590                 if (Wings[cur_wing].flags & WF_IGNORE_COUNT)
591                         m_ignore_count = 1;
592                 else
593                         m_ignore_count = 0;
594
595                 if (Wings[cur_wing].flags & WF_NO_ARRIVAL_MUSIC)
596                         m_no_arrival_music = 1;
597                 else
598                         m_no_arrival_music = 0;
599
600                 if ( Wings[cur_wing].flags & WF_NO_ARRIVAL_MESSAGE )
601                         m_no_arrival_message = 1;
602                 else
603                         m_no_arrival_message = 0;
604
605                 if ( Wings[cur_wing].flags & WF_NO_ARRIVAL_WARP )
606                         m_no_arrival_warp = 1;
607                 else
608                         m_no_arrival_warp = 0;
609
610                 if ( Wings[cur_wing].flags & WF_NO_DEPARTURE_WARP )
611                         m_no_departure_warp = 1;
612                 else
613                         m_no_departure_warp = 0;
614
615                 ptr = (CComboBox *) GetDlgItem(IDC_WING_SPECIAL_SHIP);
616                 ptr->ResetContent();
617                 for (i=0; i<Wings[cur_wing].wave_count; i++)
618                         ptr->AddString(Ships[Wings[cur_wing].ship_index[i]].ship_name);
619
620                 m_threshold_spin.SetRange(0, Wings[cur_wing].wave_count - 1);
621                 for (i=0; i<Num_reinforcements; i++)
622                         if (!stricmp(Reinforcements[i].name, Wings[cur_wing].name))
623                                 break;
624
625                 if (i < Num_reinforcements)
626                         m_reinforcement = TRUE;
627                 else
628                         m_reinforcement = FALSE;
629         }
630
631         if (full_update)
632                 UpdateData(FALSE);
633
634         GetDlgItem(IDC_WING_NAME)->EnableWindow(enable);
635         GetDlgItem(IDC_WING_SPECIAL_SHIP)->EnableWindow(enable);
636         GetDlgItem(IDC_WING_WAVES)->EnableWindow(player_enabled);
637         GetDlgItem(IDC_WING_WAVE_THRESHOLD)->EnableWindow(player_enabled);
638         GetDlgItem(IDC_DISBAND_WING)->EnableWindow(enable);
639         GetDlgItem(IDC_SPIN_WAVES)->EnableWindow(player_enabled);
640         GetDlgItem(IDC_SPIN_WAVE_THRESHOLD)->EnableWindow(player_enabled);
641         GetDlgItem(IDC_ARRIVAL_LOCATION)->EnableWindow(enable);
642
643         GetDlgItem(IDC_ARRIVAL_DELAY)->EnableWindow(player_enabled);
644         GetDlgItem(IDC_ARRIVAL_DELAY_MIN)->EnableWindow(player_enabled);
645         GetDlgItem(IDC_ARRIVAL_DELAY_MAX)->EnableWindow(player_enabled);
646         GetDlgItem(IDC_ARRIVAL_DELAY_SPIN)->EnableWindow(player_enabled);
647         if (m_arrival_location) {
648                 GetDlgItem(IDC_ARRIVAL_DISTANCE)->EnableWindow(enable);
649                 GetDlgItem(IDC_ARRIVAL_TARGET)->EnableWindow(enable);
650         } else {
651                 GetDlgItem(IDC_ARRIVAL_DISTANCE)->EnableWindow(FALSE);
652                 GetDlgItem(IDC_ARRIVAL_TARGET)->EnableWindow(FALSE);
653         }
654         GetDlgItem(IDC_NO_DYNAMIC)->EnableWindow(enable);
655
656         if ( m_departure_location ) {
657                 GetDlgItem(IDC_DEPARTURE_TARGET)->EnableWindow(enable);
658         } else {
659                 GetDlgItem(IDC_DEPARTURE_TARGET)->EnableWindow(FALSE);
660         }
661
662         if (player_wing)
663                 GetDlgItem(IDC_ARRIVAL_TREE)->EnableWindow(0);
664         else
665                 GetDlgItem(IDC_ARRIVAL_TREE)->EnableWindow(enable);
666
667         GetDlgItem(IDC_DEPARTURE_LOCATION)->EnableWindow(enable);
668         GetDlgItem(IDC_DEPARTURE_DELAY)->EnableWindow(enable);
669         GetDlgItem(IDC_DEPARTURE_DELAY_SPIN)->EnableWindow(enable);
670         GetDlgItem(IDC_DEPARTURE_TREE)->EnableWindow(enable);
671         GetDlgItem(IDC_GOALS2)->EnableWindow(enable);
672         GetDlgItem(IDC_DELETE_WING)->EnableWindow(enable);
673         GetDlgItem(IDC_REINFORCEMENT)->EnableWindow(enable);
674         GetDlgItem(IDC_HOTKEY)->EnableWindow(enable);
675         GetDlgItem(IDC_IGNORE_COUNT)->EnableWindow(enable);
676         GetDlgItem(IDC_NO_ARRIVAL_MUSIC)->EnableWindow(enable);
677         GetDlgItem(IDC_NO_ARRIVAL_MESSAGE)->EnableWindow(enable);
678         GetDlgItem(IDC_NO_ARRIVAL_WARP)->EnableWindow(enable);
679         GetDlgItem(IDC_NO_DEPARTURE_WARP)->EnableWindow(enable);
680
681         if (cur_wing >= 0) {
682                 enable = TRUE;
683
684                 // check to see if the wing has a ship which is not a fighter/bomber type.  If so, then disable
685                 // the wing_waves and wing_threshold  stuff
686                 for (i = 0; i < Wings[cur_wing].wave_count; i++ ) {
687                         int sflag;
688
689                         sflag = Ship_info[Ships[Wings[cur_wing].ship_index[i]].ship_info_index].flags;
690                         if ( !(sflag & SIF_FIGHTER) && !(sflag & SIF_BOMBER) )
691                                 enable = FALSE;
692                 }
693
694         } else
695                 enable = FALSE;
696 }
697
698 void wing_editor::initialize_data(int full_update)
699 {
700         int i;
701         CWnd *w = NULL;
702
703         nprintf(("Fred routing", "Wing dialog load\n"));
704         if (!GetSafeHwnd())
705                 return;
706
707         m_arrival_tree.select_sexp_node = m_departure_tree.select_sexp_node = select_sexp_node;
708         select_sexp_node = -1;
709         if (cur_wing == -1)
710                 m_wing_name = _T("");
711         else
712                 m_wing_name = _T(Wings[cur_wing].name);
713
714         initialize_data_safe(full_update);
715         modified = 0;
716         if (w)
717                 w -> SetFocus();
718
719         i = m_arrival_tree.select_sexp_node;
720         if (i != -1) {
721                 w = GetDlgItem(IDC_ARRIVAL_TREE);
722                 m_arrival_tree.hilite_item(i);
723
724         } else {
725                 i = m_departure_tree.select_sexp_node;
726                 if (i != -1) {
727                         w = GetDlgItem(IDC_DEPARTURE_TREE);
728                         m_departure_tree.hilite_item(i);
729                 }
730         }
731 }
732
733 // update wing structure(s) with dialog data.  The data is first checked for errors.  If
734 // no errors occur, returns 0.  If an error occurs, returns -1.  If the update is bypassed,
735 // returns 1.  Bypass is necessary to avoid an infinite loop, and it doesn't actually
736 // update the data.  Bypass only occurs if bypass mode is active and we still get an error.
737 // Once the error no longer occurs, bypass mode is cleared and data is updated.
738 int wing_editor::update_data(int redraw)
739 {
740         char *str, old_name[255], buf[512];
741         int i, z;
742         object *ptr;
743
744         nprintf(("Fred routing", "Wing dialog save\n"));
745         if (!GetSafeHwnd())
746                 return 0;
747
748         UpdateData(TRUE);
749         UpdateData(TRUE);
750
751         if (cur_wing >= 0) {
752                 if (!strnicmp(m_wing_name, "player ", 7)) {
753                         if (bypass_errors)
754                                 return 1;
755
756                         bypass_errors = 1;
757                         z = MessageBox("Wing names can't start with the word 'player'\n"
758                                 "Press OK to restore old name", "Error", MB_ICONEXCLAMATION | MB_OKCANCEL);
759
760                         if (z == IDCANCEL)
761                                 return -1;
762
763                         m_wing_name = _T(Wings[cur_wing].name);
764                         UpdateData(FALSE);
765                 }
766
767                 for (i=0; i<MAX_WINGS; i++)
768                         if (Wings[i].wave_count && !stricmp(Wings[i].name, m_wing_name) && (i != cur_wing)) {
769                                 if (bypass_errors)
770                                         return 1;
771
772                                 bypass_errors = 1;
773                                 z = MessageBox("This wing name is already being used by another wing\n"
774                                         "Press OK to restore old name", "Error", MB_ICONEXCLAMATION | MB_OKCANCEL);
775
776                                 if (z == IDCANCEL)
777                                         return -1;
778
779                                 m_wing_name = _T(Wings[cur_wing].name);
780                                 UpdateData(FALSE);
781                         }
782
783                 ptr = GET_FIRST(&obj_used_list);
784                 while (ptr != END_OF_LIST(&obj_used_list)) {
785                         if (ptr->type == OBJ_SHIP) {
786                                 if (!stricmp(m_wing_name, Ships[ptr->instance].ship_name)) {
787                                         if (bypass_errors)
788                                                 return 1;
789
790                                         bypass_errors = 1;
791                                         z = MessageBox("This wing name is already being used by a ship\n"
792                                                 "Press OK to restore old name", "Error", MB_ICONEXCLAMATION | MB_OKCANCEL);
793
794                                         if (z == IDCANCEL)
795                                                 return -1;
796
797                                         m_wing_name = _T(Wings[cur_wing].name);
798                                         UpdateData(FALSE);
799                                 }
800                         }
801
802                         ptr = GET_NEXT(ptr);
803                 }
804
805                 for (i=0; i<MAX_WAYPOINT_LISTS; i++)
806                         if (Waypoint_lists[i].count && !stricmp(Waypoint_lists[i].name, m_wing_name)) {
807                                 if (bypass_errors)
808                                         return 1;
809
810                                 bypass_errors = 1;
811                                 z = MessageBox("This wing name is already being used by a waypoint path\n"
812                                         "Press OK to restore old name", "Error", MB_ICONEXCLAMATION | MB_OKCANCEL);
813
814                                 if (z == IDCANCEL)
815                                         return -1;
816
817                                 m_wing_name = _T(Wings[cur_wing].name);
818                                 UpdateData(FALSE);
819                         }
820
821                 for (i=0; i<Num_jump_nodes; i++)
822                         if (!stricmp(Jump_nodes[i].name, m_wing_name)) {
823                                 if (bypass_errors)
824                                         return 1;
825
826                                 bypass_errors = 1;
827                                 z = MessageBox("This wing name is already being used by a jump node\n"
828                                         "Press OK to restore old name", "Error", MB_ICONEXCLAMATION | MB_OKCANCEL);
829
830                                 if (z == IDCANCEL)
831                                         return -1;
832
833                                 m_wing_name = _T(Wings[cur_wing].name);
834                                 UpdateData(FALSE);
835                         }
836
837                 strcpy(old_name, Wings[cur_wing].name);
838                 string_copy(Wings[cur_wing].name, m_wing_name, NAME_LENGTH, 1);
839                 update_data_safe();
840
841                 bypass_errors = 0;
842                 modified = 0;
843                 str = Wings[cur_wing].name;
844                 if (stricmp(old_name, str)) {
845                         update_sexp_references(old_name, str);
846                         ai_update_goal_references(REF_TYPE_WING, old_name, str);
847                         for (i=0; i<Num_reinforcements; i++)
848                                 if (!stricmp(old_name, Reinforcements[i].name)) {
849                                         Assert(strlen(str) < NAME_LENGTH);
850                                         strcpy(Reinforcements[i].name, str);
851                                 }
852
853                         for (i=0; i<Wings[cur_wing].wave_count; i++) {
854                                 if ((Objects[wing_objects[cur_wing][i]].type == OBJ_SHIP) || (Objects[wing_objects[cur_wing][i]].type == OBJ_START)) {
855                                         sprintf(buf, "%s %d", str, i + 1);
856                                         rename_ship(Wings[cur_wing].ship_index[i], buf);
857                                 }
858                         }
859
860                         Update_window = 1;
861                 }
862
863                 if (set_reinforcement(str, m_reinforcement) == 1) {
864                         free_sexp2(Wings[cur_wing].arrival_cue);
865                         Wings[cur_wing].arrival_cue = Locked_sexp_false;
866                 }
867         }
868
869         if (redraw)
870                 update_map_window();
871
872         return 0;
873 }
874
875 // update parts of wing that can't fail.  This is useful if for when you need to change
876 // something in a wing that this updates elsewhere in Fred.  Normally when auto-update
877 // kicks in, the changes you make will be wiped out by the auto=update, so instead you
878 // would call this function to update the wing, make your changes, and then call the
879 // initialize_data_safe() function to show your changes in the dialog
880 void wing_editor::update_data_safe()
881 {
882         char buf[512];
883         int i, d, hotkey = -1;
884
885         nprintf(("Fred routing", "Wing dialog save safe\n"));
886         if (!GetSafeHwnd())
887                 return;
888
889         UpdateData(TRUE);
890         UpdateData(TRUE);
891
892         if (cur_wing < 0)
893                 return;
894
895         if (m_threshold >= Wings[cur_wing].wave_count) {
896                 m_threshold = Wings[cur_wing].wave_count - 1;
897                 if (!bypass_errors)
898                         sprintf(buf, "Wave threshold is set too high.  Value has been lowered to %d", (int) m_threshold);
899
900                 MessageBox(buf);
901         }
902
903         if (m_threshold + Wings[cur_wing].wave_count > MAX_SHIPS_PER_WING) {
904                 m_threshold = MAX_SHIPS_PER_WING - Wings[cur_wing].wave_count;
905                 if (!bypass_errors)
906                         sprintf(buf, "Wave threshold is set too high.  Value has been lowered to %d", (int) m_threshold);
907
908                 MessageBox(buf);
909         }
910
911         if (m_waves < 1) {
912                 m_waves = 1;
913                 if (!bypass_errors)
914                         sprintf(buf, "Number of waves illegal.  Has been set to 1.", (int) m_waves);
915
916                 MessageBox(buf);
917         }
918
919         MODIFY(Wings[cur_wing].special_ship, m_special_ship);
920         MODIFY(Wings[cur_wing].num_waves, m_waves);
921         MODIFY(Wings[cur_wing].threshold, m_threshold);
922         MODIFY(Wings[cur_wing].arrival_location, m_arrival_location);
923         MODIFY(Wings[cur_wing].departure_location, m_departure_location);
924         MODIFY(Wings[cur_wing].arrival_delay, m_arrival_delay);
925         if (m_arrival_delay_min > m_arrival_delay_max) {
926                 if (!bypass_errors)
927                         sprintf(buf, "Arrival delay minimum greater than maximum.  Value lowered to %d", m_arrival_delay_max);
928
929                 MessageBox(buf);
930                 m_arrival_delay_min = m_arrival_delay_max;
931         }
932
933         MODIFY(Wings[cur_wing].wave_delay_min, m_arrival_delay_min);
934         MODIFY(Wings[cur_wing].wave_delay_max, m_arrival_delay_max);
935         MODIFY(Wings[cur_wing].arrival_distance, m_arrival_dist);
936         if (m_arrival_target >= 0) {
937                 i = ((CComboBox *) GetDlgItem(IDC_ARRIVAL_TARGET)) -> GetItemData(m_arrival_target);
938                 MODIFY(Wings[cur_wing].arrival_anchor, i);
939
940                 // when arriving near or in front of a ship, be sure that we are far enough away from it!!!
941                 if (((m_arrival_location != ARRIVE_AT_LOCATION) && (m_arrival_location != ARRIVE_FROM_DOCK_BAY)) && (i >= 0) && (i < SPECIAL_ARRIVAL_ANCHORS_OFFSET)) {
942                         d = int(min(500, 2.0f * Objects[Ships[i].objnum].radius));
943                         if ((Wings[cur_wing].arrival_distance < d) && (Wings[cur_wing].arrival_distance > -d)) {
944                                 if (!bypass_errors)
945                                         sprintf(buf, "Ship must arrive at least %d meters away from target.\n"
946                                                 "Value has been reset to this.  Use with caution!\r\n"
947                                                 "Reccomended distance is %d meters.\r\n", d, (int)(2.0f * Objects[Ships[i].objnum].radius) );
948
949                                 MessageBox(buf);
950                                 if (Wings[cur_wing].arrival_distance < 0)
951                                         Wings[cur_wing].arrival_distance = -d;
952                                 else
953                                         Wings[cur_wing].arrival_distance = d;
954
955                                 m_arrival_dist = Wings[cur_wing].arrival_distance;
956                         }
957                 }
958         }
959
960         i = ((CComboBox*)GetDlgItem(IDC_DEPARTURE_TARGET))->GetItemData(m_departure_target);
961         MODIFY(Wings[cur_wing].departure_anchor,  i);
962
963         MODIFY(Wings[cur_wing].departure_delay, m_departure_delay);
964         hotkey = m_hotkey - 1;
965         MODIFY(Wings[cur_wing].hotkey, hotkey);
966         if ( m_ignore_count ) {
967                 if ( !(Wings[cur_wing].flags & WF_IGNORE_COUNT) )
968                         set_modified();
969                 Wings[cur_wing].flags |= WF_IGNORE_COUNT;
970
971         } else {
972                 if ( Wings[cur_wing].flags & WF_IGNORE_COUNT )
973                         set_modified();
974                 Wings[cur_wing].flags &= ~WF_IGNORE_COUNT;
975         }
976
977         if ( m_no_arrival_music ) {
978                 if ( !(Wings[cur_wing].flags & WF_NO_ARRIVAL_MUSIC) )
979                         set_modified();
980                 Wings[cur_wing].flags |= WF_NO_ARRIVAL_MUSIC;
981
982         } else {
983                 if ( Wings[cur_wing].flags & WF_NO_ARRIVAL_MUSIC )
984                         set_modified();
985                 Wings[cur_wing].flags &= ~WF_NO_ARRIVAL_MUSIC;
986         }
987
988         // check the no message flag
989         if ( m_no_arrival_message ) {
990                 if ( !(Wings[cur_wing].flags & WF_NO_ARRIVAL_MESSAGE) )
991                         set_modified();
992                 Wings[cur_wing].flags |= WF_NO_ARRIVAL_MESSAGE;
993
994         } else {
995                 if ( Wings[cur_wing].flags & WF_NO_ARRIVAL_MESSAGE )
996                         set_modified();
997                 Wings[cur_wing].flags &= ~WF_NO_ARRIVAL_MESSAGE;
998         }
999
1000         // set the no warp effect for wings flag
1001         if ( m_no_arrival_warp ) {
1002                 if ( !(Wings[cur_wing].flags & WF_NO_ARRIVAL_WARP) )
1003                         set_modified();
1004                 Wings[cur_wing].flags |= WF_NO_ARRIVAL_WARP;
1005         } else {
1006                 if ( Wings[cur_wing].flags & WF_NO_ARRIVAL_WARP )
1007                         set_modified();
1008                 Wings[cur_wing].flags &= ~WF_NO_ARRIVAL_WARP;
1009         }
1010         // set the no warp effect for wings flag
1011         if ( m_no_departure_warp ) {
1012                 if ( !(Wings[cur_wing].flags & WF_NO_DEPARTURE_WARP) )
1013                         set_modified();
1014                 Wings[cur_wing].flags |= WF_NO_DEPARTURE_WARP;
1015         } else {
1016                 if ( Wings[cur_wing].flags & WF_NO_DEPARTURE_WARP )
1017                         set_modified();
1018                 Wings[cur_wing].flags &= ~WF_NO_DEPARTURE_WARP;
1019         }
1020
1021         if ( m_no_dynamic ) {
1022                 if ( !(Wings[cur_wing].flags & WF_NO_DYNAMIC) )
1023                         set_modified();
1024                 Wings[cur_wing].flags |= WF_NO_DYNAMIC;
1025         } else {
1026                 if ( Wings[cur_wing].flags & WF_NO_DYNAMIC )
1027                         set_modified();
1028                 Wings[cur_wing].flags &= ~WF_NO_DYNAMIC;
1029         }
1030
1031         if (Wings[cur_wing].arrival_cue >= 0)
1032                 free_sexp2(Wings[cur_wing].arrival_cue);
1033         Wings[cur_wing].arrival_cue = m_arrival_tree.save_tree();
1034
1035         if (Wings[cur_wing].departure_cue >= 0)
1036                 free_sexp2(Wings[cur_wing].departure_cue);
1037         Wings[cur_wing].departure_cue = m_departure_tree.save_tree();
1038
1039         if (modified)
1040                 set_modified();
1041 }
1042
1043 BOOL wing_editor::OnCommand(WPARAM wParam, LPARAM lParam) 
1044 {
1045         int id, wing;
1046
1047         id = LOWORD(wParam);
1048         if (id >= ID_WING_MENU && id < ID_WING_MENU + MAX_WINGS) {
1049                 if (!update_data()) {
1050                         wing = id - ID_WING_MENU;
1051                         mark_wing(wing);
1052                         return 1;
1053                 }
1054         }
1055
1056         return CDialog::OnCommand(wParam, lParam);
1057 }
1058
1059 void wing_editor::OnDeltaposSpinWaves(NMHDR* pNMHDR, LRESULT* pResult) 
1060 {
1061         int new_pos;
1062         NM_UPDOWN* pNMUpDown = (NM_UPDOWN*)pNMHDR;
1063         
1064         new_pos = pNMUpDown->iPos + pNMUpDown->iDelta;
1065         if (new_pos > 0 && new_pos < 100)       {
1066                 *pResult = 0;
1067                 modified = 1;
1068
1069         } else
1070                 *pResult = 1;
1071 }
1072
1073 void wing_editor::OnRclickArrivalTree(NMHDR* pNMHDR, LRESULT* pResult) 
1074 {
1075         m_arrival_tree.right_clicked(); 
1076         *pResult = 0;
1077 }
1078
1079 void wing_editor::OnRclickDepartureTree(NMHDR* pNMHDR, LRESULT* pResult) 
1080 {
1081         m_departure_tree.right_clicked();
1082         *pResult = 0;
1083 }
1084
1085 void wing_editor::OnBeginlabeleditArrivalTree(NMHDR* pNMHDR, LRESULT* pResult) 
1086 {
1087         TV_DISPINFO* pTVDispInfo = (TV_DISPINFO*)pNMHDR;
1088
1089         if (m_arrival_tree.edit_label(pTVDispInfo->item.hItem) == 1)    {
1090                 *pResult = 0;
1091                 modified = 1;
1092
1093         } else
1094                 *pResult = 1;
1095 }
1096
1097 void wing_editor::OnBeginlabeleditDepartureTree(NMHDR* pNMHDR, LRESULT* pResult) 
1098 {
1099         TV_DISPINFO* pTVDispInfo = (TV_DISPINFO*)pNMHDR;
1100
1101         if (m_departure_tree.edit_label(pTVDispInfo->item.hItem) == 1)  {
1102                 *pResult = 0;
1103                 modified = 1;
1104
1105         } else
1106                 *pResult = 1;
1107 }
1108
1109 void wing_editor::OnEndlabeleditArrivalTree(NMHDR* pNMHDR, LRESULT* pResult) 
1110 {
1111         TV_DISPINFO* pTVDispInfo = (TV_DISPINFO*)pNMHDR;
1112
1113         *pResult = m_arrival_tree.end_label_edit(pTVDispInfo->item.hItem, pTVDispInfo->item.pszText);
1114 }
1115
1116 void wing_editor::OnEndlabeleditDepartureTree(NMHDR* pNMHDR, LRESULT* pResult) 
1117 {
1118         TV_DISPINFO* pTVDispInfo = (TV_DISPINFO*)pNMHDR;
1119
1120         *pResult = m_departure_tree.end_label_edit(pTVDispInfo->item.hItem, pTVDispInfo->item.pszText);
1121 }
1122
1123 int wing_editor::verify()
1124 {
1125         nprintf(("Fred routing", "Wing dialog verify\n"));
1126         if (!GetSafeHwnd() || !modified)
1127                 return 0;
1128
1129         if (bypass_errors)
1130                 return 1;
1131
1132         return 0;
1133 }
1134
1135 // delete wing and all ships that are part of the wing
1136 void wing_editor::OnDeleteWing()
1137 {
1138         modified = 0;  // no need to run update checks, since wing will be gone shortly anyway.
1139         delete_wing(cur_wing);
1140 }
1141
1142 // delete wing, but leave ships intact and wingless
1143 void wing_editor::OnDisbandWing()
1144 {
1145         modified = 0;  // no need to run update checks, since wing will be gone shortly anyway.
1146         remove_wing(cur_wing);
1147 }
1148
1149 void wing_editor::OnGoals2()
1150 {
1151         ShipGoalsDlg dlg_goals;
1152
1153         Assert(cur_wing != -1);
1154         dlg_goals.self_wing = cur_wing;
1155         dlg_goals.DoModal();
1156         if (query_initial_orders_conflict(cur_wing))
1157                 MessageBox("One or more ships of this wing also has initial orders",
1158                         "Possible conflict");
1159 }
1160
1161 void wing_editor::OnReinforcement()
1162 {
1163         UpdateData(TRUE);
1164         UpdateData(TRUE);
1165         //if (m_reinforcement)
1166         //      m_arrival_tree.clear_tree("false");
1167 }
1168
1169 void wing_editor::OnPrev() 
1170 {
1171         int wing, count = 0;
1172
1173         if (!update_data() && num_wings) {
1174                 wing = cur_wing - 1;
1175                 if (wing < 0)
1176                         wing = MAX_WINGS - 1;
1177
1178                 while (!Wings[wing].wave_count) {
1179                         wing--;
1180                         if (count++ > MAX_WINGS)
1181                                 return;
1182
1183                         if (wing < 0)
1184                                 wing = MAX_WINGS - 1;
1185                 }
1186
1187                 mark_wing(wing);
1188                 Wing_editor_dialog.initialize_data(1);
1189                 Update_wing = 0;
1190         }
1191
1192         return;
1193 }
1194
1195 void wing_editor::OnNext() 
1196 {
1197         int wing, count = 0;
1198
1199         if (!update_data() && num_wings) {
1200                 wing = cur_wing + 1;
1201                 if (wing >= MAX_WINGS)
1202                         wing = 0;
1203
1204                 while (!Wings[wing].wave_count) {
1205                         wing++;
1206                         if (count++ > MAX_WINGS)
1207                                 return;
1208
1209                         if (wing >= MAX_WINGS)
1210                                 wing = 0;
1211                 }
1212
1213                 mark_wing(wing);
1214                 Wing_editor_dialog.initialize_data(1);
1215                 Update_wing = 0;
1216         }
1217
1218         return;
1219 }
1220
1221 void wing_editor::OnSelchangedArrivalTree(NMHDR* pNMHDR, LRESULT* pResult) 
1222 {
1223         HTREEITEM h;
1224
1225         NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
1226         h = pNMTreeView->itemNew.hItem;
1227         if (h)
1228                 m_arrival_tree.update_help(h);
1229
1230         *pResult = 0;
1231 }
1232
1233 void wing_editor::OnSelchangedDepartureTree(NMHDR* pNMHDR, LRESULT* pResult) 
1234 {
1235         HTREEITEM h;
1236
1237         NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
1238         h = pNMTreeView->itemNew.hItem;
1239         if (h)
1240                 m_departure_tree.update_help(h);
1241
1242         *pResult = 0;
1243 }
1244
1245 void wing_editor::calc_cue_height()
1246 {
1247         CRect cue;
1248
1249         GetDlgItem(IDC_CUE_FRAME)->GetWindowRect(cue);
1250         cue_height = cue.bottom - cue.top + 10;
1251         if (Show_sexp_help)
1252                 cue_height += SEXP_HELP_BOX_SIZE;
1253
1254         if (Hide_wing_cues) {
1255                 ((CButton *) GetDlgItem(IDC_HIDE_CUES)) -> SetCheck(1);
1256                 OnHideCues();
1257         }
1258 }
1259
1260 void wing_editor::show_hide_sexp_help()
1261 {
1262         CRect rect;
1263
1264         if (Show_sexp_help)
1265                 cue_height += SEXP_HELP_BOX_SIZE;
1266         else
1267                 cue_height -= SEXP_HELP_BOX_SIZE;
1268
1269         if (((CButton *) GetDlgItem(IDC_HIDE_CUES)) -> GetCheck())
1270                 return;
1271
1272         GetWindowRect(rect);
1273         if (Show_sexp_help)
1274                 rect.bottom += SEXP_HELP_BOX_SIZE;
1275         else
1276                 rect.bottom -= SEXP_HELP_BOX_SIZE;
1277
1278         MoveWindow(rect);
1279 }
1280
1281 void wing_editor::OnHideCues() 
1282 {
1283         CRect rect;
1284
1285         GetWindowRect(rect);
1286         if (((CButton *) GetDlgItem(IDC_HIDE_CUES)) -> GetCheck()) {
1287                 rect.bottom -= cue_height;
1288                 Hide_wing_cues = 1;
1289
1290         } else {
1291                 rect.bottom += cue_height;
1292                 Hide_wing_cues = 0;
1293         }
1294
1295         MoveWindow(rect);
1296 }
1297
1298 void wing_editor::OnSelchangeArrivalLocation() 
1299 {
1300         CComboBox *box;
1301
1302         box = (CComboBox *)GetDlgItem(IDC_ARRIVAL_TARGET);
1303         UpdateData();
1304         if (m_arrival_location) {
1305                 GetDlgItem(IDC_ARRIVAL_DISTANCE)->EnableWindow(TRUE);
1306                 GetDlgItem(IDC_ARRIVAL_TARGET)->EnableWindow(TRUE);
1307                 if (m_arrival_target < 0) {
1308                         m_arrival_target = 0;
1309                 }
1310
1311                 // determine which items we should put into the arrival target combo box
1312                 if ( m_arrival_location == ARRIVE_FROM_DOCK_BAY ) {
1313                         management_add_ships_to_combo( box, SHIPS_2_COMBO_DOCKING_BAY_ONLY );
1314                 } else {
1315                         management_add_ships_to_combo( box, SHIPS_2_COMBO_SPECIAL | SHIPS_2_COMBO_ALL_SHIPS );
1316                 }
1317         } else {
1318                 m_arrival_target = -1;
1319                 GetDlgItem(IDC_ARRIVAL_DISTANCE)->EnableWindow(FALSE);
1320                 GetDlgItem(IDC_ARRIVAL_TARGET)->EnableWindow(FALSE);
1321         }
1322         UpdateData(FALSE);
1323 }
1324
1325 void wing_editor::OnSelchangeDepartureLocation() 
1326 {
1327         CComboBox *box;
1328
1329         box = (CComboBox *)GetDlgItem(IDC_DEPARTURE_TARGET);
1330         UpdateData();
1331         if (m_departure_location) {
1332                 GetDlgItem(IDC_DEPARTURE_TARGET)->EnableWindow(TRUE);
1333                 if (m_departure_target < 0) {
1334                         m_departure_target = 0;
1335                 }
1336                 // we need to build up the list box content based on the departure type.  When
1337                 // from a docking bay, only show ships in the list which have them.  Show all ships otherwise
1338                 if ( m_departure_location == DEPART_AT_DOCK_BAY ) {
1339                         management_add_ships_to_combo( box, SHIPS_2_COMBO_DOCKING_BAY_ONLY );
1340                 } else {
1341                         // I think that this section is currently illegal
1342                         Int3();
1343                 }
1344         } else {
1345                 m_departure_target = -1;
1346                 GetDlgItem(IDC_DEPARTURE_TARGET)->EnableWindow(FALSE);
1347         }
1348         UpdateData(FALSE);
1349 }
1350
1351 // see if hotkey should possibly be reserved for player starting wing
1352 void wing_editor::OnSelchangeHotkey() 
1353 {
1354         char buf[256];
1355         int set_num, i;
1356         
1357         UpdateData(TRUE);
1358         set_num = m_hotkey - 1; // hotkey sets are 1 index based
1359
1360         // first, determine if we are currently working with a starting wing
1361         for ( i = 0; i < MAX_STARTING_WINGS; i++ ) {
1362                 if ( !stricmp( Wings[cur_wing].name, Starting_wing_names[i]) )
1363                         break;
1364         }
1365         if ( i == MAX_STARTING_WINGS )
1366                 return;
1367
1368         // we have a player starting wing.  See if we assigned a non-standard hotkey
1369         if ( (set_num >= MAX_STARTING_WINGS) || (set_num != i) ) {
1370                 sprintf(buf, "Assigning nonstandard hotkey to wing %s (default is F%d)", Wings[cur_wing].name, 5+i);
1371                 MessageBox(buf, NULL, MB_OK | MB_ICONEXCLAMATION );
1372         }
1373         
1374 }