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