2 * Copyright (C) Volition, Inc. 1999. All rights reserved.
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
10 * $Logfile: /Freespace2/code/fred2/wing_editor.cpp $
15 * Wing editor dialog box handler code
18 * Revision 1.3 2002/06/09 04:41:17 relnev
19 * added copyright header
21 * Revision 1.2 2002/05/07 03:16:44 theoddone33
22 * The Great Newline Fix
24 * Revision 1.1.1.1 2002/05/03 03:28:09 root
28 * 3 8/16/99 10:52p Andsager
29 * Allow closer ship positioning for NEAR_SHIP ship and wing arrivals.
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.
36 * 1 10/07/98 3:02p Dave
38 * 1 10/07/98 3:00p Dave
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
44 * 82 6/17/98 4:50p Hoffoss
45 * Added error checking for arrival delays used on wing player is in.
47 * 81 5/22/98 10:10a Hoffoss
48 * Fixed bug with hide cue button not working correctly.
50 * 80 3/24/98 12:30p Allender
51 * arrival/departure target boxes were getting initialized incorrectly
53 * 79 3/21/98 7:36p Lawrance
54 * Move jump nodes to own lib.
56 * 78 3/16/98 8:27p Allender
57 * Fred support for two new AI flags -- kamikaze and no dynamic goals.
59 * 77 3/10/98 6:11p Hoffoss
60 * Added jump node renaming abilities to Fred.
62 * 76 2/23/98 9:48p Allender
63 * added no arrival/departure warps to wings
65 * 75 12/31/97 3:56p Hoffoss
66 * Forced alpha wing to always have a true arrival cue.
68 * 74 12/29/97 4:55p Johnson
71 * 73 12/18/97 10:40a Hoffoss
72 * Fixed bug with a few of the checkboxes not initializing properly.
74 * 72 11/25/97 10:03a Allender
75 * added no arrival message checkbox to wing editor
77 * 71 11/25/97 9:42a Hoffoss
78 * Removed starting wing checkbox from wing editor.
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
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.
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.
93 * 67 10/28/97 3:33p Hoffoss
94 * Fixed bug where <1 num_waves was being allowed to be entered into Fred.
96 * 66 10/14/97 5:33p Hoffoss
97 * Added Fred support (and fsm support) for the no_arrival_music flags in
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.
104 * 64 9/04/97 5:35p Hoffoss
105 * Fixed arrival distance stuff.
107 * 63 9/04/97 5:04p Johnson
108 * Fixed bug with arrival target distance checking.
110 * 62 9/04/97 4:30p Hoffoss
111 * Removed sexp tree info from grayed trees.
113 * 61 8/30/97 9:52p Hoffoss
114 * Implemented arrival location, distance, and anchor in Fred.
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.
120 * 59 8/21/97 3:20p Duncan
121 * Fixed bug in wing renaming when a player is in the wing.
123 * 58 8/19/97 1:44p Hoffoss
124 * Fixed bug with updating too quickly (i.e. via prev and next buttons).
126 * 57 8/15/97 5:14p Hoffoss
127 * Completely changed around how initial orders dialog worked. It's
128 * pretty awesome now.
130 * 56 8/15/97 11:24a Hoffoss
131 * Changed order of events.
133 * 55 8/13/97 11:31p Hoffoss
134 * Added bound checking on min/max wave delay.
136 * 54 8/13/97 11:22p Hoffoss
137 * Implemented wave delay min and max in Fred.
139 * 53 8/12/97 7:17p Hoffoss
140 * Added previous button to ship and wing editors.
142 * 52 8/12/97 6:32p Hoffoss
143 * Added code to allow hiding of arrival and departure cues in editors.
145 * 51 8/12/97 3:33p Hoffoss
146 * Fixed the "press cancel to go to reference" code to work properly.
148 * 50 8/12/97 1:55a Hoffoss
149 * Made extensive changes to object reference checking and handling for
150 * object deletion call.
152 * 49 8/10/97 4:22p Hoffoss
153 * Made main display update when ships or wings are renamed.
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.
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.
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.
167 * 45 7/30/97 12:31p Hoffoss
168 * Made improvements to ship goals editor (initial orders) to disallow
171 * 44 7/28/97 2:28p Hoffoss
172 * Added bypasses to MFC integer validation routines.
174 * 43 7/25/97 2:40p Hoffoss
175 * Fixed bug in sexp tree selection updating handling.
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.
181 * 41 7/18/97 2:05p Hoffoss
182 * Fixed some bugs BoundsChecker turned up.
184 * 40 7/16/97 6:30p Hoffoss
185 * Added icons to sexp trees, mainly because I think they will be required
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
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
198 * 37 7/02/97 3:30p Hoffoss
199 * Put in code to validate and bash if necessary the wing wave threshold.
201 * 36 6/18/97 3:07p Hoffoss
202 * Wing ship names are 1 indexes instead of 0 indexed now.
204 * 35 6/05/97 6:10p Hoffoss
205 * Added features: Autosaving, object hiding. Also fixed some minor bugs.
207 * 34 5/30/97 11:33a Allender
208 * more hotkey combo box stuff
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.
216 * 32 5/01/97 4:15p Hoffoss
219 * 31 4/28/97 2:37p Hoffoss
220 * Added hotkey editing to Fred for ships and wings.
222 * 30 4/23/97 11:55a Hoffoss
223 * Fixed many bugs uncovered while trying to create Mission 6.
225 * 29 4/07/97 1:53p Hoffoss
226 * Fixed a few bugs, and added sexp chain duplicating for object
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.
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.
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
242 * 25 3/17/97 4:29p Hoffoss
243 * Automated player's wing flaging as a starting player wing.
245 * 24 3/05/97 10:54a Hoffoss
246 * removed special arrival/departure cue token usage in wing editor.
248 * 23 2/28/97 11:31a Hoffoss
249 * Implemented modeless dialog saving and restoring, and changed some
252 * 22 2/27/97 3:16p Allender
253 * major wing structure enhancement. simplified wing code. All around
254 * better wing support
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.
260 * 20 2/21/97 5:34p Hoffoss
261 * Added extensive modification detection and fixed a bug in initial
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.
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.
279 #include "management.h"
281 #include "linklist.h"
283 #include "fredview.h"
284 #include "starfield.h"
285 #include "jumpnode.h"
287 #define ID_WING_MENU 9000
290 #define new DEBUG_NEW
292 static char THIS_FILE[] = __FILE__;
295 /////////////////////////////////////////////////////////////////////////////
296 // wing_editor dialog
298 wing_editor::wing_editor(CWnd* pParent /*=NULL*/)
299 : CDialog(wing_editor::IDD, pParent)
301 //{{AFX_DATA_INIT(wing_editor)
302 m_wing_name = _T("");
306 m_arrival_location = -1;
307 m_departure_location = -1;
309 m_departure_delay = 0;
310 m_reinforcement = FALSE;
312 m_ignore_count = FALSE;
313 m_arrival_delay_max = 0;
314 m_arrival_delay_min = 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;
325 select_sexp_node = -1;
329 void wing_editor::DoDataExchange(CDataExchange* pDX)
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);
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)
364 GetDlgItem(IDC_DEPARTURE_DELAY)->GetWindowText(str);
365 m_departure_delay = atoi(str);
366 if (m_departure_delay < 0)
367 m_departure_delay = 0;
369 GetDlgItem(IDC_WING_WAVES)->GetWindowText(str);
374 GetDlgItem(IDC_WING_WAVE_THRESHOLD)->GetWindowText(str);
375 m_threshold = atoi(str);
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;
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;
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);
399 BEGIN_MESSAGE_MAP(wing_editor, CDialog)
400 //{{AFX_MSG_MAP(wing_editor)
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)
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)
425 /////////////////////////////////////////////////////////////////////////////
426 // wing_editor message handlers
428 BOOL wing_editor::Create()
434 r = CDialog::Create(IDD, Fred_main_wnd);
435 box = (CComboBox *) GetDlgItem(IDC_ARRIVAL_LOCATION);
437 for (i=0; i<MAX_ARRIVAL_NAMES; i++)
438 box->AddString(Arrival_location_names[i]);
440 box = (CComboBox *) GetDlgItem(IDC_DEPARTURE_LOCATION);
442 for (i=0; i<MAX_DEPARTURE_NAMES; i++)
443 box->AddString(Departure_location_names[i]);
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);
458 void wing_editor::OnInitMenu(CMenu* pMenu)
462 m = pMenu->GetSubMenu(0);
464 generate_wing_popup_menu(m, ID_WING_MENU, MF_ENABLED);
466 m->CheckMenuItem(ID_WING_MENU + cur_wing, MF_BYCOMMAND | MF_CHECKED);
468 CDialog::OnInitMenu(pMenu);
471 void wing_editor::OnOK()
479 GetDlgItem(IDC_ARRIVAL_TREE)->SetFocus();
484 void wing_editor::OnClose()
486 if (verify() && (!bypass_errors)) {
487 SetWindowPos(&wndTop, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
493 SetWindowPos(&wndTop, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
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);
502 // initialize everything that update_data_safe() saves.
503 void wing_editor::initialize_data_safe(int full_update)
505 int i, enable = TRUE, player_wing = 0, player_enabled = 1;
506 CComboBox *arrival_box, *departure_box;
508 nprintf(("Fred routing", "Wing dialog load safe\n"));
512 arrival_box = (CComboBox *) GetDlgItem(IDC_ARRIVAL_TARGET);
513 departure_box = (CComboBox *)GetDlgItem(IDC_DEPARTURE_TARGET);
518 m_arrival_location = -1;
519 m_departure_location = -1;
521 m_arrival_delay_min = 0;
522 m_arrival_delay_max = 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;
534 m_no_arrival_music = 0;
535 m_no_arrival_message = 0;
536 m_no_arrival_warp = 0;
537 m_no_departure_warp = 0;
539 player_enabled = enable = FALSE;
544 if (cur_wing == wing_name_lookup("alpha", 1))
547 if ((The_mission.game_type & MISSION_TYPE_MULTI_TEAMS) && (cur_wing == wing_name_lookup("zeta", 1)))
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)) ) {
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)
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;
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 );
578 management_add_ships_to_combo( arrival_box, SHIPS_2_COMBO_SPECIAL | SHIPS_2_COMBO_ALL_SHIPS );
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);
586 if ( m_departure_target >= 0 )
587 m_departure_target = departure_box->FindStringExact(-1, Ships[m_departure_target].ship_name);
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 );
593 departure_box->ResetContent();
596 m_departure_delay = Wings[cur_wing].departure_delay;
598 m_arrival_tree.load_tree(Locked_sexp_true);
600 m_arrival_tree.load_tree(Wings[cur_wing].arrival_cue);
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)
609 if (Wings[cur_wing].flags & WF_NO_ARRIVAL_MUSIC)
610 m_no_arrival_music = 1;
612 m_no_arrival_music = 0;
614 if ( Wings[cur_wing].flags & WF_NO_ARRIVAL_MESSAGE )
615 m_no_arrival_message = 1;
617 m_no_arrival_message = 0;
619 if ( Wings[cur_wing].flags & WF_NO_ARRIVAL_WARP )
620 m_no_arrival_warp = 1;
622 m_no_arrival_warp = 0;
624 if ( Wings[cur_wing].flags & WF_NO_DEPARTURE_WARP )
625 m_no_departure_warp = 1;
627 m_no_departure_warp = 0;
629 ptr = (CComboBox *) GetDlgItem(IDC_WING_SPECIAL_SHIP);
631 for (i=0; i<Wings[cur_wing].wave_count; i++)
632 ptr->AddString(Ships[Wings[cur_wing].ship_index[i]].ship_name);
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))
639 if (i < Num_reinforcements)
640 m_reinforcement = TRUE;
642 m_reinforcement = FALSE;
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);
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);
665 GetDlgItem(IDC_ARRIVAL_DISTANCE)->EnableWindow(FALSE);
666 GetDlgItem(IDC_ARRIVAL_TARGET)->EnableWindow(FALSE);
668 GetDlgItem(IDC_NO_DYNAMIC)->EnableWindow(enable);
670 if ( m_departure_location ) {
671 GetDlgItem(IDC_DEPARTURE_TARGET)->EnableWindow(enable);
673 GetDlgItem(IDC_DEPARTURE_TARGET)->EnableWindow(FALSE);
677 GetDlgItem(IDC_ARRIVAL_TREE)->EnableWindow(0);
679 GetDlgItem(IDC_ARRIVAL_TREE)->EnableWindow(enable);
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);
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++ ) {
703 sflag = Ship_info[Ships[Wings[cur_wing].ship_index[i]].ship_info_index].flags;
704 if ( !(sflag & SIF_FIGHTER) && !(sflag & SIF_BOMBER) )
712 void wing_editor::initialize_data(int full_update)
717 nprintf(("Fred routing", "Wing dialog load\n"));
721 m_arrival_tree.select_sexp_node = m_departure_tree.select_sexp_node = select_sexp_node;
722 select_sexp_node = -1;
724 m_wing_name = _T("");
726 m_wing_name = _T(Wings[cur_wing].name);
728 initialize_data_safe(full_update);
733 i = m_arrival_tree.select_sexp_node;
735 w = GetDlgItem(IDC_ARRIVAL_TREE);
736 m_arrival_tree.hilite_item(i);
739 i = m_departure_tree.select_sexp_node;
741 w = GetDlgItem(IDC_DEPARTURE_TREE);
742 m_departure_tree.hilite_item(i);
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)
754 char *str, old_name[255], buf[512];
758 nprintf(("Fred routing", "Wing dialog save\n"));
766 if (!strnicmp(m_wing_name, "player ", 7)) {
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);
777 m_wing_name = _T(Wings[cur_wing].name);
781 for (i=0; i<MAX_WINGS; i++)
782 if (Wings[i].wave_count && !stricmp(Wings[i].name, m_wing_name) && (i != cur_wing)) {
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);
793 m_wing_name = _T(Wings[cur_wing].name);
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)) {
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);
811 m_wing_name = _T(Wings[cur_wing].name);
819 for (i=0; i<MAX_WAYPOINT_LISTS; i++)
820 if (Waypoint_lists[i].count && !stricmp(Waypoint_lists[i].name, m_wing_name)) {
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);
831 m_wing_name = _T(Wings[cur_wing].name);
835 for (i=0; i<Num_jump_nodes; i++)
836 if (!stricmp(Jump_nodes[i].name, m_wing_name)) {
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);
847 m_wing_name = _T(Wings[cur_wing].name);
851 strcpy(old_name, Wings[cur_wing].name);
852 string_copy(Wings[cur_wing].name, m_wing_name, NAME_LENGTH, 1);
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);
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);
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;
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()
897 int i, d, hotkey = -1;
899 nprintf(("Fred routing", "Wing dialog save safe\n"));
909 if (m_threshold >= Wings[cur_wing].wave_count) {
910 m_threshold = Wings[cur_wing].wave_count - 1;
912 sprintf(buf, "Wave threshold is set too high. Value has been lowered to %d", (int) m_threshold);
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;
920 sprintf(buf, "Wave threshold is set too high. Value has been lowered to %d", (int) m_threshold);
928 sprintf(buf, "Number of waves illegal. Has been set to 1.", (int) m_waves);
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) {
941 sprintf(buf, "Arrival delay minimum greater than maximum. Value lowered to %d", m_arrival_delay_max);
944 m_arrival_delay_min = m_arrival_delay_max;
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);
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)) {
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) );
964 if (Wings[cur_wing].arrival_distance < 0)
965 Wings[cur_wing].arrival_distance = -d;
967 Wings[cur_wing].arrival_distance = d;
969 m_arrival_dist = Wings[cur_wing].arrival_distance;
974 i = ((CComboBox*)GetDlgItem(IDC_DEPARTURE_TARGET))->GetItemData(m_departure_target);
975 MODIFY(Wings[cur_wing].departure_anchor, i);
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) )
983 Wings[cur_wing].flags |= WF_IGNORE_COUNT;
986 if ( Wings[cur_wing].flags & WF_IGNORE_COUNT )
988 Wings[cur_wing].flags &= ~WF_IGNORE_COUNT;
991 if ( m_no_arrival_music ) {
992 if ( !(Wings[cur_wing].flags & WF_NO_ARRIVAL_MUSIC) )
994 Wings[cur_wing].flags |= WF_NO_ARRIVAL_MUSIC;
997 if ( Wings[cur_wing].flags & WF_NO_ARRIVAL_MUSIC )
999 Wings[cur_wing].flags &= ~WF_NO_ARRIVAL_MUSIC;
1002 // check the no message flag
1003 if ( m_no_arrival_message ) {
1004 if ( !(Wings[cur_wing].flags & WF_NO_ARRIVAL_MESSAGE) )
1006 Wings[cur_wing].flags |= WF_NO_ARRIVAL_MESSAGE;
1009 if ( Wings[cur_wing].flags & WF_NO_ARRIVAL_MESSAGE )
1011 Wings[cur_wing].flags &= ~WF_NO_ARRIVAL_MESSAGE;
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) )
1018 Wings[cur_wing].flags |= WF_NO_ARRIVAL_WARP;
1020 if ( Wings[cur_wing].flags & WF_NO_ARRIVAL_WARP )
1022 Wings[cur_wing].flags &= ~WF_NO_ARRIVAL_WARP;
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) )
1028 Wings[cur_wing].flags |= WF_NO_DEPARTURE_WARP;
1030 if ( Wings[cur_wing].flags & WF_NO_DEPARTURE_WARP )
1032 Wings[cur_wing].flags &= ~WF_NO_DEPARTURE_WARP;
1035 if ( m_no_dynamic ) {
1036 if ( !(Wings[cur_wing].flags & WF_NO_DYNAMIC) )
1038 Wings[cur_wing].flags |= WF_NO_DYNAMIC;
1040 if ( Wings[cur_wing].flags & WF_NO_DYNAMIC )
1042 Wings[cur_wing].flags &= ~WF_NO_DYNAMIC;
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();
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();
1057 BOOL wing_editor::OnCommand(WPARAM wParam, LPARAM lParam)
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;
1070 return CDialog::OnCommand(wParam, lParam);
1073 void wing_editor::OnDeltaposSpinWaves(NMHDR* pNMHDR, LRESULT* pResult)
1076 NM_UPDOWN* pNMUpDown = (NM_UPDOWN*)pNMHDR;
1078 new_pos = pNMUpDown->iPos + pNMUpDown->iDelta;
1079 if (new_pos > 0 && new_pos < 100) {
1087 void wing_editor::OnRclickArrivalTree(NMHDR* pNMHDR, LRESULT* pResult)
1089 m_arrival_tree.right_clicked();
1093 void wing_editor::OnRclickDepartureTree(NMHDR* pNMHDR, LRESULT* pResult)
1095 m_departure_tree.right_clicked();
1099 void wing_editor::OnBeginlabeleditArrivalTree(NMHDR* pNMHDR, LRESULT* pResult)
1101 TV_DISPINFO* pTVDispInfo = (TV_DISPINFO*)pNMHDR;
1103 if (m_arrival_tree.edit_label(pTVDispInfo->item.hItem) == 1) {
1111 void wing_editor::OnBeginlabeleditDepartureTree(NMHDR* pNMHDR, LRESULT* pResult)
1113 TV_DISPINFO* pTVDispInfo = (TV_DISPINFO*)pNMHDR;
1115 if (m_departure_tree.edit_label(pTVDispInfo->item.hItem) == 1) {
1123 void wing_editor::OnEndlabeleditArrivalTree(NMHDR* pNMHDR, LRESULT* pResult)
1125 TV_DISPINFO* pTVDispInfo = (TV_DISPINFO*)pNMHDR;
1127 *pResult = m_arrival_tree.end_label_edit(pTVDispInfo->item.hItem, pTVDispInfo->item.pszText);
1130 void wing_editor::OnEndlabeleditDepartureTree(NMHDR* pNMHDR, LRESULT* pResult)
1132 TV_DISPINFO* pTVDispInfo = (TV_DISPINFO*)pNMHDR;
1134 *pResult = m_departure_tree.end_label_edit(pTVDispInfo->item.hItem, pTVDispInfo->item.pszText);
1137 int wing_editor::verify()
1139 nprintf(("Fred routing", "Wing dialog verify\n"));
1140 if (!GetSafeHwnd() || !modified)
1149 // delete wing and all ships that are part of the wing
1150 void wing_editor::OnDeleteWing()
1152 modified = 0; // no need to run update checks, since wing will be gone shortly anyway.
1153 delete_wing(cur_wing);
1156 // delete wing, but leave ships intact and wingless
1157 void wing_editor::OnDisbandWing()
1159 modified = 0; // no need to run update checks, since wing will be gone shortly anyway.
1160 remove_wing(cur_wing);
1163 void wing_editor::OnGoals2()
1165 ShipGoalsDlg dlg_goals;
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");
1175 void wing_editor::OnReinforcement()
1179 //if (m_reinforcement)
1180 // m_arrival_tree.clear_tree("false");
1183 void wing_editor::OnPrev()
1185 int wing, count = 0;
1187 if (!update_data() && num_wings) {
1188 wing = cur_wing - 1;
1190 wing = MAX_WINGS - 1;
1192 while (!Wings[wing].wave_count) {
1194 if (count++ > MAX_WINGS)
1198 wing = MAX_WINGS - 1;
1202 Wing_editor_dialog.initialize_data(1);
1209 void wing_editor::OnNext()
1211 int wing, count = 0;
1213 if (!update_data() && num_wings) {
1214 wing = cur_wing + 1;
1215 if (wing >= MAX_WINGS)
1218 while (!Wings[wing].wave_count) {
1220 if (count++ > MAX_WINGS)
1223 if (wing >= MAX_WINGS)
1228 Wing_editor_dialog.initialize_data(1);
1235 void wing_editor::OnSelchangedArrivalTree(NMHDR* pNMHDR, LRESULT* pResult)
1239 NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
1240 h = pNMTreeView->itemNew.hItem;
1242 m_arrival_tree.update_help(h);
1247 void wing_editor::OnSelchangedDepartureTree(NMHDR* pNMHDR, LRESULT* pResult)
1251 NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
1252 h = pNMTreeView->itemNew.hItem;
1254 m_departure_tree.update_help(h);
1259 void wing_editor::calc_cue_height()
1263 GetDlgItem(IDC_CUE_FRAME)->GetWindowRect(cue);
1264 cue_height = cue.bottom - cue.top + 10;
1266 cue_height += SEXP_HELP_BOX_SIZE;
1268 if (Hide_wing_cues) {
1269 ((CButton *) GetDlgItem(IDC_HIDE_CUES)) -> SetCheck(1);
1274 void wing_editor::show_hide_sexp_help()
1279 cue_height += SEXP_HELP_BOX_SIZE;
1281 cue_height -= SEXP_HELP_BOX_SIZE;
1283 if (((CButton *) GetDlgItem(IDC_HIDE_CUES)) -> GetCheck())
1286 GetWindowRect(rect);
1288 rect.bottom += SEXP_HELP_BOX_SIZE;
1290 rect.bottom -= SEXP_HELP_BOX_SIZE;
1295 void wing_editor::OnHideCues()
1299 GetWindowRect(rect);
1300 if (((CButton *) GetDlgItem(IDC_HIDE_CUES)) -> GetCheck()) {
1301 rect.bottom -= cue_height;
1305 rect.bottom += cue_height;
1312 void wing_editor::OnSelchangeArrivalLocation()
1316 box = (CComboBox *)GetDlgItem(IDC_ARRIVAL_TARGET);
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;
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 );
1329 management_add_ships_to_combo( box, SHIPS_2_COMBO_SPECIAL | SHIPS_2_COMBO_ALL_SHIPS );
1332 m_arrival_target = -1;
1333 GetDlgItem(IDC_ARRIVAL_DISTANCE)->EnableWindow(FALSE);
1334 GetDlgItem(IDC_ARRIVAL_TARGET)->EnableWindow(FALSE);
1339 void wing_editor::OnSelchangeDepartureLocation()
1343 box = (CComboBox *)GetDlgItem(IDC_DEPARTURE_TARGET);
1345 if (m_departure_location) {
1346 GetDlgItem(IDC_DEPARTURE_TARGET)->EnableWindow(TRUE);
1347 if (m_departure_target < 0) {
1348 m_departure_target = 0;
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 );
1355 // I think that this section is currently illegal
1359 m_departure_target = -1;
1360 GetDlgItem(IDC_DEPARTURE_TARGET)->EnableWindow(FALSE);
1365 // see if hotkey should possibly be reserved for player starting wing
1366 void wing_editor::OnSelchangeHotkey()
1372 set_num = m_hotkey - 1; // hotkey sets are 1 index based
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]) )
1379 if ( i == MAX_STARTING_WINGS )
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 );